カスタムSpring Bootにtomcatを内蔵する404ページ
15291 ワード
spring boot の関連404ページ構成は、プロジェクトパスの下にあるものです. context-path)
context-pathが空でない場合、アクセス経路がcontext-pathを持たない場合、空白ページまたはtomcatデフォルト404ページが表示されます.
この時はどうやってtomcatを内蔵する404ページをカスタマイズしますか?
tomcatのエラーページのソースコードorg.apphe.aparaina.valves.Error Report Valueを確認します.
レポート方法では、まずエラーページが登録されているかどうかを検索します.デフォルトではエラーページは登録されていません.その後、sendError Pageでエラーページを送信します.
ここには二つの実現方法があります.
1、AOPでデフォルト登録のErrerReport Valueを修正する
context-pathが空でない場合、アクセス経路がcontext-pathを持たない場合、空白ページまたはtomcatデフォルト404ページが表示されます.
この時はどうやってtomcatを内蔵する404ページをカスタマイズしますか?
tomcatのエラーページのソースコードorg.apphe.aparaina.valves.Error Report Valueを確認します.
レポート方法では、まずエラーページが登録されているかどうかを検索します.デフォルトではエラーページは登録されていません.その後、sendError Pageでエラーページを送信します.
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でデフォルト登録のErrerReport Valueを修正する
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 })
@Component
public 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、カスタマイズしたBenPostProcessorを通じてカスタマイズしたErrerReport Valveを追加します.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
@Slf4j
public 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);
});
}
}
上記の2つの方法はいずれも達成でき、プロジェクトがプロジェクト名にアクセスする場合、任意のエラーパス(プロジェクトパスではないパス)にアクセスし、カスタマイズされた404ページを指す.