统一数据返回格式 及 可能遇到的问题;统一异常处理

统一数据返回格式

统一数据返回格式就像我们寄快递一样,不管你需要寄的东西具体是什么都需要将它打包到统一的快递箱中。

此时我们需要一个"快递箱"用来将返回的数据"装"在里面。这个类是根据业务情况来自行定义的。

java 复制代码
@Data
public class Resp<T> {
    //200-正常  0-发生异常
    private Integer code;
    //错误信息
    private String desc;
    //返回数据
    private T data;
    //成功
    public static <T> Resp<T> seccess(T data) {
        Resp<T> resp = new Resp<>();
        resp.setCode(200);
        resp.setData(data);
        return resp;
    }
}

有了"快递箱之后"还需要一个"工作人员"来将"快递"进行打包,此时我们需要创建一个新类并使其实现ResponseBodyAdvice 接口并重写里面的方法,然后给当前类加上@ControllerAdvice注解。

java 复制代码
@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return null;
    }
}

supports():这个方法用来决定是否执行beforeBodyWrite()方法,如果返回true表示执行,否则返回false。通过该方法可以选择哪些类或哪些方法的响应要进行处理,其他的不进行处理;beforeBodyWrite():对响应进行具体操作处理。

先创建两个用于测试的接口:

java 复制代码
@RestController
@RequestMapping("/test")
public class Test {

    @RequestMapping("/fun1")
    public boolean fun1() {
        return false;
    }

    @RequestMapping("/fun2")
    public Integer fun2() {
        return 34;
    }
}

接下来将fun1和fun2方法的返回值进行"打包"。

java 复制代码
@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Resp.seccess(body);
    }
}

但是实际应用时还有几个问题:

问题一:重复打包

如果此时fun1返回的就是Resp类型的值那么就会出现重复打包的问题。

java 复制代码
@RequestMapping("/fun1")
public Resp<Boolean> fun1() {
    return Resp.seccess(false);
}

解决方法就是可以在打包前进行一次判断,如果已经被打包了就直接返回,否则进行打包。

java 复制代码
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    if (body instanceof Resp) {
        return body;
    }
    return Resp.seccess(body);
}

问题二:ClassCastException: com.example.Spring_demo.Resp cannot be cast to java.lang.String

这个问题的出现场景是在返回值为String类型时出现的。假设fun1现在返回值是String类型:

java 复制代码
@RequestMapping("/fun1")
public String fun1() {
    return "hahaha";
}

解决方法就是如果返回结果为String类型, 使用SpringBoot内置提供的Jackson来实现信息的序列化。

java 复制代码
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    if (body instanceof String) {
        return new ObjectMapper().writeValueAsString(Resp.seccess(body));
    }
    if (body instanceof Resp) {
        return body;
    }
    return Resp.seccess(body);
}

注意:此时返回的是字符串。

使用这个就可以解决:@RequestMapping(value = "/fun1", produces = "application/json")

优点

  • 方便前端程序员更好的接收和解析后端数据接口返回的数据;
  • 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就可以了,因为所有接口都是这样返回的;
  • 有利于项目统一数据的维护和修改;
  • 有利于后端技术部门的统一规范的标准制定,不会出现稀奇古怪的返回内容。

统一异常处理

如果fun1方法在执行时出现异常也会出现不合理的返回信息:

java 复制代码
@RequestMapping(value = "/fun1", produces = "application/json")
public String fun1() {
    System.out.println(3/0);
    return "hahaha";
}

此时就需要用到统一异常处理来对程序执行过程中发生的异常进行捕获和处理。统一异常处理需要使用两个注解@ExceptionHandler@ControllerAdvice,如果返回的是数据还需要加上@ResponseBody注解。

下面代码表示,如果代码出现Exception异常(包括Exception的子类)才会被捕获,然后执行该方法。

java 复制代码
@ControllerAdvice
@ResponseBody
public class ErrorAdvice {
    @ExceptionHandler
    public Object handler(Exception e) {
        return Resp.fail("Exception: 程序出现异常");
    }
}

当有多个异常通知时,匹配顺序为当前类及其子类向上依次匹配。如此时有两个,继续访问fun1方法。

java 复制代码
@ControllerAdvice
@ResponseBody
public class ErrorAdvice {
    @ExceptionHandler
    public Object handler(Exception e) {
        return Resp.fail("Exception: 程序出现异常");
    }

    @ExceptionHandler
    public Object handler(ArithmeticException e) {
        return Resp.fail("ArithmeticException: 程序出现算数异常");
    }
}
相关推荐
lightqjx6 分钟前
【数据结构】顺序表(sequential list)
c语言·开发语言·数据结构·算法
巨人张15 分钟前
信息素养Python编程题
开发语言·python
东阳马生架构17 分钟前
订单初版—5.售后退货链路中的技术问题说明文档
java
小小寂寞的城22 分钟前
JAVA策略模式demo【设计模式系列】
java·设计模式·策略模式
阿猿收手吧!39 分钟前
【计算机网络】HTTP1.0 HTTP1.1 HTTP2.0 QUIC HTTP3 究极总结
开发语言·计算机网络
JAVA学习通40 分钟前
图书管理系统(完结版)
java·开发语言
abigalexy1 小时前
深入Java锁机制
java
paishishaba1 小时前
处理Web请求路径参数
java·开发语言·后端
七七七七071 小时前
C++类对象多态底层原理及扩展问题
开发语言·c++