Springboot项目如何在controller层统一返回数据以及处理异常

github源码:controller-handler-master

在开发项目中,对于controller返回数据同时返回可能大家都能够做到。也就是定义一个相应类,里面有code, msg,content(或data)
在此基础上可能还会再封装以下,搞个基础controller类,有success,fail等方法可以调用。
但是对于异常信息返回,可能稍微有点麻烦。
首先,是code确定,报错时可能直接在try-catch中返回一个错误状态码500,或是403等等非200的状态码。但是由于不是使用变量管理,也就意味着不同方法不同异常的状态码可能相同,或是相同异常,返回的状态码不同。
第二,msg确定。不同方法catch到错误,返回code可能相同,但是msg可能就是当前异常的相关信息,甚至直接写成e.getMessage()。特别是e.getMessage()可能会暴露不必要的信息,甚至是数据库信息。

那么怎么才能保证code跟msg一对一对应起来呢?
此时枚举都起到了关键作用。可能有的人想到静态变量和map,也可以但是没有枚举类更直观。
这个枚举类可以参考Spring-Framework的HttpStatus
自定义项目相关枚举类:

public enum ReturnTEnum {
    SUCCESS(200, "SUCCESS"),
    ERROR(500, "服务异常"),
    UNKNOWN_ERROR(5000, "未知错误"),

    PARAMETER_EMPTY(210,"参数为空"),
    PARAMETER_INVALID(211,"参数错误"),

    ARITHMETIC_ERROR(212,"计算错误"),


    DATE_ERROR_FORMAT_ERROR(212,"日期格式错误"),
    DATE_ERROR_START_LARGE_END(213,"开始时间大于结束时间"),

    FORBIDDEN(403, "拒绝访问"),

    // todo: 更多自定义返回错误信息,均在此重新定义
    ;

    private int code;
    private String msg;
// ....省略构造,get方法
}

枚举类建好了,怎么在处理异常时获取相应的枚举类值呢?
可以自定义异常类SkyException,里面有code,msg。

整体思路具体参考如下:

Controller响应数据统一管理

1. 返回数据统一:

所有controller都继承BaseController

  • 返回正常数据:return success("hello world");
  • 返回错误数据:return error(ReturnTEnum.ARITHMETIC_ERROR, e);throw new SkyException(ReturnTEnum.ARITHMETIC_ERROR, e);即可
{
    "code": 200,
    "msg": "SUCCESS",
    "content": "sdf"
}

{
    "code": 500,
    "msg": "服务器内部异常",
    "content": "/test/err"
}

其中

字段 类型 说明
code int 状态码
msg String 状态信息
content 泛型T。允许序列化类 业务数据

2. 全局异常处理

  • 使用@ControllerAdvice@ExceptionHandler 注解处理全局异常
  • 参考cn.skyjilygao.springboot.core.interceptor.GlobalExceptionHandler

为了能够更好统一返回状态信息,捕获异常需要同时状态码和状态信息,怎么办?使用自定义异常类SkyException

-1. 增加了枚举类cn.skyjilygao.springboot.controller.ReturnTEnum也可以使用HttpStatus.

-2. 异常类SkyException

/**
 * 自定义异常处理类。用于接口返回时可以指定异常枚举类。便于返回状态码管理
 * @author skyjilygao
 * @since 1.8
 */
public class SkyException extends SkyExceptionBase {

    public SkyException(ReturnTEnum httpStatus) {
        super(httpStatus.getCode(), httpStatus.getMsg());
    }

    public SkyException(ReturnTEnum httpStatus, Exception e) {
        super(httpStatus.getCode(), httpStatus.getMsg(), e);
    }

    public SkyException(HttpStatus httpStatus) {
        super(httpStatus);
    }

    public SkyException(HttpStatus httpStatus, Exception e) {
        super(httpStatus, e);
    }
}

-3. 对于可控异常,可以抛出SkyException同时指定相应枚举类即可
例如:对于计算,可能抛出被除数不能为0,则可以捕获以下。枚举类就是ReturnTEnum.ARITHMETIC_ERROR

    public ReturnT err(){
        try {
            int a = 2;
            int b = 0;
            return success(a/b);
        }catch (Exception e){
//            return error(ReturnTEnum.ARITHMETIC_ERROR, e);
            throw new SkyException(ReturnTEnum.ARITHMETIC_ERROR, e);
        }
    }

-4. 对于不可控异常,可以在全局异常处理类中指定默认状态码。

    @ResponseBody
    @ExceptionHandler(value = {Exception.class})
    public ReturnT defaulExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
        String uri = getUri(request);
        log.error("handler Exception: request uri={}. with error message={}", uri, e.getMessage(), e);
        return new ReturnT(ReturnTEnum.ERROR.getCode(), "服务器内部异常", uri);
    }

3. 记录调用者IP以及请求参数信息

利用拦截器记录IP和请求相关数据。这样跟其他配合时,就能清楚看到参数等数据不至于相互扯皮

4. 日志记录

使用logback记录,保留最近3天的日志

如何移至到自己的项目中

  1. cn.skyjilygao.springboot.core下所有文件复制到自己项目公共模块或第三方库中,重新编译安装
  2. ReturnTEnum,BaseController,SkyException复制到项目的公共文件夹中。然后在ReturnTEnum增加自定义枚举即可

如何使用

  1. 使用本项目测试时,只需在ReturnTEnum增加自定义枚举即可
参考
  1. Spring Boot 无侵入式 实现API接口统一JSON格式返回
  2. 你怎么天天就会 try...catch
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容