springBoot统一异常处理

一、概述:

    1.1.Spring在3.2版本增加了一个注解@ControllerAdvice,可以与@ExceptionHandler@InitBinder@ModelAttribute 等注解注解配套使用。

简单的说,该注解可以把异常处理器应用到所有控制器,而不是单个控制器。借助该注解,我们可以实现:在独立的某个地方,比如单独一个类,定义一套对各种异常的处理机制,然后在类的签名加上注解@ControllerAdvice,统一对 不同阶段的、不同异常 进行处理。这就是统一异常处理的原理。

  1.2.对异常按阶段进行分类,大体可以分成:进入Controller前的异常 和 Service 层异常。

统一异常处理的作用: 目标就是消灭95%以上的 try catch 代码块,并以优雅的 Assert(断言) 方式来校验业务的异常情况,只关注业务逻辑,而不用花费大量精力写冗余的 try catch 代码块。  用于捕获Controller中抛出的指定类型的异常,从而达到全局不同类型的异常区别处理的目的。

  1.3.优点:

  • 不用强制写try-catch,由全局异常处理器统一捕获处理。
  • 自定义异常,只能用全局异常来捕获。不能直接返回给客户端,客户端是看不懂的,需要接入全局异常处理器
  • JSR303规范的Validator参数校验器,参数校验不通过会抛异常,是无法使用try-catch语句直接捕获,只能使用全局异常处理器。

二、统一异常处理相关注解:

@ControllerAdvice 详解
作用范围:
@ControllerAdvice 注解可以用于类级别,用于标记一个类为全局异常处理器。
它也可以与 @RestController、@Controller 注解一起使用,用于指定全局异常处理器只处理带有 @RestController 或 @Controller 注解的控制器类中抛出的异常。
异常处理:
通过在 @ControllerAdvice 注解标记的类中定义异常处理方法,可以统一处理应用程序中的各种异常。
异常处理方法需要使用 @ExceptionHandler 注解进行标记,以指定处理的异常类型。
作用域:
@ControllerAdvice 注解可以限定作用的范围,即指定哪些控制器类的异常会被当前的全局异常处理器处理。
可以通过 annotations、basePackages、basePackageClasses 等属性来指定作用的范围。
其他用途:
除了处理异常之外,@ControllerAdvice 还可以用于其他方面,比如全局数据绑定、全局数据预处理等。
5.@ExceptionHandler 详解
用法:
@ExceptionHandler 注解可以用于方法级别,用于标记一个方法为异常处理方法。
异常处理方法需要定义在控制器类中,并且可以有任意的访问修饰符。
参数:
异常处理方法的参数可以是异常类型,也可以是其他类型的参数。
如果异常处理方法的参数是异常类型,则该方法只会处理指定类型的异常。
如果异常处理方法的参数是其他类型的参数,则该方法会处理所有类型的异常,并且异常对象会作为参数传递给方法。
异常处理逻辑:
异常处理方法可以编写任意的异常处理逻辑,比如记录日志、返回错误信息、执行特定的补救措施等。

在方法中可以通过异常对象来获取异常信息,如异常消息、堆栈轨迹等。
多个异常处理方法:
一个控制器类可以有多个异常处理方法,用来处理不同类型的异常。
当多个异常处理方法都能处理同一类型的异常时,Spring 框架会选择最匹配的异常处理方法来处理异常。
总的来说,@ExceptionHandler 注解提供了一种在控制器中处理异常的机制,能够根据不同类型的异常来执行不同的异常处理逻辑,使代码更加清晰和易于维护。

三、代码实现:

3.1.pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>08_globalexception</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>08_globalException</name>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <!--<dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>-->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <version>${spring-boot.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring-boot.version}</version>
            <scope>test</scope>
        </dependency>

        <!--添加Knife4j依赖-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
            <version>4.3.0</version>
        </dependency>

        <!--引入Lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.32</version>
        </dependency>


        <!-- Spring Boot支持Spring Validation的依赖项,用于检查参数的基本有效性 -->
        <!--有时候idea要求必须写version否则报错-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>3.2.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
            <version>${spring-boot.version}</version>
        </dependency>
    </dependencies>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>



    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.zyq.globalException.Application</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

3.2.application.properties

# 应用服务 WEB 访问端口
spring.profiles.active=dev
# 使用yml配置方式,Jackson全局过滤null值
spring.jackson.default-property-inclusion=NON_NULL

3.2.application-dev.properties

server.port=9080
# 日志级别
logging.level.com.zyq.globalException=trace
# 热部署
spring.devtools.restart.enabled=true
spring.devtools.restart.additional-paths=src/main/java

3.3.统一异常处理类:

package com.zyq.globalException.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//@RestControllerAdvice是什么
//@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    @ResponseBody
    public String handleServiceException(RuntimeException e){
        log.debug("GlobalExceptionHandler---->handleServiceException()::捕获到RuntimeException:{}", e.getMessage());
        return  e.getMessage();
    }

    @ExceptionHandler
    @ResponseBody
    public String handleThrowable(Throwable e){
        log.debug("GlobalExceptionHandler---->handleServiceException()::捕获到Throwable:{}", e.getMessage());
        e.printStackTrace(); // 强烈建议
        String message = "程序运行时出现未知错误,请联系系统管理员!";
        return  message;
    }
}


//@RestControllerAdvice的特点:
//1.通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。
//2.注解了@RestControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
//3.@RestControllerAdvice注解, 会生效于标注了 @RequestMapping的控制器的方法上。

//4.@ExceptionHandler:用于指定异常处理方法。当与@RestControllerAdvice配合使用时,用于全局处理控制器里的异常。
//5.@InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
//6.@ModelAttribute:当与@ControllerAdvice配合使用时,可以让全局的@RequestMapping都能获得在此处设置的键值对(本来作用是绑定键值对到Model中)

//注: @RestControllerAdvice和@ControllerAdvice可以用basePackages指定 Controller 范围
//basePackages: 指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理,比如:
//@RestControllerAdvice(basePackages={"com.zyq.controller"})
//@Slf4j
//public class ExceptionHandlerAdvice {   }

//basePackageClasses: 是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的
// 包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理

//assignableTypes: 指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理

//annotations: 指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理

//相关链接: https://blog.csdn.net/user2025/article/details/105458842

3.4.UserController:

package com.zyq.globalException.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class UserController {

    @GetMapping("/user")
    public String getUser() {
        log.info("UserController.getUser");
        System.out.println(5/0);
        return "user";
    }


    @GetMapping("/user2")
    public String getUser2() {
        log.info("UserController.getUser2");
        return "zyq-user";
    }

}

3.5.主启动类:

package com.zyq.globalException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

  • 30
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值