自定义全局异常处理类:优雅管理应用错误,告别杂乱代码
感觉本篇对你有帮助可以关注一下我的微信公众号(深入浅出谈java),会不定期更新知识和面试资料、技巧!!!
优点:
自定义全局异常处理类在开发中有以下几个主要用途和好处:
- 集中管理异常:通过自定义全局异常处理类,可以集中处理应用程序中所有的异常,而不需要在每个控制器中重复编写异常处理逻辑。这有助于代码的整洁性和可维护性。
- 统一的异常响应:全局异常处理类可以统一格式化异常的返回结果,确保前端接收到的一致性和规范性,这样在处理错误时,用户体验更加友好。
- 细粒度控制:可以根据不同类型的异常,定制不同的处理方式。例如,可以根据业务逻辑的需要返回不同的状态码和错误信息,方便前端进行处理。
- 记录日志:在全局异常处理类中,可以统一记录异常信息,便于后续的排查和分析。这有助于提高系统的监控和维护能力。
- 简化代码:通过自动化处理一些常见的异常(如请求参数异常、认证异常等),可以减少每个处理方法中的异常处理代码,使得业务逻辑更加清晰。
- 增强安全性:通过统一处理异常,可以有效避免敏感信息(如堆栈跟踪信息等)泄露到客户端,提高了应用程序的安全性。
全局异常处理实现原理
- @ControllerAdvice:声明全局异常处理类,监控所有Controller的异常。
- @ExceptionHandler:标注具体处理异常的方法,支持按异常类型匹配。
- 统一响应体:封装错误码、错误信息、数据等标准结构。
代码实现部分
2.1、定义全局异常处理类
在 Spring Boot 中,可以使用 @ControllerAdvice 注解来定义全局异常处理类- import lombok.extern.slf4j.Slf4j;
- import org.springframework.http.HttpStatus;
- import org.springframework.web.bind.MethodArgumentNotValidException;
- import org.springframework.web.bind.annotation.ControllerAdvice;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.bind.annotation.ResponseStatus;
- /**
- * @Classname GlobalExceptionHandlerAdvice
- * @Description 自定义全局异常处理类
- * @Version 1.0.0
- * @Date 2024/6/6 16:02
- * @Created by Administrator
- */
- @Slf4j
- @ControllerAdvice
- public class GlobalExceptionHandlerAdvice {
- /**-------- 通用异常处理方法 --------**/
- @ExceptionHandler(Exception.class)
- @ResponseBody
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public R error(Exception e) {
- e.printStackTrace();
- log.error("全局异常捕获:" + e);
- return R.fail(); // 通用异常结果
- }
- /**-------- 指定异常处理方法 --------**/
- @ExceptionHandler(NullPointerException.class)
- @ResponseBody
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public R error(NullPointerException e) {
- e.printStackTrace();
- log.error("全局异常捕获:" + e);
- return R.setResult(ResultCodeEnum.NULL_POINT);
- }
- /**-------- 下标越界处理方法 --------**/
- @ExceptionHandler(IndexOutOfBoundsException.class)
- @ResponseBody
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public R error(IndexOutOfBoundsException e) {
- e.printStackTrace();
- log.error("全局异常捕获:" + e);
- return R.setResult(ResultCodeEnum.INDEX_OUT_OF_BOUNDS);
- }
- /**
- * 方法参数校验
- */
- @ExceptionHandler(MethodArgumentNotValidException.class)
- @ResponseBody
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
- log.error(e.getMessage(), e);
- return R.setResult(ResultCodeEnum.PARAM_ERROR).message(e.getBindingResult().getFieldError().getDefaultMessage());
- }
- /**-------- 自定义定异常处理方法 --------**/
- @ExceptionHandler(UserException.class)
- @ResponseBody
- @ResponseStatus(HttpStatus.OK)
- public R error(UserException e) {
- e.printStackTrace();
- log.error("全局异常捕获:" + e);
- return R.fail().message(e.getMessage()).code(e.getCode());
- }
- }
复制代码 2.2 自定义定异常处理方法
这里我们可以定义自己的异常方法(UserException 类),可后续在业务代码中使用- /**
- * 自定义异常类
- *
- * @author admin
- * @date 2018/10/15
- */
- public class UserException extends RuntimeException {
- private Integer code;
- public UserException(String message) {
- super(message);
- this.code = ResultCodeEnum.CUSTOM_ERROR.getCode();
- }
- public UserException(Integer code, String message) {
- super(message);
- this.code = code;
- }
- public UserException(ResultCodeEnum resultCodeEnum) {
- super(resultCodeEnum.getMessage());
- this.code = resultCodeEnum.getCode();
- }
- public String toString() {
- return "UserException{code=" + this.code + ", message=" + this.getMessage() + '}';
- }
- public Integer getCode() {
- return this.code;
- }
- public void setCode(final Integer code) {
- this.code = code;
- }
- public boolean equals(final Object o) {
- if (o == this) {
- return true;
- } else if (!(o instanceof UserException)) {
- return false;
- } else {
- UserException other = (UserException)o;
- if (!other.canEqual(this)) {
- return false;
- } else {
- Object this$code = this.getCode();
- Object other$code = other.getCode();
- if (this$code == null) {
- if (other$code != null) {
- return false;
- }
- } else if (!this$code.equals(other$code)) {
- return false;
- }
- return true;
- }
- }
- }
- protected boolean canEqual(final Object other) {
- return other instanceof UserException;
- }
- public int hashCode() {
- int result = 1;
- Object $code = this.getCode();
- result = result * 59 + ($code == null ? 43 : $code.hashCode());
- return result;
- }
- }
复制代码 2.3、状态码枚举类
定义要用的状态枚举类,可做到统一的返回格式,这里也是可以自己定义和修改,只不过我提供的 UserException有用到该枚举类- public enum ResultCodeEnum {
- SUCCESS(true, 0, "成功"),
- UNKNOWN_ERROR(false, 999999, "未知错误"),
- DAO_INSERT_ERROR(false, 100000, "插入数据异常"),
- DAO_SELECT_ERROR(false, 100001, "查询数据异常"),
- DAO_UPDATE_ERROR(false, 100002, "更新数据异常"),
- DAO_DELETE_ERROR(false, 100003, "删除数据异常"),
- NULL_POINT(false, 100004, "空指针异常"),
- INDEX_OUT_OF_BOUNDS(false, 100005, "下标越界异常"),
- REQUEST_TIMEOUT(false, 100006, "请求超时"),
- PARAM_ERROR(false, 100007, "参数错误"),
- NOT_INIT_DATA(false, 100008, "数据未初始化"),
- CUSTOM_ERROR(false, 200000, "自定义错误"),
- USER_FORBIDDEN(false, 200001, "用户被禁用"),
- NOT_LOGIN_ERROR(false, 200002, "未登录");
- private Boolean success;
- private Integer code;
- private String message;
- private ResultCodeEnum(boolean success, Integer code, String message) {
- this.success = success;
- this.code = code;
- this.message = message;
- }
- public Boolean getSuccess() {
- return this.success;
- }
- public Integer getCode() {
- return this.code;
- }
- public String getMessage() {
- return this.message;
- }
- }
复制代码 3、使用方法
在需要地方代码中使用:throw new UserException()- @Operation(summary = "文件下载")
- @GetMapping("/download")
- public R download(@RequestParam("fileName") String fileName, HttpServletResponse res) {
- // 我这里就演示一下
- if(ObjectUtil.isEmpty(fileName)){
- throw new UserException("文件名不能为空!");
- }
- minioUtil.download(fileName,res);
- return R.success();
- }
复制代码
4、测试结果
控制台打印:- 2024-09-27T10:12:29.042+08:00 ERROR 20732 --- [eip] [nio-8069-exec-4] c.e.e.c.GlobalExceptionHandlerAdvice : 全局异常捕获:UserException{code=200000, message=文件名不能为空!}
- Disconnected from the target VM, address: '127.0.0.1:62663', transport: 'socket'
复制代码 参数为空,返回前端就会提示定义的消息- {
- "success": false,
- "code": 200000,
- "message": "文件名不能为空!",
- "data": null,
- "dataList": null,
- "total": 0
- }
复制代码 最后文章有啥不对,欢迎大佬在评论区指点!!!
如果感觉对你有帮助就点赞推荐或者关注一下吧!!!
****
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |