自定义全局异常处理
- 一. 创建所需类
- 1. 自定义异常接口
- 2. 自定义枚举类
- 3. 自定义异常类
- 4. 自定义异常处理类
- 5. 自定义全局响应类
- 5.1 BaseResponse类
- 5.2 RespGenerator类
- 二. 效果演示
我们在 SpringBoot 项目中,往往会写许多 Controler 接口类,由于 Controller
类接口中传递的参数各不相同,出现错误时抛出的异常以及异常的处理方式也不尽相同。java程序中,异常有很多种,所有异常的父类都是Throwable类,其中Exception异常是可以进行手动处理的,在程序运行过程中,也会出现各种业务异常,需要自定义,可能返回500,404,等等,前端拿到这些异常可能不方便处理,如果可以统一一个全局异常,是什么错误就返回什么信息和code码给前端,前端更便于处理。
一. 创建所需类
1. 自定义异常接口
为了代码解耦,创建一个接口类出来,定义自定义接口所需要的方法
/**
* @author gf
* @date 2023/2/2
*/
// 第一步:为了代码解耦,创建一个接口类出来,定义自定义接口所需要的方法
// 抽象类,提供自定义异常所需的方法
public interface BaseErrorInfoInterface {
String getCode();
String getMessage();
}
2. 自定义枚举类
定义一个枚举类,实现上述BaseErrorInfoInterface接口,重写上述接口的两个方法来操作这个枚举类内部的各个具体枚举值
/**
* @author gf
* @date 2023/2/2
*/
//第二步:定义一个枚举类,实现上述接口,重写上述接口的两个方法来操作这个枚举类内部的各个具体枚举值
public enum BaseErrorEnum implements BaseErrorInfoInterface {
//定义异常枚举
SUCCESS("200","成功"),
USER_NOT_EXIST("1001","用户不存在");
// 错误码
private String code;
// 错误信息提示
private String message;
BaseErrorEnum(String code, String message) {
this.code = code;
this.message = message;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
后续方便管理所有错误枚举的错误信息以及code码,通过构造方法传入code值和message或者直接传入一个枚举值都行
3. 自定义异常类
自定义一个异常类,就像空指针异常类、IO流异常类一样。此处自定义的异常类属于异常类,所有肯定是要继承一个异常类的,此处需要继承RuntimeException,原因如下
RuntimeException相比Exception来讲,他是在程序运行时才会爆出异常,在编译时是不会出现异常的,这就表示,如果你throw了一个RuntimeException,不需要做额外操作;而throw一个Exception,程序会要求你try-catch,否则你根本启动不了程序,程序会提示(必须对其进行捕获或声明以便抛出)。
@Data
public class BaseException extends RuntimeException {
// 错误码
private String code;
// 错误信息提示
private String message;
public BaseException(){
super();
}
// 自定义异常构造方法
public BaseException(BaseErrorEnum baseErrorEnum){
super(baseErrorEnum.getCode());
this.code=baseErrorEnum.getCode();
this.message=baseErrorEnum.getMessage();
}
}
4. 自定义异常处理类
/**
- @author gf
- @date 2023/2/2
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义异常
@ExceptionHandler({BaseException.class})
public BaseResponse<Object> baseExceptionHandler(BaseException e) {
log.debug("请求错误:{}", e.getMessage());
return RespGenerator.failure(e.getCode(), e.getMessage());
}
// 处理空指针异常
@ExceptionHandler({NullPointerException.class})
public BaseResponse<Object> exceptionHandler(NullPointerException e) {
log.error("运行时异常:{}", e.getMessage());
return RespGenerator.failure(BaseErrorEnum.USER_NOT_EXIST);
}
// 处理其他异常
@ExceptionHandler({Exception.class})
public BaseResponse<Object> exceptionHandler(Exception exception) {
log.error("未知异常:{}", exception);
return RespGenerator.failure("500", "系统未知异常");
}
}
注解说明:
- @ControllerAdvice注解:结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。
- @ExceptionHandler注解 :统一处理某一类异常,从而能够减少代码重复率和复杂度,value值为什么异常类型,就处理什么异常类型的逻辑。
5. 自定义全局响应类
上面使用的方法返回值类BaseResponse类和RespGenerator类都是属于规范方法返回值结构体的类,也有利于一致化后端所有接口的返回结构,方便前端读取所需要的数据。
5.1 BaseResponse类
规定返回值结构
/**
* @author gf
* @date 2023/2/2
*/
@Data
public class BaseResponse<T> {
private String code;
private String messgae;
private T Data;
public BaseResponse() {
super();
}
public BaseResponse(String code, String messgae, T data) {
this.code = code;
this.messgae = messgae;
Data = data;
}
}
5.2 RespGenerator类
将逻辑处理后的数据包装转换成BaseResponse类进行返回给前端。
/**
* @author gf
* @date 2023/2/2
*/
public class RespGenerator {
// 正常返回时调用方法
public static BaseResponse success(Object data){
return new BaseResponse(BaseErrorEnum.SUCCESS.getCode(),"接口调用成功",data);
}
// 失败时调用方法
public static BaseResponse<Object> failure(BaseErrorEnum baseErrorEnum){
return new BaseResponse(baseErrorEnum.getCode(),baseErrorEnum.getMessage(),null);
}
// 失败时调用方法(提供给GlobalExceptionHandler类使用)
public static BaseResponse<Object> failure(String code,String message){
return new BaseResponse(code,message,null);
}
}
二. 效果演示
创建测试类
@RestController
public class ExceptionTest {
@GetMapping("/test")
public BaseResponse<String> sayHello(@RequestParam("name") String name){
if(!name.equals("老王")){
throw new BaseException(BaseErrorEnum.USER_NOT_EXIST);
}
else{
return RespGenerator.success("调用成功");
}
}
}
从代码中可以看到,若name不是老王,会抛出自定义异常如果姓名时老王,则返回成功
-----------------------------------------------------完毕----------------------------------------------------------