springboot ErrorPageFilter的实际应用详解

 更新时间:2022年01月27日 14:50:56   作者:零零落落。  
这篇文章主要介绍了springboot ErrorPageFilter的实际应用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

ErrorPageFilter的实际应用

Spring框架错误页过滤器

springboot提供了一个ErrorPageFilter,用来处理当程序发生错误时如何展现错误,话不多说请看代码

private void doFilter(HttpServletRequest request, HttpServletResponse response,
            FilterChain chain) throws IOException, ServletException {
    ErrorWrapperResponse wrapped = new ErrorWrapperResponse(response);
    try {
        chain.doFilter(request, wrapped);
        if (wrapped.hasErrorToSend()) {
            // 重点关注此方法
            handleErrorStatus(request, response, wrapped.getStatus(),
                    wrapped.getMessage());
            response.flushBuffer();
        }
        else if (!request.isAsyncStarted() && !response.isCommitted()) {
            response.flushBuffer();
        }
    }
    catch (Throwable ex) {
        Throwable exceptionToHandle = ex;
        if (ex instanceof NestedServletException) {
            exceptionToHandle = ((NestedServletException) ex).getRootCause();
        }
        handleException(request, response, wrapped, exceptionToHandle);
        response.flushBuffer();
    }
}
private void handleErrorStatus(HttpServletRequest request,
            HttpServletResponse response, int status, String message)
                    throws ServletException, IOException {
    if (response.isCommitted()) {
        handleCommittedResponse(request, null);
        return;
    }
    // 获取错误页,来关注下这个属性this.statuses,就是一个map,而错误页就是从这属性中获取,那此属性的内容是什么时候添加进去的呢
    String errorPath = getErrorPath(this.statuses, status);
    if (errorPath == null) {
        response.sendError(status, message);
        return;
    }
    response.setStatus(status);
    setErrorAttributes(request, status, message);
    // 拿到错误页地址后,通过服务器重定向的方式跳转到错误页面
    request.getRequestDispatcher(errorPath).forward(request, response);
}

ErrorPageFilter implements Filter, ErrorPageRegistry,此类实现了ErrorPageRegistry接口,接口内方法如下,我们可以看到这个入参errorPages便是错误页集合,然后把所有错误页put到statuses属性内,但是此方法入参从何而来呢?

@Override
public void addErrorPages(ErrorPage... errorPages) {
    for (ErrorPage errorPage : errorPages) {
        if (errorPage.isGlobal()) {
            this.global = errorPage.getPath();
        }
        else if (errorPage.getStatus() != null) {
            this.statuses.put(errorPage.getStatus().value(), errorPage.getPath());
        }
        else {
            this.exceptions.put(errorPage.getException(), errorPage.getPath());
        }
    }
}

通过源码分析,发现此接口,只要实现此接口并生成bean交给spring,便可以往ErrorPageRegistry添加你自己的错误页了。

public interface ErrorPageRegistrar {
    /**
     * Register pages as required with the given registry.
     * @param registry the error page registry
     */
    void registerErrorPages(ErrorPageRegistry registry);
}

看个例子吧,这样就可以了,是不是很简单。

@Component
public class MyErrorPage implements ErrorPageRegistrar {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/WEB-INF/errorpage/404.html");
        ErrorPage error405Page = new ErrorPage(HttpStatus.METHOD_NOT_ALLOWED, "/WEB-INF/errorpage/405.html");
        ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/WEB-INF/errorpage/500.html");
        registry.addErrorPages(error404Page, error405Page, error500Page);
    }
}

springboot项目出现ErrorPageFilter异常

今天用springboot(2.2.12.RELEASE)+beetl模板的时候,由于某个模板找不到,

系统一直出现报错日子

[http-nio-8080-exec-1] ERROR o.s.b.w.s.s.ErrorPageFilter - [handleCommittedResponse,219] - Cannot forward to error page for request [/yuantuannews/list/index_1.html] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false

看了网上的一些解决方法,大体上都是重写ErrorPageFilter,然后在FilterRegistrationBean中设置 filterRegistrationBean.setEnabled(false);

