经常开发接口的同学肯定知道,接口返回的数据格式必须有固定的格式,方便调用者
对于不同的异常我们在实际开发中最好也有统一的处理
在spring boot中与默认的异常页面,如果我们要开发rest风格的api,返回的json数据
那么异常提示也要是json格式的,返回一个页面的错误异常就不友好了
接下来我看怎么统一处理这些异常信息以及自己定义一些常用的异常
先定义一个全局的异常类,继承Exception ,里面有code属性,表示请求的响应状态码
public class GlobalException extends Exception {
private static final long serialVersionUID = -5701182284190108797L;
private int code;
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public GlobalException(String message) {
super(message);
}
public GlobalException(String message, int code) {
super(message);
this.code = code;
}
}
定义一个响应码的枚举类,400参数错误,500服务器内部错误,可以根据自己的需求添加自定义的响应码
public enum ResponseCode {
PARAM_ERROR_CODE(400),
SERVER_ERROR_CODE(500);
private int code;
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
private ResponseCode(int code) {
this.code = code;
}
}
然后创建刚刚异常码对应的异常类
//服务器异常类
public class ServerException extends GlobalException {
private static final long serialVersionUID = -1355046108056594333L;
public ServerException(String message) {
super(message, ResponseCode.SERVER_ERROR_CODE.getCode());
}
}
//参数异常类
public class ParamException extends GlobalException {
private static final long serialVersionUID = 6021390821349937519L;
public ParamException(String message) {
super(message, ResponseCode.PARAM_ERROR_CODE.getCode());
}
}
接着我们定义一个统一的接口返回格式类
里面有状态,响应码,消息,返回的数据等属性
public class ResponseData {
private Boolean status = true;
private int code = 200;
private String message;
private Object data;
public static ResponseData ok(Object data) {
return new ResponseData(data);
}
public ResponseData(Object data) {
super();
this.data = data;
}
public ResponseData() {
super();
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
重点来了,定义一个全局异常处理Handler
在这边拦截异常,然后封装统一的返回格式
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = GlobalException.class)
@ResponseBody
public ResponseData jsonErrorHandler(HttpServletRequest req, GlobalException e)
throws Exception {
ResponseData r = new ResponseData();
r.setMessage(e.getMessage());
r.setCode(e.getCode());
r.setData(null);
r.setStatus(false);
return r;
}
}
或
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = GlobalException.class)
public ResponseData jsonErrorHandler(HttpServletRequest req, GlobalException e)
throws Exception {
ResponseData r = new ResponseData();
r.setMessage(e.getMessage());
r.setCode(e.getCode());
r.setData(null);
r.setStatus(false);
return r;
}
}
使用的地方我们使用ResponseData返回统一的数据格式
@RequestMapping("/students")
Object queryStudents() throws GlobalException {
return ResponseData.ok(studentService.queryStudents());
}
访问接口可以看到返回的数据格式如下:
{
"status": true,
"code": 200,
"message": null,
"data": [
{
"id": "5805d908c243812068ee674f",
"name": "大地"
},
{
"id": "5805e5e6c2438117b452c5e3",
"name": "yinjihuan"
}
]
}
下面的列子模拟的怎么使用自定义的异常
@RequestMapping("/students/{name}")
Object queryStudentByName(@PathVariable String name) throws Exception {
if(name.equals("1")) {
throw new ParamException("参数错误");
}
if(name.equals("2")) {
throw new ServerException("内部错误");
}
return ResponseData.ok(studentRepository.findByName(name));
}
我们假设参数等于1的时候,是参数错误,然后跑出参数错误异常,那么客户端收到的返回结果如下:
status为false,code为400,还有错误说明message
{
"status": false,
"code": 400,
"message": "参数错误",
"data": null
}
假设参数为2的时候,是内部错误,返回的结果如下:
{
"status": false,
"code": 500,
"message": "内部错误",
"data": null
}
这边只是举例使用,像一般的开发平台api有很多的响应码以及说明,比如百度开发api什么的,原理都类似。