无论我做什么,Spring Boot应用程序中的JSP都会产生404错误



我首先会说,我已经研究并尝试了我能找到的每个问题的解决方案。最大的问题是,这些解决方案大多都很旧,而Spring Boot在过去几年中发生了很大变化。要明确的是,我试过这个,这个,这个和更多。我还阅读了许多教程。什么都不管用。

我有一个全新的Spring Boot应用程序,我正在尝试让JSP渲染与之一起工作

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>[2.3.4.RELEASE,3)</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>[2.8.0,3)</version>
</dependency>
<dependency>
<groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId>
<version>[2.7,3)</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>[8.0.21,9)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>[2.3.2,)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>[9.0.38,)</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

我的项目布局如下:

- source
- production
- java
- [my source code packages]
- resources
- WEB-APP
- jsp
- initialization
- begin.jsp
- [my resource packages]
- test
- java
- resources

"WEB-APP/jsp";这只是我尝试过的最新迭代。我试过";WEB-INF/jsp"META-INF/jsp"webapp/jsp";,没有父级(只有"jsp")等等,所有这些都具有相同的结果。

我知道父目录有点不标准,但它在Maven中配置正确,我已经确认问题的根源是而不是

<build>
<sourceDirectory>source/production/java</sourceDirectory>
<resources>
<resource>
<directory>source/production/resources</directory>
</resource>
</resources>
...
</build>

我的应用程序类如下:

@SpringBootApplication(scanBasePackages="com.my.project")
@EnableWebMvc
@EnableJpaRepositories("com.my.project.repository")
@EntityScan("com.my.project.model")
public class Application
{
private static final Logger LOGGER = LogManager.getLogger(Application.class);
public Application()
{
}
@Bean
public ViewResolver viewResolver()
{
LOGGER.info("Constructing InternalResourceViewResolver[JstlView]");
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-APP/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setRedirectContextRelative(true);
resolver.setRedirectHttp10Compatible(false);
return resolver;
}
public static void main(final String[] args)
{
SpringApplication.run(Application.class, args);
}
}

我的控制器:

@Controller
public class InitializationController
{
private static final Logger LOGGER = LogManager.getLogger(InitializationController.class);
@GetMapping("/initialize_application")
public String beginInitialization(ModelMap model)
{
LOGGER.info("Beginning initialization");
...
LOGGER.info("Returning view");
return "initialization/begin";
}
...
}

在启动时,我看到";构造InternalResourceViewResolver";日志条目(创建了我的视图解析器bean)。当我转到/initialize_application时,我得到以下错误:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Oct 18 21:45:26 CDT 2020
There was an unexpected error (type=Not Found, status=404).

再次查看日志,我看到";开始初始化";以及";返回视图;所以我知道404是我的JSP,而不是我的控制器。我的控制器正在工作。

我尝试过的其他东西:

  • 最初我的应用程序中没有@EnableWebMvc。没有它,除了我的日志语句之外,日志都是空的。当我添加@EnableWebMvc时,它现在用404:No mapping for GET /WEB-APP/jsp/initialization/begin.jsp(或者我尝试过的除"WEB-APP"之外的任何其他目录)进行记录
  • 我已经尝试过使用mvn spring-boot:run在纯命令行上直接运行它
  • 我曾尝试在IntelliJ IDEA中使用Maven运行配置和命令spring-boot:run运行此程序(结果相同)
  • 我尝试过<packaging>jar</packaging><packaging>war</packaging>,但都没有什么不同,因为从来没有创建过JAR和WAR。Maven直接从target/classes目录中运行应用程序,而不是创建工件
  • 当我尝试WEB-INFMETA-INF而不是WEB-APPwebapp或其他东西时,我看到了一个记录的警告:Path with "WEB-INF" or "META-INF": [WEB-INF/jsp/initialization/begin.jsp]

我还确认我的JSP存在于target/classes/WEB-APP/jsp(或我尝试过的除"WEB-APP"之外的任何其他目录)中,因此它们确实存在。

我不知道该怎么办。我开始觉得我需要放弃Spring Boot,坚持使用带有Servlet配置和Tomcat安装的传统样板Spring Web MVC应用程序,但我真的很兴奋;只是运行";Spring Boot方面。如有任何帮助,我们将不胜感激。

更新1

在阅读了这篇关于JSP限制的Spring文档后,我现在知道我必须使用<packaging>war</packaging>,而且我现在正在使用它,但它并没有产生任何影响。我开始怀疑这里的根本问题是maven spring-boot:run没有创建并运行WAR,它只是将所有内容构建到target/classes并从那里运行它。

此外,在找到这个旧的、官方的Spring引导示例应用程序后,我对我的项目结构进行了一些更改:

- source
- production
- java
- [my source code packages]
- resources
- [my resource packages]
- webapp
- META-INF
- WEB-INF
- jsp
- initialization
- begin.jsp
- test
- java
- resources

更新了我的视图解析程序配置:

resolver.setPrefix("/jsp/");
resolver.setSuffix(".jsp");

并将此添加到我的POM:中

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warSourceDirectory>source/production/webapp</warSourceDirectory>
</configuration>
</plugin>

如果我运行mvn package,我的WAR会被正确创建(类和JSP都在它们应该在的地方),但mvn spring-boot:runmvn package spring-boot:run都不起作用——我在解析JSP时仍然会遇到404个错误。

链接到上面的旧的SpringBoot示例应用程序将JSP放在WEB-INF/jsp中,但我不能这样做,因为这会导致警告Path with "WEB-INF" or "META-INF": [WEB-INF/jsp/initialization/begin.jsp](仍然是404)。令人沮丧的是,这个示例应用程序已经不存在了,也没有任何新的变体。我找不到任何与最新版本的Spring Boot兼容的更新版本。样本应用程序已在2.2.x中删除。

您是否可以尝试将tomcat-embed-jasper的作用域更改为provided,因为编译JSP需要此依赖项。

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>[9.0.38,)</version>
<scope>provided</scope>
</dependency>

编辑:

我在互联网上寻找各种spring-boot + jsp项目。我注意到他们也有spring-boot-starter-tomcatprovided范围。你能试试这个吗。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>[2.3.4.RELEASE,3)</version>
<scope>provided</scope>
</dependency>

参考文献:

https://mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/

https://dzone.com/articles/spring-boot-2-with-jsp-view

第2版:

所以这次我创建了一个新的springboot项目。只做了最低限度的设置就可以呈现jsp。所以基本上我遵循了这个教程,我的项目运行得很好。

然后我用你的pom.xml替换了pom.xml,我得到了与你在问题中提到的相同的错误。

然后,在进行试错时,我从<artifactId>tomcat-embed-jasper</artifactId>中删除了<version>[9.0.38,)</version>,它开始为我工作

<!--I have removed version here and it started working for me-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--            <version>[9.0.38,)</version>-->
<scope>provided</scope>
</dependency>

虽然我有不同的目录结构。但正如你提到的,这并不是问题的原因。

我已将该项目上传到github。随意拉它在本地运行。

Github

假设web内容的以下位置(应该在类路径AFAIK之外)source/production/webapp。Spring Boot将忽略这一点,因为在从命令行或IDE运行时,DocumentRoot中有一个用于检测目录的硬编码路径(它在构建war并运行它时会起作用)。

作为一种变通方法,您可以添加一个TomcatContextCustomizer作为bean来检测路径,并将其设置为正确的基。

package com.my.project;
@SpringBootApplication
public class Application extends SpringBootServletInitializer 
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) 
{
return application.sources(DemoApplication.class);
}
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public TomcatContextCustomizer docBaseCustomizer() 
{
return new TomcatContextCustomizer() 
{
public void customize(Context context) 
{
File root = new File("source/production/webapp");
if (root.exists() && root.isDirectory()) 
{
context.setDocBase(root.getAbsolutePath());
}        
}
}
} 
}

现在将以下内容添加到您的application.properties

spring.mvc.view.prefix=/jsp/
spring.mvc.view.suffix=.jsp

注意:只有当您的@SpringBootApplication带注释类位于com.my.project包中时,才能删除其他注释。然后它将自动检测其他类(如实体和存储库)。

最新更新