共计 5377 个字符,预计需要花费 14 分钟才能阅读完成。
1、自定义错误页面
1.1、概述
SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制。
一旦程序中出现了异常 SpringBoot 会向 /error 的 url 发送请求。在 springBoot 中提供了一个叫 BasicExceptionController 来处理 /error 请求,然后跳转到默认显示异常的页面来展示异常信息。
1.2、自定义错误页面
在 src/main/resources/templates 目录下创建 error.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
出错了,请与管理员联系。。。</body>
</html>
** 注意:** 名称必须叫 error, 工程中要添加 thymeleaf 依赖
2、@ExceptionHandler 注解处理局部异常
2.1、Controller
@Controller
public class HelloController {@GetMapping("/hello")
public String hello(){int result=10/0;
return "index";
}
/**
* java.lang.ArithmeticException
* 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视
图的指定
* 参数 Exception e: 会将产生异常对象注入到方法中
*/
@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception e){ModelAndView mv = new ModelAndView();
mv.addObject("error", e.toString());
mv.setViewName("error");
return mv;
}
}
2.2、修改 error.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title> 错误页面 </title>
</head>
<body>
<span th:text="${error}"></span>, 请与管理员联系......
</body>
</html>
3、处理全局异常
3.1、@ControllerAdvice+@ExceptionHandler:
@ControllerAdvice
public class GlobalException {/**
* java.lang.ArithmeticException
* 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视
图的指定
* 参数 Exception e: 会将产生异常对象注入到方法中
*/
@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception e){ModelAndView mv = new ModelAndView();
mv.addObject("error", e.toString());
mv.setViewName("error");
return mv;
}
}
3.2、配置 SimpleMappingExceptionResolver 处理异常
在全局异常类中添加一个方法完成异常的统一处理, 代码如下:
@Configuration
public class GlobalException {/**
* 该方法必须要有返回值。返回值类型必须是:* SimpleMappingExceptionResolver
*/
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {SimpleMappingExceptionResolver resolver = new
SimpleMappingExceptionResolver();
Properties mappings = new Properties();
/**
* 参数一:异常的类型,注意必须是异常类型的全名
* 参数二:视图名称
*/
mappings.put("java.lang.ArithmeticException", "error");
// 设置异常与视图映射信息的
resolver.setExceptionMappings(mappings);
return resolver;
}
}
3.3、自定义 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");
}
mv.addObject("error", ex.toString());
return mv;
}
}
4、Spring Boot 应用正常退出
查看 SpringApplication 源码
public class SpringApplication {
......
// 退出方法
public static int exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators) {// 断言 conext 不能为 null
Assert.notNull(context, "Context must not be null");
byte exitCode = 0;
int exitCode;
try {try {// 创建退出码生成器
ExitCodeGenerators generators = new ExitCodeGenerators();
// 从 Spring 容器中获取所有的退出码生成器实例
Collection<ExitCodeGenerator> beans = context.getBeansOfType(ExitCodeGenerator.class).values();
generators.addAll(exitCodeGenerators);
generators.addAll(beans);
// 获得退出码
exitCode = generators.getExitCode();
// 如果退出码不为 0
if (exitCode != 0) {// 发布退出码事件监听
context.publishEvent(new ExitCodeEvent(context, exitCode));
}
} finally {close(context);
}
} catch (Exception var9) {var9.printStackTrace();
exitCode = exitCode != 0 ? exitCode : 1;
}
// 返回退出码
return exitCode;
}
}
案例:
验证程序退出时 ExitCodeGenerators 的 getExitCode() 方法执行了
@EnableAutoConfiguration
public class ExiteCodeGeneratorBootstrap {@Bean
public ExitCodeGenerator exitCodeGenerator(){System.out.println("ExitCodeGenerator Bean 创建...");
return ()->{System.out.println("执行退出码 88");
return 88;
};
}
public static void main(String[] args) {// 在非 Web 应用中退出
SpringApplication.exit(new SpringApplicationBuilder(ExiteCodeGeneratorBootstrap.class)
.web(WebApplicationType.NONE)
.run(args));
}
}
5、Spring Boot 应用异常退出
源码:
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {try {try {// 处理退出码
this.handleExitCode(context, exception);
// 如果 Spring 应用运行监听器不为 null
if (listeners != null) {// 监听异常退出
listeners.failed(context, exception);
}
} finally {// 报告错误
this.reportFailure(exceptionReporters, exception);
// 关闭 Spring 上下文
if (context != null) {context.close();
}
}
} catch (Exception var9) {logger.warn("Unable to close ApplicationContext", var9);
}
ReflectionUtils.rethrowRuntimeException(exception);
}
// 退出码处理方法
private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) {// 从异常中获取退出码
int exitCode = this.getExitCodeFromException(context, exception);
if (exitCode != 0) {if (context != null) {// 如果退出码不为 0,context 不为 null,发布退出码事件监听
context.publishEvent(new ExitCodeEvent(context, exitCode));
}
// 获取 SpringBoot 异常处理器
SpringBootExceptionHandler handler = this.getSpringBootExceptionHandler();
if (handler != null) {// 如果处理器不为 null,注册退出码
handler.registerExitCode(exitCode);
}
}
}
// 从异常中获得退出码
private int getExitCodeFromException(ConfigurableApplicationContext context, Throwable exception) {// 从 MappedException 获得退出码
int exitCode = this.getExitCodeFromMappedException(context, exception);
// 如果 exitCode==0
if (exitCode == 0) {// 从异常退出码生成器中获取退出码
exitCode = this.getExitCodeFromExitCodeGeneratorException(exception);
}
// 退出码
return exitCode;
}
private int getExitCodeFromExitCodeGeneratorException(Throwable exception) {// 如果 exception==null, 直接返回 0
if (exception == null) {return 0;
} else {// 从退出码生成器中获得退出码
return exception instanceof ExitCodeGenerator ? ((ExitCodeGenerator)exception).getExitCode() : this.getExitCodeFromExitCodeGeneratorException(exception.getCause());
}
}
由源码可知当异常实现 ExitCodeGenerator 接口时, 退出码直接采用 getExitCode() 方法返回。
正文完
星哥玩云-微信公众号