基于SpringMVC的全局异常处理器介绍

【基于SpringMVC的全局异常处理器介绍】完整攻略

前言

在开发 Web 应用程序时,异常是不可避免的问题。当 Web 应用程序运行时发生异常时,SpringMVC 提供了一种集中处理异常的方式 -- 全局异常处理器。本文将详细介绍基于 SpringMVC 的全局异常处理器的使用方法以及示例。

步骤1:新建全局异常处理类

我们需要使用一个能够捕获应用程序中所有异常的全局异常处理器类。可以通过定义一个简单的类,然后添加一个带有 throwable 参数和返回错误信息的方法来实现。请参考以下代码块:

@ControllerAdvice
public class GlobalExceptionHandler {


    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<ErrorResponse> defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        // TODO: 错误处理逻辑

    }
}

在代码中的 @ControllerAdvice 注解使得该类成为一个全局异常处理器,在整个应用程序容器中任何位置发生的异常都会被此处进行捕捉;@ExceptionHandler 注解则标明了该方法需要捕捉的异常类型。

步骤2:定义错误处理逻辑

当异常发生时,全局异常处理器会将异常的信息封装到一个自定义的错误响应对象中,然后将其返回给客户端。我们需要将捕捉到的异常、请求的 url 和一些额外的异常信息封装到这个自定义的对象中,并最终将它返回给客户端。

自定义的错误响应对象应该包含以下几个属性:

  • status: HTTP 状态码。

  • message: 错误描述信息。

  • timestamp: 错误发生时间戳。

请参考以下代码块:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
    private int status;
    private String message;
    private long timestamp;
 }

在代码中使用了 Lombok 注解 @Data 来简化 getter/setter、toString 等方法的编写。

为了将异常、url 和时间戳封装到错误响应对象中,可以使用如下代码块:

@ExceptionHandler(value = Exception.class)
public ResponseEntity<ErrorResponse> defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
    int statusCode = getStatus(req);
    ErrorResponse errorResponse = new ErrorResponse(statusCode, e.getMessage(), System.currentTimeMillis());
    return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(statusCode));
  }

  private int getStatus(HttpServletRequest request) {
      Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
      if (statusCode != null) {
          return statusCode;
      }
      return HttpStatus.INTERNAL_SERVER_ERROR.value();
  }

在代码中,getStatus() 方法可以获取 HTTP 状态码,将异常信息、url 和时间戳作为 ErrorResponse 对象的属性,最后将其作为 HTTP 响应返回给客户端。

步骤3:测试全局异常处理器

最后,我们需要测试全局异常处理器是否生效。可以使用 Restful API 调用该异常处理器,将异常信息封装到 Json 对象中,POST 方法调用该 API,并打印 HTTP 响应。请参考以下代码块:

{
  "message":"This is an unexpected error.",
  "stackTrace":"java.lang.NullPointerException\nat com.example.demo.DemoController.index(DemoController.java:20)\n",
}
@Test
public void testException() throws Exception {
    HttpRequest request = HttpRequest.POST("http://localhost:8080/api/error")
            .contentType("application/json")
            .send("{\"message\":\"This is an unexpected error.\",\"stackTrace\":\"java.lang.NullPointerException\\nat com.example.demo.DemoController.index(DemoController.java:20)\\n\"}");
    String response = request.body();
    System.out.println(response);
}

示例1:DTO 对象校验异常处理

一个常见的异常场景是对象校验异常,如果我们在代码中实现校验逻辑,那么我们需要在每个控制器处理请求时都做好异常处理工作。但是全局异常处理器为我们提供了一种更优雅的处理方式。我们只需要在我们的 DTO 对象中添加注解如 @NotBlank@NotNull 等,SpringMVC 将为我们自动进行对象校验,并捕获异常。代码如下:

@PostMapping("/user")
public User createUser(@Valid @RequestBody User user) {
    // ...
}

在这个代码块中,我们使用 @Valid 注解在 POST /user API 中自动进行 User 对象的校验,如果 User 对象校验不通过,全局异常处理器会捕捉到这个异常,并返回一个 400 Bad Request 的 HTTP 响应。

示例2:未捕获异常处理

还有一种常见的场景是未捕获的运行时异常。例如,一个 IndexOutOfBoundsException 异常很有可能是由数组越界等原因导致的。如果在我们的代码中未将其捕获处理,那么 SpringMVC 将会将异常直接返回给客户端,并显示 500 Internal Server Error 的 HTTP 响应。但是使用全局异常处理器,我们可以将异常信息封装到一个自定义的错误响应对象中,并返回一个更可读性更好的 HTTP 响应。对于这种场景,我们可以使用以下方法:

