Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Controller 404 retuned after POST method Invoked

I have a Spring controller which is being called from JQuery.post(). When it is called the controller's method is invoked and returns. But then, in the background, Spring changes the URL and calls the server gain. The server responds with a 404.

I think this is in response to Spring trying to find a View after the POST method has been processed.

How do I stop the Spring controller from doing this.

Here is my Spring Controller:

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

import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping("/person")
public class DataController {

  private List<Person> people = new ArrayList<Person>();

  @RequestMapping(value="put", method = RequestMethod.POST)
  public void addPerson(@ModelAttribute("person") Person person){
    System.out.println(">>>>>>> person: " + person);
    System.out.println(">>>>>>>>> " + person.getFirstName());
    people.add(person);
  }
}

Here is my application context xml file:

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="uk.co.jeeni" />

    <mvc:annotation-driven />

</beans>

Here is my web.xml file:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:applicationContext-web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/data/*</url-pattern>
    </servlet-mapping>
</web-app>

Here is my JQuery call from my HTML file:

function attachSendDataEvent(){
    $("#sendData").click(function(){

        var data = "firstName=" + $("#firstName").val() + "&" +
                "lastName=" + $("#lastName").val() + "&" +
                "address=" + $("#address").val() + "&" +
                "postcode=" + $("#postcode").val();

        $.post("data/person/put",
                data,
                dataSentOK
        );
    });

    return false;
}

The dataSentOK function just does a alert("DONE").

So when the JQuery method the URL invoked is:

http://localhost:8080/jquery/data/person/put

and on the server side the System.out.println(...) method print out the data as expected.

However in Firebug, the server sends back a 404.

So I switched on logging with Spring and got this:

[01] DispatcherServlet [DEBUG] DispatcherServlet with name 'dispatcherServlet' processing POST request for [/jquery/data/person/put]
[02] AbstractHandlerMethodMapping [DEBUG] Looking up handler method for path /person/put
[03] AbstractHandlerMethodMapping [DEBUG] Returning handler method [public void uk.co.jeeni.DataController.addPerson(uk.co.jeeni.Person)]
[04] AbstractBeanFactory [DEBUG] Returning cached instance of singleton bean 'dataController'
[05] DispatcherServlet [DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'person/put'; URL [person/put]] in DispatcherServlet with name 'dispatcherServlet'
[06] AbstractView [DEBUG] Added model object 'org.springframework.validation.BindingResult.person' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'person/put'
[07] AbstractView [DEBUG] Added model object 'person' of type [uk.co.jeeni.Person] to request in view with name 'person/put'
[08] InternalResourceView [DEBUG] Forwarding to resource [person/put] in InternalResourceView 'person/put'
[09] DispatcherServlet [DEBUG] DispatcherServlet with name 'dispatcherServlet' processing POST request for [/jquery/data/person/person/put]
[10] AbstractHandlerMethodMapping [DEBUG] Looking up handler method for path /person/person/put
[11] AbstractHandlerMethodMapping [DEBUG] Did not find handler method for [/person/person/put]
[12] DispatcherServlet [ WARN] No mapping found for HTTP request with URI [/jquery/data/person/person/put] in DispatcherServlet with name 'dispatcherServlet'
[13] FrameworkServlet [DEBUG] Successfully completed request
[14] FrameworkServlet [DEBUG] Successfully completed request

In response to the URL POST request (/jquery/data/person/put), the correct method is found and invoked (lines 1 to 7), but then Spring forwards to an InternalResourceView at line 8, which changes the URL to /jquery/data/person/person/put, and this can not be found.

How do I stop Spring from trying to find a view at all. All I want it to do is return cleanly and be done.

Thanks for your help.

like image 420
Adam Davies Avatar asked Feb 25 '13 12:02

Adam Davies


2 Answers

Solved.

The problem was as #CodeChimp suggested, except I still wanted a void return type.

I added the @ResponseBody to the addPerson method and everything worked fine:

@RequestMapping(value="put", method = RequestMethod.POST)
**@ResponseBody**
public void addPerson(@ModelAttribute("person") Person person){
  System.out.println(">>>>>>> person: " + person);
  System.out.println(">>>>>>>>> " + person.getFirstName());
  people.add(person);
}

The clue came from http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-responsebody. Although the documentation is not clear what happens with a void return. Just tried it and it worked.

like image 70
Adam Davies Avatar answered Nov 14 '22 05:11

Adam Davies


I believe if you have a null or void return type, Spring will try to resolve the view based on the request URL. I think the proper form here would be to simply return an OK page, since this doesn't appear to be JSON or anything like that. Or, just tag it with @ResponseBody and return an empty string.

like image 22
CodeChimp Avatar answered Nov 14 '22 03:11

CodeChimp