首先定义一个异常类CustomException 。
/**
* 自定义异常类型
* @author kavito
* @date 2019/5/31 16:39
*/
public class CustomException extends RuntimeException {
//错误代码
ResultCode resultCode;
public CustomException(ResultCode resultCode){
this.resultCode = resultCode;
}
public ResultCode getResultCode(){
return resultCode;
}
}
ResultCode接口:
/**
* 返回结果代码接口
*/
public interface ResultCode {
//操作是否成功,true为成功,false操作失败
boolean success();
//操作代码
int code();
//提示信息
String message();
}
按照模块划分,可以定义不同实现类(比如UserCode)。下面是一个公共的(枚举类)实现类:
@ToString
public enum CommonCode implements ResultCode{
INVALID_PARAM(false,10003,"非法参数!"),
SUCCESS(true,10000,"操作成功!"),
FAIL(false,11111,"操作失败!"),
UNAUTHENTICATED(false,10001,"此操作需要登陆系统!"),
UNAUTHORISE(false,10002,"权限不足,无权操作!"),
SERVER_ERROR(false,99999,"抱歉,系统繁忙,请稍后重试!");
//操作是否成功
boolean success;
//操作代码
int code;
//提示信息
String message;
private CommonCode(boolean success,int code, String message){
this.success = success;
this.code = code;
this.message = message;
}
@Override
public boolean success() {
return success;
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
}
对异常类静态封装,省去不必要的代码:
/**
* 静态封装,省去throw new()
* @author kavito
* @date 2019/5/31 16:39
*/
public class ExceptionCast {
public static void cast(ResultCode resultCode){
throw new CustomException(resultCode);
}
}
全局统一异常处理类:
import com.google.common.collect.ImmutableMap;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.framework.model.response.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一捕获类(抛出的异常被这个类捕获)
* @author kavito
* @date 2019/5/31 16:39
*/
@ControllerAdvice//控制器增强,(如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody)
public class ExceptionCatch {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class);
//定义map,配置异常类型所对应的错误代码
private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
//定义map的builder对象,去构建ImmutableMap
protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();
//捕获CustomException此类异常,(捕获自定义异常)
@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseResult customException(CustomException customException){
//记录日志
LOGGER.error("catch exception:{}",customException.getMessage());
ResultCode resultCode = customException.getResultCode();
return new ResponseResult(resultCode);
}
//捕获Exception此类异常
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult exception(Exception exception){
//记录日志
LOGGER.error("catch exception:{}",exception.getMessage());
if(EXCEPTIONS == null){
EXCEPTIONS = builder.build();//EXCEPTIONS构建成功
}
//从EXCEPTIONS中找异常类型所对应的错误代码,如果找到了将错误代码响应给用户,如果找不到给用户响应99999异常
ResultCode resultCode = EXCEPTIONS.get(exception.getClass());
if(resultCode !=null){
return new ResponseResult(resultCode);
}else{
//返回99999异常
return new ResponseResult(CommonCode.SERVER_ERROR);
}
}
static {
//定义异常类型所对应的错误代码
builder.put(HttpMessageNotReadableException.class,CommonCode.INVALID_PARAM);
}
}
@ControllerAdvice//控制器增强
@ExceptionHandler(CustomException.class):当抛出(自定义)CustomException异常后,会被这个方法捕获。
ResponseResult:响应结果接口的实现类。其他模块可以通过继承该类来扩展,比如UserResult中我通过构造返回一个User对象。
@Data
@ToString
@NoArgsConstructor
public class ResponseResult implements Response {
//操作是否成功
boolean success = SUCCESS;
//操作代码
int code = SUCCESS_CODE;
//提示信息
String message;
public ResponseResult(ResultCode resultCode){
this.success = resultCode.success();
this.code = resultCode.code();
this.message = resultCode.message();
}
public static ResponseResult SUCCESS(){
return new ResponseResult(CommonCode.SUCCESS);
}
public static ResponseResult FAIL(){
return new ResponseResult(CommonCode.FAIL);
}
}
@Data
@NoArgsConstructor
public class UserResult extends ResponseResult {
User user;
public UserResult(ResultCode resultCode,User user) {
super(resultCode);
this.user= user;
}
}
写一个简单的controller测试抛出异常:
@RestController
@RequestMapping("/exception")
public class ExceptionController {
@PostMapping("/test/{id}")
public ResponseResult test(@PathVariable("id") int id) {
if (id != 1) {
//id不是1抛出非法参数异常
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
return new ResponseResult(CommonCode.SUCCESS);
//return new UserResult (CommonCode.SUCCESS,user);
}
}
当我们请求localhost:31400/exception/test/2的时候,抛出我们自定义的异常customException,然后被ExceptionCatch捕获到。
响应给客户端: