ResponseBodyAdvice踩坑及解决

2025-05-29 0 100

场景

通过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;

}

}

到此切面增强功能就实现了,可以直接在实战项目中使用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持快网idc。

原文链接:https://blog.csdn.net/zuo_xiaosi/article/details/103520172

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 ResponseBodyAdvice踩坑及解决 https://www.kuaiidc.com/104586.html

相关文章

发表评论
暂无评论