8

I have read some many similiar problems inlcluding: JQuery, Spring MVC @RequestBody and JSON - making it work together JSON request with JQuery/Ajax with Spring

The requirement is that the server will only accept application/json types. I am using a Spring MVC Controller. The code sends a response back as JSON through @ResponseBody. I want to get information through the @RequestBody in my Spring MVC Controller. I am using JSP to send JSON to Spring MVC Controller. My code and Spring MVC can be seen below:

I am new to JSON and Javascript.

JSP - index.jsp

<%@page language="java" contentType="text/html"%> 
<html> 
<head> 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>   
<script type="text/javascript"> 
$('#myForm').on('submit', function(e) {  
var frm = $("#myForm"); 
var dat = JSON.stringify(frm.serializeArray());  

 $.ajax({  
 type: 'POST',  
 url: $('#myForm').attr('action'),  
 data: dat, 
 contentType: 'application/json', 
 dataType: 'json', 
 error: function() { 
    alert('failure'); 
 } 
 success: function(hxr) {  
     alert("Success: " + xhr);  
 } 
  });  
);  
   };  
</script>  
</head> 
<body> 
<h2>Application</h2> 
<form id="myForm" action="/application/save" method="POST" accept="application/json" onclick="i()"> 
<input type="text" name="userId" value="User"> 
<input type="submit" value="Submit"> 
</form> 
</body> 
</html> 

When running this I am not getting any output. In the Chrome I get 404 Not found error and in Tomcat I get the following error:

org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver                        handleNoSuchRequestHandlingMethod 
WARNING: No matching handler method found for servlet request: path '/application/sa 
 ve', method 'POST', parameters map['userId' -> array<String>['User']] 

Is something wrong here in the JSP part?

web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<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_5.xsd" 
 version="2.5"> 

 <display-name>WebApp</display-name> 

 <context-param> 
    <!-- Specifies the list of Spring Configuration files in comma separated format.--> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>/WEB-INF/spring/service.xml</param-value> 
 </context-param> 

 <listener> 
    <!-- Loads your Configuration Files--> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
 </listener> 

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

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

 <welcome-file-list> 
    <welcome-file>index.jsp</welcome-file> 
 </welcome-file-list>     
</web-app> 

service.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:util="http://www.springframework.org/schema/util" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xsi:schemaLocation="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 
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> 

<context:component-scan base-package="com.web"/> 

<mvc:annotation-driven/> 

<context:annotation-config/> 

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> 

<bean id="jacksonMessageChanger" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> 
    <property name="supportedMediaTypes" value="application/json"/> 
</bean> 

<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="messageConverters"> 
        <list> 
            <ref bean="jacksonMessageChanger"/> 
        </list> 
    </property> 
</bean>--> 

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="messageConverters"> 
        <util:list id="beanList"> 
            <ref bean="jacksonMessageChanger"/> 
        </util:list> 
    </property> 
</bean> 

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
    <property name="prefix" value="/WEB-INF/jsp/"/> 
    <property name="suffix" value=".jsp"/> 
</bean> 

<!-- <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 
    <property name="mediaTypes"> 
        <map> 
            <entry key="json" value="application/json"/> 
        </map> 
    </property> 
</bean>-->   

Controller

package com.web; 

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 org.springframework.web.bind.annotation.RequestBody; 
import com.webchannel.domain.User; 
import com.webchannel.domain.UserResponse; 

@Controller 
@RequestMapping("/application/*") 
public class SaveController { 

 @RequestMapping(value = "save", method = RequestMethod.POST, headers = {"content-type=application/json"}) 
 public @ResponseBody UserResponse save(@RequestBody User user) throws Exception { 
  UserResponse userResponse = new UserResponse(); 
 System.out.println("UserId :" + " " + user.getUserId()); 
 return userResponse; 
} 

@RequestMapping(value = "delete", method = RequestMethod.GET) 
public @ResponseBody UserResponse delete() { 
   System.out.println("Delete"); 
   UserResponse userResponse = new UserResponse(); 
   userResponse.setSuccess(true); 
   userResponse.setVersionNumber("1.0"); 
   return userResponse; 

} }

When invoking /application/delete I get JSON returned. So I know my JacksonProcessor is configured correctly. The problem is in @RequestBody.

Where am I going wrong?

If I remove the headers in the code below I get a 415 error.

@RequestMapping(value = "save", method = RequestMethod.POST) 
 public @ResponseBody UserResponse save(@RequestBody User user) throws Exception { 
  UserResponse userResponse = new UserResponse(); 
 System.out.println("UserId :" + " " + user.getUserId()); 
 return userResponse; 
} 

I am almost close but help would be appreciated.

Community
  • 1
  • 1
user1646481
  • 1,267
  • 6
  • 21
  • 29
  • What happens when you remove @RequestBody annotation from the save method? Jackson should be able to map to User from the request parameters since you have a member variable 'userId' in the the User class anyway. – ramsinb Sep 18 '12 at 11:42
  • That does not work. I don't know whether I calling Javascript in the right way. I don't know. – user1646481 Sep 18 '12 at 11:55
  • So there is no solution I don't think? – user1646481 Sep 18 '12 at 12:58

1 Answers1

12

I tried to play around a little more with your code however was unable to get the same error as you are getting. I've reworked the HTML:

<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>

<script type="text/javascript"> 

    $(function() { 
        $('#myForm').submit(function() {
            var form = $( this ),
                url = form.attr('action'),
                userId = form.find('input[name="userId"]').val(),
                dat = JSON.stringify({ "userId" : userId });

            $.ajax({
                url : url,
                type : "POST",
                traditional : true,
                contentType : "application/json",
                dataType : "json",
                data : dat,
                success : function (response) {
                    alert('success ' + response);
                },
                error : function (response) {
                    alert('error ' + response);
                },
            });

            return false;
        });
    });

</script>
</head>
<body>
    <h2>Application</h2>
    <form id="myForm" action="application/save">
        <input type="text" name="userId" value="User">
        <input type="submit" value="Submit">
    </form>
</body>
</html>

I had a very simple method similar to yours:

@RequestMapping(value = "save", method = RequestMethod.POST, headers = {"content-type=application/json"})
public @ResponseBody String save (@RequestBody User user) throws Exception
{
    return "save-test";
}

My User class looks like this:

public class User
{
    private String userId;

    public User()
    {
    }

    public String getUserId ()
    {
        return userId;
    }

    public void setUserId (String userId)
    {
        this.userId = userId;
    }
}

My spring config was stripped down to contain:

<context:component-scan base-package="com.web"/> 
<mvc:annotation-driven/> 
<context:annotation-config/> 

I'm using spring version 3.1.1 and jquery 1.8.1 (the latest I believe). I'm not getting the same error as you so perhaps you can try some of what I've done and see if that helps.

ramsinb
  • 1,985
  • 12
  • 17
  • thanks, I will try this. Can you tell me what you put in your form code section please? – user1646481 Sep 18 '12 at 14:10
  • 1 more thing. You mentioned that you stripped down this Spring config to the 1 above. Are you using the JSON Jackson Processor? – user1646481 Sep 18 '12 at 14:13
  • The form is ok to be the same as what you had and the spring config you don't need the Jackson processor because spring will use that by default if it finds Jackson on the classpath. I belive your issue was really just the data you were sending. You tried to turn your form into a JSON string however that won't work - because spring/jackson won't be able to map that to the User object. You need to do what I have done to resolve the problem. – ramsinb Sep 18 '12 at 14:16
  • Not sure whether 1 thing is missing. You are not calling the Javascript within the Submit button call? Is this missing in your code above? – user1646481 Sep 18 '12 at 14:24
  • When you click on submit button JQuery events take over and the following code handles the javascript $('#myForm').submit(function() – ramsinb Sep 18 '12 at 14:25
  • Thank you. This worked. I had to change to Spring 3.1.1. However it does not work in Internet Explorer. It gives Http 415 error but works in Chrome. Any ideas? – user1646481 Sep 18 '12 at 15:07
  • Edit: It works with Spring 3. However it does not work in Internet Explorer. It gives 415 error but works in Chrome. – user1646481 Sep 18 '12 at 15:14
  • I'm no expert on IE however if your getting 415 (unsupported media type) it means IE is not sending headers correctly to your spring controller (its missing the 'application/json' in the header). You can confirm that by using something like http watch to capture the request and see what content type is being sent in IE. If this is the case then try doing some research to see if others have had similar issues - I'd expect there will be plenty around. – ramsinb Sep 18 '12 at 21:12