带有 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.xmlbuild.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 服务

在 Spring Boot 应用程序中嵌入带有作业定义的 Spring Batch Admin

带有spring-cloud的Spring Boot:gradle构建失败