目录
1.引入pom依赖
- 主要几个异常注解都在web依赖中;
- thymeleaf: 查看静态界面;
<!--引入springboot父工程依赖-->
<!--引入依赖作用:
可以省去version标签来获得一些合理的默认配置
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<dependencies>
<!--模板引擎 -用于查看界面-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--引入提供Web开发场景依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--两个用来做测试的jar包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
2.application.yml配置
- 主要是配置进行错误页面跳转时 springBoot可以自动携带错误信息
# 错误页面的异常信息都是在DefaultErrorAttributes类中进行封装的,
# 它有一个属性是includeException并且默认值是false,
# 在封装exception对象的时候,
# 它通过判断includeException是否为true来决定是否封装
server:
error:
include-exception: true #这里如果是false(默认是false) springboot就不会封装exception html页面也就拿不到数据
3.配置启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述: 异常处理测试
* SpringBoot默认的处理异常的机制:SpringBoot默认的已经提供一套处理异常的机制。
* 一旦程序中出现了异常SpringBoot会像/error的url发送请求,在SpringBoot中提供了一个
* 叫BasicExceptionController来处理/error请求,然后跳转到默认显示异常来展示异常信息。
*/
@SpringBootApplication
public class ExceptionHandlingApplication {
public static void main(String[] args) {
SpringApplication.run(ExceptionHandlingApplication.class, args);
}
}
3. 异常使用实例
3.1 自定义错误异常
创建自定义异常
- 自定义异常类只需从Exception类或者它的子类派生一个子类即可。
- 自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。
- 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述: 自定义异常
*/
public class CustomException extends Exception {
public CustomException() {
super();
}
public CustomException(String s) {
super(s);
}
}
自定义异常测试结果:
- 自定义异常的使用.
- 这里的自定义异常继承的是Exception,为受检异常,所有需要throws抛出,如果继承的是RuntimeException运行时异常则就不用抛出.
import com.it.mhh.exception.CustomException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述:
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class ExceptionHandling {
/*
* @explain : 自定义异常测试
*
* @Author Mhh
* @param null :
* @return
* @Date 2022/2/11 16:10
*/
@Test
public void CustomExceptionTest() throws CustomException {
throw new CustomException("自定义异常错误");
}
}
3.2 @ExceptionHandler()局部针对某种异常的异常处理方法
- 作用:用来定义针对某种异常的异常处理方法
- 参数:定义该异常处理器捕获控制器里面出现的哪些异常;可传入集合。
- 比如,传RuntimeException.class,该处理方法只会捕获RuntimeException异常进行处理。
- 局限性:只对被定义在当前类中请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
import com.it.mhh.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述: 测试局部异常处理器
*/
@RestController
@RequestMapping("localExceptionHandling")
public class LocalExceptionHandlingController {
//-----------------------------------------------------------------------------------------------------
/*
* @explain : 捕获捉住指定在@ExceptionHandler中的异常
* @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
* // 后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
* //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
* @Author Mhh
* @param request :会自动注入
* @param e : 会将产生异常对象注入到方法中
* @return java.lang.String
* @Date 2022/2/12 13:42
*/
@ExceptionHandler(RuntimeException.class)
public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
e.printStackTrace();
StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
// System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
// System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
// System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
return request.getRequestURI() + "请求<br/>" + "错误异常: " + e + "<br/>错误类名为: " + stackTraceElement.getFileName() + "<br/>错误方法名为: " + stackTraceElement.getMethodName() + "<br/>错误java行号为: " + stackTraceElement.getLineNumber();
}
//-----------------------------------------------------------------------------------------------------
}
@ExceptionHandler()测试结果:
- @ExceptionHandler()只对被定义在当前类中请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法.
import com.it.mhh.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述: 测试局部异常处理器
*/
@RestController
@RequestMapping("localExceptionHandling")
public class LocalExceptionHandlingController {
//-----------------------------------------------------------------------------------------------------
/*
* @explain :返回一个自定义异常,被@ExceptionHandler()注解捕获测试
* @Author Mhh
* @return void
* @Date 2022/2/12 13:49
*/
@GetMapping("tryReturnRuntimeException")
public void tryReturnRuntimeException() throws CustomException {
throw new RuntimeException("局部错误异常测试");
}
/*
* @explain : 捕获捉住指定在@ExceptionHandler中的异常
* @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
* // 后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
* //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
* @Author Mhh
* @param request :会自动注入
* @param e : 会将产生异常对象注入到方法中
* @return java.lang.String
* @Date 2022/2/12 13:42
*/
@ExceptionHandler(RuntimeException.class)
public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
e.printStackTrace();
StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
// System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
// System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
// System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
return request.getRequestURI() + "请求<br/>" + "错误异常: " + e + "<br/>错误类名为: " + stackTraceElement.getFileName() + "<br/>错误方法名为: " + stackTraceElement.getMethodName() + "<br/>错误java行号为: " + stackTraceElement.getLineNumber();
}
//-----------------------------------------------------------------------------------------------------
}
3.3 @ExceptionHandler+@ControllerAdvice 全局异常处理方式
- 该注解(@ControllerAdvice)可以把异常处理器(被@ExceptionHandler注解的方法)应用到所有的Controller,而不是单单的一个Controller类。
- 全局异常处理的原理:在独立的一个类中,定义一套对各种异常的处理机制,然后用@ControllerAdvice注解该类,统一对不同位置的不同异常进行处理。
- @RestControllerAdvice注解的 basePackages 和 basePackageClasses 属性 表示此全局处理器的作用域,不填则是全局
import com.it.mhh.exception.CustomException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
/**
* @创建人: Mhh
* @创建时间: 2022/2/12
* @描述: 全局性异常处理类
*/
//basePackages 和 basePackageClasses 属性 表示此全局处理器的作用域,不填则是全局
@RestControllerAdvice
public class GlobalExceptionAdviceHandling {
//@RestControllerAdvice+@ExceptionHandler则就是全局性异常处理
/*
* @explain : 捕获捉住指定在@ExceptionHandler中的异常
* @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
* // 后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
* //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
* @Author Mhh
* @param request :会自动注入
* @param e : 会将产生异常对象注入到方法中
* @return java.lang.String
* @Date 2022/2/12 13:42
*/
@ExceptionHandler(CustomException.class)
public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
e.printStackTrace();//在后台打印错误日志
StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
// System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
// System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
// System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
return request.getRequestURI() + "请求<br/>" + "错误异常: " + e + "<br/>错误类名为: " + stackTraceElement.getFileName() + "<br/>错误方法名为: " + stackTraceElement.getMethodName() + "<br/>错误java行号为: " + stackTraceElement.getLineNumber();
}
}
全局异常测试结果:
- 不在存在@ExceptionHandler()注解的局限性,可以对全局指定的异常进行捕获
import com.it.mhh.exception.CustomException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @创建人: Mhh
* @创建时间: 2022/2/13
* @描述: 测试全局异常处理器
*/
@RestController
@RequestMapping("adviceExceptionHandling")
public class AdviceExceptionHandlingController {
/*
* @explain :返回一个自定义异常,被@ExceptionHandler()注解捕获测试
* @Author Mhh
* @return void
* @Date 2022/2/12 13:49
*/
@GetMapping("tryReturnCustomExceptionAdvice")
public void tryReturnCustomException() throws CustomException {
throw new CustomException("自定义异常出错---");
}
}
3.4 自定义错误页面
- SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制,一旦程序中出现了异常, SpringBoot 会像/error 的 url 发送请求.在 springBoot 中提供了一个叫 BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。
- 如果我们需要将所有的异常统一跳转到自定义的错误页面,需要在src/main/resources/templates 目录下创建error.html 页面.
注意:名称必须叫error.html
error.html视图配置:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>错误页面提示</title>
</head>
<body>
<h2 align="center" style="color: red">系统出错 请联系--Mhh</h2>
<h4 align="center" th:text="'status: '+${status}"></h4>
<h4 align="center" th:text="'timestamp: '+${timestamp}"></h4>
<h4 align="center" th:text="'exception: '+${exception}"></h4>
<h4 align="center" th:text="'error: '+${error}"></h4>
<h4 align="center" th:text="'message: '+${message}"></h4>
<h4 align="center" th:text="'detail: '+${detail}"></h4>
<h4 align="center" th:text="'path: '+${path}"></h4>
<!--
错误页面最终能获取到信息有如下:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常信息
errors:JSR303数据校验都在这里
-->
</body>
</html>
自定义错误页面:
- 只有异常没有被捕获或被处理的前提下才会进错误页面
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @创建人: Mhh
* @创建时间: 2022/2/11
* @描述: 测试进入自定义错误页面
*/
@RestController
@RequestMapping("errorExceptionHandling")
public class ErrorExceptionHandlingController {
/*http://localhost:8080/exceptionHandling/tryReturnArrayIndexOutOfBoundsException
* @explain :出现错误异常走自定义错误页面
*
* @Author Mhh
* @return void
* @Date 2022/2/12 10:08
*/
@GetMapping("tryReturnArrayIndexOutOfBoundsException")
public void tryReturnArrayIndexOutOfBoundsException() {
int[] a = new int[3];
int i = a[4];
}
}
3.5 配置 SimpleMappingExceptionResolver 全局处理异常
SimpleMappingExceptionResolver 配置:
- SimpleMappingExceptionResolver只能简单的处理异常
- 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示异常信息
- 以异常全路径名和视图名称进行绑定 来确认 报什么异常走什么视图
- 注意: 实现HandlerExceptionResolver 接口类全局处理异常优先级比SimpleMappingExceptionResolver 全局处理异常高
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
/**
* 通过 SimpleMappingExceptionResolver 做全局异常映射视图处理(其局限性传递不了异常信息,只是简单的 具体错误映射到具体视图界面)
* @创建人: Mhh
* @创建时间: 2022/2/12
* @描述: 是通过简单映射关系来决定由哪个错误视图来处理当前的异常信息。它提供了多种映射关系可以使用
*/
@Configuration
public class GlobalExceptionSimpleMappingExceptionResolver {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
/**
* 如果找不到视图 那么就是走的error视图
* 参数一:异常的类型,注意必须是异常类型的全名
* 参数二:视图名称
*/
properties.put("java.lang.NullPointerException","nullPointerException");
// properties.put("java.lang.ArithmeticException","arithmeticException");
//设置异常与视图映射信息
simpleMappingExceptionResolver.setExceptionMappings(properties);
simpleMappingExceptionResolver.setExceptionAttribute("exception");
return simpleMappingExceptionResolver;
}
}
nullPointerException.html视图配置:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title>NullPointerException</title>
</head>
<body>
<h1 style="color: red">NullPointerException异常界面</h1>
<h4 th:text="'message: '+${exception.message}"></h4>
<h4 th:text="'exception: '+${exception}"></h4>
<h4 th:text="'fileName: '+${exception.stackTrace[0].fileName}"></h4>
<h4 th:text="'methodName: '+${exception.stackTrace[0].methodName}"></h4>
<h4 th:text="'lineNumber: '+${exception.stackTrace[0].lineNumber}"></h4>
</body>
</html>
SimpleMappingExceptionResolver 全局处理异常测试结果:
- 只能返回简单的错误异常信息.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @创建人: Mhh
* @创建时间: 2022/2/13
* @描述: 测试SimpleMappingExceptionResolver方法(具体错误映射到具体视图界面)
*/
@RestController
@RequestMapping("nullPointerExceptionHandling")
public class NullPointerExceptionHandlingController {
/*http://localhost:8080/nullPointerExceptionHandling/tryReturnNullPointerException
* @explain :出现错误异常走自定义错误页面(异常没有被捕获或被处理的前提下)
*
* @Author Mhh
* @return void
* @Date 2022/2/12 10:08
*/
@GetMapping("tryReturnNullPointerException")
public void tryReturnNullPointerException() {
String s = null;
s.toString();
}
}
3.6 配置 实现HandlerExceptionResolver 接口 全局处理异常
实现HandlerExceptionResolver 接口配置:
- 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示自定义异常信息
- 需要实现 resolveException 方法,该方法返回一个 ModelAndView 对象,在方法内部对异常的类型进行判断,然后返回合适的 ModelAndView 对象,如果该方法返回了 null,则 Spring 会继续寻找其他的实现了 HandlerExceptionResolver 接口的 Bean。换句话说,Spring 会搜索所有注册在其环境中的实现了 HandlerExceptionResolver 接口的 Bean,逐个执行,直到返回了一个 ModelAndView 对象。
- 比SimpleMappingExceptionResolver 全局处理异常的优势在于可以传递自定义参数,其它没区别
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @创建人: Mhh
* @创建时间: 2022/2/12
* @描述: 通过实现 HandlerExceptionResolver 接口做全局异常(可以传递异常信息,只是简单的 具体错误映射到具体视图界面)
*/
@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
//根据返回错误异常 指定视图
// if (e instanceof NullPointerException)
// modelAndView.setViewName("nullPointerException");
if (e instanceof ArithmeticException)
modelAndView.setViewName("arithmeticException");
modelAndView.addObject("status", httpServletResponse.getStatus());//状态码
modelAndView.addObject("exception",e);//异常错误类型
modelAndView.addObject("uri",httpServletRequest.getRequestURI());//错误请求地址
modelAndView.addObject("fileName", stackTraceElement.getFileName());//错误地方类名
modelAndView.addObject("methodName", stackTraceElement.getMethodName());//错误方法名
modelAndView.addObject("lineNumber", stackTraceElement.getLineNumber());//错误行号
return modelAndView;
}
}
arithmeticException.html视图配置:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title>ArithmeticException</title>
</head>
<body>
<h1 style="color: red" >ArithmeticException异常界面</h1>
<h4 th:text="'status: '+${status}"></h4>
<h4 th:text="'exception: '+${exception}"></h4>
<h4 th:text="'uri: '+${uri}"></h4>
<h4 th:text="'fileName: '+${fileName}"></h4>
<h4 th:text="'methodName: '+${methodName}"></h4>
<h4 th:text="'lineNumber: '+${lineNumber}"></h4>
</body>
</html>
现HandlerExceptionResolver 接口 全局处理异常测试结果:
- 比SimpleMappingExceptionResolver 全局处理异常优点在于可以自定义数据返回到视图界面上.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @创建人: Mhh
* @创建时间: 2022/2/13
* @描述: 实现HandlerExceptionResolver接口测试类
*/
@RestController
@RequestMapping("arithmeticExceptionHandling")
public class ArithmeticExceptionHandlingController {
/*http://localhost:8080/arithmeticExceptionHandling/tryReturnArithmeticException
* @explain :出现错误异常走自定义错误页面(异常没有被捕获或被处理的前提下)
*
* @Author Mhh
* @return void
* @Date 2022/2/12 10:08
*/
@GetMapping("tryReturnArithmeticException")
public void tryReturnArithmeticException() {
int i = 1/0;
}
}