1.全局异常处理器

在开发springboot项目过程中,我们不可避免的需要处理各种异常,spring mvc架构中各层会出现大量的try-catch代码块,不仅有大量的冗余代码,而且还影响代码的可读性。

同时,通常来说,我们对于业务的期望,是有一条明确的主线的。而我们后期的处理原则很简单,只要出现不符合主线预期的情况,我们就可以通过手动控制抛出异常的方式,来控制程序执行。

【使用思路】:

我们之前碰到请求结果不符合预期的时候,解决方案是在service层手动抛出异常(比如,密码错误,用户被禁用,信息未找到,用户越权访问等),然后在controller层统一解决异常。而我们在controller层的解决方式,也无非就是try-catch,如果发现异常,就返回给客户端一个请求失败的响应信息。

而全局异常处理器,它的功能就是捕捉并处理Controller中指定的异常。

这样,我们只需要定义一个业务异常的父类BusinessException ,然后创建多个具体的业务异常,且都继承自BusinessException。这样,我们只需要在全局异常处理器中处理BusinessException这个业务异常的父类,就能捕捉并统一处理所有具体的业务异常。

2. 代码实现

目录结构如下

config                      
 └─ GlobalExceptionHandler  # 全局异常处理器
exception
 └─ BusinessException       # 业务异常父类
 └─ XXXException            # 具体的业务异常1
 └─ XXXException            # 具体的业务异常2
    ........

我们以登录模块全局异常处理为例子

在登录的功能中,我们期望的结果是,用户名密码正确,登录成功,服务器返回给客户端登陆成功的信息。

在下面的例子中,我们可能碰到的请求失败的结果,大概分为以下三类:

1. 用户名不存在

2. 密码错误

3. 用户被禁用

GlobalExceptionHandler.java

全局异常处理器。我们主要通过注解@RestControllerAdvice标明这是一个全局异常处理类。在方法上通过@ExceptionHandler注解指明你需要处理的异常类型

/**
 * 全局异常处理器类
 * @Author Mosfield
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理异常BusinessException及其子异常
    @ExceptionHandler(BusinessException.class)
    public Result handleException(BusinessException exception){
        // 统一返回请求失败结果
        return Result.error(exception.getMessage());
    }
}

BusinessException.java

业务异常父类

/**
 * 业务异常父类
 * @Author Mosfield
 */
public class BusinessException extends RuntimeException{

    public BusinessException() {
        super();
    }

    public BusinessException(String message) {
        super(message);
    }
}

UserNotFoundException.java

业务异常例子:用户未找到异常,继承自业务异常父类

/**
 * 未找到用户异常
 * @Author Mosfield
 */
public class UserNotFoundException extends BusinessException{
    public UserNotFoundException() {
        super();
    }

    public UserNotFoundException(String message) {
        super(message);
    }
}

Service

具体实现登录逻辑的service

/**
 * 具体登录方法 
 */
@Override
public User login(User user) {
    // 根据用户名获取对应的用户数据
    User result = userMapper.findUserByUserName(user.getUsername());
    // 判断用户是否存在
    if(result == null){
        throw new UserNotFoundException("用户名不存在");
    }
    // 计算md5加密后的密码
    String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));

    // 判断密码是否正确
    if(!result.getPassword().equals(md5Pass)){
        throw new PasswordMismatchException("密码错误");
    }

    // 判断用户是否被禁用
    if(result.getStatus() == 0){
        throw new UserDisableException("用户已禁用");
    }
    return result;
}
如人饮水,冷暖自知。
最后更新于 2023-08-05