带有 Spring Boot 的 Spring MVC 不适用于 Eclipse 的 Tomcat 服务器
Posted
技术标签:
【中文标题】带有 Spring Boot 的 Spring MVC 不适用于 Eclipse 的 Tomcat 服务器【英文标题】:Spring MVC with Spring Boot doesn't work with the Tomcat server of Eclipse 【发布时间】:2014-06-22 10:48:39 【问题描述】:我尝试遵循 Spring Getting Started Guide for "Serving Web Content with Spring MVC",它使用 Spring Boot 和 Gradle 以及 Maven。 我在 Eclipse 中安装了 Gradle 插件。
我想在 Eclipse 中使用 Tomcat 服务器运行应用程序,因为我还遵循“将 Spring Boot JAR 应用程序转换为 WAR”指南并更改了指南中提到的“build.gradle”文件。基本上,我添加了行“应用插件:'eclipse-wtp'”、“应用插件:'war'”、配置 providedRuntime 和提供的运行时间(“org.springframework.boot:spring-boot-starter-tomcat”);并将 jar 设置更改为战争设置。这是 build.gradle 文件:
buildscript
repositories
maven url "http://repo.spring.io/libs-milestone"
mavenLocal()
dependencies
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.2.RELEASE")
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'war'
eclipse.project
natures 'org.springsource.ide.eclipse.gradle.core.nature'
war
baseName = 'gs-serving-web-content'
version = '0.1.0'
repositories
mavenCentral()
maven url "http://repo.spring.io/libs-milestone"
configurations
providedRuntime
dependencies
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
testCompile("junit:junit")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
task wrapper(type: Wrapper)
gradleVersion = '1.11'
我还添加了他们提到的 HelloWebXml 类。这是课程:
package hello;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class HelloWebXml extends SpringBootServletInitializer
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
return application.sources(Application.class);
除此之外,我还需要稍微更改 pom.xml,因为它抱怨 Java SE 7 的特性。在 pom.xml 中添加以下行:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<showWarnings>true</showWarnings>
<compilerVersion>1.7</compilerVersion>
<fork>true</fork>
</configuration>
</plugin>
其余与入门指南相同。
为了建设,我跑
gradlew eclipseWtp
gradlew clean build
命令。在此之后,war 文件将在项目的 build/libs 文件夹中创建。如果我将 war 文件复制到本地 Tomcat 服务器并启动服务器,一切都会按预期工作。
如果我将项目拖到“服务器”选项卡下的 Tomcat 服务器(使用相同的本地 Tomcat 创建)并运行该服务器,则会引发 ClassCastException 并抱怨: “无法将 org.springframework.web.SpringServletContainerInitializer 转换为 javax.servlet.ServletContainerInitializer”。
我在两个部署位置检查了项目的文件夹结构。 在本地(非 Eclipse)部署位置,服务器启动后,会按预期创建一个名为 war 文件的文件夹。在 WEB-INF 文件夹中,有一个 lib-provided 目录。我检查了 Eclipse 的 Tomcat 的部署位置,它没有包含名为 lib-provided 的目录。我猜问题是这个目录没有被创建,但我找不到解决方案。
我已经在使用 Spring MVC,并且我知道如何使用 web.xml 创建 MVC 项目,但我是 Spring Boot 的新手。 Eclipse 的 Tomcat 服务器可以很好地运行我之前的 Spring MVC 项目。所以问题出在 Spring Boot 项目上。
我检查了几个相关的问题,但它们与我的不同。我找不到解决问题的方法。
我在这里错过了什么?
提前致谢。
【问题讨论】:
为什么你同时拥有pom.xml
和build.gradle
。您现在有 2 个构建系统竞争控制权。要么使用 maven 要么使用 gradle 不要同时使用。
好吧,正如我所提到的,这是来自 Spring 的指南。我认为他们应该比我更了解如何构建 Spring 项目。我也更喜欢只使用 Maven,但我不想通过偏离指南所说的内容来增加可能出错的事情的数量。
【参考方案1】:
我想你正在与servlet-api
JAR 发生冲突。如果您使用嵌入式 Tomcat 进行开发(创建 JAR),您需要在 compile
范围内的类路径中包含 servlet-api
JAR。当您部署到现有的 Tomcat 安装(创建 WAR)时,您必须在 provided
范围内声明 servlet-api
jar,否则它将最终在 web-inf/lib
中并导致与容器提供的版本冲突。
这是来自示例 Spring Boot WAR 项目的 POM: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-traditional/pom.xml
注意spring-boot-starter-tomcat
如何使用provided
范围。
【讨论】:
我尝试了很多东西,包括那个。正如你提到的,我改变了 pom.xml 。结果是一样的。另外,正如我上面提到的,我可以创建一个 WAR,当我将它复制到 Webapps 目录时,它可以与本地 Tomcat 一起使用。我只是不使用 Eclipse 的 Tomcat。 另外,我猜对 build.gradle 文件所做的更改是为了提供 servlet-api。正如我所提到的,添加了一个“configurations”元素和一个providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") 元素。【参考方案2】:Spring Boot 做了一些特殊处理,以允许在嵌入式或容器中运行的可执行 WAR。必须特别注意 provided
范围内的依赖关系,因为它们可能与容器冲突。详细信息在in the Spring Boot reference guide 中描述。通过构建的 WAR 而不是通过 Eclipse 部署时,您的构建工作的原因是 Eclipse WTP 实际上并不使用 Maven 来执行构建,因此 Maven 构建和 WTP 构建不会完全匹配。
我自己也在努力解决同样的问题。我打算做的是专门为此目的创建一个单独的“dev”maven模块,并使用标签将provided
条目(部分)切换为runtime
。
【讨论】:
如果有效,请再次发布。我现在停止使用 Spring Boot。【参考方案3】:@meribald 你可以这样配置你的 pom.xml:
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<packaging-profile>jar</packaging-profile>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>prod</id>
<properties>
<packaging-profile>war</packaging-profile>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
在你的 pom.xml 的顶部
<packaging>$packaging-profile</packaging>
因此,当您开发时,您将应用程序作为 Java 应用程序运行,maven 将生成一个 jar 文件。当你想打包一个war文件部署在服务器上时,你在maven命令行上运行
mvn -Pprod package
或在 Eclipse 中运行为 >> Maven Build ...,并将“package”放在目标字段上,将“prod”(不带引号)放在配置文件字段上。
【讨论】:
以上是关于带有 Spring Boot 的 Spring MVC 不适用于 Eclipse 的 Tomcat 服务器的主要内容,如果未能解决你的问题,请参考以下文章
带有 spring-boot 和 spring-security 的 JWT
带有 spring-boot-starter-web 的 Spring Cloud Gateway
带有 Spring Boot 的 Spring Restful 服务 - NoSuchBeanDefinitionException
带有 MVC 的 Spring Boot SOAP Web 服务