代码如下

    @Bean
    public ErrorPageFilter errorPageFilter() {
        return new ErrorPageFilter();
    }
 
    @Bean
    public FilterRegistrationBean disableSpringBootErrorFilter(ErrorPageFilter filter) {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(filter);
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

按照这个方法,我做了多次尝试,系统直接报错说errorPageFilter冲突了,原来是

ErrorPageFilterConfiguration.java中已经定义了这么一个bean:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.boot.web.servlet.support;
import javax.servlet.DispatcherType;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(
    proxyBeanMethods = false
)
class ErrorPageFilterConfiguration {
    ErrorPageFilterConfiguration() {
    }
    @Bean
    ErrorPageFilter errorPageFilter() {
        return new ErrorPageFilter();
    }
    @Bean
    FilterRegistrationBean<ErrorPageFilter> errorPageFilterRegistration(ErrorPageFilter filter) {
        FilterRegistrationBean<ErrorPageFilter> registration = new FilterRegistrationBean(filter, new ServletRegistrationBean[0]);
        registration.setOrder(filter.getOrder());
        registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ASYNC});
        return registration;
    }
}

最后我的解决方式是在启动类中设置:

@SpringBootApplication
public class App extends SpringBootServletInitializer {
public App() {
    super();
    //下面设置为false
    setRegisterErrorPageFilter(false); 
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(App.class);
}
public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}

问题解决。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot配置文件中数据库密码加密两种方案(推荐)

    SpringBoot配置文件中数据库密码加密两种方案(推荐)

    SpringBoot项目经常将连接数据库的密码明文放在配置文件里,安全性就比较低一些,尤其在一些企业对安全性要求很高,因此我们就考虑如何对密码进行加密,文中给大家介绍加密的两种方式,感兴趣的朋友一起看看吧
    2019-10-10
  • Java线程休眠之sleep方法详解

    Java线程休眠之sleep方法详解

    这篇文章主要介绍了Java线程休眠之sleep方法详解,Thread 类中有一个静态方法的sleep方法,当该线程调用sleep方法后,就会暂时让CPU的调度权,但是监视器资源比如锁并不会释放出去,需要的朋友可以参考下
    2024-01-01
  • Mybatis分页插件使用方法详解

    Mybatis分页插件使用方法详解

    这篇文章主要为大家详细介绍了Mybatis分页插件的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 最常用的1000个Java类(附代码示例)

    最常用的1000个Java类(附代码示例)

    这篇文章主要介绍了最常用的1000个Java类(附代码示例),需要的朋友可以参考下
    2015-04-04
  • 详解Spring boot上配置与使用mybatis plus

    详解Spring boot上配置与使用mybatis plus

    这篇文章主要介绍了详解Spring boot上配置与使用mybatis plus,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Java设计模式之观察者模式

    Java设计模式之观察者模式

    这篇文章主要介绍了Java设计模式之观察者模式,观察者模式,是一种行为性模型,又叫发布-订阅模式,他定义对象之间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新,需要的朋友可以参考下
    2023-11-11
  • springboot2.3 整合mybatis-plus 高级功能及用法详解

    springboot2.3 整合mybatis-plus 高级功能及用法详解

    这篇文章主要介绍了springboot2.3 整合mybatis-plus 高级功能,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Java Map 按照Value排序的实现方法

    Java Map 按照Value排序的实现方法

    Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。这篇文章主要介绍了Java Map 按照Value排序的实现方法,需要的朋友可以参考下
    2016-08-08
  • java实现cassandra高级操作之分页实例(有项目具体需求)

    java实现cassandra高级操作之分页实例(有项目具体需求)

    这篇文章主要介绍了java实现cassandra高级操作之分页实例(有项目具体需求),具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-04-04
  • 一文彻底弄懂零拷贝原理以及java实现

    一文彻底弄懂零拷贝原理以及java实现

    零拷贝(英语: Zero-copy) 技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域,下面这篇文章主要给大家介绍了关于零拷贝原理以及java实现的相关资料,需要的朋友可以参考下
    2021-08-08

最新评论