• 17. 异常处理



    17.1 介绍

    1. 默认情况下,Spring Boot 提供 /error 处理所有错误的映射,也就是说当出现错误时,SpringBoot底层会请求转发/error 这个映射
    2. 比如使用浏览器访问不存在的接口 (路径映射) ,响应一个 “whitelabel” 错误视图,以 HTML 格式呈现给用户

    在这里插入图片描述


    在这里插入图片描述

    1. SpringBoot 底层默认由 DefaultErrorViewResolver 处理错误

      => Debug 分析一下

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    • 如果请求的路径不存在,先去默认的静态资源目录下找 404.html
    • 如果找不到 404.html 就去默认的静态资源目录下找 4xx.html
    • 如果4xx.html 依然找不到,就创建一个 ModelAndView 返回,也就是 我们最先看到的 Whitelabel Error Page 页面

    17.2 拦截器VS过滤器

    1. 使用范围不同
    • 过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于 Tomcat等容器,Filter只能在web程序中使用
    • 拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application等程序中
    1. 过滤器和拦截器的触发时机也不同

    在这里插入图片描述

    • 过滤器 Filter 是在请求进入容器后,但在进入 servlet 之前进行预处理,请求结束是在 servlet 处理完以后
    • 拦截器 Interceptor 是在请求进入 servlet 后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束
    1. 特别说明
    • 过滤器不会处理请求转发
    • 拦截器会处理请求转发

    17.3 自定义异常页面

    17.3.1 文档

    17.3.2 自定义异常页面说明

    1. 如何找到这个文档位置,看下面一步步的指引

    在这里插入图片描述

    17.3.3 自定义异常页面-应用实例

    17.3.3.1 需求说明

    • 自定义 404.html 500.html 4xx.html 5xx.html
    • 当发生相应错误时,显示自定义的页面信息

    17.3.3.2 代码实现

    1. 创建 4 个页面

    在这里插入图片描述

    1. 测试 404.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>logintitle>
    head>
    <body bgcolor="#CED3FE">
    <img src="images/1.GIF"/>
    <hr/>
    <div style="text-align: center">
        <h1>4o4 Not Foundh1>
        <a href='#' th:href="@{/}">返回主页面a>
        状态码: <h1 th:text="${status}">h1> <br/>
        错误信息: <h1 th:text="${error}">h1>
    div>
    <hr/>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 浏览器请求 http://localhost:8080/xxx

    在这里插入图片描述

    • debug 可以看到 Model 的信息 (Model的数据最终是放到request域中的),所以可以在 404.html 取出显示

    在这里插入图片描述

    1. 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\controller\MyErrorController.java ,用于模拟错误
    package com.xjs.springboot.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     */
    @Controller
    public class MyErrorController {
    
        //模拟服务器内部错误 500
        @GetMapping("/err")
        public String err() {
            int i = 10 / 0;
            return "manage";
        }
    
        //这里我们配置的是 post方式请求 /err2
        //一会 使用get方式请求 /err2 ,这样就会出现一个 405 的客户端错误
        @PostMapping("/err2")
        public String err2() {
            return "manage";
        }
    
    }
    
    
    • 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
    1. 完成测试
    • 浏览器 http://localhost:8080/err

    在这里插入图片描述

    • 浏览器 http://localhost:8080/err2

    在这里插入图片描述

    17.3.3.2 底层机制分析

    • 先根据对应的错误状态码找对应的 页面,比如 405.html
    • 如果找不到就找 4xx.html,我们这里提供了,所以就显示 4xx.html
    • 如果 4xx.html 也找不到,就显示默认错误页面
    • 底层将错误信息封装到 Model中,Model 数据最终会放到request域中
    • 所以我们可以在对应的错误页面中取出对应的错误信息

    在这里插入图片描述

    在这里插入图片描述

    17.3 全局异常

    17.3.1 说明

    1. @ControllerAdvice+@ExceptionHandler 处理全局异常
    2. 底层是 ExceptionHandlerExceptionResolver 支持的

    17.3.2 全局异常-应用实例

    1. 需求:演示全局异常使用,当发生 ArithmeticException、NullPointerException 时,不使用默认异常机制匹配的 xxx.html ,而是通过全局异常机制显示指定的错误页面

    在这里插入图片描述

    1. 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\exception\GlobalExceptionHandle.java
    package com.xjs.springboot.exception;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * @ControllerAdvice : 使用该注解可以标识一个全局异常处理器/对象
     * 该全局异常处理器 会被注入到 spring容器
     *
     */
    @ControllerAdvice
    @Slf4j
    public class GlobalExceptionHandle {
    
        /**
         * 1. 编写方法 处理指定的异常, 比如这里处理 算数异常和空指针异常,可以指定多个异常
         * 2. 这里要处理的异常,由程序员指定即可
         * 3. Exception e 表示异常发生后,传递过来的异常对象
         * 4. Model model 可以将我们的异常信息,放入到 model,并传递给显示页面
         */
        @ExceptionHandler({ArithmeticException.class, NullPointerException.class})
        public String handleAritException(Exception e, Model model) {
    
            log.info("异常信息={}", e.getMessage());
            //这里将发生的异常信息放入到model => request域 , 然后可以在错误页面取出显示
            model.addAttribute("msg", e.getMessage());
    
            return "/error/global"; //视图地址
    
        }
    
    }
    
    
    • 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
    1. 创建 templates/error/global.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>全局异常title>
    head>
    <body bgcolor="#CED3FE">
    <hr/>
    <div style="text-align: center">
        <h1>全局异常/错误 发生了!h1><br/>
        异常/错误信息: <h1 th:text="${msg}">h1><br/>
        <a href="#" th:href="@{/}">返回主页面a>
    div>
    <hr/>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 完成测试,浏览器 http://localhost:8080/err

    在这里插入图片描述

    17.3.2 全局异常处理过程Debug

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    17.3.3 获取异常发生的方法

    package com.xjs.springboot.exception;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.method.HandlerMethod;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * @ControllerAdvice : 使用该注解可以标识一个全局异常处理器/对象
     * 该全局异常处理器 会被注入到 spring容器
     *
     */
    @ControllerAdvice
    @Slf4j
    public class GlobalExceptionHandle {
    
        /**
         * 1. 编写方法 处理指定的异常, 比如这里处理 算数异常和空指针异常,可以指定多个异常
         * 2. 这里要处理的异常,由程序员指定即可
         * 3. Exception e 表示异常发生后,传递过来的异常对象
         * 4. Model model 可以将我们的异常信息,放入到 model,并传递给显示页面
         *
         * ==> 提出问题:如何获取到异常发生的方法 ?
         */
        @ExceptionHandler({ArithmeticException.class, NullPointerException.class})
        public String handleAritException(Exception e, Model model, HandlerMethod handlerMethod) {
    
            log.info("异常信息={}", e.getMessage());
            //这里将发生的异常信息放入到model => request域 , 然后可以在错误页面取出显示
            model.addAttribute("msg", e.getMessage());
    
            //得到异常发生的方法是哪个?
            log.info("异常发生的方法是={}",handlerMethod.getMethod());
    
            return "/error/global"; //视图地址
    
        }
    
    }
    
    
    • 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

    在这里插入图片描述

    17.4 自定义异常

    17.4.1 说明

    1. 如果 Spring Boot 提供的异常不能满足开发需求,程序员也可以自定义异常
    2. @ResponseStatus + 自定义异常
    3. 底层是 ResponseStatusExceptionResolver ,底层调用 response.sendError(statusCode, resolvedReason);
    4. 当抛出自定义异常后,仍然会根据状态码,去匹配使用 xxx.html 显示
    5. 当然也可以将自定义异常,放在全局异常处理器去处理

    17.4.2 自定义异常-应用实例

    17.4.2.1 需求说明

    • 自定义一个异常 AccessException
    • 当用户访问某个无权访问的路径时,抛出该异常
    • 显示自定义异常状态码

    17.4.2.2 代码实现

    回顾一下自定义异常 ==> 文章链接

    1. 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\exception\AccessException.java
    package com.xjs.springboot.exception;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * 1. AccessException : 我们自定义的一个异常 ==> 回顾 Java基础
     * 2. @ResponseStatus(value = HttpStatus.FORBIDDEN) 表示发生AccessException异常,我们通过http协议返回的状态码是 403
     * 3. 这个状态码和自定义异常的对应关系是由程序员来决定[尽量合理设置]
     */
    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    public class AccessException extends RuntimeException {
    
        //提供一个构造器,可以指定信息
        public AccessException(String message) {
            super(message);
        }
    
        //显示的定义一下无参构造器
        public AccessException() {
        }
    
    }
    
    
    • 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
    1. 修改 MyErrorController.java

    在这里插入图片描述

    package com.xjs.springboot.controller;
    
    import com.xjs.springboot.exception.AccessException;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     */
    @Controller
    public class MyErrorController {
    
        //模拟服务器内部错误 500
        @GetMapping("/err")
        public String err() {
            int i = 10 / 0; //模拟算数异常
            return "manage";
        }
    
        //这里我们配置的是 post方式请求 /err2
        //一会 使用get方式请求 /err2 ,这样就会出现一个 405 的客户端错误
        @PostMapping("/err2")
        public String err2() {
            return "manage";
        }
    
        //编写方法,模拟一个 AccessException
        @GetMapping("/err3")
        public String err3(String name) {
    
            //如果用户不是tom , 我们就认为 无权访问
            if (!"tom".equals(name)) {
                throw new AccessException();
            }
    
            return "manage";//视图地址, 请求转发
    
    		//return "redirect:/manage.html";
        }
    
    }
    
    
    • 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
    1. 完成测试,浏览器 http://localhost:8080/err3?name=xjs

    在这里插入图片描述

    在这里插入图片描述

    17.4.2.3 Debug自定义异常处理过程

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    17.4.2.3 注意事项和细节

    1. 如果把自定义异常类型,放在全局异常处理器,那么仍然走全局异常处理机制
    • 修改全局异常处理器 GlobalExceptionHandle.java

    在这里插入图片描述

    package com.xjs.springboot.exception;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.method.HandlerMethod;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * @ControllerAdvice : 使用该注解可以标识一个全局异常处理器/对象
     * 该全局异常处理器 会被注入到 spring容器
     *
     */
    @ControllerAdvice
    @Slf4j
    public class GlobalExceptionHandle {
    
        /**
         * 1. 编写方法 处理指定的异常, 比如这里处理 算数异常和空指针异常,可以指定多个异常
         * 2. 这里要处理的异常,由程序员指定即可
         * 3. Exception e 表示异常发生后,传递过来的异常对象
         * 4. Model model 可以将我们的异常信息,放入到 model,并传递给显示页面
         *
         * ==> 提出问题:如何获取到异常发生的方法 ?
         */
        @ExceptionHandler({ArithmeticException.class, AccessException.class, NullPointerException.class})
        public String handleAritException(Exception e, Model model, HandlerMethod handlerMethod) {
    
            log.info("异常信息={}", e.getMessage());
            //这里将发生的异常信息放入到model => request域 , 然后可以在错误页面取出显示
            model.addAttribute("msg", e.getMessage());
    
            //得到异常发生的方法是哪个?
            log.info("异常发生的方法是={}",handlerMethod.getMethod());
    
            return "/error/global"; //视图地址
    
        }
    
    }
    
    
    • 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
    • 修改 MyErrorController.java

    在这里插入图片描述

    • Debug

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    TCP粘包和拆包
    Nacos配置中心
    阿里云布置net core 项目
    大促来咯,有些事情不得不提
    ES本地分片逆文档频率评分策略(Shard Local IDF)导致的评分异常原理解析
    【java】poi-tl 1.9.1 word模板插入文本及动态复杂表格
    leetcode - 360周赛
    Windows下Nacos安装和下载
    Linux中,黑窗口使用vi编辑文件
    【nginx根据特定header值设置proxy_set_header】
  • 原文地址:https://blog.csdn.net/weixin_60766221/article/details/126250522