2.14、异常处理
2.14.1、定义错误页面
SpringBoot 默认的异常处理机制:一旦程序中出现了异常 SpringBoot 就会请求 /error 的 url 。在 SpringBoot 中提供了一个叫 BasicExceptionController 来处理 /error 请求,它会跳转到默认显示异常的页面来展示异常信息。
不过我们可以在 resources/templates/ 内添加 error 页面来自定义异常页面,名字和路径不能更改,因为BasicExceptionController 默认跳转到这此路径。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>恭喜你啊,你进入了异常页面</h1>
</body>
</html>
2.14.2、局部异常
在SpringBoot中可以使用 @ExceptionHandler
注解处理局部异常,它是在Controller 内定义一个方法,内部写发生异常后的处理逻辑,然后在方法上添加 @ExceptionHandler(value={}) 注解,表明要捕捉的异常,然后此Controller内发生异常时就会使用此方法进行处理。
-
定义一个错误页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>恭喜你啊,你进入了异常页面</h1> <p th:text="${msg}"></p> </body> </html>
-
Controller:不写
@ExceptionHandler
@Controller @RequestMapping("/test") public class HelloController { @GetMapping("/hello") public String hello(String name){ int i = 9/0; return "login"; } }
-
此时在Controller中 添加
@ExceptionHandler
注解,并完成相关的方法,发生异常时做处理@Controller @RequestMapping("/test") @Slf4j public class HelloController { @GetMapping("/hello") public String hello(String name){ int i = 9/0; return "login"; } @ExceptionHandler(value = {Exception.class}) public String exceptionHandling(Model model,Exception e){ model.addAttribute("msg","发生了异常:"+e.getMessage()); log.info(e.getMessage()); return "error"; } }
2.14.3、全局异常
使用 @ExceptionHandler
注解处理的是局部的异常,它仅仅在一个Controller中有效,我们一般要求进行全局的异常处理,也就是对所有的Controller都生效。
创建一个专门处理异常的类,然后在类上使用 @ControllerAdvice
注解,然后内部创建异常处理的方法,并且在方法上添加 @ExceptionHandler
注解后,这个类就能够处理全局异常。
-
定义全局异常处理类
@ControllerAdvice @Slf4j public class HandleException { @ExceptionHandler public String exceptionHandling(Model model, Exception e){ model.addAttribute("msg","全局异常处理:"+e.getMessage()); log.info(e.getMessage()); return "error"; } }
-
将Controller 中原本的局部异常方法去掉
@Controller @RequestMapping("/test") public class HelloController { @GetMapping("/hello") public String hello(String name){ int i = 9/0; return "login"; } }
在使用全局异常处理的时候,一样可以使用局部的异常处理,它的优先级高于全局异常处理,也就是说一个Controller定义了局部异常处理方法后,就不会再执行全局的异常处理了
上面的例子给Controller添加局部异常处理方法
@Controller
@RequestMapping("/test")
public class HelloController {
@GetMapping("/hello")
public String hello(String name){
int i = 9/0;
return "login";
}
@ExceptionHandler(value = {Exception.class})
public String exceptionHandling(Model model,Exception e){
model.addAttribute("msg","局部异常处理:"+e.getMessage());
return "error";
}
}
2.14.4、异常配置类
除了@ControllerAdvice
+ @ExceptionHandler
注解能进行全局的异常处理外,还可以通过配置类创建SimpleMappingExceptionResolver 对象处理异常,此对象也是全局的。
但是使用SimpleMappingExceptionResolver 获取不到异常对象,无法得知异常消息,但是它可以在一个方法内判断多个异常种类,根据不同的异常,跳转到不同的页面。
@Configuration
public class MyExceptionConfig {
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
System.out.println("处理异常");
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
//参数:异常类型全限定名,异常的视图名称
properties.put("java.lang.Exception","error2");
// properties.put()可以写多个,使不同的异常类型跳转到不同的异常页面
resolver.setExceptionMappings(properties);
return resolver;
}
}
还是使用上面的Controller,但是注意需要将全局异常和局部异常都删除,SimpleMappingExceptionResolver 优先级三者里最小。
2.14.5、异常处理接口
通过实现 HandlerExceptionResolver
接口,一样可以处理异常,这种处理的方式不仅可以获取到异常的对象,也可以根据不同的异常,跳转到不同的页面
@Configuration
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "HandlerExceptionResolver 接口处理异常:"+ex.getMessage());
//可以根据不同的异常类型进行跳转
if(ex instanceof ArithmeticException){
modelAndView.setViewName("error");
}else if(ex instanceof NumberFormatException){
modelAndView.setViewName("error2");
}
return modelAndView;
}
}
2.14.6、优先级和区别
4种异常处理的优先级为:@ExceptionHandler的局部异常处理 > @ControllerAdvice
+ @ExceptionHandler
的全局异常处理 > HandlerExceptionResolver 接口的全局异常处理 > SimpleMappingExceptionResolver全局异常处理
@ExceptionHandler是局部异常处理,只能处理单个Controller的异常,其余三种能处理全局异常
HandlerExceptionResolver
、SimpleMappingExceptionResolver
可以在一个方法内针对异常的不同种类做出不同的跳转,而@ControllerAdvice
+ @ExceptionHandler
的全局异常处理和 @ExceptionHandler
局部异常处理 如果要实现不同异常类型跳转不同页面需要多个方法才能实现。
SimpleMappingExceptionResolver不能获取异常对象,其余三种都可以获取异常对象