5

Actually I am trying to send data from jQuery to Spring controller and in Spring controller I am trying to get that data in a custom bean using @RequestBody. But I am unable to do so. It's not working. But when I am sending the same data as @RequestParam it's working fine, but in case of @RequestBody nothing is happened. I have serialized the html form and posting that data to the controller. I am pasting all the codes. I am using jQuery version jquery-1.6.2.min.js and below is the list of the jars I am using :

commons-fileupload-1.1.1.jar
commons-io-1.2.jar
commons-logging-1.1.1.jar
hibernate-validator-4.0.2.GA.jar
jackson-all-1.7.6.jar
jackson-mapper-asl-1.5.2.jar
jstl-1.2.jar
log4j-1.2.14.jar
servlet-2.3.jar
slf4j-api-1.5.6.jar
slf4j-log4j12-1.5.6.jar
spring-asm-3.0.5.RELEASE.jar
spring-beans-3.0.5.RELEASE.jar
spring-context-3.0.5.RELEASE.jar
spring-core-3.0.5.RELEASE.jar
spring-expression-3.0.5.RELEASE.jar
spring-tx-2.5.5.jar
spring-web-3.0.5.RELEASE.jar
spring-webmvc-3.0.5.RELEASE.jar
validation-api-1.0.0.GA.jar

Below is the controller code :

package com.devmanuals.tutorial.controller;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.devmanuals.tutorial.service.ArithmeticService;

/**
 * Handles and retrieves the main requests
 */
@Controller
@RequestMapping("/main/ajax")
public class AjaxController {

    protected static Logger logger = Logger.getLogger("controller");

    @Resource(name="springService")
    private ArithmeticService springService;

    /**
     * Handles and retrieves the AJAX Add page
     */
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String getAjaxAddPage() {

        System.out.println("Received request to show AJAX, add page");
        logger.debug("Received request to show AJAX, add page");

        // It resolves the /WEB-INF/jsp/ajax-add-page.jsp
        return "ajax-add-page";
    }

    /**
     * Handles request for adding two numbers
     */
    /**
     * Handles request for adding two numbers
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public @ResponseBody Integer create(@RequestParam(value="inputNumber1", required=true) Integer inputNumber1,
                                @RequestParam(value="inputNumber2", required=true) Integer inputNumber2,
                                Model model) {
        logger.debug("Received request to add two numbers");
        Integer sum = springService.add(inputNumber1, inputNumber2);
        logger.debug("Result is ........" +sum);
        return sum;
    }


    @RequestMapping(method=RequestMethod.POST, value = "/bean")
        public @ResponseBody Integer create(@RequestBody NumberBean account, HttpServletResponse response,ModelMap model) {

        System.out.println("Test...........");

            if (account==null) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return 1;
            } else {
                return 20;
            }
        }


    /**
     * Handles request for adding two numbers
     */
    /* @RequestMapping(value = "/add", method = RequestMethod.POST)
    public @ResponseBody Integer add(@RequestBody NumberBean number,
                                Model model) {
        //logger.debug("Received request to add two numbers");

        System.out.println(number);

        Integer sum = springService.add(number.getInputNumber1(), number.getInputNumber2());
        return sum;
    }*/
}

And the jsp is as below:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<script type="text/javascript"
    src="/SpringjQueryTest/jquery/jquery-1.6.2.min.js"></script>
<script type="text/javascript">
    var jq = jQuery.noConflict();
</script>

</head>
<body>
<center>
<h3>Enter Two Numbers for Addition:</h3>
<form id="test">
<table border="1" height="10%" width="10%">
<tr><td><table border="0" height="100%" width="100%">

    <tr>
        <td><input id="x" type="text" size="5" name="inputNumber1"></td>
        <td>+</td>
        <td><input id="y" type="text" size="5" name="inputNumber2"></td>
    </tr>
    <tr>
        <td colspan="3" align="center"><input type="submit" value=" Submit "
            onclick=add(); /></td>
    </tr>

</table>
</td></tr></table>
</form>

