场景
通过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