如何在spring引导应用程序中预编译jsp?

如何在spring引导应用程序中预编译jsp?,spring,maven,jsp,spring-mvc,spring-boot,Spring,Maven,Jsp,Spring Mvc,Spring Boot,我用的是Spring boot,在那之前我们用的是Tomcat的Spring。 两年前,当我们使用Spring和Tomcat时,我们使用了一个maven插件来预编译jsp。 避免在部署后的每次首次访问中都进行这种编译是非常有用的 然而,我们知道的所有maven插件都会转储一个web.xml文件,其中列出所有jsp和相关生成的servlet。 在SpringBoot中,它不再使用web.xml,因此该文件被忽略 我们仍然有汇编,这是一个安全带,但每一页的第一次访问都会受到惩罚 有人知道是否可以在S

我用的是Spring boot,在那之前我们用的是Tomcat的Spring。 两年前,当我们使用Spring和Tomcat时,我们使用了一个maven插件来预编译jsp。 避免在部署后的每次首次访问中都进行这种编译是非常有用的

然而,我们知道的所有maven插件都会转储一个web.xml文件,其中列出所有jsp和相关生成的servlet。 在SpringBoot中,它不再使用web.xml,因此该文件被忽略

我们仍然有汇编,这是一个安全带,但每一页的第一次访问都会受到惩罚


有人知道是否可以在Spring boot应用程序中预编译jsp吗?

我可以在服务器启动时(不必使用JspC,所以更简单的构建文件)和构建时(更快的服务器启动时间)进行预编译。我动态注册生成的servlet,因此如果添加/删除JSP,就不必手动更改任何文件

在服务器启动时 用于为每个JSP注册Servlet。 使用
jspFile
设置JSP文件名()

e、 g.对于a()中的SpringBoot:

@Bean
公共ServletContextInitializer预编译JSPSATStartup(){
返回servletContext->{
GetDeepResourcePath(servletContext,“/WEB-INF/jsp/”).forEach(jspPath->{
info(“注册JSP:{}”,jspPath);
ServletRegistration.Dynamic reg=servletContext.addServlet(jspPath,Constants.JSP\u SERVLET\u类);
reg.setInitParameter(“jspFile”,jspPath);
注册设置加载启动(99);
注册地址映射(jspPath);
});
};
}
私有静态流GetDeepResourcePath(ServletContext ServletContext,字符串路径){
return(path.endsWith(“/”)?servletContext.getResourcePath(path.stream().flatMap(p->getDeepResourcePath(servletContext,p))
:溪流(路径);
}
在构建时 使用()为每个JSP和a及其servlet映射生成Java源文件

然后将它们注册到(通过使用Tomcat解析
web.xml
,例如SpringBoot:

@Value(“classpath:precompiledjspweb.xml”)
私有资源预编译JSPWebXML;
@豆子
公共ServletContextInitializer注册表重新编译JSP(){
返回servletContext->{
//使用Tomcat的web.xml解析器(假设完整的xml文件并进行验证)。
WebXmlParser=新的WebXmlParser(false、true、true);
try(InputStream=precompiledJspWebXml.getInputStream()){
WebXml WebXml=新的WebXml();
boolean success=parser.parseWebXml(新输入源(is),webXml,false);
如果(!成功){
抛出新的RuntimeException(“错误解析Web XML”+预编译JSPWebXML);
}
for(ServletDef:webXml.getServlets().values()){
info(“注册预编译JSP:{}={}->{}”,def.getServletName(),def.getServletClass());
ServletRegistration.Dynamic reg=servletContext.addServlet(def.getServletName(),def.getServletClass());
注册设置加载启动(99);
}
for(Map.Entry映射:webXml.getServletMappings().entrySet()){
log.info(“映射servlet:{}->{}”,Mapping.getValue(),Mapping.getKey());
getServletRegistration(mapping.getValue()).addMapping(mapping.getKey());
}
}捕获(IOE异常){
抛出新的RuntimeException(“注册预编译JSP时出错”,e);
}
};
}
示例Maven配置以生成和编译JSP类,并生成
预编译的jspweb.xml


org.apache.tomcat
金龟子蚂蚁
8.0.32
假如
maven antrun插件
1.8
预编译jsp生成java
编译
跑
org.codehaus.mojo
构建助手maven插件
添加预编译的jsp java源代码
生成源
添加源
${project.basedir}/generated sources/jspc/java
添加预编译的jsp资源
产生资源
添加资源
${project.basedir}/generated sources/jspc/resources
上面概述的“在服务器启动时”的注释:如果应用程序打包在可执行jar中,您创建的servlet默认处于开发模式,因此如果您在生产模式下使用它,您还应该设置development=false++以防止JSP再次编译:

reg.setInitParameter("genStringAsCharArray", "true");
reg.setInitParameter("trimSpaces", "true");
reg.setInitParameter("development", "false");

基于paulcm的优秀答案,我提出了自己的解决方案,因为上面的解决方案不适用于我,我无法跟踪错误。可能上面的答案对于tomcat9来说已经过时了。或者多模块设置有问题。但是:所有学分都属于paulcm

这只是编译时解决方案

将这两个插件添加到pom.xml中


org.eclipse.jetty
jetty jspc maven插件
9.4.15.v20190215
jspc
jspc
真的
1.8
1.8
org.apache.maven.plugins
maven战争插件
${project.basedir}/target/web.xml