Spring Boot可执行Jar启动失败(tomcat-embed-jasper相关问题)
解决方案:Spring Boot可执行Jar中JSP渲染+zip file closed异常修复
问题本质
Spring Boot可执行Jar采用嵌套Jar结构,而tomcat-embed-jasper默认的资源加载逻辑不支持从嵌套Jar中读取JSP文件,导致Zip资源被提前关闭,触发java.lang.IllegalStateException: zip file closed异常。IDEA中运行正常是因为它直接使用项目本地文件目录,而非嵌套Jar结构。
可选解决方案
方案1:打包为WAR文件(推荐,兼容性更好)
WAR文件结构无需嵌套Jar,Tomcat可直接读取JSP资源,步骤如下:
- 修改pom.xml的打包类型为war
<packaging>war</packaging>
- 调整依赖配置,将tomcat starter设为provided,保留jasper依赖
<dependencies> <!-- 其他依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> </dependencies>
- 让主类继承
SpringBootServletInitializer
@SpringBootApplication public class YourApp extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(YourApp.class, args); } }
- 执行打包命令:
mvn clean package
生成的WAR文件可直接用java -jar your-app.war启动,JSP能正常渲染,无zip文件异常。
方案2:自定义Tomcat资源加载器(保持Jar打包)
通过将JSP文件提取到临时目录,避免嵌套Jar的读取限制:
- 添加配置类,自定义Tomcat上下文和资源加载逻辑
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.web.servlet.view.InternalResourceViewResolver; import java.io.File; import java.io.IOException; import java.nio.file.Files; @Configuration public class TomcatJspConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatJspCustomizer() { return factory -> factory.addContextCustomizers(context -> { try { // 把classpath下的JSP复制到临时目录 ClassPathResource jspDir = new ClassPathResource("WEB-INF/jsp/"); File tempJspDir = Files.createTempDirectory("spring-boot-jsp").toFile(); copyDir(jspDir.getFile(), tempJspDir); // 设置Tomcat上下文的文档根为临时目录 context.setDocBase(tempJspDir.getAbsolutePath()); } catch (IOException e) { throw new RuntimeException("Failed to copy JSP files to temp dir", e); } }); } @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/jsp/"); resolver.setSuffix(".jsp"); return resolver; } // 递归复制目录 private void copyDir(File source, File target) throws IOException { if (source.isDirectory()) { if (!target.exists()) target.mkdirs(); for (String child : source.list()) { copyDir(new File(source, child), new File(target, child)); } } else { Files.copy(source.toPath(), target.toPath()); } } }
- 修改pom.xml,确保打包时包含JSP资源
<build> <resources> <resource> <directory>src/main/webapp</directory> <includes> <include>WEB-INF/jsp/**</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeResources> <include>WEB-INF/jsp/**</include> </includeResources> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 执行
mvn clean install后,运行Jar文件即可正常渲染JSP。
验证步骤
- 执行打包命令后,检查生成的Jar/WAR文件是否包含
WEB-INF/jsp目录下的文件 - 启动应用,访问JSP页面,确认页面正常渲染且无启动异常
内容的提问来源于stack exchange,提问作者Joni Jansson
相关产品推荐
相关产品推荐