<script type="text/javascript">
    function add() {
        jq(function() {

            var number = jq('form').serialize();
            alert(number);

            jq.post("/SpringjQueryTest/dev/main/ajax/bean", number,

            function(data) {
                alert("Added Number below the button");
                alert(data);

            });
        });
    }
</script>
</center>
</body>
</html>

And here is the applicationContext.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: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">

    <!-- Activates various annotations to be detected in bean classes -->
    <context:annotation-config />

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
     For example @Controller and @Service. Make sure to set the correct base-package-->
    <context:component-scan base-package="com.devmanuals.tutorial" />

    <!-- Configures the annotation-driven Spring MVC Controller programming model.
    Note that, with Spring 3.0, this tag works in Servlet MVC only!  -->
    <mvc:annotation-driven /> 

</beans>

And here is spring-servlet.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:tx="http://www.springframework.org/schema/tx"
    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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


<bean id="jacksonMessageConverter"
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>


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

    <!-- Declare a view resolver -->
 <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Here is the NumberBean.java

package com.devmanuals.tutorial.controller;

import java.io.Serializable;

public class NumberBean implements Serializable{

    private int inputNumber1;
    private int inputNumber2;

    public int getInputNumber1() {
        return inputNumber1;
    }
    public void setInputNumber1(int inputNumber1) {
        this.inputNumber1 = inputNumber1;
    }
    public int getInputNumber2() {
        return inputNumber2;
    }
    public void setInputNumber2(int inputNumber2) {
        this.inputNumber2 = inputNumber2;
    }
    @Override
    public String toString() {
        return "NumberBean [inputNumber1=" + inputNumber1 + ", inputNumber2="
                + inputNumber2 + "]";
    }




}

And here is the ArithmeticService.java

package com.devmanuals.tutorial.service;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Service enables the class to be used as a Spring service
 * @Transactional enables transaction support for this class
 */
@Service("springService")
@Transactional
public class ArithmeticService {

    protected static Logger logger = Logger.getLogger("service");

    /**
     * Adds two numbers
     */
    public Integer add(Integer operand1, Integer operand2) {
        logger.debug("Adding two numbers");
        return operand1 + operand2;
    }

}

Here is my web.xml :

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" 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">

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

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/dev/*</url-pattern>
    </servlet-mapping>

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

    <welcome-file-list>
        <welcome-file>/WEB-INF/jsp/ajax-add-page.jsp</welcome-file>
    </welcome-file-list>
</web-app>

UPDATE :

as per the answers I am converting the serialized form value into json and in controller end I am getting it as a java bean through @RequestBody. But now the problem is the @ResponseBody is not working. Within the jq.ajax function the success callback method is not getting invoked. I am totally confused,as it was successfully working before I tried @RequestBody,with @RequestParam. Plz help me.......

the jQuery function :

jq.ajax( {
                url : "/SpringjQueryTest/dev/main/ajax/test",
                type : "POST",
                data : json, 
                dataType : "json",
                contentType : "application/json; charset=utf-8",
                success : function(data) {
                    alert("Added Number below the button");
                    alert(data);
                },
            error : function(xhr, desc, err) {
                alert("Desc: " + desc + "\nErr:" + err);
            }
            });

Updated controller method :

/**
     * Handles request for adding two numbers
     */
     @RequestMapping(value = "/test", method = RequestMethod.POST)
    public @ResponseBody 
    Integer test(@RequestBody NumberBean number,HttpServletResponse response ) {
        logger.debug("Received request to add two numbers");
        response.setContentType("application/json");
        System.out.println(number);

        Integer sum = springService.add(number.getInputNumber1(), number.getInputNumber2());
        return sum;
    }

I am able to see the output

Received request to add two numbers

in my console and even the sum is getting generated. But the success function of jq.ajax

success : function(data) {
                    alert("Added Number below the button");
                    alert(data);
                                   }

is not getting invoked. Nothing is happened. Even no error messages.

Also I noticed in the log of HttpTrace tool that though I am explicitly setting the response content type as application/json in the controller method but the content type remains text/html only.

I am just wondering as it was successfully executing when I was using @RequestParam, but with @RequestBody is not working.

Please find the applicationContext.xml also

