如何优雅的进行Controller全局异常处理?

如何优雅的进行Controller全局异常处理?_第1张图片

【Spring Boot系列】 如何优雅的进行Controller全局异常处理?

在进入正题之前,先给大家看一段代码,如下所示。

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 getUserInfo(String userId) {
        try {
            return userService.getUserInfo(userId);
        } catch (Exception e) {
            throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("listUserInfo")
    public Result> listUserInfo(UserVO query) {
        try {
            return userService.listUserInfo(query);
        } catch (Exception e) {
            throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("saveUser")
    public Result saveUser(User user) {
        try {
            return userService.saveUser(user);
        } catch (Exception e) {
            throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("updateUser")
    public Result updateUser(User user) {
        try {
            return userService.updateUser(user);
        } catch (Exception e) {
            throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("deleteUser")
    public Result 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全局异常处理?_第2张图片

全局异常处理

所谓全局异常处理,也叫统一异常处理,是一种统一处理异常的思路。

这种方法的好处在于,只需要在一个地方处理异常逻辑,就可以将controller的异常给捕获掉,而不用我们在每个controller类中写重复且丑陋的try-catch代码块,来捕获异常。

Spring Boot 的全局异常处理有两个很重要的注解,一个是ControllerAdvice注解或者RestControllerAdvice注解,另一个是ExceptionHandler注解。

ControllerAdvice注解或者RestControllerAdvice注解在类上使用,表示开启全局异常的捕获

ExceptionHandler注解在方法上使用,可以通过value属性指定一个或多个异常,并捕获指定的异常,一般在方法体内对捕获到的异常进行解析,然后进行输出或返回等操作

ControllerAdvice注解

简介

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注解

简介

RestControllerAdvice注解是一个组合注解,由ControllerAdvice注解和ResponseBody注解组成。可见其作用和ControllerAdvice注解差不多。

RestControllerAdvice注解是Spring 4.3中新增的一个注解,也是Controller的增强器,它的作用同样是给Controller(控制器)添加统一的操作或处理。

RestControllerAdvice注解和ControllerAdvice注解的区别

1、当我们自定义的全局异常处理类加上ControllerAdvice注解时,如果异常处理方法需要返回json数据,则需要给每个异常处理方法添加ResponseBody注解。

2、当我们自定义的全局异常处理类加上RestControllerAdvice注解时,异常处理方法自动返回JSON格式的数据,我们不需要在该方法上再添加ResponseBody注解。

属性

该注解的属性和ControllerAdvice注解的属性相同,不再赘述。

ExceptionHandler注解

简介

ExceptionHandler注解用来统一处理方法抛出的异常。

被ExceptionHandler注解标注的方法支持以下参数类型

  1. 异常参数,如Exception.class、RuntimeException等。
  2. 请求和/或响应对象(通常来自Servlet API),例如javax.servlet.ServletRequest 或者 javax.servlet.http.HttpServletRequest。
  3. session对象,如javax.servlet.http.HttpSession。
  4. org.springframework.web.context.request.WebRequest 或者 org.springframework.web.context.request.NativeWebRequest。
  5. 表示当前请求区域设置的的java.util.Locale对象,例如org.springframework.web.servlet.LocaleResolver。
  6. java.io.InputStream 或者 java.io.Reader。
  7. java.io.OutputStream 或者 java.io.Writer。
  8. org.springframework.ui.Model。

被ExceptionHandler注解标注的方法支持以下返回类型

  1. ModelAndView类型。
  2. org.springframework.ui.Model类型。
  3. java.util.Map类型。
  4. org.springframework.web.servlet.View类型。
  5. String类型。
  6. ResponseBody注解方法(仅限Servlet)以设置响应内容。
  7. HttpEntity 或者 ResponseEntity 类型。
  8. void类型。

属性

value

指定需要处理的一个或者多个异常类。

如果为空,则默认处理异常处理方法参数列表中列出的所有异常。

@ExceptionHandler(value = BusinessException.class)
public  Result businessExceptionHandler(BusinessException businessException) {
    log.error(businessException.getErrorMsg(), businessException);
    return Result.fail(businessException.getCode(), businessException.getErrorMsg());
}

@ExceptionHandler
public  Result 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项目的过程就不在赘述了,项目结构如下所示。

如何优雅的进行Controller全局异常处理?_第3张图片

POM.xml代码



    
        mykits
        com.panda
        0.0.1-SNAPSHOT
    
    4.0.0

    handle-try-catch-gracefully

    
        11
        11
    

    
        
            com.google.guava
            guava
        

        
            org.apache.commons
            commons-lang3
        

        
            commons-io
            commons-io
        

        
            commons-collections
            commons-collections
        

        
            commons-codec
            commons-codec
        
    

UserController.java代码

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 updateUser(User user) {
        return userService.updateUser(user);
    }

    @PostMapping("deleteUser")
    public Result deleteUser(@RequestParam("userId") String userId) {
        return userService.deleteUser(userId);
    }
}

Result.java代码

封装的统一返回结果。

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 {
    private String code;

    private String msg;

    private Boolean successFlag;

    private T data;

    public static  Result success() {
        Result result = new Result<>();
        result.successFlag(true);
        return result;
    }

    public static  Result success(T data) {
        Result result = new Result<>();
        result.successFlag(true).data(data);
        return result;
    }

    public static  Result fail(String code, String errorMsg) {
        Result result = new Result<>();
        result.successFlag(false).code(code).msg(errorMsg);
        return result;
    }

    public static  Result fail(ExceptionEnum exceptionEnum) {
        Result result = new Result<>();
        result.successFlag(false).code(exceptionEnum.getCode()).msg(exceptionEnum.getErrorMsg());
        return result;
    }

    public Result code(String code) {
        this.code = code;
        return this;
    }

    public Result msg(String msg) {
        this.msg = msg;
        return this;
    }

    public Result successFlag(Boolean successFlag) {
        this.successFlag = successFlag;
        return this;
    }

    public Result 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.java代码

用户信息实体类。

在实际项目中,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;
}

UserVO.java代码

用户信息。

返回给前端的实体类。

在本文中,为了省事,也作为查询条件。在实际项目中,应该和查询条件区分开,用类似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 {
    
}

ExceptionEnum.java代码

异常枚举类。

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;
    }
}

BusinessException.java代码

在实际项目中,推荐使用自定义的业务异常类,而不用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;
    }

}

UnifiedExceptionHandler.java代码

统一异常处理类。

注意@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  Result businessExceptionHandler(BusinessException businessException) {
        log.error(businessException.getErrorMsg(), businessException);
        return Result.fail(businessException.getCode(), businessException.getErrorMsg());
    }

    /**
     * 未知异常处理
     *
     * @param exception 异常信息
     */
    @ExceptionHandler(value = Exception.class)
    public  Result exceptionHandler(Exception exception) {
        log.error(exception.getMessage(), exception);
        return Result.fail(ExceptionEnum.UNKNOWN.getCode(), ExceptionEnum.UNKNOWN.getErrorMsg());
    }

    /**
     * 参数异常处理
     *
     * @param exception 异常信息
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    public  Result illegalArgumentExceptionHandler(IllegalArgumentException exception) {
        log.error(exception.getMessage(), exception);
        return Result.fail(ExceptionEnum.ILLEGAL_ARGUMENT_ERROR.getCode(), ExceptionEnum.ILLEGAL_ARGUMENT_ERROR.getErrorMsg());
    }
}

IUserService.java代码

用户接口类。

在本例中定义了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 getUserInfo(String userId);

    Result> listUserInfo(UserVO query);

    Result saveUser(User user);

    Result updateUser(User user);

    Result deleteUser(String userId);
}

UserServiceImpl.java代码

用户接口实现类。

由于本文的重点不是实现业务逻辑,因此各个实现方法并没有详细的业务逻辑,而是抛出不同的异常,验证我们上面给出统一异常处理类是否可以真的处理各种异常。

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 getUserInfo(String userId) {
        // 默认抛出异常
        throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }

    @Override
    public Result> listUserInfo(UserVO query) {
        // 默认抛出异常
        throw new IllegalArgumentException();
    }

    @Override
    public Result saveUser(User user) {
        // 默认抛出异常
        throw new IndexOutOfBoundsException();
    }

    @Override
    public Result updateUser(User user) {
        // 默认抛出异常
        throw new RuntimeException();
    }

    @Override
    public Result deleteUser(String userId) {
        // 默认抛出异常
        throw new ClassCastException();
    }
}

测试

1、service方法抛出BusinessException异常

测试方法

http://localhost:8080/user/getUserInfo

测试结果
{
  "code": "500",
  "msg": "服务器内部错误!",
  "successFlag": false,
  "data": null
}

从上面的代码可知,getUserInfo方法抛出的异常如下:

throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);

恰好可以被UnifiedExceptionHandler的businessExceptionHandler方法监听。

测试结论

测试成功。

统一异常处理类可以正常捕获BusinessException异常。

2、service方法抛出IllegalArgumentException异常

测试方法

http://localhost:8080/user/listUserInfo

测试结果
{
  "code": "10000",
  "msg": "非法参数异常!",
  "successFlag": false,
  "data": null
}

从上面的代码可知,listUserInfo方法抛出的异常如下:

throw new IllegalArgumentException();

恰好可以被UnifiedExceptionHandler的illegalArgumentExceptionHandler方法监听。

测试结论

测试成功。

统一异常处理类可以正常捕获IllegalArgumentException异常。

3、service方法抛出IndexOutOfBoundsException异常

测试方法

http://localhost:8080/user/saveUser

测试结果
{
  "code": "500",
  "msg": "服务器内部错误!",
  "successFlag": false,
  "data": null
}

从上面的代码可知,saveUser方法抛出的异常如下:

throw new IndexOutOfBoundsException();

虽然UnifiedExceptionHandler没有专门处理IndexOutOfBoundsException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。

而IndexOutOfBoundsException异常恰好是Exception的子类,因此可以被正常监听到。

测试结论

测试成功。

统一异常处理类可以正常捕获IndexOutOfBoundsException异常。

4、service方法抛出RuntimeException异常

测试方法

http://localhost:8080/user/updateUser

测试结果
{
  "code": "9999",
  "msg": "未知异常!",
  "successFlag": false,
  "data": null
}

从上面的代码可知,updateUser方法抛出的异常如下:

throw new RuntimeException();

同上。

虽然UnifiedExceptionHandler没有专门处理RuntimeException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。

而RuntimeException异常恰好是Exception的子类,因此可以被正常监听到。

测试结论

测试成功。

统一异常处理类可以正常捕获RuntimeException异常。

5、service方法抛出ClassCastException异常

测试方法

http://localhost:8080/user/deleteUser

测试结果
{
  "code": "9999",
  "msg": "未知异常!",
  "successFlag": false,
  "data": null
}

从上面的代码可知,deleteUser方法抛出的异常如下:

throw new ClassCastException();

同上。

虽然UnifiedExceptionHandler没有专门处理ClassCastException异常的方法,但是有一个兜底的exceptionHandler方法,该方法可以监听Exception及其子类的异常类型。

而ClassCastException异常恰好是Exception的子类,因此可以被正常监听到。

测试结论

测试成功。

统一异常处理类可以正常捕获ClassCastException异常。

你可能感兴趣的:(java,开发语言)