springspring-mvctomcat

Running Spring MVC web app w/o Spring Boot in Tomcat and getting 404


I would like to create simple "Hello World" Spring MVC web app without Spring Boot and deploy it to Tomcat. I build WAR file and deploy it to standalone Tomcat. When I open url http://localhost:8080/simple-spring-mvc/home I'm getting 404 from Tomcat. There are no errors in catalina out and other log files.

I'm using the following versions: Tomcat 11; Spring MVC 6.2.4

Project Directory Structure:

simple-spring-mvc/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── config/
│   │   │           │   ├── WebAppInitializer.java
│   │   │           │   └── WebConfig.java
│   │   │           └── controller/
│   │   │               └── HomeController.java
│   │   └── webapp/
│   │       └── WEB-INF/
│   │           └── views/
│   │               └── home.jsp

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>simple-spring-mvc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <java.version>21</java.version>
        <spring.version>6.2.4</spring.version>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Spring Web MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- JSP API -->
        <dependency>
            <groupId>jakarta.servlet.jsp</groupId>
            <artifactId>jakarta.servlet.jsp-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>jakarta.servlet.jsp.jstl</groupId>
            <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>jakarta.servlet.jsp.jstl</artifactId>
            <version>3.0.1</version>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>simple-spring-mvc</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
            </plugin>
        </plugins>
    </build>
</project>

WebAppInitializer:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

WebConfig:

@Configuration
@EnableWebMvc
@ComponentScan("com.example.controller")
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        registry.viewResolver(resolver);
    }
}

HomeController:

@Controller
@RequestMapping("/home")
public class HomeController {

    @GetMapping()
    public String home(Model model) {
        model.addAttribute("message", "Hello World!");
        return "home";
    }
}

home.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>Spring MVC Demo</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>

Solution

  • I have duplicated your project here and it works as is - https://github.com/KoosieDeMoer/annoyingtomcat404

    Clone it, build it (mvn install), drop the warfile in webapps and compare logs:

    catalina start:

    
    catalina start
    Using CATALINA_BASE:   "C:\apache-tomcat-10.1.39"
    Using CATALINA_HOME:   "C:\apache-tomcat-10.1.39"
    Using CATALINA_TMPDIR: "C:\apache-tomcat-10.1.39\temp"
    Using JRE_HOME:        ""C:\java\jdk-21.0.5+11""
    Using CLASSPATH:       "C:\apache-tomcat-10.1.39\bin\bootstrap.jar;C:\apache-tomcat-10.1.39\bin\tomcat-juli.jar"
    Using CATALINA_OPTS:   ""
    

    tomcat sdtout:

    19-Mar-2025 15:06:24.028 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/10.1.39
    19-Mar-2025 15:06:24.033 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Mar 4 2025 19:02:32 UTC
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.39.0
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Windows 10
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            10.0
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             C:\java\jdk-21.0.5+11
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           21.0.5+11-adhoc.Administrator.jdk21u
    19-Mar-2025 15:06:24.034 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            OpenLogic
    19-Mar-2025 15:06:24.035 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         C:\apache-tomcat-10.1.39
    19-Mar-2025 15:06:24.035 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         C:\apache-tomcat-10.1.39
    19-Mar-2025 15:06:24.056 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\apache-tomcat-10.1.39\conf\logging.properties
    19-Mar-2025 15:06:24.056 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    19-Mar-2025 15:06:24.056 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
    19-Mar-2025 15:06:24.056 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
    19-Mar-2025 15:06:24.057 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
    19-Mar-2025 15:06:24.057 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
    19-Mar-2025 15:06:24.057 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
    19-Mar-2025 15:06:24.057 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
    19-Mar-2025 15:06:24.057 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
    19-Mar-2025 15:06:24.058 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
    19-Mar-2025 15:06:24.058 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
    19-Mar-2025 15:06:24.058 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\apache-tomcat-10.1.39
    19-Mar-2025 15:06:24.058 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\apache-tomcat-10.1.39
    19-Mar-2025 15:06:24.059 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\apache-tomcat-10.1.39\temp
    19-Mar-2025 15:06:24.199 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.4].
    19-Mar-2025 15:06:24.219 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.14 4 Jun 2024]
    19-Mar-2025 15:06:24.520 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
    19-Mar-2025 15:06:24.560 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [724] milliseconds
    19-Mar-2025 15:06:24.625 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
    19-Mar-2025 15:06:24.625 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.39]
    19-Mar-2025 15:06:24.648 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [C:\apache-tomcat-10.1.39\webapps\simple-spring-mvc.war]
    19-Mar-2025 15:06:25.863 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.
    19-Mar-2025 15:06:26.027 INFO [main] org.springframework.web.servlet.FrameworkServlet.initServletBean Initializing Servlet 'dispatcher'
    19-Mar-2025 15:06:26.768 INFO [main] org.springframework.web.servlet.FrameworkServlet.initServletBean Completed initialization in 739 ms
    19-Mar-2025 15:06:26.781 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [C:\apache-tomcat-10.1.39\webapps\simple-spring-mvc.war] has finished in [2,131] ms
    19-Mar-2025 15:06:26.783 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\apache-tomcat-10.1.39\webapps\docs]
    19-Mar-2025 15:06:26.834 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\apache-tomcat-10.1.39\webapps\docs] has finished in [52] ms
    19-Mar-2025 15:06:26.834 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\apache-tomcat-10.1.39\webapps\examples]
    19-Mar-2025 15:06:28.473 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\apache-tomcat-10.1.39\webapps\examples] has finished in [1,639] ms
    19-Mar-2025 15:06:28.474 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\apache-tomcat-10.1.39\webapps\host-manager]
    19-Mar-2025 15:06:28.548 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\apache-tomcat-10.1.39\webapps\host-manager] has finished in [75] ms
    19-Mar-2025 15:06:28.549 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\apache-tomcat-10.1.39\webapps\manager]
    19-Mar-2025 15:06:28.626 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\apache-tomcat-10.1.39\webapps\manager] has finished in [76] ms
    19-Mar-2025 15:06:28.626 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\apache-tomcat-10.1.39\webapps\ROOT]
    19-Mar-2025 15:06:28.670 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\apache-tomcat-10.1.39\webapps\ROOT] has finished in [44] ms
    19-Mar-2025 15:06:28.674 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
    19-Mar-2025 15:06:28.709 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [4147] milliseconds