IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 全局异常处理:Assert+枚举+自定义异常 -> 正文阅读

[Java知识库]全局异常处理:Assert+枚举+自定义异常

? ? ? ? 业务开发过程中涉及大量的异常处理,通常采用@ControllerAdvice搭配@ExceptionHandler来处理各种异常,但是抛出异常的过程任然避免不了大量的if...else判断,刚好今天看到一篇文章(为什么不建议用try catch处理异常?)采用自定义Assert+枚举+自定义异常的方式优雅的解决了该问题,现整理实现思路:

  1. 异常最重要的两个信息code和message,为了表示不同的业务异常信息,采用枚举的方式是个不错的选择。因为不同的业务异常有不同的划分方式,所以我们采用面向接口编程的思想,将IResponseEnum作为BaseException的组合元素之一。
    public interface IResponseEnum {
        int getCode();
        String getMessage();
    }
  2. 全局异常引入IResponseEnum作为自己的属性,保证抛出的异常信息全部为服务自己定义。
    /**
     * @ClassName: BaseException
     * @Author: whp
     * @Description: 基础异常类
     * @Date: 2022/3/4 11:20
     * @Version: 1.0
     */
    @Getter
    public class BaseException extends RuntimeException{
        protected IResponseEnum responseEnum;
        protected Object[] args;
    
        public BaseException(IResponseEnum responseEnum){
            super(responseEnum.getMessage());
            this.responseEnum=responseEnum;
        }
    
        public BaseException(int code,String msg){
            super(msg);
            this.responseEnum=new IResponseEnum() {
                @Override
                public int getCode() {
                    return code;
                }
    
                @Override
                public String getMessage() {
                    return msg;
                }
            };
        }
    
        public BaseException(IResponseEnum responseEnum,Object[] args,String message){
            super(message);
            this.responseEnum=responseEnum;
            this.args=args;
        }
    
        public BaseException(IResponseEnum responseEnum,Object[] args,String message,Throwable cause){
            super(message,cause);
            this.responseEnum=responseEnum;
            this.args=args;
        }
    }
  3. 定义Assert,一共有两个作用:1>添加判断逻辑,例如:判断对象是否为空,AssertTrue判断是否为真等;2> 抛出自定义异常。
    /**
     * @ClassName: Assert
     * @Author: whp
     * @Description: 自定义断言
     * @Date: 2022/3/4 11:25
     * @Version: 1.0
     */
    public interface Assert {
    
        BaseException newException(Object ... args);
    
        BaseException newException(Throwable t,Object... args);
    
        default void assertNotNull(Object obj){
            if(obj==null){
                throw newException(obj);
            }
        }
    
        default void assertNotNull(Object obj,Object... args){
            if(obj==null){
                throw newException(args);
            }
        }
    }
  4. 定义BusinessExceptionAssert同时实现Assert判断逻辑和枚举类区分不同业务异常逻辑。
    
    /**
     * @ClassName: Assert
     * @Author: whp
     * @Description: 自定义断言
     * @Date: 2022/3/4 11:25
     * @Version: 1.0
     */
    public interface Assert {
    
        BaseException newException(Object ... args);
    
        BaseException newException(Throwable t,Object... args);
    
        default void assertNotNull(Object obj){
            if(obj==null){
                throw newException(obj);
            }
        }
    
        default void assertNotNull(Object obj,Object... args){
            if(obj==null){
                throw newException(args);
            }
        }
    }
    
  5. 使用@Controlleradvice统一处理抛出的异常类:
     */
    @ControllerAdvice
    @ResponseBody
    @Slf4j
    public class ExceptionHandlerAdvice {
    
        private static final String ENV_PROD="online";
    
        @Value("${spring.profiles.active}")
        private String profile;
    
        @ExceptionHandler(value = BaseException.class)
        public Response commonException(BaseException exception, WebRequest request){
            return new Response().failure().code(exception.getResponseEnum().getCode()).message(exception.getMessage());
        }
    
        /**
         * Controller上一层相关异常
         *
         * @param e 异常
         * @return 异常结果
         */
        @ExceptionHandler({
                NoHandlerFoundException.class,
                HttpRequestMethodNotSupportedException.class,
                HttpMediaTypeNotSupportedException.class,
                MissingPathVariableException.class,
                MissingServletRequestParameterException.class,
                TypeMismatchException.class,
                HttpMessageNotReadableException.class,
                HttpMessageNotWritableException.class,
                HttpMediaTypeNotAcceptableException.class,
                ServletRequestBindingException.class,
                ConversionNotSupportedException.class,
                MissingServletRequestPartException.class,
                AsyncRequestTimeoutException.class
        })
        @ResponseBody
        public Response handleServletException(Exception e) {
            log.error(e.getMessage(), e);
            int code = ServletResponseEnum.SEVER_EXCEPTION.getCode();
            try {
                ServletResponseEnum servletExceptionEnum = ServletResponseEnum.valueOf(e.getClass().getSimpleName());
                return new Response().failure().code(servletExceptionEnum.getCode()).message(servletExceptionEnum.getMessage());
            } catch (IllegalArgumentException e1) {
                log.error("class [{}] not defined in enum {}", e.getClass().getName(), ServletResponseEnum.class.getName());
            }
            return new Response().failure().code(code).message(ServletResponseEnum.SEVER_EXCEPTION.getMessage());
        }
    }

    ? ? ? ?当然,全局异常的应用也要按照不同的服务进行区分,例如在API层异常结果是要返回给用户的,需要将异常信息展示为对用户友好的语言。服务间调用则需要让对应开发能够快速明确问题。相关代码实现可以参考:GitHub - whpHarper/spring-boot-study: 企业级spring boot框架

问题思考:

1. 全局异常可以分为业务到达接口前异常(例如:NoHandlerFoundException状态码对应404,HttpRequestMethodNotSupportedException状态码对应405)、参数校验异常、自定义业务异常等,各类异常如何返回客户端或对应调用方,需要合理规划下。

2. 业务异常定义构造函数携带参数throwable的目的是什么?

答:可以封装将不必要的异常不在接口返回,容易追踪最开始问题点。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:48:23  更:2022-03-06 12:52:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:51:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码