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>login</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<hr/>
<div style="text-align: center">
    <h1>4o4 Not Found</h1>
    <a href='#' th:href="@{/}">返回主页面</a>
    状态码: <h1 th:text="${status}"></h1> <br/>
    错误信息: <h1 th:text="${error}"></h1>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>
  • 浏览器请求 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. 完成测试
  • 浏览器 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. 创建 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. 完成测试,浏览器 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"; //视图地址

    }

}

在这里插入图片描述

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. 修改 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. 完成测试,浏览器 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"; //视图地址

    }

}

  • 修改 MyErrorController.java

在这里插入图片描述

  • Debug

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要学就学灰太狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值