Alexio Cassani Alexio Cassani - 5 months ago 107
Java Question

Spring MVC Rest: No mapping found for HTTP request with URI [/ecommerce-api/rest/checkout] in DispatcherServlet

(probably) solved `or at least it seems to be. I'm not really sure where it was the problem. For sure the config suggested by Biju Kunjummen, it's working and seems to me cleaner. What I'm doing now, to not generate mess is to work only inside Eclipse, sometimes cleaning the projects and never using maven to package & deploy it (at least during day to day programming, I guess with some robust maven script or CI Server everything will work fine too).

I'm trying to setup a Rest API with Spring MVC. I've read a lot of documentation but I'm still getting the error in the subject:


No mapping found for HTTP request with URI [/ecommerce-api/rest/checkout] in DispatcherServlet


The problem is exactly the same reported (and solved) in other similar questions, like this one FIXED: "No mapping found" Trying to set up a RESTfull interface using Spring-MVC

The really strange thing is that, without apparently changing anything in my code, sometime it works and sometimes it doesn't. I'm pretty sure nothing changes between the two moments, since for example sometime I'm physically away then I come back and it stops working.

At this particular moment, my code is the following:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/api-dispatcher-servlet.xml
</param-value>
</context-param>


<servlet>
<servlet-name>api-dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>api-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>


</web-app>


api-dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan base-package="com.myapp.api.ecommerce.controller" />
<context:annotation-config />
<mvc:annotation-driven />

</beans:beans>


com.myapp.ecommerce.controller.CheckoutController

package com.myapp.api.ecommerce.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.myapp.ecommerce.service.checkout.manager.CheckoutManager;
import com.myapp.ecommerce.service.checkout.manager.CheckoutManagerImpl;
import com.myapp.ecommerce.service.checkout.model.Checkout;


@Controller
@RequestMapping("/checkout")
public class CheckoutController {


private CheckoutManager checkoutManager = new CheckoutManagerImpl();

@RequestMapping(method = RequestMethod.GET)
public @ResponseBody Checkout getCheckout() {

return checkoutManager.findById("514f2a8e20f7a78a1400001f");
}


}


A snippet of the log file of the application server (VFabric but I've also tried with Tomcat 7) when I try to GET ecommerce-api/rest/checkout:

2013-09-05 22:31:37,760 DEBUG [tomcat-http--5] servlet.DispatcherServlet (DispatcherServlet.java:823) - DispatcherServlet with name 'api-dispatcher' processing GET request for [/ecommerce-api/rest/checkout]
2013-09-05 22:31:37,763 DEBUG [tomcat-http--5] handler.AbstractHandlerMethodMapping (AbstractHandlerMethodMapping.java:220) - Looking up handler method for path /checkout
2013-09-05 22:31:37,763 DEBUG [tomcat-http--5] handler.AbstractHandlerMethodMapping (AbstractHandlerMethodMapping.java:230) - Did not find handler method for [/checkout]
2013-09-05 22:31:37,764 WARN [tomcat-http--5] servlet.DispatcherServlet (DispatcherServlet.java:1108) - No mapping found for HTTP request with URI [/ecommerce-api/rest/checkout] in DispatcherServlet with name 'api-dispatcher'
2013-09-05 22:31:37,764 DEBUG [tomcat-http--5] servlet.FrameworkServlet (FrameworkServlet.java:966) - Successfully completed request


I really don't know what to do since it worked since last time I shut down my Mac and until that moment I thought to know how to do it.

Answer

I see one problem, you are loading up the same context file (api-dispatcher-servlet.xml) twice. Essentially a typical Spring based web application has two application contexts, the first is the ROOT application context loaded up through the ContextLoaderListener, the second is the Web application context loaded up through DispatcherServlet, in your case both these are pointing to the exact same configuration file which is api-dispatcher-servlet.xml. I would recommend you do this and see if it fixes the inconsistent behavior:

.1. Create say a applicationContext.xml file, for now it need not have any beans defined, later you can put your service related beans in this file.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">


</beans>

.2. Load this context through your ContextLoaderListener, in your web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationContext.xml
    </param-value>
</context-param>

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

.3. Load up api-dispatcher-servlet.xml through your DispatcherServlet, you have the right entries for this already, but it may be better to make this explicit this way:

<servlet>
    <servlet-name>api-dispatcher</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/api-dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>api-dispatcher</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>