I am trying to make a web app using Spring 6 (no Spring Boot), with mostly XML configuration. I'm trying to learn this in order to maintain an existing legacy application that uses plain Spring with XML config. So "just use Spring Boot" or "just use xyz annotation" are not acceptable answers.
I've boiled it down to a minimal app with a single JSP (code below). When I deploy the app and navigate to localhost:8080/jsp-example
, I get the Tomcat 404 page with the message No endpoint GET /jsp-example/WEB-INF/pages/index.jsp.
:
Notice how the path is /WEB-INF/pages/index.jsp
- this indicates the view resolver is correctly identifying the JSP, but then actually serving the JSP fails. If I go to another route, it just tells me that route itself doesn't exist:
However, localhost-access-[date].log
logs the plain path that I typed in the search bar, not the resolved JSP. Maybe this means my hypothesis about the view resolver working correctly is wrong after all. (the first entry is where it said No endpoint GET /jsp-example/WEB-INF/pages/index.jsp
):
127.0.0.1 - - [18/Mar/2025:14:19:19 +0100] "GET /jsp-example/ HTTP/1.1" 404 774
127.0.0.1 - - [18/Mar/2025:14:19:19 +0100] "GET /favicon.ico HTTP/1.1" 200 21630
127.0.0.1 - - [18/Mar/2025:14:29:18 +0100] "GET /jsp-example/home HTTP/1.1" 404 747
I'm using Tomcat 10.1.34 with Amazon Corretto JDK 17.0.8_8 on Windows 11 and building it with Maven 3.9.2 using mvn clean package
.
If I add a handler mapping, component scan, and mvc:annotation-driven
to context.xml
and create a controller class, I can access that controller. This indicates that the basic web app setup and dispatcher servlet are working.
If I try moving the JSP outside of WEB-INF and adapting the viewResolver's prefix (as per HTTP 404 problem JSP can not see in web, although it's different from my use case), the exact same thing happens - it prints the resolved JSP path, but says it can't find it.
I tried adding dependencies for jakarta.servlet.jsp.jstl-api
and jakarta.servlet.jsp-api
and adding <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
to the resolver, like https://www.baeldung.com/spring-mvc-view-resolver-tutorial does. No change.
I tried removing all non-HTML elements from index.jsp
in case its syntax is somehow wrong, no change. I also tried replacing it with index.html
and adapting the resolver's suffix accordingly, same result.
I found two similar posts, here and here. The former has only one answer that's pretty much gibberish and for the latter, the problem apparently just... went away? Based on that, I tried making a new blank application and restarting Tomcat. I'm not sure what other kinds of "turning it off and on again" I could try. Any ideas?
I've checked all the Tomcat logs, there is nothing. Some tips on how to get more information on what's going on would be helpful too.
pom.xml
:
<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>
<groupId>com.example</groupId>
<artifactId>jsp-example</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.3</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</build>
</project>
src/main/webapp/WEB-INF/web.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<display-name>jsp-example</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value> <!-- inherit context.xml -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
src/main/webapp/WEB-INF/context.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:view-controller path="/" view-name="index" />
</beans>
src/main/webapp/WEB-INF/pages/index.jsp
:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
</body>
</html>
EDIT: Well, here's a clue, I suppose: if I change the viewResolver
's prefix
property to /WEB-INF/pagezzz/
(i.e. nonsense), I get the exact same error "No endpoint GET /jsp-example/WEB-INF/pagezzz/index.jsp.". This indicates that there is a problem locating the JSP file at all. I have checked a thousand times that it's there, though. And all my leading and trailing slashes match those from all the examples, too - including that legacy app which really does work.
EDIT 2: thank you @life888888! I tried around a bit, and replacing
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
with
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
is sufficient to get my example working.
jsp-example
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ └── controller
│ └── HomeController.java
└── webapp
└── WEB-INF
├── context.xml
├── pages
│ └── index.jsp
├── spring-mvc.xml
└── web.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<groupId>com.example</groupId>
<artifactId>jsp-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>jsp-example</name>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring.version>6.2.3</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>jsp-example</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Hello, Spring MVC with Tomcat 10.1!");
return "index";
}
}
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
version="6.0">
<display-name>jsp-example</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<url-pattern>/</url-pattern>
, not /*
<init-param>
add <param-value>/WEB-INF/spring-mvc.xml</param-value>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.example.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/"/>
</beans>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello - Spring MVC on Tomcat 10</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
mvn clean package
put jsp-example.war into apache-tomcat-10.1.34/webapps/
http://localhost:8080/jsp-example/