站内搜索

搜索

06-02 13:26
05-31 17:11

SpringBoot实现全局异常处理

47

主题

38

点数

151

积分

地衡测影

积分
151

柴到了

发表于 2025-3-21 02:12:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x

Spring Boot实现全局异常处理

​ 在项目开发中出现异常时很平常不过的事情,我们处理异常也有很多种方式,可能如下:

public int test(int a ,int b){
    int c=0;
    try{
        c=a/b;
    }catch (Exception ex){
        ex.printStackTrace();
    }
    return c;
}

​ 如果我们这样处理异常,代码中就会出现特别多的异常处理模块,这样代码就会变得可读性非常差,而且业务模块逻辑会夹杂特别多的非业务逻辑。但是在项目开发的过程中我们应该将主要精力放在业务模块,除了必要的异常处理模块最好不要再包含其他无关紧要的代码。那么我们如何处理项目中无处不在的异常呢?这就引出了我们要介绍的全局异常处理方法,主要有两种种方式:

  • HandlerExceptionResolver。
  • @RestControllerAdvice+@ExceptionHandler

​ 今天我们主要介绍一下@RestControllerAdvice+@ExceptionHandler模式处理全局异常。

全局异常处理

首先我们先介绍一下@RestControllerAdvice和@ExceptionHandler

  • @RestControllerAdvice注解:他是一个比较特殊的@Component,用于定义全局异常处理类作用在所有的@RestController类型的接口上。(和@ControllerAdvice注解作用类似)
  • @ExceptionHandler注解:用于声明处理异常的方法

配置全局异常

@RestControllerAdvice+@ExceptionHandler只要设计得当,就不需要在Controller层使用trg-catch了!下面我们先写介绍一个Controller层全局异常处理类。

package com.alex.advice;

import com.alex.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: springboot-exception
 * @description: 全局异常处理类
 * @author: <a href="https://sunalex.cn">Alex</a>
 * @create: 2023-08-04 09:19
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    @ExceptionHandler(value = Exception.class)
    public Result<String> exception(HttpServletRequest request, Exception e){
        Result<String> result = new Result<>();
        result.setCode(-1);
        result.setMessage("系统错误");
        result.setData(e.getMessage() + " " + request.getRequestURL());
        log.error("系统错误,错误类型:{}",e.getMessage());
        log.error("系统错误,错误地址:{}",request.getRequestURL());
        return result;
    }
}

至此 , 一个简单的全局异常处理解决方式就完成了,这只是一个简单的异常处理方式,远不能达到完整项目中全局异常处理的方案。

: Result 是自定义的全局统一返回结果集

全局异常处理的完善

​ 项目中业务繁杂 , 可以通过自定义的异常知道哪一个模块发生了异常 , 并且不同的业务模块也有不同的异常处理方式,这也方便我们做扩展

package com.alex.exception;

import lombok.Data;

/**
 * @program: springboot-exception
 * @description: 自定义异常类
 * @author: <a href="https://sunalex.cn">Alex</a>
 * @create: 2023-08-04 09:46
 **/
@Data
public class BaseException extends RuntimeException {

    private String code;

    private String msg;

    public BaseException() {
        super();
    }

    public BaseException(String msg) {
        super(msg);
        this.msg = msg;
    }

    public BaseException(String code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg;
    }

    public BaseException(String msg, Throwable e) {
        super(msg, e);
        this.msg = msg;
    }

    public BaseException(String code, String msg, Throwable e) {
        super(msg, e);
        this.code = code;
        this.msg = msg;
    }

    public BaseException(Throwable e) {
        super(e);
    }
}

加入自定义异常处理

package com.alex.advice;

import com.alex.exception.BaseException;
import com.alex.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: springboot-exception
 * @description: 全局异常处理类
 * @author: <a href="https://sunalex.cn">Alex</a>
 * @create: 2023-08-04 09:19
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    /**
     * 处理所有不可知的异常
     * @param request 请求
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(value = Exception.class)
    public Result<String> exception(HttpServletRequest request, Exception e){
        Result<String> result = new Result<>();
        result.setCode(-1);
        result.setMessage("系统错误");
        result.setData(e.getMessage() + " " + request.getRequestURL());
        log.error("系统错误,错误类型:{}",e.getMessage());
        log.error("系统错误,错误地址:{}",request.getRequestURL());
        return result;
    }

    /**
     * 自定义异常处理
     * @param request 请求
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(value = BaseException.class)
    public Result<String> baseException(HttpServletRequest request, BaseException e){
        if (e.getCode() == null) {
            return Result.error(e.getMessage() + " " + request.getRequestURL());
        }
        return Result.error("错误编码为" + e.getCode());
    }
}

处理 Controller 数据绑定、数据校验的异常

在用户登录Model字段上注解数据校验规则。

package com.alex.entity;

import lombok.Data;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

/**
 * @program: springboot-exception
 * @description: 用户登陆实体类
 * @author: <a href="https://sunalex.cn">Alex</a>
 * @create: 2023-08-04 10:32
 **/
@Data
public class UserLogin {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @NotNull(message = "密码不能为空")
    private String password;
}

SpringBoot中可以使用@Validated + @RequestBody注解方式实现数据绑定和数据校验。例如登录方式为:

package com.alex.controller;

import com.alex.entity.UserLogin;
import com.alex.util.Result;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: springboot-exception
 * @description: 用户控制器
 * @author: <a href="https://sunalex.cn">Alex</a>
 * @create: 2023-08-04 10:33
 **/
@RestController
public class UserController {

    @PostMapping("/login")
    public Result<?> login(@RequestBody @Validated UserLogin user){
        // 这里仅作模拟 测试Validated功能
        if ("123456".equals(user.getPassword()) && "admin".equals(user.getUsername())){
            return Result.ok("登录成功");
        }
        return Result.error("登录失败,用户名或密码错误");
    }
}

如果数据校验不对数据抛出的异常为MethodArgumentNotValidException,所以我们可以在全局异常处理类中添加对MethodArgumentNotValidException异常的处理声明,就可以实现全局处理数据校验和绑定的异常了,实现如下:

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result<String> methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e){
        log.error("参数校验异常:{}" , e.getMessage());
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        if (bindingResult.hasErrors()){
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null){
                message = fieldError.getField() + fieldError.getDefaultMessage();
            }
        }
        return Result.error(message + " " + request.getRequestURL());
    }

通过上面介绍的未知异常、数据校验和自定义全局异常所有的Controller层的异常处理方式全部都集中到了GlobalExceptionHandler类中,那么我们在Controller类中就不再需要收到记录错误了。

总结

今天主要讲解了@RestControllerAdvice+@ExceptionHandler进行统一的在Controller层上的全局异常处理。详细代码可在Gitee了解

温馨提示:看帖回帖是一种美德,您的每一次发帖、回帖都是对论坛最大的支持,谢谢! [这是默认签名,点我更换签名]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入社群

加入社群

Pixtech

Powered by Pixtech

© 2025 Pixtech Team.