好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ResponseBodyAdvice踩坑及解决

场景

通过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踩坑及解决的详细内容...

  阅读:18次