1. Introduction

Spring MVC is a traditional application built using the Front Controller Pattern. DispatcherServlet, which acts as the front controller, is responsible for routing and request processing.

As with any web application or website, Spring MVC returns the HTTP 404 response code when the requested resource can’t be found. In this tutorial, we’ll look at common causes for 404 errors in Spring MVC.

2. Possible Causes for 404 Response

2.1. Wrong URI

Let’s say we have a GreetingController that is mapped to /greeting and renders greeting.jsp:

@Controller
public class GreetingController {

    @RequestMapping(value = "/greeting", method = RequestMethod.GET)
    public String get(ModelMap model) {
        model.addAttribute("message", "Hello, World!");
        return "greeting";
    }
}

The corresponding view renders the value of the message variable:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Greeting</title>
    </head>
    <body>
        <h2>${message}</h2>
    </body>
</html>

As expected, making a GET request to /greeting works:

curl http://localhost:8080/greeting

We’ll see an HTML page with the message “Hello World”:

<html>
    <head>
        <title>Greeting</title>
    </head>
    <body>
        <h2>Hello, World!</h2>
    </body>
</html>

One of the most common reasons for seeing 404 is using an incorrect URI. For example, it would be wrong to make GET request to /greetings instead of /greeting:

curl http://localhost:8080/greetings

In such a case, we’d see a warning message in the server logs:

[http-nio-8080-exec-6] WARN  o.s.web.servlet.PageNotFound - 
  No mapping found for HTTP request with URI [/greetings] in DispatcherServlet with name 'mvc'

And the client would see an error page:

<html>
    <head>
        <title>Home</title>
    </head>
    <body>
        <h1>Http Error Code : 404. Resource not found</h1>
    </body>
</html>

To avoid this, we need to make sure that we have entered the URI correctly.

2.2. Incorrect Servlet Mapping

As explained earlier, DispatcherServlet is the front controller in Spring MVC. Hence, just as in a standard servlet-based application, we need to create a mapping for the servlet using the web.xml file.

We define the servlet inside the servlet tag and map it to a URI inside the servlet-mapping tag. We need to ensure that the value of url-pattern is correct because it’s quite common to see suggestions where the servlet is mapped to “/*” — note the trailing asterisk:

<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
    <!-- Additional config omitted -->
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <!-- Additional config omitted -->
</web-app>

Now, if we request /greeting, we’d see a warning in the server logs:

curl http://localhost:8080/greeting
WARN  o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI 
  [/WEB-INF/view/greeting.jsp] in DispatcherServlet with name 'mvc'

This time the error states that greeting.jsp is not found, and the user sees a blank page.

To fix the error, we need to map DispatcherServlet to “/” (without the trailing asterisk) instead:

<servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

After fixing the mapping, everything should work correctly. Requesting /greeting now shows the message “Hello, World!”:

curl http://localhost:8080/greeting
<html>
    <head>
        <title>Greeting</title>
    </head>
    <body>
        <h2>Hello, World!</h2>
    </body>
</html>

The reasoning behind the problem is that if we map DispatcherServlet to /*, then we are telling the application that every single request arriving at our application is to be served by DispatcherServlet. However, that’s not a correct approach because DispatcherServlet is not capable of doing this. Instead, Spring MVC expects an implementation of ViewResolver to serve views such as JSP files.

3. Conclusion

In this quick article, we explained how to debug 404 errors in Spring MVC. We went through the two most common reasons for receiving a 404 response from our Spring application. The first was using an incorrect URI while making the request. The second was mapping the DispatcherServlet to the wrong url-pattern in web.xml.

As always, the full implementation of this tutorial can be found over on Github.