场景
通过ResponseBodyAdvice实现Rest接口的日志统一管理
正文
ResponseBodyAdvice原理自己百度,代码比较少但是我实践的时候发现有几个坑需要注意一下
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 |
@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()不调用
spring切面接口ResponseBodyAdvice的分析及使用
ResponseBodyAdvice接口属于springMVC 和springBoot框架基础的底层切面接口;实现这个接口的类,可以修改直接作为 ResponseBody类型处理器的返回值,即进行功能增强。
1、有两种类型的处理器会将返回值作为ResponseBody:
返回值为HpptEntity
加了@ResponseBody或@RestController注解,
实现了这个接口的类,处理返回的json值在传递给 HttpMessageConverter之前;应用场景在spring项目开发过程中,对controller层返回值进行修改增强处理。比如返回值5,需要封装成
{"code":"0","data":5,,"msg":"success"}格式返回前端
接口源码如下:
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 |
public interface ResponseBodyAdvice<T> { / * * *该组件是否支持给定的控制器方法返回类型 *和选择的{ @code HttpMessageConverter}类型。 返回类型 * @param converterType选择的转换器类型 * @return { @code true }如果{ @link #beforeBodyWrite}应该被调用; * { @code false }否则 * / boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType); / * * *在{ @code HttpMessageConverter}被选中之后和之前调用 *它的write方法被调用。 * @param body要写入的主体 控制器方法的返回类型: * @param selectedContentType通过内容协商选择的内容类型 * @param selectedConverterType选择写入响应的转换器类型 * @param request当前请求 * @param response当前响应 * @return 传入的主体或修改过的(可能是新的)实例 * / @Nullable T beforeBodyWrite( @Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response); } |
2、应用场景在spring项目开发过程中
对controller层返回值进行修改增强处理。比如返回值5,需要封装成
{"code":"0","data":5,,"msg":"success"} 格式返回前端
controller层业务代码:
1 2 3 4 5 6 7 8 9 10 |
@RestController //此注解包含@ResponseBody注解 @RequestMapping ( "/nandao" ) public class ResponseBodyAdviceController {
@RequestMapping (value = "/hello" , method = RequestMethod.GET) public int hello() { //业务代码省略 return 5 ; } } |
实现ResponseBodyAdvice接口的切面类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/** *此注解针对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) {
//定义一个统一的返回类 RestResult responseResult = new RestResult( "0" , body, "success" ); //如果handler处理类的返回类型是String(即控制层的返回值类型),为了保证一致性,这里需要将ResponseResult转回去 if (body instanceof String) { return JSON.toJSONString(responseResult); } //封装后的数据返回到前端页面 return JSONObject.toJSON(responseResult); } } |
返回公共类的创建:
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 |
/** * @author nandao * Created on 2021/1/12-21:47. * 统一返回Rest风格的数据结构 */ public class RestResult<T> implements Serializable {
/** * 成功的code码 */ private String code = "2000" ; /** * 成功时返回的数据,失败时返回具体的异常信息 */ 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; } } |
到此切面增强功能就实现了,可以直接在实战项目中使用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
原文链接:https://blog.csdn.net/zuo_xiaosi/article/details/103520172
查看更多关于ResponseBodyAdvice踩坑及解决的详细内容...