spring boot freemarker 500异常跳转自定义错误页


项目环境

  使用idea + maven + springboot 搭建的项目。

需求

  跳转自定义错误页。三方系统链接。

问题

  遇到问题是spring 定义的全局异常捕捉不到 freemarker 模板渲染时候的异常。

       1)尝试AOP的异常通知进行 捕获失败( @ControllerAdvice+ @ExceptionHandler(Exception.class)

       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

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM