ResponseBodyAdvice踩坑及解決
場(chǎng)景
通過ResponseBodyAdvice實(shí)現(xiàn)Rest接口的日志統(tǒng)一管理
正文
ResponseBodyAdvice原理自己百度,代碼比較少但是我實(shí)踐的時(shí)候發(fā)現(xiàn)有幾個(gè)坑需要注意一下
@RestControllerAdvice(basePackages = "com.alan.api.controller") public class ApiResponseBodyAdvice implements ResponseBodyAdvice { static org.slf4j.Logger logger = LoggerFactory.getLogger("logback_api"); @Override public boolean supports(MethodParameter returnType, Class converterType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest serverHttpRequest, ServerHttpResponse response) { HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); if(request != null){ Object obj = request.getSession().getAttribute(BaseController.session_user); String path = request.getServletPath(); if (StringUtils.isBlank(path)) { path = request.getPathInfo(); } if (obj != null) { path = request.getPathInfo(); logger.info("userId:"+ ((DataUser) obj).getUserId()); } logger.info("url:"+ path); logger.info("request:"+ JSON.toJSONString(request.getParameterMap())); logger.info("response:"+body); } return body; } }
沒了就這么簡(jiǎn)單
生效可能情況
1.ApiResponseBodyAdvice bean沒有scan,沒有什么配置
2.如果Controller的注解為@Controller,生效的方法為@ResponseBody
3.supports()支持類型返回false,beforeBodyWrite()不調(diào)用
spring切面接口ResponseBodyAdvice的分析及使用
ResponseBodyAdvice接口屬于springMVC 和springBoot框架基礎(chǔ)的底層切面接口;實(shí)現(xiàn)這個(gè)接口的類,可以修改直接作為 ResponseBody類型處理器的返回值,即進(jìn)行功能增強(qiáng)。
1、有兩種類型的處理器會(huì)將返回值作為ResponseBody:
返回值為HpptEntity
加了@ResponseBody或@RestController注解,
實(shí)現(xiàn)了這個(gè)接口的類,處理返回的json值在傳遞給 HttpMessageConverter之前;應(yīng)用場(chǎng)景在spring項(xiàng)目開發(fā)過程中,對(duì)controller層返回值進(jìn)行修改增強(qiáng)處理。比如返回值5,需要封裝成
{"code":"0","data":5,,"msg":"success"}格式返回前端
接口源碼如下:
public interface ResponseBodyAdvice<T> { / * * *該組件是否支持給定的控制器方法返回類型 *和選擇的{@code HttpMessageConverter}類型。 返回類型 * @param converterType選擇的轉(zhuǎn)換器類型 * @return {@code true}如果{@link #beforeBodyWrite}應(yīng)該被調(diào)用; * {@code false}否則 * / boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType); / * * *在{@code HttpMessageConverter}被選中之后和之前調(diào)用 *它的write方法被調(diào)用。 * @param body要寫入的主體 控制器方法的返回類型: * @param selectedContentType通過內(nèi)容協(xié)商選擇的內(nèi)容類型 * @param selectedConverterType選擇寫入響應(yīng)的轉(zhuǎn)換器類型 * @param request當(dāng)前請(qǐng)求 * @param response當(dāng)前響應(yīng) * @return傳入的主體或修改過的(可能是新的)實(shí)例 * / @Nullable T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response); }
2、應(yīng)用場(chǎng)景在spring項(xiàng)目開發(fā)過程中
對(duì)controller層返回值進(jìn)行修改增強(qiáng)處理。比如返回值5,需要封裝成
{"code":"0","data":5,,"msg":"success"} 格式返回前端
controller層業(yè)務(wù)代碼:
@RestController //此注解包含@ResponseBody注解 @RequestMapping("/nandao") public class ResponseBodyAdviceController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public int hello() { //業(yè)務(wù)代碼省略 return 5; } }
實(shí)現(xiàn)ResponseBodyAdvice接口的切面類:
/** *此注解針對(duì)controller層的類做增強(qiáng)功能,即對(duì)加了@RestController注解的類進(jìn)行處理 */ @ControllerAdvice(annotations = RestController.class) public class RestResultWrapper implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //定義一個(gè)統(tǒng)一的返回類 RestResult responseResult = new RestResult( "0", body, "success"); //如果handler處理類的返回類型是String(即控制層的返回值類型),為了保證一致性,這里需要將ResponseResult轉(zhuǎn)回去 if(body instanceof String) { return JSON.toJSONString(responseResult); } //封裝后的數(shù)據(jù)返回到前端頁(yè)面 return JSONObject.toJSON(responseResult); } }
返回公共類的創(chuàng)建:
/** * @author nandao * Created on 2021/1/12-21:47. * 統(tǒng)一返回Rest風(fēng)格的數(shù)據(jù)結(jié)構(gòu) */ public class RestResult<T> implements Serializable { /** * 成功的code碼 */ private String code = "2000"; /** * 成功時(shí)返回的數(shù)據(jù),失敗時(shí)返回具體的異常信息 */ private T data; /** * 請(qǐng)求失敗返回的提示信息,給前端進(jìn)行頁(yè)面展示的信息 */ private String message ; public RestResult() { } @Override public String toString() { return "RestResult{" + "code='" + code + '\'' + ", data=" + data + ", message=" + message + '}'; } public RestResult(String code, T data, String message) { this.code = code; this.data = data; this.message = message; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
到此切面增強(qiáng)功能就實(shí)現(xiàn)了,可以直接在實(shí)戰(zhàn)項(xiàng)目中使用。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 8 Function函數(shù)式接口及函數(shù)式接口實(shí)例
函數(shù)式接口(Functional Interface)就是一個(gè)有且僅有一個(gè)抽象方法,但是可以有多個(gè)非抽象方法的接口。接下來(lái)通過本文給大家介紹Java 8 Function函數(shù)式接口及函數(shù)式接口實(shí)例代碼,需要的朋友可以參考下2018-05-05SpringBoot整合Drools的實(shí)現(xiàn)步驟
Drools是一個(gè)易于訪問企業(yè)策略、易于調(diào)整以及易于管理的開源業(yè)務(wù)規(guī)則引擎,符合業(yè)內(nèi)標(biāo)準(zhǔn),速度快、效率高。業(yè)務(wù)分析師或?qū)徍巳藛T可以利用它輕松查看業(yè)務(wù)規(guī)則,從而檢驗(yàn)是否已編碼的規(guī)則執(zhí)行所需的業(yè)務(wù)規(guī)則。本文將講述SpringBoot整合Drools的步驟2021-05-05Java排序之Comparable和Comparator比較器詳解
這篇文章主要介紹了Java排序之Comparable和Comparator比較器詳解,Comparable<T>是內(nèi)部比較器,Comparator<T>是外部比較器,最推薦使用Comparator<T>接口排序,Comparator提供靜態(tài)方法很方便,推薦使用,需要的朋友可以參考下2024-01-01Spring Data JPA使用JPQL與原生SQL進(jìn)行查詢的操作
這篇文章主要介紹了Spring Data JPA使用JPQL與原生SQL進(jìn)行查詢的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06一文搞懂并學(xué)會(huì)使用SpringBoot的Actuator運(yùn)行狀態(tài)監(jiān)控組件的詳細(xì)教程
這篇文章主要介紹了一文搞懂并學(xué)會(huì)使用SpringBoot的Actuator運(yùn)行狀態(tài)監(jiān)控組件,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09java數(shù)據(jù)結(jié)構(gòu)與算法之冒泡排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之冒泡排序,結(jié)合實(shí)例形式詳細(xì)分析了java冒泡排序的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05Java switch case數(shù)據(jù)類型原理解析
這篇文章主要介紹了Java switch case數(shù)據(jù)類型原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題
這篇文章主要介紹了關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06java解析xml匯總_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了java解析xml匯總_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-07-07