美文网首页
springboot 统一返回体(随笔)

springboot 统一返回体(随笔)

作者: 简楼 | 来源:发表于2021-04-19 22:03 被阅读0次

    前言

    在我们日常开发中,总是要和APP、H5、PC等多端的进行对接;
    此时就需要设计一个合适的接口返回体,以便统一交互;

    思路

    1. 定义一个泛型返回体,以此包装所有的接口返回值,让开发只关注业务就行;
    2. 自定义返回体注解,用于标注哪些类或方法需要包装返回值;
    3. ResponseBodyAdvice 实现类,并结合 @ControllerAdvice 注解,实现正常返回值或异常情况时返回值的封装;

    定义一个泛型返回体

    @Data
    public class Response<T> implements Serializable {
    
        private static final long serialVersionUID = -1220656299702215742L;
        private String code;
        private String message;
        private T data;
    
        public static <T> Response ok(T data) {
            return new Response("200", "success", data);
        }
    
        public static <T> Response ok(String code, String message, T data) {
            return new Response(code, message, data);
        }
    
        public static <T> Response fail(T data) {
            return new Response("500", "fail request", data);
        }
    
        public static <T> Response fail(String code, String message, T data) {
            return new Response(code, message, data);
        }
    
        private Response(String code, String message, T data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }
    }
    

    这里,只是简单的定义了返回体,有兴趣的同学,可以了解下枚举+返回体的操作;
    返回体中,我们只定义了三个变量:

    code:返回码
    message:消息
    data:返回的具体数据

    这里我们还把构造私有化了,这里时防止调用的时候有人通过 new 的方式包装数据,这不符合我们一开始定义的规范,需要通过我们定义好的静态方法实现返回值的包装;

    自定义返回体注解

    @Target({TYPE, METHOD})
    @Retention(RUNTIME)
    @Documented
    public @interface ResponseResult {
    }
    

    这个就不需要多解释了,声明这个注解可以使用在类和方法上;

    ResponseBodyAdvice 实现类

    @Slf4j
    @ResponseBody
    public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    
      /**
       * 判断是否包含 @ResponseResult 注解,不包含直接返回,不重写返回体
       *
       * @param returnType
       * @param converterType
       * @return boolean
       */
      @Override
      public boolean supports(
          MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        Class<?> clazz = returnType.getExecutable().getDeclaringClass();
        return clazz.isAnnotationPresent(ResponseResult.class) ? Boolean.TRUE : Boolean.FALSE;
      }
    
      /**
       * 返回体重构
       *
       * @param body
       * @param returnType
       * @param selectedContentType
       * @param selectedConverterType
       * @param request
       * @param response
       * @return java.lang.Object
       */
      @Override
      public Object beforeBodyWrite(
          Object body,
          MethodParameter returnType,
          MediaType selectedContentType,
          Class<? extends HttpMessageConverter<?>> selectedConverterType,
          ServerHttpRequest request,
          ServerHttpResponse response) {
        log.info("重写结构。。。。");
        return Response.ok(body);
      }
    
      /**
       * 自定义异常拦截
       *
       * @param e
       * @return com.example.demo.utils.Response
       */
      @ExceptionHandler(MyException.class)
      public Response getException(MyException e) {
        log.error("自定义异常:{},{}", e.getCode(), e.getMessage());
        return Response.fail(e.getCode(), e.getMessage(), null);
      }
    
      /**
       * 最大异常拦截
       *
       * @param e
       * @return com.example.demo.utils.Response
       */
      @ExceptionHandler(Exception.class)
      public Response getException(Exception e) {
        log.error("异常:{}", e);
        return Response.fail(e.getMessage());
      }
    }
    

    重写 supports 和 beforeBodyWrite 方法,以及拦截异常;

    通过阅读 ResponseBodyAdvice 源码中的 supports 和 beforeBodyWrite 方法,可以知道,当 supports 返回
    true 时,才会执行 beforeBodyWrite方法;

    supports 方法中可以通过 MethodParameter 来获取类或方法上的注解,借此判断注解上是否有我们自定义的 @ResponseResult注解,如果有的话,就返回true,否则就是false;

    beforeBodyWrite 将返回值包装到我们自定的返回体中;

    拦截异常,就是 @ExceptionHandler 注解中指定异常类型,那么该方法就会拦截你指定的异常,拦截后就会执行我们自定义的异常处理逻辑,最后返回时,使用我们自定的返回体封装结果,就万事大吉了;

    注意:拦截异常时,需要有一个最大的异常兜底,因为没有最大异常兜底的话,那么当系统抛出一个拦截异常中最大异常还大的异常,就会捕捉不到,那么我们设置的异常拦截,那将毫无意义;

    总结

    小伙伴们,最好亲自动手,写一写,总会有不一样的收获,比如 你的最爱--BUG!!!

    相关文章

      网友评论

          本文标题:springboot 统一返回体(随笔)

          本文链接:https://www.haomeiwen.com/subject/cxmwlltx.html