@GetMapping("/exception")
public void throwException() {
    throw new RuntimeException("Unexpected exception occurs.");
}

在这个 API 中,我们使用 throw new RuntimeException() 来手动触发一个未被捕获的运行时异常。当我们向这个 API 发送请求时,全局异常处理器将捕获这个异常,并返回一个 500 Internal Server Error 的 HTTP 响应,其中包含了自定义的异常信息。

结语

通过本文的介绍,你学会了如何使用 SpringMVC 提供的全局异常处理器来集中处理 Web 应用程序中的异常,使得代码更加简洁、优雅,更好地满足了异常处理的需求。并且,我们分别从对象校验异常和未捕获的异常两个场景给出了实际的代码示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于SpringMVC的全局异常处理器介绍 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • 详解Spring Security怎么从数据库加载我们的用户

    下面我就来详细讲解如何用Spring Security从数据库中加载用户。 1. 创建数据表 首先我们需要在数据库中创建数据表,用于存储我们的用户信息,常用的表结构如下: CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(45) NOT NULL, …

    Java 2023年6月3日
    00
  • 求解旋转数组的最小数字

    对于旋转数组的最小数字问题,有以下几个步骤: 理解问题:旋转数组是将一个有序数组的最开始若干个元素搬到数组的末尾,形成一个新的数组的过程。问题即为在这个旋转后的数组中寻找最小值。 思考解法:由于数组是旋转后的有序数组,我们需要利用这个性质来解决这个问题。可以采用以下三种解法: 二分查找:将数组分为两部分,其中一部分一定是有序的。根据二分查找的思想,在有序部分…

    Java 2023年5月19日
    00
  • 如何开发一个简单的Akka Java应用

    如何开发一个简单的Akka Java应用 Akka 是一个构建并发、分布式、可扩展的消息驱动应用程序的工具包与运行时。 要开发一个简单的Akka Java应用,可以按照以下步骤进行。 步骤一:添加依赖 在项目的 pom.xml 文件中添加以下依赖: <dependencies> <dependency> <groupId>…

    Java 2023年5月26日
    00
  • 浅谈JS如何写出漂亮的条件表达式

    下面是详细讲解“浅谈JS如何写出漂亮的条件表达式”的完整攻略: 1. 使用三元运算符 三元运算符是一种简洁的条件表达式语法,可以用来简化if-else语句的编码。三元运算符包含一个条件判断语句和两个表达式,形式如下: condition ? expression1 : expression2 其中,condition是一个布尔表达式,如果计算结果为true,…

    Java 2023年6月15日
    00
  • Java线程中断的本质深入理解

    Java线程中断的本质深入理解 Java中断是一种非常有用的工具,它可以停止正在运行的线程。然而,这个过程并不总是那么简单。 理解线程中断 线程中断可以被认为是设置一个标志,让线程知道它应该停止执行。线程可以使用isInterrupted()方法来检查标志是否被设置。也可以使用Thread.interrupted()方法来检查标志并清除它。 例如,以下代码段…

    Java 2023年5月26日
    00
  • java使用三层架构实现电影购票系统

    下面是详细讲解Java使用三层架构实现电影购票系统的完整攻略: 1. 什么是三层架构 三层架构是将一个软件系统分成三个层次进行开发和管理的架构,分别是: 表示层,也叫用户界面层,是用户直接看到和交互的部分,主要负责图形化的展示和与用户的交互。 业务逻辑层,也叫服务层,是处于表示层和数据存储层之间的一层,主要负责处理数据的业务逻辑。 数据存储层,也叫持久化层,…

    Java 2023年5月24日
    00
  • Spring boot2.0 日志集成方法分享(1)

    Spring Boot2.0 日志集成方法分享(1) 在Spring Boot2.0中,我们可以使用多种方式来集成日志框架,如Logback、Log4j2、Java Util Logging等。本文将详细讲解Spring Boot2.0日志集成方法的完整攻略,并提供两个示例。 1. 集成Logback 以下是集成Logback的基本流程: 在pom.xml文…

    Java 2023年5月15日
    00
  • Java 如何实现POST(x-www-form-urlencoded)请求

    实现POST(x-www-form-urlencoded)请求的过程如下所示: 构建URL和请求参数 创建URL对象和HttpURLConnection对象 设置请求头 写入请求参数 发起请求并接受服务器响应 以下为代码示例: 示例一 import java.net.*; import java.io.*; public class PostRequestE…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部