- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- Spring Boot統一返回體的踩坑記錄
在Spring Boot項目中我們可以通過(guò)RestControllerAdvice配合實(shí)現ResponseBodyAdvice<T>接口來(lái)保證Spring MVC接口具有統一的返回格式,以保證前端同學(xué)能夠封裝統一的數據接收工具。但是很多網(wǎng)上的文章并沒(méi)有對實(shí)際開(kāi)發(fā)中的細節作出更多的講解。今天胖哥就來(lái)分享一下我的采坑經(jīng)歷,也算作一個(gè)總結。
我記得在前面關(guān)于Swagger3的文章中提過(guò),如果我們不指定范圍將導致Swagger無(wú)法識別接口的元信息。因此如果你使用了Swagger必須指定其范圍,這里你可以通過(guò)指定掃描包來(lái)指定其作用域:
@RestControllerAdvice("cn.felord.controller")
如果你的Spring MVC控制器有統一的父類(lèi)控制器的話(huà),
@RestController @RequestMapping("/foo") public class FooController extends BaseController { //todo 省略 }
也可以這樣:
@RestControllerAdvice(assignableTypes = BaseController.class)
有些接口可能根據業(yè)務(wù)需要或者協(xié)議需要不能使用統一返回體,例如支付的通知應答。這就需要一個(gè)類(lèi)似白名單的機制來(lái)繞過(guò)統一返回體控制器通知類(lèi)。我們可以借助于ResponseBodyAdvice<T>的下列方法實(shí)現:
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
這個(gè)方法如果返回false就表示不執行統一返回體的封裝邏輯。這里我推薦注解實(shí)現。定義一個(gè)標記注解,可以定義在類(lèi)上或者方法上:
@Documented @Inherited @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface IgnoreRestBody { }
然后上面的supports方法這樣實(shí)現:
@Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return !returnType.hasMethodAnnotation(IgnoreRestBody.class); }
如果某個(gè)Controller下所有的方法都繞過(guò),就把這個(gè)注解標記在控制器類(lèi)上;如果只想忽略某個(gè)方法上就把它標記在該方法上即可。
有些接口我們會(huì )返回一個(gè)字符串:
@GetMapping("/get") public String getStr(){ //返回了一個(gè)字符串 return "felord.cn"; }
我們希望這個(gè)字符串被統一返回體處理,類(lèi)似這樣:
{ code: 200, data: "felord.cn", msg: "返回成字符串", }
但是你會(huì )發(fā)現并沒(méi)有達到期望的效果,會(huì )拋出類(lèi)型轉換異常。這是因為當我們的Spring MVC接口返回數據時(shí),會(huì )根據Content-Type來(lái)選擇一個(gè)HttpMessageConverter來(lái)處理,而字符串在不聲明Content-Type的情況下優(yōu)先使用StringHttpMessageConverter ,就導致了轉換異常,需要設定成MappingJackson2HttpMessageConverter用Jackson來(lái)處理,Spring MVC的對應配置如下:
@Configuration(proxyBeanMethods = false) public class SpringMvcConfiguration implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 解決 String 統一封裝RestBody的問(wèn)題 converters.add(0, new MappingJackson2HttpMessageConverter()); } }
嗯,這樣就起效了!你以為這樣就完了?你會(huì )發(fā)現你的JSON序列化不按照你設置的策略執行了。因為你new了一個(gè)而不是采用系統初始化的那個(gè)。解決方法為,將Spring IoC中的ObjectMapper注入到MappingJackson2HttpMessageConverter中去?;蛘吣闶褂肈ebug調試出系統默認的MappingJackson2HttpMessageConverter的位置,比如我的索引為7,就可以這樣配置:
@Configuration(proxyBeanMethods = false) public class SpringMvcConfiguration implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 解決 String 統一封裝RestBody的問(wèn)題 HttpMessageConverter<?> httpMessageConverter = converters.get(7); if (!(httpMessageConverter instanceof MappingJackson2HttpMessageConverter)) { // 確保正確,如果有改動(dòng)就重新debug throw new RuntimeException("MappingJackson2HttpMessageConverter is not here"); } converters.add(0, httpMessageConverter); } }
曾經(jīng)一個(gè)安卓開(kāi)發(fā)同學(xué)說(shuō),你這統一結構中的data如果是數組:
{ code: 200, data: ['a','b'], msg: "返回成字符串", }
后續如果data添加其它與數組沒(méi)有關(guān)系的屬性就不兼容了,你應該保證這個(gè)data是個(gè)Map。是的,這也是問(wèn)題,實(shí)際中發(fā)現不僅僅是數組,如果是int、long等原始類(lèi)型或者String類(lèi)型都面臨這種情況,需要加一個(gè)額外的判斷body是不是可能改變data類(lèi)型的類(lèi)型:
private boolean checkPrimitive(Object body) { Class<?> clazz = body.getClass(); return clazz.isPrimitive() || clazz.isArray() || Collection.class.isAssignableFrom(clazz) || body instanceof Number || body instanceof Boolean || body instanceof Character || body instanceof String; }
然后我們在ResponseBodyAdvice<T>實(shí)現中增加一個(gè)判斷:
// 增強擴展性 if (checkPrimitive(body)) { return RestBody.okData(Collections.singletonMap("result", body)); }
就解決問(wèn)題了。
今天對Spring Boot中統一返回體的一些細節問(wèn)題進(jìn)行了分享,希望能夠幫助你解決一些實(shí)際開(kāi)發(fā)中遇到的同樣問(wèn)題。
到此這篇關(guān)于Spring Boot統一返回體踩坑記錄的文章就介紹到這了,更多相關(guān)Spring Boot統一返回體內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站