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

编程入门 行业动态 更新时间:2024-10-16 02:22:14

如何优雅的进行Controller<a href=https://www.elefans.com/category/jswz/34/1765343.html style=全局异常处理?"/>

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

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

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

package com.panda.handle_try_catch_gracefully.controller;import com.panda.handle_try_catch_gracefullymon.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 {@Resourceprivate 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 zeroException in thread "main" java.lang.NullPointerExceptionException 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注解

简介

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

POM.xml代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .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><mavenpiler.source>11</mavenpiler.source><mavenpiler.target>11</mavenpiler.target></properties><dependencies><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency><dependency><groupId>org.apachemons</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>

UserController.java代码

controller类,和上面的OriginUserController相比,代码量少了很多——try-catch代码块消失了。

放眼望去,整体代码清爽不少,核心代码尽收眼底。

package com.panda.handle_try_catch_gracefully.controller;import com.panda.handle_try_catch_gracefullymon.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 {@Resourceprivate IUserService userService;@GetMapping("getUserInfo")public Result<UserVO> getUserInfo(String userId) {return userService.getUserInfo(userId);}@PostMapping("listUserInfo")public Result<List<UserVO>> listUserInfo(UserVO query) {return userService.listUserInfo(query);}@PostMapping("saveUser")public Result<String> 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);}
}

Result.java代码

封装的统一返回结果。

code:响应结果代码,在本文中,可以是自定义的代码,也可以是ExceptionEnum枚举的code。

msg:错误信息。主要在方法调用失败时,返回给前端的提示信息。当然在方法调用成功时,也可以返回给前端一个类似“请求成功”之类的信息。

successFlag:响应成功与否的标志。true表示成功,false表示失败。

data:返回给前端的数据。一般只有在响应成功时才会向前端返回数据,以查询类方法居多。

package com.panda.handle_try_catch_gracefullymon;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.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_gracefullymon.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());}
}

IUserService.java代码

用户接口类。

在本例中定义了5个方法:

getUserInfo:根据用户ID查询用户信息。

listUserInfo:根据查询条件查询符合条件用户列表。

saveUser:保存用户信息。

updateUser:更新用户信息。

deleteUser:删除用户信息。

package com.panda.handle_try_catch_gracefully.service;import com.panda.handle_try_catch_gracefullymon.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);
}

UserServiceImpl.java代码

用户接口实现类。

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

package com.panda.handle_try_catch_gracefully.service.impl;import com.panda.handle_try_catch_gracefullymon.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 {@Overridepublic Result<UserVO> getUserInfo(String userId) {// 默认抛出异常throw new BusinessException(ExceptionEnum.INTERNAL_SERVER_ERROR);}@Overridepublic Result<List<UserVO>> listUserInfo(UserVO query) {// 默认抛出异常throw new IllegalArgumentException();}@Overridepublic Result<String> saveUser(User user) {// 默认抛出异常throw new IndexOutOfBoundsException();}@Overridepublic Result<Boolean> updateUser(User user) {// 默认抛出异常throw new RuntimeException();}@Overridepublic Result<Boolean> 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异常。

更多推荐

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

本文发布于:2023-12-07 03:38:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1669982.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:全局   优雅   异常   Controller

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!