前言
在业务开发中,异常捕捉是必不可少的一步,最简单的方法就是使用try/catch。
但是,当程序规模逐渐扩大,每个都使用catch时,就会使得代码非常臃肿,耦合度也可能大大增加。所以我们需要利用Spring的AOP特性解决这一问题。
代码结构
涉及依赖
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--参数验证工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
代码
NykbExceptionEnum
/**
* 异常类型枚举
*/
public enum NykbExceptionEnum {
/**
* 操作成功
*/
SUCCESS(200, "操作成功"),
/**
* 请求格式错误
*/
BAD_REQUEST(400, "请求格式错误"),
/**
* 未登录或者身份已过期
*/
NOT_AUTH(401, "未登录或者凭证已过期"),
/**
* 无权操作
*/
REFUSER(403, "无权操作"),
/**
* 请求的资源找不到
*/
NOT_FOUND(404, "请求的资源找不到"),
/**
* 服务器内部错误
*/
SERVER_ERROR(500, "服务器错误");
private int code;
private String message;
NykbExceptionEnum() {
}
NykbExceptionEnum(int code, String message) {
this.code = code;
this.message = message;
}
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;
}
}
NykbException
/**
* 自定义异常
*/
@RestControllerAdvice
public class NykbException extends RuntimeException {
private int code;
public NykbException() {
}
public NykbException(String message) {
super(message);
this.code = NykbExceptionEnum.SERVER_ERROR.getCode();
}
public NykbException(NykbExceptionEnum exceptionEnum) {
super(exceptionEnum.getMessage());
this.code = exceptionEnum.getCode();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
NykbExceptionHandler
/**
* 异常处理中心
*/
@Slf4j
@RestController
@RestControllerAdvice
public class NykbExceptionHandler {
/**
* 自定义异常
*/
@ExceptionHandler(value = NykbException.class)
@ResponseStatus(HttpStatus.OK)
public <T> CommonResult<T> handler(NykbException e) {
log.error(e.getMessage());
return CommonResult.failed(e);
}
/**
* 数据校验异常
*/
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(HttpStatus.OK)
public <T> CommonResult<T> handler(ConstraintViolationException e) {
log.error(e.getMessage());
return CommonResult.failed(e.getMessage());
}
/**
* 缺少参数异常
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.OK)
public <T> CommonResult<T> handler(MissingServletRequestParameterException e) {
log.error(e.getMessage());
return CommonResult.failed(e.getMessage());
}
/**
* 其他异常
*/
@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.OK)
public <T> CommonResult<T> handler(Exception e) {
log.error(ErrorUtil.getErrorCause(e));
return CommonResult.failed(ErrorUtil.getErrorCause(e));
}
}
CommonResult
/**
* 返回数据封装
*/
@Data
public class CommonResult<T> {
private int code;
private String message;
private T data;
public CommonResult() {
}
public CommonResult(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> CommonResult<T> success() {
return new CommonResult<>(NykbExceptionEnum.SUCCESS.getCode(),
NykbExceptionEnum.SUCCESS.getMessage(), null);
}
public static <T> CommonResult<T> success(String message) {
return new CommonResult<>(NykbExceptionEnum.SUCCESS.getCode(),
message, null);
}
public static <T> CommonResult<T> success(T data) {
return new CommonResult<>(NykbExceptionEnum.SUCCESS.getCode(),
NykbExceptionEnum.SUCCESS.getMessage(), data);
}
public static <T> CommonResult<T> success(String message, T data) {
return new CommonResult<>(NykbExceptionEnum.SUCCESS.getCode(),
message, data);
}
public static <T> CommonResult<T> failed() {
return new CommonResult<>(NykbExceptionEnum.SERVER_ERROR.getCode(),
NykbExceptionEnum.SERVER_ERROR.getMessage(), null);
}
public static <T> CommonResult<T> failed(NykbException e) {
return new CommonResult<>(e.getCode(),
e.getMessage(), null);
}
public static <T> CommonResult<T> failed(String message) {
return new CommonResult<>(NykbExceptionEnum.SERVER_ERROR.getCode(),
message, null);
}
public static <T> CommonResult<T> failed(NykbExceptionEnum exceptionEnum) {
return new CommonResult<>(exceptionEnum.getCode(),
exceptionEnum.getMessage(), null);
}
}
ErrorUtil
/**
* 异常工具类
*/
public class ErrorUtil {
/**
* 将栈错误信息转成String返回
*/
public static String getErrorCause(Throwable t) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
开始使用
如果启动器和异常处理中心不在同一个包,还需要在启动器上添加注解:
@ComponentScan(basePackages = "这里写公共包")
空指针异常
@GetMapping("get")
public CommonResult<String> get() {
String s = null;
String[] strings = s.split("/");
return CommonResult.success();
}
数据校验异常
控制器上需要加上注解@Validated
@GetMapping("get")
public CommonResult<String> get(@NotBlank(message = "姓名不能为空") String name) {
return CommonResult.success(name);
}
缺少参数异常
@GetMapping("get")
public CommonResult<String> get(@RequestParam(value = "name")@NotBlank(message = "姓名不能为空") String name) {
return CommonResult.success(name);
}
自定义异常
模拟验证登录信息,对于未登录的情况直接抛出异常
@GetMapping("get")
public CommonResult<String> get() {
throw new NykbException(NykbExceptionEnum.NOT_AUTH);
}
还有其他抛异常不再一一举例
@GetMapping("get")
public CommonResult<String> get() {
throw new NykbException("未知的内部错误,请联系开发人员!");
}