在开发项目中,对于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天的日志
如何移至到自己的项目中
将cn.skyjilygao.springboot.core下所有文件复制到自己项目公共模块或第三方库中,重新编译安装
将ReturnTEnum,BaseController,SkyException复制到项目的公共文件夹中。然后在ReturnTEnum增加自定义枚举即可
如何使用
使用本项目测试时,只需在ReturnTEnum增加自定义枚举即可
参考