博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义内置 tomcat,自定义spring boot 内置tomcat的404页面
阅读量:6923 次
发布时间:2019-06-27

本文共 6840 字,大约阅读时间需要 22 分钟。

hot3.png

spring boot 的相关404页面配置都是针对项目路径下的(如果配置了
context-path
在context-path不为空的情况下,如果访问路径不带context-path,这时候会显示空白页面或者是tomcat默认404页面
 
这时候如何自定义内置tomcat的404页面呢?
 
查看tomcat错误页面的实现源码org.apache.catalina.valves.ErrorReportValue:
report方法中先查找是否注册了错误页面,默认情况未注册任何错误页面,然后通过sendErrorPage方法发送错误页面
private boolean sendErrorPage(String location, Response  response) {        File file = new File(location);        if (!file.isAbsolute()) {            file = new  File(getContainer().getCatalinaBase(), location);        }        if (!file.isFile() || !file.canRead()) {            getContainer().getLogger().warn(                     sm.getString("errorReportValve.errorPageNotFound",  location));            return false;        }        // Hard coded for now. Consider making this  optional. At Valve level or        // page level?        response.setContentType("text/html");        response.setCharacterEncoding("UTF-8");        try (OutputStream os = response.getOutputStream();                InputStream is = new  FileInputStream(file);){            IOTools.flow(is, os);        } catch (IOException e) {            getContainer().getLogger().warn(                     sm.getString("errorReportValve.errorPageIOException",  location), e);            return false;        }        return true;    }

由于spring boot 默认打成的jar包运行tomcat,所以必须要把404页面放到外部,这里先将404.html放到resource目录下,然后启动过程中将页面复制到tomcat临时目录,将404路径指向该页面就可以了。

这里有两种实现办法:

1、通过AOP修改默认注册的ErrorReportValue

 

import java.io.File;import java.io.IOException;import javax.servlet.Servlet;import org.apache.catalina.startup.Tomcat;import org.apache.catalina.valves.ErrorReportValve;import org.apache.coyote.UpgradeProtocol;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import  org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import  org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;import  org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;import org.springframework.core.io.ClassPathResource;import org.springframework.stereotype.Component;import org.springframework.util.FileCopyUtils;import com.bc.core.util.FileUtil;@Aspect@ConditionalOnClass({ Servlet.class, Tomcat.class,  UpgradeProtocol.class,  TomcatWebServerFactoryCustomizer.class })@Componentpublic class TomcatCustomizerAspect {     @Pointcut("execution(public void  org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer.customize(*))")     public void customize() {     }     @After(value = "customize()")     public void doAfter(JoinPoint joinPoint) throws  Throwable {          if (!(joinPoint.getArgs()[0] instanceof  ConfigurableTomcatWebServerFactory)) {              return;          }          ConfigurableTomcatWebServerFactory factory =  (ConfigurableTomcatWebServerFactory)  joinPoint.getArgs()[0];          addTomcat404CodePage(factory);     }     private static void  addTomcat404CodePage(ConfigurableTomcatWebServerFactory  factory) {          factory.addContextCustomizers((context) -> {              String path =  context.getCatalinaBase().getPath() + "/404.html";              ClassPathResource cr = new  ClassPathResource("404.html");              if (cr.exists()) {                   File file404 = new File(path);                   if (!file404.exists()) {                        try {                             FileCopyUtils.copy(cr.getInputStream(),  FileUtil.openOutputStream(file404));                        } catch (IOException e) {                             e.printStackTrace();                        }                   }              }              ErrorReportValve valve = new  ErrorReportValve();              valve.setProperty("errorCode.404", path);              valve.setShowServerInfo(false);              valve.setShowReport(false);              valve.setAsyncSupported(true);              context.getParent().getPipeline().addValve(valve);          });     }}

2、通过自定义BeanPostProcessor添加自定义的ErrorReportValve

import java.io.File;import java.io.IOException;import javax.servlet.Servlet;import org.apache.catalina.startup.Tomcat;import org.apache.catalina.valves.ErrorReportValve;import org.apache.coyote.UpgradeProtocol;import org.springframework.beans.BeansException;import  org.springframework.beans.factory.config.BeanPostProcessor;import  org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import  org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;import  org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;import org.springframework.core.io.ClassPathResource;import org.springframework.stereotype.Component;import org.springframework.util.FileCopyUtils;import com.bc.core.util.FileUtil;import lombok.extern.slf4j.Slf4j;@ConditionalOnClass({ Servlet.class, Tomcat.class,  UpgradeProtocol.class,  TomcatWebServerFactoryCustomizer.class })@Component@Slf4jpublic class TomcatCustomizerBeanPostProcessor implements  BeanPostProcessor {     @Override     public Object postProcessAfterInitialization(Object  bean, String beanName) throws BeansException {          if (bean instanceof  ConfigurableTomcatWebServerFactory) {              ConfigurableTomcatWebServerFactory  configurableTomcatWebServerFactory =  (ConfigurableTomcatWebServerFactory) bean;                            addTomcat404CodePage(configurableTomcatWebServerFactory);          }          return  BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);     }     private static void  addTomcat404CodePage(ConfigurableTomcatWebServerFactory  factory) {          factory.addContextCustomizers((context) -> {              String tomcatTempPath =  context.getCatalinaBase().getPath();              log.info("tomcat目录:{}", tomcatTempPath);              String path = tomcatTempPath + "/404.html";              ClassPathResource cr = new  ClassPathResource("404.html");              if (cr.exists()) {                   File file404 = new File(path);                   if (!file404.exists()) {                        try {                             FileCopyUtils.copy(cr.getInputStream(),  FileUtil.openOutputStream(file404));                        } catch (IOException e) {                             e.printStackTrace();                        }                   }              }              ErrorReportValve valve = new  ErrorReportValve();              valve.setProperty("errorCode.404", path);              valve.setShowServerInfo(false);              valve.setShowReport(false);              valve.setAsyncSupported(true);              context.getParent().getPipeline().addValve(valve);          });     }}

 

上面两种办法,都就可以达到,如果项目访问带项目名,访问任意错误路径(非项目路径下的路径),指向自定义的404页面

转载于:https://my.oschina.net/u/1428688/blog/3045483

你可能感兴趣的文章
记录 dts 里面添加 SD cd
查看>>
PDFBOX详解
查看>>
RK3288以太网的mac地址调试笔记【学习笔记】【原创】
查看>>
5.5 进入编辑模式 5.6 vim命令模式 5.7 vim实践
查看>>
xapp1052之dma_test.v
查看>>
mysql17---增量备份
查看>>
Oracle用户被锁定解决方法
查看>>
拥抱变化-记我的2017
查看>>
工作总结 页面 ActionResult / JsonResult 将对象以 Json() 返回
查看>>
SQL Server 2017 SELECT…INTO 创建的新表指定到文件组
查看>>
MySQL复制以及调优
查看>>
PostgreSQL命令列表
查看>>
Android笔记---点击事件的四种写法
查看>>
优先队列
查看>>
BZOJ 1115: [POI2009]石子游戏Kam (阶梯nim)
查看>>
【来龙去脉系列】什么是区块链?
查看>>
wx小程序的学习
查看>>
2018.03小结
查看>>
54. Spiral Matrix
查看>>
ribbion的负载均衡之端口的切换
查看>>