項目環境
使用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