【基于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技术站