Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 304|回复: 0

小白的springboot之路(十)、全局异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-12 10:48:47 | 显示全部楼层 |阅读模式

    0、前言

      任何系统,我们不会傻傻的在每一个地方进行异常捕获和处理,整个系统一般我们会在一个的地方统一进行异常处理,spring boot全局异常处理很简单;

      介绍前先说点题外话,我们现在开发系统,都是前后端完全分离的,后端只提供RESTfull API,禁止涉及任何界面,什么thymeleaf、JSP那些后端模板,是绝对禁止使用的,那些东西请扔垃圾箱,不要浪费大好青春去研究,那是堕落;前端则负责界面相关,常用Vue;如果公司还没前后端分离,还在thymeleaf还在前后端一起写,那你还是早做跳槽打算吧,他们养不起你,更养不起你的家人;

      前后端分离,后端API,一般对于异常处理,要做得无非两件事,

        1是记录日志及相应通知处理,这是对内的,

        2是给出返回结果给API调用者,这是对外的;

    对API调用者来说,他只需要一个返回结果(包含错误代码、提示信息),其他的他不关心

    对后端来说,他只需要记录日志,通知或者给发布相应消息给其他队列处理相关事项;

    所以:看到过不少人封装了很多个自定义异常类,其实,完全没有必要,只需要一个异常处理来处理所有异常即可,然后封装一个错误识别码和提示消息的枚举,用于返回给API调用者;然后后端的处理,直接在一个异常处理方法中全部处理就行了,完全没必要封装N多个自定义异常,那没有任何意义;

     

    0-1、关于异常的思想认识

      我们应该认识到,一切异常,对系统来说,都是不正常的表现,都是属于缺陷,都属于BUG,尽管有些异常是我们主动抛出的;

      我们要做的,是应该尽量提高系统可用性,最大限度避免任何异常的出现,而不是去指望完善异常处理来完善系统;

      异常处理,是异常无法避免的出现了而采取的一种应急措施,主要目的是对外增加友好性,对内提供补救线索;

      不要认为完善的异常处理是系统核心,他不是,不要指望异常处理尽善尽美,不要指望异常处理来给系统缺陷擦屁股;

      如果系统异常过多,那么你要做的不是去完善异常处理机制,而是要好好去反思:系统架构设计是否合理,系统逻辑设计是否合理;

     

    1、全局异常处理

    使用@ControllerAdvice、@ExceptionHandler注解封装一个异常处理类即可
    package com.anson.common.exception;
    
    import com.anson.common.result.ResultBody;
    import com.anson.common.result.ResultCode;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * @description: 全局异常处理类
     * @author: anson
     * @Date: 2019/12/17 20:56
     */
    
    @ControllerAdvice
    public class GlobalExceptionHandler
    {
        private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
        /**
         * 所有异常处理
         * @param e
         * @return
         */
        @ExceptionHandler(value =Exception.class)
        @ResponseBody
        public ResultBody exceptionHandler(Exception e)
        {
            //1、写日志及其他处理,对内
            logger.error("未知异常!原因是:",e);
            System.out.println("未知异常!原因是:"+e);
            
            //2、返回错误识别码和提示给API调用者、对外
            return ResultBody.failed(ResultCode.FAILED);
        }
    }

    这样就可以了,

    ResultBody、ResultCode这个我们下节会说到;

    -------------------华丽丽的分割线--------------------------

    2、自定义异常

      上面的异常处理可以处理所有异常了,但是有时候,比如在拦截器、AOP、侦听器中,我们要主动抛出特定异常,比如没有权限、登录过期等,这个时候,我们可以增加一个自动以异常来统一处理,如下:

    2.1、增加一个自定义异常类:

    package com.anson.common.exception;
    
    import com.anson.common.result.IErrorCode;
    
    /**
     * @description: 自定义异常类
     * @author: anson
     * @Date: 2019/12/30 9:14
     */
    public class BizException extends RuntimeException
    {
        private static final long serialVersionUID = 1L;
    
        protected long errorCode;  //错误码
        protected String errorMsg;  //错误信息
    
        //构造1
        public BizException()
        {
            super();
        }
        //构造2
        public BizException(IErrorCode errorInfoInterface) {
            super(String.valueOf(errorInfoInterface.getCode()));
            this.errorCode = errorInfoInterface.getCode();
            this.errorMsg = errorInfoInterface.getMessage();
        }
    
        public BizException(IErrorCode errorInfoInterface, Throwable cause) {
            super(String.valueOf(errorInfoInterface.getCode()), cause);
            this.errorCode = errorInfoInterface.getCode();
            this.errorMsg = errorInfoInterface.getMessage();
        }
    
        public BizException(String errorMsg) {
            super(errorMsg);
            this.errorMsg = errorMsg;
        }
    
        public BizException(long errorCode, String errorMsg) {
            super(String.valueOf(errorCode));
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
        }
    
        public BizException(long errorCode, String errorMsg, Throwable cause) {
            super(String.valueOf(errorCode), cause);
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
        }
    
    
        public long getErrorCode() {
            return errorCode;
        }
    
        public void setErrorCode(long errorCode) {
            this.errorCode = errorCode;
        }
    
        public String getErrorMsg() {
            return errorMsg;
        }
    
        public void setErrorMsg(String errorMsg) {
            this.errorMsg = errorMsg;
        }
    
        public String getMessage() {
            return errorMsg;
        }
    
        @Override
        public Throwable fillInStackTrace() {
            return this;
        }
    
    }

    2.2、在全局异常处理中增加处理自定义异常:

    package com.anson.common.exception;
    
    import com.anson.common.result.ResultBody;
    import com.anson.common.result.ResultCode;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * @description: 全局异常处理类
     * @author: anson
     * @Date: 2019/12/10 20:56
     */
    
    @ControllerAdvice
    public class GlobalExceptionHandler
    {
        private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
        /**
         * 1、处理自定义的业务异常
         * @param req
         * @param e
         * @return
         */
        @ExceptionHandler(value = BizException.class)
        @ResponseBody
        public  ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){
            logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
            return ResultBody.failed(e.getErrorCode(),e.getErrorMsg());
        }
    
    
        /**
         * 2、处理其他异常
         * @param e
         * @return
         */
        @ExceptionHandler(value =Exception.class)
        @ResponseBody
        public ResultBody exceptionHandler(Exception e)
        {
    //1、写日志及其他处理,对内
    
            logger.error("未知异常!原因是:",e);
            System.out.println("未知异常!原因是:"+e);
    
    
            logger.trace("trace level");
            logger.debug("debug level");
            logger.info("info level");
            logger.warn("warn level");
            logger.error("error level");
    
            long beginTime = System.currentTimeMillis();
            logger.info("请求处理结束,耗时:{}毫秒", (System.currentTimeMillis() - beginTime));    //第一种用法
            logger.info("请求处理结束,耗时:" + (System.currentTimeMillis() - beginTime)  + "毫秒");    //第二种用法
    //------------------------------
    
    //2、返回错误识别码和提示给API调用者、对外
            return ResultBody.failed(ResultCode.FAILED);
        }
    }

    2.3、然后,在需要的地方上抛异常即可

            //主动抛出自定义异常
            throw new BizException(ResultCode.UNAUTHORIZED.getCode(),ResultCode.UNAUTHORIZED.getMessage());

    运行后即可看到上抛了自定义异常:

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-1 03:53 , Processed in 0.062041 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表