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入门到精通教程
查看: 333|回复: 0

SpringMVC实现全局异常处理器 (转)

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-8 10:50:07 | 显示全部楼层 |阅读模式

    出处:  SpringMVC实现全局异常处理器

      

      我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。这篇博文主要总结一下SpringMVC中如何统一处理异常。 

    异常处理思路

      首先来看一下在springmvc中,异常处理的思路

    Spring MVC处理异常有4种方式: 

    (1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; 

    (2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器; 

    (3)使用@ExceptionHandler注解实现异常处理;
    (4)使用@ControllerAdvice + @ExceptionHandler

     

    下面使用 @ControllerAdvice + @ExceptionHandler来实现

    通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。
    注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,这对所有注解了 @RequestMapping 的控制器内的方法都有效。

      1:@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。
      2:@InitBinder:用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到 Model 中。
      3:@ModelAttribute@ModelAttribute 本来的作用是绑定键值对到 Model 里,此处是让全局的@RequestMapping 都能获得在此处设置的键值对。
    本文使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理。只要设计得当,就再也不用在 Controller 层进行 try-catch 了!

    一、经典案例
     需求:希望通过全局统一的异常处理将自定义错误码以json的形式发送给前端。

    1、统一返回结果类 ApiResult
    首先,定义一个统一结果返回类,最终需要将这个结果类的内容返回给前端。:

    /**
     * Api统一的返回结果类
     */
    public class ApiResult {
    
        /**
         * 结果码
         */
        private String code;
        
        /**
         * 结果码描述
         */
        private String msg;
        
        
        public ApiResult() {
        }
    
        public ApiResult(ResultCode resultCode) {
            this.code = resultCode.getCode();
            this.msg = resultCode.getMsg();
        }
        
        /**
         * 生成一个ApiResult对象, 并返回
         *
         * @param resultCode
         * @return
         */
        public static ApiResult of(ResultCode resultCode) {
            return new ApiResult(resultCode);
        }
    
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        @Override
        public String toString() {
            return "ApiResult{" +
                    "code='" + code + '\'' +
                    ", msg='" + msg + '\'' +
                    '}';
        }
        
    }

    2、错误码枚举类 ResultCode

    有了 ApiResult ,接下来需要定义一个枚举类, 来包含所有自定义的结果码。

    /**
     * 错误码
     */
    public enum ResultCode {
        SUCCESS("0", "success"),
        UNKNOWN_ERROR("0x10001", "unkonwn error"),
        USERNAME_ERROR("0x10002", "username error or does not exist"),
        PASSWORD_ERROR("0x10003", "password error"),
        USERNAME_EMPTY("0x10004", "username can not be empty");
        
        private String code;
        private String msg;
        
        ResultCode(String code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public String getCode() {
            return code;
        }
    
        public String getMsg() {
            return msg;
        }
    
    }

    3、自定义业务异常类 BusinessRuntimeException

    接下来需要定义我们自己的业务异常类,以后和业务相关的异常通通抛出这个异常类,我们将错误码枚举变量的值存于其中。

    /**
     *    自定义业务异常
     */
    public class BusinessRuntimeException extends RuntimeException{
        
        private String code;
        private String msg;
        private ResultCode resultCode;
        
        public BusinessRuntimeException(ResultCode resultCode) {
            super(resultCode.getMsg());
            this.code = resultCode.getCode();
            this.msg = resultCode.getMsg();
            this.resultCode = resultCode;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public ResultCode getResultCode() {
            return resultCode;
        }
    
        public void setResultCode(ResultCode resultCode) {
            this.resultCode = resultCode;
        }
    
    }

    4、全局异常处理类 GlobalExceptionResolver
    最后便是定义全局异常处理类。

      1:通过 @ControllerAdvice 指定该类为 Controller 增强类。
      2:通过 @ExceptionHandler 自定捕获的异常类型。
      3:通过 @ResponseBody 返回 json 到前端。
    注意一点:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller

    /**
     *  全局Controller层异常处理类
     */
    @ControllerAdvice
    public class GlobalExceptionResolver {
    
        /**
         *处理所有不可知异常
         * @param e 异常
         * @return json结果
         */
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public ApiResult handleException(Exception e) {
            System.out.println(e.getMessage());
            return ApiResult.of(ResultCode.UNKNOWN_ERROR);
        }
        
        /**
                 * 处理所有业务异常
         * @param e 业务异常
         * @return json结果
         */
        @ExceptionHandler(BusinessRuntimeException.class)
        @ResponseBody
        public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
            System.out.println(e.getMessage());
            return ApiResult.of(e.getResultCode());
        }
    
    }

    二、测试

    1、测试 TestExceptionController

    @Controller
    @RequestMapping("/test/")
    public class TestExceptionController {
    
        /**
         * 测试返回异常信息
         * @return
         */
        @RequestMapping(value = "exception.do",method = RequestMethod.GET)
        public String returnExceptionInfo() {
    
            if (1 != 2) {
                // 用户民错误或不存在异常
                throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR);
            }
    
            return "success";
        }
    
    }

     

    效果:

     

    其他比较全的文章可以看这个: SpringMVC中的统一异常处理

     

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

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-20 03:44 , Processed in 0.069097 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

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