<?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: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">

    <!-- Activates various annotations to be detected in bean classes -->
    <context:annotation-config />

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
     For example @Controller and @Service. Make sure to set the correct base-package-->
    <context:component-scan base-package="com.devmanuals.tutorial" />

    <!-- Configures the annotation-driven Spring MVC Controller programming model.
    Note that, with Spring 3.0, this tag works in Servlet MVC only!  -->
    <mvc:annotation-driven /> 

    <bean id="jacksonMessageConverter"
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>


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

    <bean id="exceptionMessageAdapter"
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
        <property name="messageConverters">
            <list>
                <!-- Support JSON -->
                <ref bean="jacksonMessageConverter" />  
            </list>
        </property>
    </bean>

</beans>

And I do have jackson-all-1.8.3.jar in my classpath even. I am really confused.

Neel
  • 429
  • 7
  • 17
  • No..I am not getting any errors even. – Neel Jul 19 '11 at 13:19
  • Could you add your `web.xml` please? – andyb Jul 19 '11 at 13:26
  • Can you quantify what "but in case of @RequestBody nothing is happened" means? Do you mean your @RequestMapping method is not invoked? Have you tried debugging using a simple utility to send http requests like `curl` to rule the javascript layer out? – matt b Jul 19 '11 at 13:29

1 Answers1

6

See here and here. JQuery.serialize() isn't going to convert the form to JSON for you. It will only create a query string out of it.

You may also need to change

        jq.post("/SpringjQueryTest/dev/main/ajax/bean", number,

        function(data) {
            alert("Added Number below the button");
            alert(data);

        });

to

        jq.ajax({type: 'POST', url: '/SpringjQueryTest/dev/main/ajax/bean', data: number, contentType: 'application/json', 

        success: function(data) {
            alert("Added Number below the button");
            alert(data);

        }});

So that the correct Content-Type is sent and Spring can properly decode it.

If you aren't explicitly trying to use JSON, forgo using @RequestBody and follow the example here that simply binds the form values to the bean.

Community
  • 1
  • 1
laz
  • 28,320
  • 5
  • 53
  • 50
  • thanks for your answer. Now I am converting the form to json explicitly and I am sending that json object to the controller. but still the controller is not getting invoked. Do I need any other configuration? – Neel Jul 19 '11 at 18:29
  • as per your suggestion now I am converting the serialized form value into json and in controller end I am getting it as a java bean through `@RequestBody`. But now the problem is my `@ResponseBody` is not working. within the `jq.ajax` function the success callback method is not getting invoked. I am totally confused,as it was successfully working before I tried `@RequestBody`,with `@RequestParam`. Plz help me.... – Neel Jul 20 '11 at 18:03
  • The problem seems to be that the Controller isn't returning JSON but the JQuery ajax call is expecting it to. Do you really require the result to be JSON? If so, have a look here: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/view.html#view-json-mapping – laz Jul 20 '11 at 19:33
  • see Controller is returning `new Integer(100)` and there is `jackson-all-1.8.3.jar` in the classpath and I do have required `AnnotationMethodHandlerAdapter` related configurations in the `applicationContext.xml` file. So the Controller returning value should be automatically converted to `json` from `Java` by `jackson`. So i think it should have executed. For convenience please find the updated portion of my question. – Neel Jul 20 '11 at 19:55
  • I advised wrong in that last comment. It does look like `@ResponseBody` won't let you change the output though. You might want to investigate using `HttpEntity`: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-httpentity – laz Jul 20 '11 at 20:06
  • Sorry could not understand properly. Why should I not use `@ResponseBody` to send response back to the client. I can't understand why the `jquery.ajax` success function is not getting triggered. Even I am using `MappingJacksonHttpMessageConverter` to parse `java` straight into `json`. – Neel Jul 20 '11 at 20:18
  • 1
    If you are using log4j, try setting the logger `org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter` to DEBUG. See line 981 here for what it should log - https://fisheye.springsource.org/browse/spring-framework/branches/3.0.x/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java?hb=true#to981 Also, see the methods `handleResponseBody` `handleHttpEntityResponse` in that code. Using `HttpEntity` seems to let you override the `Content-Type` in the response through passing it the headers. – laz Jul 20 '11 at 22:09