ResponseBodyAdvice踩坑及解決
場景
通過ResponseBodyAdvice實現(xiàn)Rest接口的日志統(tǒng)一管理
正文
ResponseBodyAdvice原理自己百度,代碼比較少但是我實踐的時候發(fā)現(xiàn)有幾個坑需要注意一下
@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;
}
}
沒了就這么簡單
生效可能情況
1.ApiResponseBodyAdvice bean沒有scan,沒有什么配置
2.如果Controller的注解為@Controller,生效的方法為@ResponseBody
3.supports()支持類型返回false,beforeBodyWrite()不調(diào)用
spring切面接口ResponseBodyAdvice的分析及使用
ResponseBodyAdvice接口屬于springMVC 和springBoot框架基礎(chǔ)的底層切面接口;實現(xiàn)這個接口的類,可以修改直接作為 ResponseBody類型處理器的返回值,即進行功能增強。
1、有兩種類型的處理器會將返回值作為ResponseBody:
返回值為HpptEntity
加了@ResponseBody或@RestController注解,
實現(xiàn)了這個接口的類,處理返回的json值在傳遞給 HttpMessageConverter之前;應(yīng)用場景在spring項目開發(fā)過程中,對controller層返回值進行修改增強處理。比如返回值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當前請求
* @param response當前響應(yīng)
* @return傳入的主體或修改過的(可能是新的)實例
* /
@Nullable
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
}
2、應(yīng)用場景在spring項目開發(fā)過程中
對controller層返回值進行修改增強處理。比如返回值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;
}
}
實現(xiàn)ResponseBodyAdvice接口的切面類:
/**
*此注解針對controller層的類做增強功能,即對加了@RestController注解的類進行處理
*/
@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) {
//定義一個統(tǒng)一的返回類
RestResult responseResult = new RestResult( "0", body, "success");
//如果handler處理類的返回類型是String(即控制層的返回值類型),為了保證一致性,這里需要將ResponseResult轉(zhuǎn)回去
if(body instanceof String) {
return JSON.toJSONString(responseResult);
}
//封裝后的數(shù)據(jù)返回到前端頁面
return JSONObject.toJSON(responseResult);
}
}
返回公共類的創(chuàng)建:
/**
* @author nandao
* Created on 2021/1/12-21:47.
* 統(tǒng)一返回Rest風格的數(shù)據(jù)結(jié)構(gòu)
*/
public class RestResult<T> implements Serializable {
/**
* 成功的code碼
*/
private String code = "2000";
/**
* 成功時返回的數(shù)據(jù),失敗時返回具體的異常信息
*/
private T data;
/**
* 請求失敗返回的提示信息,給前端進行頁面展示的信息
*/
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;
}
}
到此切面增強功能就實現(xiàn)了,可以直接在實戰(zhàn)項目中使用。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 8 Function函數(shù)式接口及函數(shù)式接口實例
函數(shù)式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。接下來通過本文給大家介紹Java 8 Function函數(shù)式接口及函數(shù)式接口實例代碼,需要的朋友可以參考下2018-05-05
Java排序之Comparable和Comparator比較器詳解
這篇文章主要介紹了Java排序之Comparable和Comparator比較器詳解,Comparable<T>是內(nèi)部比較器,Comparator<T>是外部比較器,最推薦使用Comparator<T>接口排序,Comparator提供靜態(tài)方法很方便,推薦使用,需要的朋友可以參考下2024-01-01
Spring Data JPA使用JPQL與原生SQL進行查詢的操作
這篇文章主要介紹了Spring Data JPA使用JPQL與原生SQL進行查詢的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
一文搞懂并學會使用SpringBoot的Actuator運行狀態(tài)監(jiān)控組件的詳細教程
這篇文章主要介紹了一文搞懂并學會使用SpringBoot的Actuator運行狀態(tài)監(jiān)控組件,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
java數(shù)據(jù)結(jié)構(gòu)與算法之冒泡排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之冒泡排序,結(jié)合實例形式詳細分析了java冒泡排序的原理、實現(xiàn)技巧與相關(guān)注意事項,需要的朋友可以參考下2017-05-05
Java switch case數(shù)據(jù)類型原理解析
這篇文章主要介紹了Java switch case數(shù)據(jù)類型原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01
關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題
這篇文章主要介紹了關(guān)于SpringBoot2.7.6連接nacos遇到的一些問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06

