背景
使用了restful的小伙伴對于導出這些需求本能就是拒絕的~破壞了restful的url的一致性【嚴格矯正 不是http json就是restful 很多小伙伴都會吧暴露出一個json就直接稱為restful 】
正如上文的代碼生成器 我們會批量生成一堆代碼 其中絕大部分都是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 = "新建實體" , notes = "" ) public result add( @requestbody v vo) { service.saveselective(vo); return resultgenerator.gensuccessresult(); } @deletemapping ( "/{id}" ) @apioperation (value = "刪除實體" , notes = "" ) public result delete( @pathvariable pk id) { service.deletebyid(id); return resultgenerator.gensuccessresult(); } @putmapping @apioperation (value = "更新實體" , notes = "" ) public result update( @requestbody v vo) { service.updatebyprimarykeyselective(vo); return resultgenerator.gensuccessresult(); } @getmapping @apioperation (value = "獲取實體列表" , 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 , "數據" ); 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 = "獲取單個實體" , notes = "" ) public result detail( @pathvariable pk id) { v vo = service.findbyid(id); return resultgenerator.gensuccessresult(vo); } @deletemapping ( "/batch" ) @apioperation (value = "批量刪除實體" , notes = "" ) public result batchdelete( @requestparam string ids) { service.deletebyids(ids); return resultgenerator.gensuccessresult(); } @getmapping ( "/batch" ) @apioperation (value = "批量獲取實體" , notes = "" ) public result batchdetail( @requestparam string ids) { list<v> vos = service.findbyids(ids); return resultgenerator.gensuccessresult(vos); } @postmapping ( "/batch" ) @apioperation (value = "批量新建實體" , notes = "" ) public result add( @requestbody list<v> vos) { service.save(vos); return resultgenerator.gensuccessresult(); } @getmapping ( "/count" ) @apioperation (value = "獲取實體數目" , notes = "" ) public result count( @requestbody v v) { int count = service.selectcount(v); return resultgenerator.gensuccessresult(count); } |
那么導出如何做呢?【其實可以理解成導出就是數據的展示 不過此時結果不是json而已】
拋出一個問題那么登錄登出呢?傳統的方案都是login logout 那么換成restful資源的思路是啥呢?
提示: 登錄就是session的新建 登出就是session的刪除
實現
基于上述思路 我們自然就想到了那么我們只需要對同一個url返回多種結果不就ok了?【pdf一個版本 json一個版本 xml一個版本 xls一個版本】
bingo!這個是內容協商器的由來
內容協商器并不是spring創造出來的 事實上這個從http頭里面也能看出
1.比如給英語客戶返回英語頁面 過于客戶返回漢語頁面
http 協議中定義了質量值(簡稱 q 值),允許客戶端為每種偏好類別列出多種選項,并為每種偏好選項關聯一個優先次序。
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 是優先級最低的,而 1.0 是優先級最高的)。
注意,偏好的排列順序并不重要,只有與偏好相關的 q 值才是重要的
2.那么還有其他的一些參數 比如 accept-header
通常是先內容協商器有如下幾種方案
1.使用accept header:
這一種為教科書中通常描述的一種,理想中這種方式也是最好的,但如果你的資源要給用戶直接通過瀏覽器訪問(即html展現),那么由于瀏覽器的差異,發送上來的accept header頭將是不一樣的. 將導致服務器不知要返回什么格式的數據給你. 下面是瀏覽器的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.使用擴展名
喪失了同一url多種展現的方式,但現在這種在實際環境中是使用最多的.因為更加符合程序員的審美觀.
比如/user.json /user.xls /user.xml
使用參數 現在很多open api是使用這種方式,比如淘寶
但是對于不同瀏覽器可能accept-header并不是特別統一 因此許多實現選擇了2 3兩種方案
我們在spring中采用上述兩種方案
首先配置內容協商器
代碼
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); } |
創建對應的轉換器
1
2
3
4
|
private httpmessageconverter<object> createexcelhttpmessageconverter() { excelhttpmessageconverter excelhttpmessageconverter = new excelhttpmessageconverter(); return excelhttpmessageconverter; } |
直接使用easy-poi導出數據
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); } } |
暫時只是針對導出 因此在使用的時候如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@getmapping @apioperation (value = "獲取實體列表" , 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 , "數據" ); excelexportparam<v> param = new excelexportparam<>(); param.setclazz(voclazz); param.setexcelexport(excelexport.normalexcel); param.setexportparams(ep); param.setfilename( "文件.xls" ); f6static.setexcelexportparam(param); } |
當我們訪問時如下
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" } |
當訪問http://127.0.0.1:8079/zeus/user?format=xls 或者http://127.0.0.1:8079/zeus/user.xls
如下效果
由于這邊的數據和查詢有關 因此我們可以這樣操作http://127.0.0.1:8079/zeus/user.xls?pagesize=1000 輕而易舉實現了查詢結果xls化!
總結
以上所述是小編給大家介紹的springboot中的內容協商器圖解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://www.jianshu.com/p/f7b257585d9a