4

Summary

I'm trying to create a basic Spring Boot application from scratch, build a .war file and run it in Tomcat. I achieved to run it in Intellij, but it is not running in Tomcat.

Reproduce

I explain in the following, how to reproduce my issue. Please write a comment if I'm missing anything relevant.

How to create the project?

Generate the project on https://start.spring.io/ using the following options

Spring Initializr Options

Click the button Generate. A file demo.zip is downloaded. Extract it as directory demo. It should contain the following files:

├── HELP.md
├── demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── demo
    │   │               ├── DemoApplication.java
    │   │               └── ServletInitializer.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── example
                    └── demo
                        └── DemoApplicationTests.java

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

src/main/java/com/example/demo/DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

src/main/java/com/example/demo/ServletInitializer.java

package com.example.demo;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(DemoApplication.class);
    }

}

src/main/resources/application.properties is empty


Add a file src/main/java/com/example/demo/HelloWorldController.java with content

package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {
    @RequestMapping("/")
    public String index() {
        return "Greetings from Spring Boot!";
    }
}

How to run the project in Intellij?

Open and load the maven project in Intellij. In the menu select Run and Run 'DemoApplication'. You should see something like this in the console:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)

2021-07-09 17:31:07.447  INFO 7245 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 1.8.0_292 on MY_HOST with PID 7245 (/path/to/demo/target/classes started by USER in /path/to/demo)
2021-07-09 17:31:07.451  INFO 7245 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2021-07-09 17:31:08.636  INFO 7245 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-07-09 17:31:08.647  INFO 7245 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-07-09 17:31:08.648  INFO 7245 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.48]
2021-07-09 17:31:08.720  INFO 7245 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-09 17:31:08.720  INFO 7245 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1205 ms
2021-07-09 17:31:09.214  INFO 7245 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-09 17:31:09.229  INFO 7245 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 2.89 seconds (JVM running for 3.783)

Open http://localhost:8080/ in your browser. You should see

Greetings from Spring Boot!

How to build the .war in Intellij?

Select View > Tool Windows > Maven in the menu and run lifecycles clean and package

Maven Tool Window with highlighted lifecycles

Among other files, a file target/demo-0.0.1-SNAPSHOT.war is created.

How to run the project in Tomcat?

Note: I'm using Docker in the following to make the environment as reproducible as possible. However, I also tried Tomcat installed on another Mac using brew and got the same issue.

Run in the terminal (in the project root directory)

docker run --rm -p 8081:8080 \
  -v ${PWD}/target/demo-0.0.1-SNAPSHOT.war:/usr/local/tomcat/webapps/demo.war \
  tomcat:10-jdk8

You should get output similar to this:

09-Jul-2021 16:44:19.312 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/10.0.8
09-Jul-2021 16:44:19.315 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Jun 25 2021 23:05:41 UTC
09-Jul-2021 16:44:19.315 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.0.8.0
09-Jul-2021 16:44:19.315 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
09-Jul-2021 16:44:19.315 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            5.10.25-linuxkit
09-Jul-2021 16:44:19.315 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
09-Jul-2021 16:44:19.316 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/local/openjdk-8/jre
09-Jul-2021 16:44:19.316 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.8.0_292-b10
09-Jul-2021 16:44:19.316 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Oracle Corporation
09-Jul-2021 16:44:19.316 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
09-Jul-2021 16:44:19.316 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
09-Jul-2021 16:44:19.320 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
09-Jul-2021 16:44:19.320 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
09-Jul-2021 16:44:19.320 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
09-Jul-2021 16:44:19.320 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
09-Jul-2021 16:44:19.321 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
09-Jul-2021 16:44:19.321 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs=
09-Jul-2021 16:44:19.321 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
09-Jul-2021 16:44:19.321 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
09-Jul-2021 16:44:19.321 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
09-Jul-2021 16:44:19.335 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.30] using APR version [1.6.5].
09-Jul-2021 16:44:19.335 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true], UDS [true].
09-Jul-2021 16:44:19.339 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d  10 Sep 2019]
09-Jul-2021 16:44:19.821 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
09-Jul-2021 16:44:19.844 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [769] milliseconds
09-Jul-2021 16:44:19.898 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
09-Jul-2021 16:44:19.898 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.0.8]
09-Jul-2021 16:44:19.945 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/demo.war]
09-Jul-2021 16:44:21.248 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
09-Jul-2021 16:44:21.315 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/demo.war] has finished in [1,369] ms
09-Jul-2021 16:44:21.321 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
09-Jul-2021 16:44:21.339 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [1494] milliseconds

Note: I expect that the log of my app, i.e.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)

...

appears here too, but it is missing.

Open http://localhost:8081/demo/ in your browser. I expect to see

Greetings from Spring Boot!

but I get

404 page


What am I missing in my project or Tomcat configuration/code? How to run my Spring Boot application as .war in Tomcat?

maiermic
  • 4,764
  • 6
  • 38
  • 77
  • 2
    That is also the reason why the Docker image [`tomcat:latest`](https://hub.docker.com/_/tomcat) is a Tomcat 9.0 running on an OpenJDK 11 JVM. – Piotr P. Karwasz Jul 09 '21 at 17:32
  • 3
    Does https://stackoverflow.com/a/66808062/104891 explain why you get 404 with Tomcat 10? – CrazyCoder Jul 09 '21 at 17:38
  • @piotr-p-karwasz Yes, using `tomcat:9-jdk8` instead of `tomcat:10-jdk8` is working. Thank you so much :) – maiermic Jul 09 '21 at 18:22
  • @CrazyCoder Thanks for pointing to an explanation. – maiermic Jul 09 '21 at 18:24
  • Could I have figured this out by the logs or only by guessing/suspecting that the Tomcat version may be an issue? – maiermic Jul 09 '21 at 18:27
  • I have a bigger project (private) that behaves similar, but does not work with Tomcat 9 either. I searched a lot, but I'm still in the dark, why it is not working/running. – maiermic Jul 09 '21 at 18:35
  • 1
    @maiermic: The logs are probably empty, since Spring uses a `javax.servlet.ServletContainerInitializer`. Since Tomcat 10 does not handle it, the only thing you might notice is the lack of logs. – Piotr P. Karwasz Jul 09 '21 at 18:45

1 Answers1

1

As pointed out in the comments, running Tomcat 9 instead of 10 works

docker run --rm -p 8081:8080 \
  -v ${PWD}/target/demo-0.0.1-SNAPSHOT.war:/usr/local/tomcat/webapps/demo.war \
  tomcat:9-jdk8
maiermic
  • 4,764
  • 6
  • 38
  • 77