前言
在项目中我们会经常碰到异常处理的问题,比如用户在发送请求到我们的后端时如果请求参数或路径出现错误,在没做异常处理的情况下服务端会直接把一大串错误信息返回给用户。这种情况并不少见,用户获得这些信息并没有什么用处,我们后端可以对所有这种异常进行统一的处理然后提取重点统一返回封装后的数据。Spring官方文档给我们提供一种解决方案,使用@ControllerAdvice
和@ExceptionHandler
注解可以将组件注册为全局异常处理类和方法。@ControllerAdvice
实际上就是一个增强的@Controller
,使用该controller可以实现三个方面的功能:全局异常处理、全局数据绑定、全局数据预处理。该博文将讲解其全局异常处理的使用方法。
异常处理类的注册与使用
- 首先要建一个处理类,使用
@ControllerAdvice
将其注入到IoC容器中成为全局异常处理类 @ControllerAdvice public class WebMvcExceptionHandler { }
|
- 使用
@ExceptionHandler
在方法上注明要进行捕捉的异常(Exception为大部分异常的超类)@ControllerAdvice public class WebMvcExceptionHandler { @ExceptionHandler(value = Exception.class) @ResponseBody public ResponseResult serverHandler(Exception e){ System.out.println("服务器异常:"+e.getMessage()); return ResponseResult.internal_server_error(); } }
|
- 对出现异常的情况进行返回集合的处理。通常封装类有响应编码、响应信息、响应数据这三个基本要素,我们可以对其进行封装。
响应编码的枚举类
public enum HttpEnum {
OK(200, "请求成功"),
CREATED(201, "创建成功"),
INVALID_REQUEST(400, "非法请求"),
NOTFOUND(404, "访问内容不存在"),
UNAUTHORIZED(401,"抱歉,您没有权限"),
FORBIDDEN(403,"禁止访问"),
INTERNAL_SERVER_ERROR(500, "系统内部错误");
private String msg;
private int code;
private HttpEnum(int code, String msg) { this.msg = msg; this.code = code; }
public int code(){ return code; } public String msg(){ return msg; } }
|
返回数据封装集合
public class ResponseResult<T> implements Serializable { private static final long serialVersionUID = 1L; private int code; private String msg; private T data;
private static <T> ResponseResult<T> build( int code,String msg,T data) { return new ResponseResult<T>().setCode(code).setMsg(msg).setData(data); }
public static <T> ResponseResult<T> ok(){ return build(HttpEnum.OK.code(),HttpEnum.OK.msg(),null); } public static <T> ResponseResult<T> ok(T data){ return build(HttpEnum.OK.code(),HttpEnum.OK.msg(),data); }
public static <T> ResponseResult<T> created(){ return build(HttpEnum.CREATED.code(),HttpEnum.CREATED.msg(),null); }
public static <T> ResponseResult<T> invalid_request(){ return build(HttpEnum.INVALID_REQUEST.code(),HttpEnum.INVALID_REQUEST.msg(),null); }
public static <T> ResponseResult<T> notFound(){ return build(HttpEnum.NOTFOUND.code(),HttpEnum.NOTFOUND.msg(),null); }
public static <T> ResponseResult<T> unauthorized(){ return build(HttpEnum.UNAUTHORIZED.code(),HttpEnum.UNAUTHORIZED.msg(),null); } public static <T> ResponseResult<T> unauthorized(T data){ return build(HttpEnum.UNAUTHORIZED.code(),HttpEnum.UNAUTHORIZED.msg(),data); }
public static <T> ResponseResult<T> forbidden(){ return build(HttpEnum.FORBIDDEN.code(),HttpEnum.FORBIDDEN.msg(),null); }
public static <T> ResponseResult<T> internal_server_error(){ return build(HttpEnum.INTERNAL_SERVER_ERROR.code(),HttpEnum.INTERNAL_SERVER_ERROR.msg(),null); }
public int getCode() { return code; } public ResponseResult<T> setCode(int code) { this.code = code; return this; }
public String getMsg() { return msg; } public ResponseResult<T> setMsg(String msg) { this.msg = msg; return this; }
public T getData() { return data; } public ResponseResult<T> setData(T data) { this.data = data; return this; } }
|
用户请求常见异常
- 请求方式错误。在后端为Restful风格的接口中,通常请求的方式都会有对应的规定。处理这种情况用的是
HttpRequestMethodNotSupportedException
- 请求参数错误。如后端要求前端使用
POST
请求来传递表单信息,若表单数据不完整或不存在,则这种情况后端会解析为数据解析异常,使用HttpMessageNotReadableException
- JSON格式错误。这种情况是我使用
fastjson
解析json对象时遇到的问题。如前端传递进来的json对象K-V键值对不完整{ "keyword":"关键字", “name”: }
|
这种情况使用JSONException
(只有使用阿里的fastjson
才有,若不是使用fastjson
可无视)
- 资源不存在。这种应该是最常见的,用户访问的路径为非法路径时会报出该异常。使用
NoHandlerFoundException
。注:正常情况下使用注解方式处理全局异常是不能处理404异常的,要在配置文件application.yml
中设置spring: mvc: throw-exception-if-no-handler-found: true resources: add-mappings: false
|
- 默认异常。异常有这么多不可能全部都列出来,但我们可以使用他们的超类
Exception