
在进入正题之前,先给大家看一段代码,如下所示。
- package com.panda.handle_try_catch_gracefully.controller;
-
- import com.panda.handle_try_catch_gracefully.common.Result;
- import com.panda.handle_try_catch_gracefully.domain.po.User;
- import com.panda.handle_try_catch_gracefully.domain.vo.UserVO;
- import com.panda.handle_try_catch_gracefully.enums.ExceptionEnum;
- import com.panda.handle_try_catch_gracefully.exceptions.BusinessException;
- import com.panda.handle_try_catch_gracefully.service.IUserService;
- import org.springframework.web.bind.annotation.*;
-
- import javax.annotation.Resource;
- import java.util.List;
-
- @RestController
- @RequestMapping("ori/user")
- public class OriginUserController {
- @Resource
- private IUserService userService;
-
- @GetMapping("getUserInfo")
- public Result<UserVO> getUserInfo(String userId) {
- try {
- return userService.getUserInfo(userId);
- } catch (Exception e) {
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
- }
-
- @PostMapping("listUserInfo")
- public Result<List<UserVO>> listUserInfo(UserVO query) {
- try {
- return userService.listUserInfo(query);
- } catch (Exception e) {
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
- }
-
- @PostMapping("saveUser")
- public Result<String> saveUser(User user) {
- try {
- return userService.saveUser(user);
- } catch (Exception e) {
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
- }
-
- @PostMapping("updateUser")
- public Result<Boolean> updateUser(User user) {
- try {
- return userService.updateUser(user);
- } catch (Exception e) {
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
- }
-
- @PostMapping("deleteUser")
- public Result<Boolean> deleteUser(@RequestParam("userId") String userId) {
- try {
- return userService.deleteUser(userId);
- } catch (Exception e) {
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
- }
- }
不知道大家在项目中是否遇到过上面这种情况——controller里满屏的try-catch代码块,真的是闪瞎了我的钛合金狗眼呀。
虽然丑陋,但是这些try-catch代码块还是起到了一定的作用的——给前端响应一些通俗易懂的提示信息,如“用户编码不能为空”、“保存用户信息异常”、“更新用户信息失败”等。
如果没有这些丑陋的try-catch代码块,一旦抛出异常,用户看到的可能就是类似
- Exception in thread "main" java.lang.ArithmeticException: / by zero
-
- Exception in thread "main" java.lang.NullPointerException
-
- Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 0
之类的错误信息,对用户来说,无异于天书,极大地降低了用户体验度。
try-catch:虽然我长得丑,但是我有用呀!
这当然是我们不能容忍的!
作为一个有着强迫症的程序员,怎么能容忍这样的代码出现在我的项目中呢!
外行看热闹,可能看不出上面这段代码有什么丑陋的,但是,内行看门道,一眼就可以看出上面代码的丑陋之处。说一千道一万,上面这段代码究竟丑陋在哪里呢?
上面也提到了,try-catch代码块满屏飞,且处理逻辑一致,都是捕获异常,然后抛出异常或者返回错误信息,但这并不符合代码的可重用原则。
上面的代码只是一个controller,一个项目中可能有几十上百,甚至更多个controller呢!因此,对这块代码的主要优化思路,就是找出一种方法代替多次出现的try-catch代码块,并且原有的功能不能缺失。
这种方法就是本文要讲的内容——全局异常处理!

所谓全局异常处理,也叫统一异常处理,是一种统一处理异常的思路。
这种方法的好处在于,只需要在一个地方处理异常逻辑,就可以将controller的异常给捕获掉,而不用我们在每个controller类中写重复且丑陋的try-catch代码块,来捕获异常。
Spring Boot 的全局异常处理有两个很重要的注解,一个是ControllerAdvice注解或者RestControllerAdvice注解,另一个是ExceptionHandler注解。
ControllerAdvice注解或者RestControllerAdvice注解在类上使用,表示开启全局异常的捕获。
ExceptionHandler注解在方法上使用,可以通过value属性指定一个或多个异常,并捕获指定的异常,一般在方法体内对捕获到的异常进行解析,然后进行输出或返回等操作。
ControllerAdvice注解是Spring 3.2中新增的一个注解,是Controller的增强器,它的作用是给Controller(控制器)添加统一的操作或处理。
ControllerAdvice注解最常见的使用场景就是,结合ExceptionHandler注解用于全局异常处理。
ControllerAdvice注解是在类上声明的注解,用法主要有以下三点:
全局异常处理
结合ExceptionHandler注解,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。
全局数据预处理
结合InitBinder注解,用于对请求参数预处理,将表单中的参数绑定到实体上,或者对日期、金额类参数进行格式转换等。
全局数据绑定
结合ModelAttribute注解,将方法参数或方法返回值绑定到命名模型属性,该属性向web视图公开。
basePackages
该属性可以指定一个或多个包路径,这些包及其子包下的所有Controller都被ControllerAdvice注解管理。
- @RestControllerAdvice(basePackages={"com.panda","com.cat"})
- public class GlobalExceptionHandler {
- @ExceptionHandler(Exception.class)
- public String handleException(Exception e) {
- return "error";
- }
- }
basePackageClasses
该属性的作用和 basePackages 差不多。
该属性可以指定一个或多个Controller类,这些类所属的包及其子包下的所有 Controller 都被该ControllerAdvice注解管理。
- @RestControllerAdvice(basePackageClasses={UserController.class, OrderController.class})
- public class GlobalExceptionHandler {
- @ExceptionHandler(Exception.class)
- public String handleException(Exception e) {
- return "error";
- }
- }
assignableTypes
该属性指定一个或多个 Controller 类,这些类被该ControllerAdvice注解管理。
- @RestControllerAdvice(assignableTypes={UserController.class, OrderController.class})
- public class GlobalExceptionHandler {
- @ExceptionHandler(Exception.class)
- public String handleException(Exception e) {
- return "error";
- }
- }
annotations
该属性指定一个或多个注解,被这些注解所标记的Controller会被该ControllerAdvice注解管理。
- @RestControllerAdvice(annotations = {UserAnnotation.class, OrderAnnotation.class})
- public class GlobalExceptionHandler {
- @ExceptionHandler(Exception.class)
- public String handleException(Exception e) {
- return "error";
- }
- }
RestControllerAdvice注解是一个组合注解,由ControllerAdvice注解和ResponseBody注解组成。可见其作用和ControllerAdvice注解差不多。
RestControllerAdvice注解是Spring 4.3中新增的一个注解,也是Controller的增强器,它的作用同样是给Controller(控制器)添加统一的操作或处理。
RestControllerAdvice注解和ControllerAdvice注解的区别
1、当我们自定义的全局异常处理类加上ControllerAdvice注解时,如果异常处理方法需要返回json数据,则需要给每个异常处理方法添加ResponseBody注解。
2、当我们自定义的全局异常处理类加上RestControllerAdvice注解时,异常处理方法自动返回JSON格式的数据,我们不需要在该方法上再添加ResponseBody注解。
该注解的属性和ControllerAdvice注解的属性相同,不再赘述。
ExceptionHandler注解用来统一处理方法抛出的异常。
value
指定需要处理的一个或者多个异常类。
如果为空,则默认处理异常处理方法参数列表中列出的所有异常。
- @ExceptionHandler(value = BusinessException.class)
- public <T> Result<T> businessExceptionHandler(BusinessException businessException) {
- log.error(businessException.getErrorMsg(), businessException);
- return Result.fail(businessException.getCode(), businessException.getErrorMsg());
- }
-
- @ExceptionHandler
- public <T> Result<T> exceptionHandler1(Exception exception) {
- log.error(exception.getMessage());
- ExceptionEnum exceptionEnum = ExceptionEnum.UNKNOWN;
- if (exception instanceof BusinessException) {
- exceptionEnum = ExceptionEnum.INTERNAL_SERVER_ERROR;
- }
- if (exception instanceof IndexOutOfBoundsException) {
- exceptionEnum = ExceptionEnum.ILLEGAL_ARGUMENT_ERROR;
- }
- return Result.fail(exceptionEnum);
- }
搭建Spring Boot项目的过程就不在赘述了,项目结构如下所示。

- <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>mykits</artifactId>
- <groupId>com.panda</groupId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>handle-try-catch-gracefully</artifactId>
-
- <properties>
- <maven.compiler.source>11</maven.compiler.source>
- <maven.compiler.target>11</maven.compiler.target>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- </dependency>
-
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- </dependency>
- </dependencies>
- </project>
controller类,和上面的OriginUserController相比,代码量少了很多——try-catch代码块消失了。
放眼望去,整体代码清爽不少,核心代码尽收眼底。
- package com.panda.handle_try_catch_gracefully.controller;
-
- import com.panda.handle_try_catch_gracefully.common.Result;
- import com.panda.handle_try_catch_gracefully.domain.po.User;
- import com.panda.handle_try_catch_gracefully.domain.vo.UserVO;
- import com.panda.handle_try_catch_gracefully.service.IUserService;
- import org.springframework.web.bind.annotation.*;
-
- import javax.annotation.Resource;
- import java.util.List;
-
- @RestController
- @RequestMapping("user")
- public class UserController {
-
- @Resource
- private IUserService userService;
-
- @GetMapping("getUserInfo")
- public Result
getUserInfo(String userId) { - return userService.getUserInfo(userId);
- }
-
- @PostMapping("listUserInfo")
- public Result
> listUserInfo(UserVO query) {
- return userService.listUserInfo(query);
- }
-
- @PostMapping("saveUser")
- public Result
saveUser(User user) { - return userService.saveUser(user);
- }
-
- @PostMapping("updateUser")
- public Result<Boolean> updateUser(User user) {
- return userService.updateUser(user);
- }
-
- @PostMapping("deleteUser")
- public Result<Boolean> deleteUser(@RequestParam("userId") String userId) {
- return userService.deleteUser(userId);
- }
- }
封装的统一返回结果。
code:响应结果代码,在本文中,可以是自定义的代码,也可以是ExceptionEnum枚举的code。
msg:错误信息。主要在方法调用失败时,返回给前端的提示信息。当然在方法调用成功时,也可以返回给前端一个类似“请求成功”之类的信息。
successFlag:响应成功与否的标志。true表示成功,false表示失败。
data:返回给前端的数据。一般只有在响应成功时才会向前端返回数据,以查询类方法居多。
- package com.panda.handle_try_catch_gracefully.common;
-
- import com.panda.handle_try_catch_gracefully.enums.ExceptionEnum;
-
- public class Result<T> {
- private String code;
-
- private String msg;
-
- private Boolean successFlag;
-
- private T data;
-
- public static <T> Result<T> success() {
- Result<T> result = new Result<>();
- result.successFlag(true);
- return result;
- }
-
- public static <T> Result<T> success(T data) {
- Result<T> result = new Result<>();
- result.successFlag(true).data(data);
- return result;
- }
-
- public static <T> Result<T> fail(String code, String errorMsg) {
- Result<T> result = new Result<>();
- result.successFlag(false).code(code).msg(errorMsg);
- return result;
- }
-
- public static <T> Result<T> fail(ExceptionEnum exceptionEnum) {
- Result<T> result = new Result<>();
- result.successFlag(false).code(exceptionEnum.getCode()).msg(exceptionEnum.getErrorMsg());
- return result;
- }
-
- public Result<T> code(String code) {
- this.code = code;
- return this;
- }
-
- public Result<T> msg(String msg) {
- this.msg = msg;
- return this;
- }
-
- public Result<T> successFlag(Boolean successFlag) {
- this.successFlag = successFlag;
- return this;
- }
-
- public Result<T> data(T data) {
- this.data = data;
- return this;
- }
-
- public String getCode() {
- return code;
- }
-
- public String getMsg() {
- return msg;
- }
-
- public T getData() {
- return data;
- }
-
- public Boolean getSuccessFlag() {
- return successFlag;
- }
- }
用户信息实体类。
在实际项目中,User的各个属性一般对应用户表的各个字段。
- package com.panda.handle_try_catch_gracefully.domain.po;
-
- import lombok.Data;
-
- import java.util.Date;
-
- @Data
- public class User {
-
- private String id;
-
- private String name;
-
- private String mobilePhone;
-
- private Date createTime;
-
- private String createBy;
-
- private Date updateTime;
-
- private String updateBy;
-
- private Integer validFlag;
-
- private Integer deleteFlag;
- }
用户信息。
返回给前端的实体类。
在本文中,为了省事,也作为查询条件。在实际项目中,应该和查询条件区分开,用类似UserQuery之类的实体表示用户查询条件。
- package com.panda.handle_try_catch_gracefully.domain.vo;
-
- import com.panda.handle_try_catch_gracefully.domain.po.User;
- import lombok.Data;
-
- @Data
- public class UserVO extends User {
-
- }
异常枚举类。
code:异常代码。
errorMsg:异常提示信息。
- package com.panda.handle_try_catch_gracefully.enums;
-
- public enum ExceptionEnum {
- /**
- * 请求错误!
- */
- BAD_REQUEST("400", "请求错误!"),
- /**
- * 未经授权的请求!
- */
- UNAUTHORIZED("401", "未经授权的请求!"),
- /**
- * 没有访问权限!
- */
- FORBIDDEN("403", "没有访问权限!"),
- /**
- * 请求的资源未不到!
- */
- NOT_FOUND("404", "请求的资源未不到!"),
- /**
- * 服务器内部错误!
- */
- INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
- /**
- * 服务器正忙,请稍后再试!
- */
- BAD_GATEWAY("502", "服务器正忙,请稍后再试!"),
- /**
- * 服务器正忙,请稍后再试!
- */
- SERVICE_UNAVAILABLE("503", "服务器正忙,请稍后再试!"),
- /**
- * 网关超时!
- */
- GATEWAY_TIMEOUT("504", "网关超时!"),
- /**
- * 非法参数异常!
- */
- ILLEGAL_ARGUMENT_ERROR("10000", "非法参数异常!"),
- /**
- * 用户ID不能为空!
- */
- USER_ID_NOT_BLANK("10001", "用户ID不能为空!"),
- /**
- *
- */
- UNKNOWN("9999", "未知异常!");
-
- /**
- * 错误码
- */
- private final String code;
-
- /**
- * 错误描述
- */
- private final String errorMsg;
-
- ExceptionEnum(String code, String errorMsg) {
- this.code = code;
- this.errorMsg = errorMsg;
- }
-
- public String getCode() {
- return code;
- }
-
- public String getErrorMsg() {
- return errorMsg;
- }
- }
在实际项目中,推荐使用自定义的业务异常类,而不用RuntimeException。
如果代码中抛出了RuntimeException,IDEA会提示上图之类的信息(可能要安装插件)。
- package com.panda.handle_try_catch_gracefully.exceptions;
-
- import com.panda.handle_try_catch_gracefully.enums.ExceptionEnum;
-
- public class BusinessException extends RuntimeException {
- /**
- * 异常枚举
- */
- private ExceptionEnum exceptionEnum;
- /**
- * 错误码
- */
- private final String code;
- /**
- * 错误信息
- */
- private final String errorMsg;
-
- public BusinessException(ExceptionEnum exceptionEnum) {
- super(String.format("code = %s, errorMsg = %s", exceptionEnum.getCode(), exceptionEnum.getErrorMsg()));
- this.exceptionEnum = exceptionEnum;
- this.code = exceptionEnum.getCode();
- this.errorMsg = exceptionEnum.getErrorMsg();
- }
-
- public BusinessException(String code, String errorMsg) {
- super(String.format("code = %s, errorMsg = %s", code, errorMsg));
- this.code = code;
- this.errorMsg = errorMsg;
- }
-
- public BusinessException(String code, String errorMsg, Object... args) {
- super("code = " + code + ", errorMsg = " + String.format(errorMsg, args));
- this.code = code;
- this.errorMsg = String.format(errorMsg, args);
- }
-
- public ExceptionEnum getExceptionEnum() {
- return exceptionEnum;
- }
-
- public String getErrorMsg() {
- return errorMsg;
- }
-
- public String getCode() {
- return code;
- }
-
- }
统一异常处理类。
注意@RestControllerAdvice注解。
在本类中,我们创建三个方法,分别处理不同场景的异常。
businessExceptionHandler方法处理抛出BusinessException异常的场景,即一旦抛出BusinessException异常,就会被businessExceptionHandler方法处理。
illegalArgumentExceptionHandler方法处理抛出IllegalArgumentException异常的场景,即一旦抛出IllegalArgumentException异常,就会被illegalArgumentExceptionHandler方法处理。
exceptionHandler方法是兜底的,捕获抛出Exception异常的场景,即一旦抛出Exception异常,就会被exceptionHandler方法处理。
当然,你可以根据实际项目需要,创建更多的异常处理方法,如空指针异常处理方法、数组越界异常处理方法、类找不到异常处理方法等。
- package com.panda.handle_try_catch_gracefully.handler;
-
- import com.panda.handle_try_catch_gracefully.common.Result;
- import com.panda.handle_try_catch_gracefully.enums.ExceptionEnum;
- import com.panda.handle_try_catch_gracefully.exceptions.BusinessException;
- 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;
-
- @Slf4j
- @RestControllerAdvice
- public class UnifiedExceptionHandler {
- /**
- * 业务异常处理
- *
- * @param businessException 业务异常信息
- */
- @ExceptionHandler(value = BusinessException.class)
- public <T> Result<T> businessExceptionHandler(BusinessException businessException) {
- log.error(businessException.getErrorMsg(), businessException);
- return Result.fail(businessException.getCode(), businessException.getErrorMsg());
- }
-
- /**
- * 未知异常处理
- *
- * @param exception 异常信息
- */
- @ExceptionHandler(value = Exception.class)
- public <T> Result<T> exceptionHandler(Exception exception) {
- log.error(exception.getMessage(), exception);
- return Result.fail(ExceptionEnum.UNKNOWN.getCode(), ExceptionEnum.UNKNOWN.getErrorMsg());
- }
-
- /**
- * 参数异常处理
- *
- * @param exception 异常信息
- */
- @ExceptionHandler(value = IllegalArgumentException.class)
- public <T> Result<T> illegalArgumentExceptionHandler(IllegalArgumentException exception) {
- log.error(exception.getMessage(), exception);
- return Result.fail(ExceptionEnum.ILLEGAL_ARGUMENT_ERROR.getCode(), ExceptionEnum.ILLEGAL_ARGUMENT_ERROR.getErrorMsg());
- }
- }
用户接口类。
在本例中定义了5个方法:
getUserInfo:根据用户ID查询用户信息。
listUserInfo:根据查询条件查询符合条件用户列表。
saveUser:保存用户信息。
updateUser:更新用户信息。
deleteUser:删除用户信息。
- package com.panda.handle_try_catch_gracefully.service;
-
- import com.panda.handle_try_catch_gracefully.common.Result;
- import com.panda.handle_try_catch_gracefully.domain.po.User;
- import com.panda.handle_try_catch_gracefully.domain.vo.UserVO;
-
- import java.util.List;
-
- public interface IUserService {
-
- Result<UserVO> getUserInfo(String userId);
-
- Result<List<UserVO>> listUserInfo(UserVO query);
- Result<String> saveUser(User user);
-
- Result<Boolean> updateUser(User user);
-
- Result<Boolean> deleteUser(String userId);
- }
用户接口实现类。
由于本文的重点不是实现业务逻辑,因此各个实现方法并没有详细的业务逻辑,而是抛出不同的异常,验证我们上面给出统一异常处理类是否可以真的处理各种异常。
- package com.panda.handle_try_catch_gracefully.service.impl;
-
- import com.panda.handle_try_catch_gracefully.common.Result;
- import com.panda.handle_try_catch_gracefully.domain.po.User;
- import com.panda.handle_try_catch_gracefully.domain.vo.UserVO;
- import com.panda.handle_try_catch_gracefully.service.IUserService;
- import org.springframework.stereotype.Service;
-
- import java.util.List;
-
- @Service
- public class UserServiceImpl implements IUserService {
-
- @Override
- public Result<UserVO> getUserInfo(String userId) {
- // 默认抛出异常
- throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
- }
-
- @Override
- public Result<List<UserVO>> listUserInfo(UserVO query) {
- // 默认抛出异常
- throw new IllegalArgumentException();
- }
-
- @Override
- public Result<String> saveUser(User user) {
- // 默认抛出异常
- throw new IndexOutOfBoundsException();
- }
-
- @Override
- public Result<Boolean> updateUser(User user) {
- // 默认抛出异常
- throw new RuntimeException();
- }
-
- @Override
- public Result<Boolean> deleteUser(String userId) {
- // 默认抛出异常
- throw new ClassCastException();
- }
- }
测试方法
http://localhost:8080/user/getUserInfo
测试结果
- {
- "code": "500",
- "msg": "服务器内部错误!",
- "successFlag": false,
- "data": null
- }
从上面的代码可知,getUserInfo方法抛出的异常如下:
throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
恰好可以被UnifiedExceptionHandler的businessExceptionHandler方法监听。
测试结论
测试成功。
统一异常处理类可以正常捕获BusinessException异常。
测试方法
http://localhost:8080/user/listUserInfo
测试结果
- {
- "code": "10000",
- "msg": "非法参数异常!",
- "successFlag": false,
- "data": null
- }
从上面的代码可知,listUserInfo方法抛出的异常如下:
throw new IllegalArgumentException();
恰好可以被UnifiedExceptionHandler的illegalArgumentExceptionHandler方法监听。
测试结论
测试成功。
统一异常处理类可以正常捕获IllegalArgumentException异常。
测试方法
http://localhost:8080/user/saveUser
测试结果
- {
- "code": "500",
- "msg": "服务器内部错误!",
- "successFlag": false,
- "data": null
- }
从上面的代码可知,saveUser方法抛出的异常如下:
throw new IndexOutOfBoundsException();
虽然UnifiedExceptionHandler没有专门处理IndexOutOfBoundsException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。
而IndexOutOfBoundsException异常恰好是Exception的子类,因此可以被正常监听到。
测试结论
测试成功。
统一异常处理类可以正常捕获IndexOutOfBoundsException异常。
测试方法
http://localhost:8080/user/updateUser
测试结果
- {
- "code": "9999",
- "msg": "未知异常!",
- "successFlag": false,
- "data": null
- }
从上面的代码可知,updateUser方法抛出的异常如下:
throw new RuntimeException();
同上。
虽然UnifiedExceptionHandler没有专门处理RuntimeException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。
而RuntimeException异常恰好是Exception的子类,因此可以被正常监听到。
测试结论
测试成功。
统一异常处理类可以正常捕获RuntimeException异常。
测试方法
http://localhost:8080/user/deleteUser
测试结果
- {
- "code": "9999",
- "msg": "未知异常!",
- "successFlag": false,
- "data": null
- }
从上面的代码可知,deleteUser方法抛出的异常如下:
throw new ClassCastException();
同上。
虽然UnifiedExceptionHandler没有专门处理ClassCastException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。
而ClassCastException异常恰好是Exception的子类,因此可以被正常监听到。
测试结论
测试成功。
统一异常处理类可以正常捕获ClassCastException异常。