SpringMVC异常处理
一、引言
一般项目开发中有两类异常:
- 预期异常
- 运行时异常
其中预期异常一般是由程序员主动抛出的异常,而运行时异常很难控制,只能通过规范代码编写、增加测试等手段来减少该类异常。
通常项目是分层开发的,由外到内可分为前端项目、前端控制器、控制层、业务层、持久层。如果在控制层、业务层或持久层出现异常,SpringMVC框架如何处理呢?我们可以在前端控制器中定义全局异常处理器,之后如果控制层、业务层或持久层出现异常,直接往外抛异常即可。关于全局异常处理器,有如下定义方法:
1. 基于注解的异常处理
2. 基于配置的异常处理
二、示例
2.1 基于注解的异常处理
首先,定义一个业务异常,该异常作为预期异常在项目中手动抛出。
java
public class CustomException extends RuntimeException {
private AppHttpCodeEnum appHttpCodeEnum;
public CustomException(AppHttpCodeEnum appHttpCodeEnum){
this.appHttpCodeEnum = appHttpCodeEnum;
}
public AppHttpCodeEnum getAppHttpCodeEnum() {
return appHttpCodeEnum;
}
}
其中AppHttpCodeEnum类是一个枚举类,用于指定http响应状态码和响应信息,定义如下。
java
public enum AppHttpCodeEnum {
// 成功段0
SUCCESS(200,"操作成功"),
// 登录段1~50
NEED_LOGIN(1,"需要登录后操作"),
LOGIN_PASSWORD_ERROR(2,"密码错误"),
// TOKEN50~100
TOKEN_INVALID(50,"无效的TOKEN"),
TOKEN_EXPIRE(51,"TOKEN已过期"),
TOKEN_REQUIRE(52,"TOKEN是必须的"),
// SIGN验签 100~120
SIGN_INVALID(100,"无效的SIGN"),
SIG_TIMEOUT(101,"SIGN已过期"),
// 参数错误 500~1000
PARAM_REQUIRE(500,"缺少参数"),
PARAM_INVALID(501,"无效参数"),
PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),
SERVER_ERROR(503,"服务器内部错误"),
// 数据错误 1000~2000
DATA_EXIST(1000,"数据已经存在"),
AP_USER_DATA_NOT_EXIST(1001,"用户数据不存在"),
DATA_NOT_EXIST(1002,"数据不存在"),
// 数据错误 3000~3500
NO_OPERATOR_AUTH(3000,"无权限操作"),
NEED_ADMIND(3001,"需要管理员权限");
int code;
String errorMessage;
AppHttpCodeEnum(int code, String errorMessage){
this.code = code;
this.errorMessage = errorMessage;
}
public int getCode() {
return code;
}
public String getErrorMessage() {
return errorMessage;
}
}
之后,通过@ControllerAdvice和@ExceptionHandler注解定义全局异常处理器,分别捕获自定义的业务异常和不可控异常。
java
@ControllerAdvice //控制器增强类
public class ExceptionCatch {
/**
* 处理不可控异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult exception(Exception e){
e.printStackTrace();
return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
}
/**
* 处理可控异常 自定义异常
* @param e
* @return
*/
@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseResult exception(CustomException e){
return ResponseResult.errorResult(e.getAppHttpCodeEnum());
}
}
其中ResponseResult类是一个向前端返回的统一结果类。
java
public class ResponseResult<T> implements Serializable {
private String host;
private Integer code;
private String errorMessage;
private T data;
public ResponseResult() {
this.code = 200;
}
public ResponseResult(Integer code, T data) {
this.code = code;
this.data = data;
}
public ResponseResult(Integer code, String msg, T data) {
this.code = code;
this.errorMessage = msg;
this.data = data;
}
public ResponseResult(Integer code, String msg) {
this.code = code;
this.errorMessage = msg;
}
public static ResponseResult errorResult(int code, String msg) {
ResponseResult result = new ResponseResult(code, msg);
return result;
}
public static ResponseResult errorResult(AppHttpCodeEnum enums) {
return setAppHttpCodeEnum(enums, enums.getErrorMessage());
}
public static ResponseResult errorResult(AppHttpCodeEnum enums, String errorMessage) {
return setAppHttpCodeEnum(enums, errorMessage);
}
public static ResponseResult okResult(int code, String msg) {
ResponseResult result = new ResponseResult(code, msg);
return result;
}
public static ResponseResult okResult(Object data) {
ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getErrorMessage());
if (data != null) {
result.setData(data);
}
return result;
}
public static ResponseResult okResult(AppHttpCodeEnum enums) {
ResponseResult result = setAppHttpCodeEnum(enums);
return result;
}
public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) {
return okResult(enums.getCode(), enums.getErrorMessage());
}
private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String errorMessage) {
return okResult(enums.getCode(), errorMessage);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
2.2 基于配置的异常处理
SpringMVC提供了一个自定义异常处理器的接口,我们通过实现@HandlerExceptionResolver接口来捕获异常。
java
public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception exception) {
//根据实际业务编写代码
return null;
}
}
然后在spring配置文件中配置刚才新建的全局异常处理器,或者加上@Component注解。
xml
<!--全局异常捕捉 -->
<bean class="包名.GlobalExceptionResolver" />