项目环境
使用idea + maven + springboot 搭建的项目。
需求
跳转自定义错误页。三方系统链接。
问题
遇到问题是spring 定义的全局异常捕捉不到 freemarker 模板渲染时候的异常。
1)尝试AOP的异常通知进行 捕获失败( @ControllerAdvice+
)2)尝试继承 HandlerExceptionResolver 捕获失败
解决方案
一、使用web.xml的方式,配置 error-page 节点
1)配置文件增加自定义的freemarker 错误处理类
spring:
freemarker:
settings:
template_exception_handler: xxx.web.exception.FreemarkerExceptionHandler
类定义如下:
class MyTemplateExceptionHandler implements TemplateExceptionHandler { public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) throws TemplateException { try { out.write("[ERROR: " + te.getMessage() + "]"); } catch (IOException e) { throw new TemplateException("Failed to print error message. Cause: " + e, env); } } }
2)然后再web.xml配置捕获异常跳转到对应的url,配置如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error.jsp</location> </error-page> <!-- 优先级: 页面中配置<%@page contentType="text/html; charset=UTF-8" errorPage="/2.jsp"%> > exception-type配置的页面 > error-code配置的页面 --> </web-app>
二、使用Spring Boot默认的映射处理
1)同 第一种处理方式,略
2)定义捕捉 /error 路径的 ErrorController
Spring Boot提供了一个默认的映射:/error
,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。
import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping(value = "error") public class CustomErrorController implements ErrorController { @Override public String getErrorPath() { return "error40x";//这是个我自己写的404的页面的fileName,在template根目录下 } @RequestMapping public String error() { return getErrorPath(); } }
或者
@Controller @RequestMapping({"${server.error.path:${error.path:/error}}"}) public class BasicErrorController extends AbstractErrorController { /** * 错误的页面响应 */ @RequestMapping(produces = {"text/html"}) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = this.getStatus(request); Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); // 得到一个modelAndView对象 ModelAndView modelAndView = this.resolveErrorView(request, response, status, model); return modelAndView != null ? modelAndView : new ModelAndView("error", model); } /** * 错误的json响应 */ @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { HttpStatus status = this.getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity(status); } else { Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL)); return new ResponseEntity(body, status); } } }
3)或者使用 继承BasicErrorController来实现
/** * 覆盖spring boot默认的异常处理类 继承BasicErrorController */ @Controller public class CustomErrorController extends BasicErrorController { public CustomErrorController(ServerProperties serverProperties) { super(new DefaultErrorAttributes(), serverProperties.getError()); } //通过浏览器访问的url 如果发生异常全部会被浏览并跳转到list.html页面 @Override public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { //请求的状态 HttpStatus status = getStatus(request); response.setStatus(getStatus(request).value()); Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)); ModelAndView modelAndView = resolveErrorView(request, response, status, model); //指定自定义的视图 return(modelAndView == null ? new ModelAndView("list", model) : modelAndView); } //通过http client访问的接口如果发生异常会调用这个方法 @Override public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); //输出自定义的Json格式 Map<String, Object> map = new HashMap<String, Object>(); map.put("status", false); map.put("msg", body.get("message")); return new ResponseEntity<Map<String, Object>>(map, status); } }
三、模板引擎 默认有错误页的配置
1)同 第一种处理方式,略
2)在templates 创建/error文件夹并添加错误的状态码对应的.html文件
项目中使用的了模板引擎,如:thymeleaf 、freemarker等做为页面的渲染时。在templates创建/error文件夹并添加错误的状态码对应的.html文件,如下图:
3)文件中做二次跳转
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> window.location.href="//xxxx/xxx"; </script> </body> </html>
参考
https://juejin.im/post/6844904135259602952
https://www.codetd.com/article/3038444
https://juejin.im/post/6844904135259602952
https://blog.csdn.net/lh87270202/article/details/79925951