背景
使用了restful的小伙伴對(duì)于導(dǎo)出這些需求本能就是拒絕的~破壞了restful的url的一致性【嚴(yán)格矯正 不是http json就是restful 很多小伙伴都會(huì)吧暴露出一個(gè)json就直接稱為restful 】
正如上文的代碼生成器 我們會(huì)批量生成一堆代碼 其中絕大部分都是restcontroller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
public abstract class abstractrestcontroller<v extends vo, s extends so, pk extends serializable> { protected class <v> voclazz; @autowired private service<v, s, pk> service; public abstractrestcontroller() { typetoken<v> votype = new typetoken<v>(getclass()) { }; voclazz = ( class <v>) votype.getrawtype(); } @postmapping () @apioperation (value = "新建實(shí)體" , notes = "" ) public result add( @requestbody v vo) { service.saveselective(vo); return resultgenerator.gensuccessresult(); } @deletemapping ( "/{id}" ) @apioperation (value = "刪除實(shí)體" , notes = "" ) public result delete( @pathvariable pk id) { service.deletebyid(id); return resultgenerator.gensuccessresult(); } @putmapping @apioperation (value = "更新實(shí)體" , notes = "" ) public result update( @requestbody v vo) { service.updatebyprimarykeyselective(vo); return resultgenerator.gensuccessresult(); } @getmapping @apioperation (value = "獲取實(shí)體列表" , notes = "" ) public result list(s so) { pagehelper.startpage(so.getcurrentpage(), so.getpagesize()); list<v> list = service.findall(); pageinfo pageinfo = new pageinfo(list); excelexportparam(); return resultgenerator.gensuccessresult(pageinfo); } protected void excelexportparam() { exportparams ep = new exportparams( null , "數(shù)據(jù)" ); excelexportparam<v> param = new excelexportparam<>(); param.setclazz(voclazz); param.setexcelexport(excelexport.normalexcel); param.setexportparams(ep); param.setfilename( "文件.xls" ); f6static.setexcelexportparam(param); } @getmapping ( "/{id}" ) @apioperation (value = "獲取單個(gè)實(shí)體" , notes = "" ) public result detail( @pathvariable pk id) { v vo = service.findbyid(id); return resultgenerator.gensuccessresult(vo); } @deletemapping ( "/batch" ) @apioperation (value = "批量刪除實(shí)體" , notes = "" ) public result batchdelete( @requestparam string ids) { service.deletebyids(ids); return resultgenerator.gensuccessresult(); } @getmapping ( "/batch" ) @apioperation (value = "批量獲取實(shí)體" , notes = "" ) public result batchdetail( @requestparam string ids) { list<v> vos = service.findbyids(ids); return resultgenerator.gensuccessresult(vos); } @postmapping ( "/batch" ) @apioperation (value = "批量新建實(shí)體" , notes = "" ) public result add( @requestbody list<v> vos) { service.save(vos); return resultgenerator.gensuccessresult(); } @getmapping ( "/count" ) @apioperation (value = "獲取實(shí)體數(shù)目" , notes = "" ) public result count( @requestbody v v) { int count = service.selectcount(v); return resultgenerator.gensuccessresult(count); } |
那么導(dǎo)出如何做呢?【其實(shí)可以理解成導(dǎo)出就是數(shù)據(jù)的展示 不過此時(shí)結(jié)果不是json而已】
拋出一個(gè)問題那么登錄登出呢?傳統(tǒng)的方案都是login logout 那么換成restful資源的思路是啥呢?
提示: 登錄就是session的新建 登出就是session的刪除
實(shí)現(xiàn)
基于上述思路 我們自然就想到了那么我們只需要對(duì)同一個(gè)url返回多種結(jié)果不就ok了?【pdf一個(gè)版本 json一個(gè)版本 xml一個(gè)版本 xls一個(gè)版本】
bingo!這個(gè)是內(nèi)容協(xié)商器的由來
內(nèi)容協(xié)商器并不是spring創(chuàng)造出來的 事實(shí)上這個(gè)從http頭里面也能看出
1.比如給英語(yǔ)客戶返回英語(yǔ)頁(yè)面 過于客戶返回漢語(yǔ)頁(yè)面
http 協(xié)議中定義了質(zhì)量值(簡(jiǎn)稱 q 值),允許客戶端為每種偏好類別列出多種選項(xiàng),并為每種偏好選項(xiàng)關(guān)聯(lián)一個(gè)優(yōu)先次序。
1
|
accept-language: en;q= 0.5 , fr;q= 0.0 , nl;q= 1.0 , tr;q= 0.0 |
其中 q 值的范圍從 0.0 ~ 1.0(0.0 是優(yōu)先級(jí)最低的,而 1.0 是優(yōu)先級(jí)最高的)。
注意,偏好的排列順序并不重要,只有與偏好相關(guān)的 q 值才是重要的
2.那么還有其他的一些參數(shù) 比如 accept-header
通常是先內(nèi)容協(xié)商器有如下幾種方案
1.使用accept header:
這一種為教科書中通常描述的一種,理想中這種方式也是最好的,但如果你的資源要給用戶直接通過瀏覽器訪問(即html展現(xiàn)),那么由于瀏覽器的差異,發(fā)送上來的accept header頭將是不一樣的. 將導(dǎo)致服務(wù)器不知要返回什么格式的數(shù)據(jù)給你. 下面是瀏覽器的accept header
1
2
3
4
5
6
|
chrome: accept:application/xml,application/xhtml+xml,textml;q= 0.9 ,text/plain;q= 0.8 ,image/png,* /*;q=0.5 firefox: accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 ie8: accept:image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */ * |
2.使用擴(kuò)展名
喪失了同一url多種展現(xiàn)的方式,但現(xiàn)在這種在實(shí)際環(huán)境中是使用最多的.因?yàn)楦臃铣绦騿T的審美觀.
比如/user.json /user.xls /user.xml
使用參數(shù) 現(xiàn)在很多open api是使用這種方式,比如淘寶
但是對(duì)于不同瀏覽器可能accept-header并不是特別統(tǒng)一 因此許多實(shí)現(xiàn)選擇了2 3兩種方案
我們?cè)趕pring中采用上述兩種方案
首先配置內(nèi)容協(xié)商器
代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@bean public viewresolver contentnegotiatingviewresolver( contentnegotiationmanager manager) { // define the view resolvers viewresolver beannameviewresolver = new beannameviewresolver(); list<viewresolver> resolvers = lists.newarraylist(beannameviewresolver); contentnegotiatingviewresolver resolver = new contentnegotiatingviewresolver(); resolver.setviewresolvers(resolvers); resolver.setcontentnegotiationmanager(manager); return resolver; } @override public void configurecontentnegotiation(contentnegotiationconfigurer configurer) { configurer.favorpathextension( true ) .usejaf( false ) .favorparameter( true ) .parametername( "format" ) .ignoreacceptheader( true ) .defaultcontenttype(mediatype.application_json) .mediatype( "json" , mediatype.application_json) .mediatype( "xls" , excel_media_type); } |
創(chuàng)建對(duì)應(yīng)的轉(zhuǎn)換器
1
2
3
4
|
private httpmessageconverter<object> createexcelhttpmessageconverter() { excelhttpmessageconverter excelhttpmessageconverter = new excelhttpmessageconverter(); return excelhttpmessageconverter; } |
直接使用easy-poi導(dǎo)出數(shù)據(jù)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/* * copyright (c) 2017. lorem ipsum dolor sit amet, consectetur adipiscing elit. * morbi non lorem porttitor neque feugiat blandit. ut vitae ipsum eget quam lacinia accumsan. * etiam sed turpis ac ipsum condimentum fringilla. maecenas magna. * proin dapibus sapien vel ante. aliquam erat volutpat. pellentesque sagittis ligula eget metus. * vestibulum commodo. ut rhoncus gravida arcu. */ package com.f6car.base.web.converter; import cn.afterturn.easypoi.excel.excelexportutil; import com.f6car.base.common.result; import com.f6car.base.core.excelexport; import com.f6car.base.core.excelexportparam; import com.github.pagehelper.pageinfo; import com.google.common.collect.lists; import org.apache.poi.ss.usermodel.workbook; import org.springframework.http.httpheaders; import org.springframework.http.httpinputmessage; import org.springframework.http.httpoutputmessage; import org.springframework.http.mediatype; import org.springframework.http.converter.abstracthttpmessageconverter; import org.springframework.http.converter.generichttpmessageconverter; import org.springframework.http.converter.httpmessagenotreadableexception; import org.springframework.http.converter.httpmessagenotwritableexception; import java.io.ioexception; import java.lang.reflect.type; import java.net.urlencoder; import java.util.collection; import java.util.collections; import java.util.map; import static com.f6car.base.core.f6static.getexcelexportparam; /** * @author qixiaobo */ public class excelhttpmessageconverter extends abstracthttpmessageconverter<object> implements generichttpmessageconverter<object> { public static final mediatype excel_media_type = new mediatype( "application" , "vnd.ms-excel" ); public excelhttpmessageconverter() { super (excel_media_type); } @override protected boolean supports( class <?> clazz) { return false ; } @override protected object readinternal( class <?> clazz, httpinputmessage inputmessage) throws ioexception, httpmessagenotreadableexception { return null ; } @override protected void writeinternal(object o, httpoutputmessage outputmessage) throws ioexception, httpmessagenotwritableexception { httpheaders headers = outputmessage.getheaders(); collection data = getactualdata((result) o); excelexportparam excelexportparam = getexcelexportparam(); workbook workbook; switch (excelexportparam.getexcelexport()) { case normalexcel: workbook = excelexportutil.exportexcel( excelexportparam.getexportparams(), ( class <?>) excelexportparam.getclazz(), (collection<?>) data); break ; case mapexcel: workbook = excelexportutil.exportexcel( excelexportparam.getexportparams(), excelexportparam.getexcelexportentities(), (collection<? extends map<?, ?>>) data); break ; case bigexcel: case mapexcelgraph: case pdftemplate: case templateexcel: case templateword: default : throw new runtimeexception(); } if (workbook != null ) { if (excelexportparam.getfilename() != null ) { string codedfilename = urlencoder.encode(excelexportparam.getfilename(), "utf8" ); headers.setcontentdispositionformdata( "attachment" , codedfilename); } workbook.write(outputmessage.getbody()); } } private collection getactualdata(result r) { if (r != null && r.getdata() != null ) { object data = r.getdata(); if (data instanceof pageinfo) { return ((pageinfo) data).getlist(); } else if (!(data instanceof collection)) { data = lists.newarraylist(data); } else { return (collection) data; } } return collections.emptylist(); } @override public boolean canread(type type, class <?> contextclass, mediatype mediatype) { //不支持excel return false ; } @override public object read(type type, class <?> contextclass, httpinputmessage inputmessage) throws ioexception, httpmessagenotreadableexception { return null ; } @override public boolean canwrite(type type, class <?> clazz, mediatype mediatype) { return super .canwrite(mediatype) && clazz == result. class && support(); } private boolean support() { excelexportparam param = getexcelexportparam(); if (param == null || param.getexcelexport() == null || param.getexportparams() == null ) { return false ; } if (param.getexcelexport() == excelexport.normalexcel) { return true ; } else { logger.warn(param.getexcelexport() + " not supprot now!" ); return false ; } } @override public void write(object o, type type, mediatype contenttype, httpoutputmessage outputmessage) throws ioexception, httpmessagenotwritableexception { super .write(o, contenttype, outputmessage); } } |
暫時(shí)只是針對(duì)導(dǎo)出 因此在使用的時(shí)候如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@getmapping @apioperation (value = "獲取實(shí)體列表" , notes = "" ) public result list(s so) { pagehelper.startpage(so.getcurrentpage(), so.getpagesize()); list<v> list = service.findall(); pageinfo pageinfo = new pageinfo(list); excelexportparam(); return resultgenerator.gensuccessresult(pageinfo); } protected void excelexportparam() { exportparams ep = new exportparams( null , "數(shù)據(jù)" ); excelexportparam<v> param = new excelexportparam<>(); param.setclazz(voclazz); param.setexcelexport(excelexport.normalexcel); param.setexportparams(ep); param.setfilename( "文件.xls" ); f6static.setexcelexportparam(param); } |
當(dāng)我們?cè)L問時(shí)如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
{ "code" : 200 , "data" : { "endrow" : 10 , "firstpage" : 1 , "hasnextpage" : true , "haspreviouspage" : false , "isfirstpage" : true , "islastpage" : false , "lastpage" : 8 , "list" : [ { "cellphone" : "13857445502" , "idemployee" : 24201883434352650 , "idownorg" : 23993199378825296 , "idrole" : 88 , "idwxbstation" : "332" , "idwxbuser" : "207" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 23993199378825296 , "username" : "lingweiqiche" }, { "cellphone" : "" , "idemployee" : 0 , "idownorg" : 9999 , "idrole" : 4 , "idwxbstation" : "" , "idwxbuser" : "" , "isadmin" : 0 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434356532 , "username" : "007" }, { "cellphone" : "15715139000" , "idemployee" : 24351585207523460 , "idownorg" : 24201883434357600 , "idrole" : 89 , "idwxbstation" : "540" , "idwxbuser" : "298" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434357600 , "username" : "15715139000" }, { "cellphone" : "" , "idemployee" : 0 , "idownorg" : 24201883434357600 , "idrole" : 216 , "idwxbstation" : "" , "idwxbuser" : "" , "isadmin" : 0 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434357920 , "username" : "sunlingli" }, { "cellphone" : "" , "idemployee" : 24351585207425676 , "idownorg" : 24201883434359384 , "idrole" : 90 , "idwxbstation" : "348" , "idwxbuser" : "227" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "opzuds_v13we500kxymj6xg_gfee" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434359388 , "username" : "15952920979" }, { "cellphone" : "" , "idemployee" : 0 , "idownorg" : 24201883434359790 , "idrole" : 91 , "idwxbstation" : "315" , "idwxbuser" : "175" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434359790 , "username" : "13809056211" }, { "cellphone" : "18903885585" , "idemployee" : 24201883434366164 , "idownorg" : 24201883434359890 , "idrole" : 92 , "idwxbstation" : "317" , "idwxbuser" : "178" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434359892 , "username" : "18903885585" }, { "cellphone" : "" , "idemployee" : 24351585207425668 , "idownorg" : 24201883434359924 , "idrole" : 93 , "idwxbstation" : "318" , "idwxbuser" : "179" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434359930 , "username" : "13372299595" }, { "cellphone" : "" , "idemployee" : 0 , "idownorg" : 24201883434360052 , "idrole" : 94 , "idwxbstation" : "321" , "idwxbuser" : "188" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434360052 , "username" : "15221250005" }, { "cellphone" : "" , "idemployee" : 0 , "idownorg" : 24201883434360070 , "idrole" : 95 , "idwxbstation" : "325" , "idwxbuser" : "198" , "isadmin" : 1 , "isdel" : 0 , "isguideopen" : 0 , "limitmac" : 0 , "openid" : "" , "password" : "96e79218965eb72c92a549dd5a330112" , "pkid" : 24201883434360070 , "username" : "13837251167" } ], "navigatefirstpage" : 1 , "navigatelastpage" : 8 , "navigatepages" : 8 , "navigatepagenums" : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ], "nextpage" : 2 , "orderby" : "" , "pagenum" : 1 , "pagesize" : 10 , "pages" : 102 , "prepage" : 0 , "size" : 10 , "startrow" : 1 , "total" : 1012 }, "message" : "success" } |
當(dāng)訪問http://127.0.0.1:8079/zeus/user?format=xls 或者h(yuǎn)ttp://127.0.0.1:8079/zeus/user.xls
如下效果
由于這邊的數(shù)據(jù)和查詢有關(guān) 因此我們可以這樣操作http://127.0.0.1:8079/zeus/user.xls?pagesize=1000 輕而易舉實(shí)現(xiàn)了查詢結(jié)果xls化!
總結(jié)
以上所述是小編給大家介紹的springboot中的內(nèi)容協(xié)商器圖解,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!
原文鏈接:http://www.jianshu.com/p/f7b257585d9a