• SpringBoot异常处理


    springboot处理异常的5种方式

    程序的异常:Throwable
        严重错误问题:Error     我们不处理。这种问题一般都是很严重的,我们一般处理不了,比如说内存溢出。
        问题:Exception
            1.运行期问题:RuntimeException            这种问题我们也不处理,因为是你写代码的问题,而且这个问题的出现肯定是我们的代码不够严谨,需要修正代码的。
            2.编译期问题:不是RuntimeException的异常     必须进行处理的,因为你不处理,编译就不能通过。
                 
    如果程序出现了问题,我们没有做任何处理,最终JVM会做出默认的处理。
    1.把异常的名称、原因及出现的位置等信息输出在控制台。
    2.同时会结束程序。
    (但是呢,其余没有问题的程序就不能继续执行了)
    所以感觉JVM的默认处理不够好,既然不好那我们就自己来处理呗。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1、自定义错误页面

    SpringBoot默认的异常处理机制:springboot默认提供了一套处理异常的机制。一旦程序出现了异常,SpringBoot会向/error的url发送请求。在springboot中提供了一个叫BasicErrorController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。
    如 果 我 们 需 要 将 所 有 的 异 常 统一 跳 转 到 自 定 义 的 错 误 页 面 , 需 要 再
    src/main/resources/templates 目录下创建 error.html 页面。注意:名称必须叫 error

    还可以在src/main/resources/templates/error目录下编写状态码.html文件,会默认先从这里找,找不到再找src/main/resources/templates下的error.html

    2、@ExceptionHandle 注解处理异常

    上一种方法不管发生什么异常,都只能跳转到一个页面,颗粒度太大,这一种方式可以实现对不同的异常做不同的处理。

    @RequestMapping
    @Controller
    public class ExceptionController {
    
        @PostMapping("/exception")
        public String hello(){
            //int i = 1/0;
            return "index";
        }
    
        /**
         * 该方法返回ModelAndView:目的是为了可以让我们封装视图和错误信息
         * @param e 参数 Exception e:会将产生异常对象注入到方法中
         * @return
         */
        @ExceptionHandler(value = {java.lang.ArithmeticException.class})
        public ModelAndView arithmeticExceptionHandler(Exception e){
            ModelAndView mv = new ModelAndView();
            mv.addObject("errorMsg",e);
            mv.setViewName("error");
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    优点:可以自定义存储异常信息的key,和跳转视图的名称。

    缺点:需要编写大量的异常方法,不能跨controller,如果两个controller中出现同样的异常,需要重新编写异常处理方法。

    3、@ControllerAdvice+@ExceptionHandler 注解处理异常

    上一种方式必须要在每一个Controler里面重复写异常处理代码,代码复用性太差,这一种方法可以实现异常的全局处理。需要创建一个能够处理异常的全局异常类。在该类上需要添加@ControllerAdvice 注解

    /**
     * 全局异常处理类
     */
    @ControllerAdvice
    public class GlobalController {
    
        /**
         * 该方法返回ModelAndView:目的是为了可以让我们封装视图和错误信息
         * @param e 参数 Exception e:会将产生异常对象注入到方法中
         * @return
         */
        //拦截的异常可以写Exception
        @ExceptionHandler(value = {java.lang.ArithmeticException.class})
        public ModelAndView arithmeticExceptionHandler(Exception e){
            ModelAndView mv = new ModelAndView();
            mv.addObject("errorMsg",e+"controllerAdvice");
            mv.setViewName("error");
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    缺点:编写大量的异常处理方法,代码冗余。

    4、配置 SimpleMappingExceptionResolver 处理异常

    上一种方式,每处理一种异常就要写一个处理方法,如果有很多异常需要处理,写起来会很麻烦,这一种方式可以很好的解决这种问题,需要在全局异常类中添加一个方法完成异常的统一处理。

    /**
     * 通过 SimpleMappingExceptionResolver 做全局异常处理
     */
    @Configuration
    public class GlobalException {
    
        /**
         * 该方法必须要有返回值。返回值类型必须是: SimpleMappingExceptionResolver
         * @return
         */
        @Bean
        public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
            SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
            Properties prop = new Properties();
    
            //参数1:异常的全类名  参数2:视图的名字
            prop.setProperty("java.lang.ArithmeticException","error");
            prop.setProperty("java.lang.NullPointerException","error");
            //设置异常与视图的映射信息
            resolver.setExceptionMappings(prop);
            return resolver;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    缺点:不显示具体异常信息

    5、自定义 HandlerExceptionResolver 类处理异常

    上一种方式不能在跳转页面的同时携带异常信息,这样不利于排错,当前这种方式可以解决上述问题,我们需 要 在全局异常处理类中实现HandlerExceptionResolver 接口。

    /**
     * 通过实现 HandlerExceptionResolver 接口做全局异常处理
     */
    @Configuration
    public class GlobalException implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            ModelAndView mv = new ModelAndView();
            //判断不同的异常类型跳转不同视图
            if(ex instanceof ArithmeticException){
                mv.setViewName("error");
            }
            if(ex instanceof NullPointerException){
                mv.setViewName("error");
            }
            mv.addObject("errorMsg",ex.toString());
    
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    通用异常处理:

    1、自定义异常枚举类

    public enum ExceptionEnum {
        //枚举常量
        PRICE_CANNOT_BE_NULL(500,"商品价格不能为空"),
        ;
        private int code;  //状态码
        private String msg; //异常信息
    
        ExceptionEnum() {
        }
    
        ExceptionEnum(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2、自定义异常类

    /**
     * 自定义异常类,继承RuntimeException
     */
    public class MyException extends RuntimeException{
        private ExceptionEnum exceptionEnum;
    
        public MyException() {
        }
    
        public MyException(ExceptionEnum exceptionEnum) {
            this.exceptionEnum = exceptionEnum;
        }
    
        public ExceptionEnum getExceptionEnum() {
            return exceptionEnum;
        }
    
        public void setExceptionEnum(ExceptionEnum exceptionEnum) {
            this.exceptionEnum = exceptionEnum;
        }
    
        @Override
        public String toString() {
            return "MyException{" +
                    "exceptionEnum=" + exceptionEnum +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3、自定义异常结果处理类

    /**
     * 自定义异常结果处理类
     */
    public class ResultException {
    
        private Integer statusCode; //状态码
        private String message;     //异常信息
        private Long timeStamp; //时间戳
    
        public ResultException() {
        }
    
        public ResultException(ExceptionEnum em){
            this.statusCode = em.getCode();
            this.message = em.getMsg();
            this.timeStamp = System.currentTimeMillis();
        }
    
        public Integer getStatusCode() {
            return statusCode;
        }
    
        public void setStatusCode(Integer statusCode) {
            this.statusCode = statusCode;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public Long getTimeStamp() {
            return timeStamp;
        }
    
        public void setTimeStamp(Long timeStamp) {
            this.timeStamp = timeStamp;
        }
    
        @Override
        public String toString() {
            return "ResultException{" +
                    "statusCode=" + statusCode +
                    ", message='" + message + '\'' +
                    ", timeStamp=" + timeStamp +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    4、全局异常处理

    /**
     *  @ControllerAdvice + @ExceptionHandler +自定义异常  来做全局异常处理
     */
    @ControllerAdvice
    public class GlobalException {
    
        /**
         * 拦截自定义异常MyException
         * @param e
         * @return
         */
    //    @ExceptionHandler(MyException.class)
    //    public @ResponseBody ResultException handlerRuntimeException(MyException e){
    //        ExceptionEnum exceptionEnum = e.getExceptionEnum();
    //        ResultException res = new ResultException(exceptionEnum);
    //        return res;
    //    }
    
    	//或者
        @ExceptionHandler(MyException.class)
        public ResponseEntity<ResultException> handlerRuntimeException(MyException e){
            ExceptionEnum exceptionEnum = e.getExceptionEnum();
            //使用ResponseEntity作为返回值
            return ResponseEntity.status(exceptionEnum.getCode()).body(new ResultException(exceptionEnum));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    DBA的一天是怎样的?运维工程师告诉你答案
    论文阅读:Duplex Contextual Relation Network for Polyp Segmentation
    K8S Pod控制器:ReplicationController ReplicaSet Deployment三者的联系与区别
    Spring Boot、Spring Security登录认证及权限问题
    [附源码]计算机毕业设计学习帮扶网站设计与实现Springboot程序
    mapreduce 的工作原理以及 hdfs 上传文件的流程
    对于Mac OS10.1x合适安装的Typora版本合集
    AWS 中文入门开发教学 11- 建立公私网 - 公私分明才能网络安全
    java操作数据库的工具类简介说明
    【作业】python课-实验一
  • 原文地址:https://blog.csdn.net/Linging_24/article/details/126077782