ResponseBodyAdvice踩坑及解决

 更新时间:2021年06月29日 10:10:59   作者:zuo_xiaosi  
这篇文章主要介绍了ResponseBodyAdvice踩坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

场景

通过ResponseBodyAdvice实现Rest接口的日志统一管理

正文

ResponseBodyAdvice原理自己百度,代码比较少但是我实践的时候发现有几个坑需要注意一下

@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"}格式返回前端

接口源码如下:

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层业务代码:

@RestController //此注解包含@ResponseBody注解
@RequestMapping("/nandao")
public class ResponseBodyAdviceController {
 
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public int hello() {
         //业务代码省略
        return 5;
    } 
}

实现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) {
 
            //定义一个统一的返回类
            RestResult responseResult = new RestResult( "0", body, "success");
             //如果handler处理类的返回类型是String(即控制层的返回值类型),为了保证一致性,这里需要将ResponseResult转回去
            if(body instanceof String) {
                return JSON.toJSONString(responseResult);
            }
           //封装后的数据返回到前端页面
            return JSONObject.toJSON(responseResult);       
    } 
}

返回公共类的创建:

/**
 * @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;
    }
}

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java 8 Function函数式接口及函数式接口实例

    Java 8 Function函数式接口及函数式接口实例

    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。接下来通过本文给大家介绍Java 8 Function函数式接口及函数式接口实例代码,需要的朋友可以参考下
    2018-05-05
  • SpringBoot整合Drools的实现步骤

    SpringBoot整合Drools的实现步骤

    Drools是一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行所需的业务规则。本文将讲述SpringBoot整合Drools的步骤
    2021-05-05
  • Java排序之Comparable和Comparator比较器详解

    Java排序之Comparable和Comparator比较器详解

    这篇文章主要介绍了Java排序之Comparable和Comparator比较器详解,Comparable<T>是内部比较器,Comparator<T>是外部比较器,最推荐使用Comparator<T>接口排序,Comparator提供静态方法很方便,推荐使用,需要的朋友可以参考下
    2024-01-01
  • Spring Data JPA使用JPQL与原生SQL进行查询的操作

    Spring Data JPA使用JPQL与原生SQL进行查询的操作

    这篇文章主要介绍了Spring Data JPA使用JPQL与原生SQL进行查询的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • 一文搞懂并学会使用SpringBoot的Actuator运行状态监控组件的详细教程

    一文搞懂并学会使用SpringBoot的Actuator运行状态监控组件的详细教程

    这篇文章主要介绍了一文搞懂并学会使用SpringBoot的Actuator运行状态监控组件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java数据结构与算法之冒泡排序详解

    java数据结构与算法之冒泡排序详解

    这篇文章主要介绍了java数据结构与算法之冒泡排序,结合实例形式详细分析了java冒泡排序的原理、实现技巧与相关注意事项,需要的朋友可以参考下
    2017-05-05
  • Java switch case数据类型原理解析

    Java switch case数据类型原理解析

    这篇文章主要介绍了Java switch case数据类型原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • 关于SpringBoot2.7.6连接nacos遇到的一些问题

    关于SpringBoot2.7.6连接nacos遇到的一些问题

    这篇文章主要介绍了关于SpringBoot2.7.6连接nacos遇到的一些问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 使用linux部署Spring Boot程序

    使用linux部署Spring Boot程序

    springboot程序在linux服务器上应该怎么部署?这次就分享下linux下如何正确部署springboot程序,感兴趣的朋友一起看看吧
    2018-01-01
  • java解析xml汇总_动力节点Java学院整理

    java解析xml汇总_动力节点Java学院整理

    这篇文章主要介绍了java解析xml汇总_动力节点Java学院整理的相关资料,需要的朋友可以参考下
    2017-07-07

最新评论