您好,登錄后才能下訂單哦!
背景
使用了restful的小伙伴對(duì)于導(dǎo)出這些需求本能就是拒絕的~破壞了restful的url的一致性【嚴(yán)格矯正 不是http json就是restful 很多小伙伴都會(huì)吧暴露出一個(gè)json就直接稱為restful 】
正如上文的代碼生成器 我們會(huì)批量生成一堆代碼 其中絕大部分都是RestController
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ù)的展示 不過(guò)此時(shí)結(jié)果不是json而已】
拋出一個(gè)問(wèn)題那么登錄登出呢?傳統(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é)商器的由來(lái)
內(nèi)容協(xié)商器并不是Spring創(chuàng)造出來(lái)的 事實(shí)上這個(gè)從http頭里面也能看出
1.比如給英語(yǔ)客戶返回英語(yǔ)頁(yè)面 過(guò)于客戶返回漢語(yǔ)頁(yè)面
HTTP 協(xié)議中定義了質(zhì)量值(簡(jiǎn)稱 q 值),允許客戶端為每種偏好類別列出多種選項(xiàng),并為每種偏好選項(xiàng)關(guān)聯(lián)一個(gè)優(yōu)先次序。
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:
這一種為教科書(shū)中通常描述的一種,理想中這種方式也是最好的,但如果你的資源要給用戶直接通過(guò)瀏覽器訪問(wèn)(即html展現(xiàn)),那么由于瀏覽器的差異,發(fā)送上來(lái)的Accept Header頭將是不一樣的. 將導(dǎo)致服務(wù)器不知要返回什么格式的數(shù)據(jù)給你. 下面是瀏覽器的Accept Header
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é)商器
代碼
@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)換器
private HttpMessageConverter<Object> createExcelHttpMessageConverter() { ExcelHttpMessageConverter excelHttpMessageConverter = new ExcelHttpMessageConverter(); return excelHttpMessageConverter; }
直接使用easy-poi導(dǎo)出數(shù)據(jù)
/* * 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í)候如下
@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問(wèn)時(shí)如下
http://127.0.0.1:8079/zeus/user
{ "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)訪問(wèn)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ì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。