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
.
What I've tried
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=".springframework.web.servlet.view.JstlView" />
to the resolver, like 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.
Full project code/config
pom.xml
:
<project xmlns=".0.0" xmlns:xsi="; xsi:schemaLocation=".0.0 .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>.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=";
xmlns:xsi=";
xsi:schemaLocation=" .xsd"
version="6.0">
<display-name>jsp-example</display-name>
<listener>
<listener-class>.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>.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=";
xmlns:xsi=";
xmlns:context=";
xmlns:mvc=";
xsi:schemaLocation="
.xsd
.xsd
.3.xsd">
<mvc:annotation-driven/>
<bean id="viewResolver" class=".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.
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
.
What I've tried
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=".springframework.web.servlet.view.JstlView" />
to the resolver, like https://www.baeldung/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.
Full project code/config
pom.xml
:
<project xmlns="http://maven.apache./POM/4.0.0" xmlns:xsi="http://www.w3./2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache./POM/4.0.0 https://maven.apache./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>.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./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>.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>.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./schema/beans"
xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xmlns:context="http://www.springframework./schema/context"
xmlns:mvc="http://www.springframework./schema/mvc"
xsi:schemaLocation="http://www.springframework./schema/beans
http://www.springframework./schema/beans/spring-beans.xsd
http://www.springframework./schema/context
https://www.springframework./schema/context/spring-context.xsd
http://www.springframework./schema/mvc
http://www.springframework./schema/mvc/spring-mvc-4.3.xsd">
<mvc:annotation-driven/>
<bean id="viewResolver" class=".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.
Share Improve this question edited Mar 19 at 16:00 BalusC 1.1m376 gold badges3.7k silver badges3.6k bronze badges asked Mar 18 at 13:50 LemongrabThreeLemongrabThree 1319 bronze badges 5 |1 Answer
Reset to default 1Project Directory
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
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xmlns="http://maven.apache./POM/4.0.0"
xsi:schemaLocation="http://maven.apache./POM/4.0.0 https://maven.apache./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>
<mavenpiler.source>17</mavenpiler.source>
<mavenpiler.target>17</mavenpiler.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>.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>.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>.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
HomeController.java
package com.example.controller;
import .springframework.stereotype.Controller;
import .springframework.ui.Model;
import .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.xml
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
version="6.0">
<display-name>jsp-example</display-name>
<listener>
<listener-class>.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>.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>
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework./schema/beans"
xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xmlns:context="http://www.springframework./schema/context"
xsi:schemaLocation="
http://www.springframework./schema/beans https://www.springframework./schema/beans/spring-beans.xsd
http://www.springframework./schema/context https://www.springframework./schema/context/spring-context.xsd">
<context:component-scan base-package="com.example"/>
</beans>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework./schema/beans"
xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xmlns:context="http://www.springframework./schema/context"
xmlns:mvc="http://www.springframework./schema/mvc"
xsi:schemaLocation="
http://www.springframework./schema/beans https://www.springframework./schema/beans/spring-beans.xsd
http://www.springframework./schema/context https://www.springframework./schema/context/spring-context.xsd
http://www.springframework./schema/mvc https://www.springframework./schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.example.controller"/>
<bean class=".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>
index.jsp
<%@ 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>
Build
mvn clean package
put jsp-example.war into apache-tomcat-10.1.34/webapps/
Test
http://localhost:8080/jsp-example/
context.xml
needs to be loaded with theDispatcherServlet
not theContextLoaderListener
. I would also suggest to remove the version in yourspring-mvc-4.3.xsd
declaration. That being said why are you even using XML in the first place instead of Java config for both theweb.xml
and the Spring Config. – M. Deinum Commented Mar 18 at 14:29<mvc:view-controller .../>
creates the controller. I can replace it with a<context:component-scan .../>
and a Java controller class, but that doesn't change anything either. @M.Deinum If the dispatcher couldn't see mycontext.xml
, it wouldn't even be able to use the view resolver or themvc:view-controller
. @MarkRotteveel I was going to put the code first and then the explanation of what happens, guess I fot to delete that half-sentence. But my post is complete – LemongrabThree Commented Mar 18 at 15:11