JQuery, Spring MVC @RequestBody and JSON - making it work together
I'm pretty sure you only have to register MappingJacksonHttpMessageConverter
(the easiest way to do that is through <mvc:annotation-driven />
in XML or @EnableWebMvc
in Java)
See:
- this forum post and
- 7.6.5 Configuring Formatting in Spring MVC
Here's a working example:
Maven POM
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion><groupId>test</groupId><artifactId>json</artifactId><packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version><name>json test</name>
<dependencies>
<dependency><!-- spring mvc -->
<groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>3.0.5.RELEASE</version>
</dependency>
<dependency><!-- jackson -->
<groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.4.2</version>
</dependency>
</dependencies>
<build><plugins>
<!-- javac --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version><configuration><source>1.6</source><target>1.6</target></configuration></plugin>
<!-- jetty --><plugin><groupId>org.mortbay.jetty</groupId><artifactId>jetty-maven-plugin</artifactId>
<version>7.4.0.v20110414</version></plugin>
</plugins></build>
</project>
in folder src/main/webapp/WEB-INF
web.xml
<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>json</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>json</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
json-servlet.xml
<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">
<import resource="classpath:mvc-context.xml" />
</beans>
in folder src/main/resources:
mvc-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<mvc:annotation-driven />
<context:component-scan base-package="test.json" />
</beans>
In folder src/main/java/test/json
TestController.java
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping(method = RequestMethod.POST, value = "math")
@ResponseBody
public Result math(@RequestBody final Request request) {
final Result result = new Result();
result.setAddition(request.getLeft() + request.getRight());
result.setSubtraction(request.getLeft() - request.getRight());
result.setMultiplication(request.getLeft() * request.getRight());
return result;
}
}
Request.java
public class Request implements Serializable {
private static final long serialVersionUID = 1513207428686438208L;
private int left;
private int right;
public int getLeft() {return left;}
public void setLeft(int left) {this.left = left;}
public int getRight() {return right;}
public void setRight(int right) {this.right = right;}
}
Result.java
public class Result implements Serializable {
private static final long serialVersionUID = -5054749880960511861L;
private int addition;
private int subtraction;
private int multiplication;
public int getAddition() { return addition; }
public void setAddition(int addition) { this.addition = addition; }
public int getSubtraction() { return subtraction; }
public void setSubtraction(int subtraction) { this.subtraction = subtraction; }
public int getMultiplication() { return multiplication; }
public void setMultiplication(int multiplication) { this.multiplication = multiplication; }
}
You can test this setup by executing mvn jetty:run
on the command line, and then sending a POST request:
URL: http://localhost:8080/test/math
mime type: application/json
post body: { "left": 13 , "right" : 7 }
I used the Poster Firefox plugin to do this.
Here's what the response looks like:
{"addition":20,"subtraction":6,"multiplication":91}
Can Jackson be used with Spring MVC 3.0 to also bind the RequestBody to a Java Bean?
Yes, it is possible.
Your server side configuration is probably fine if your @ResponseBody is working.
You will need to set the content-type to application/json. The JQuery.ajax() method has a contentType parameter. A great example/summary of AJAX and Spring 3 can be found here. Note that he is using a $.postJSON method, which is most likely this simple plugin.
@RequestBody Sent Through Spring MVC JSON Jackson Processor
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.
Combine functionality of @ModelAttribute and @RequestBody in Spring MVC
Turns out no, not at time of writing anyway.
RequestMappingHandlerAdapter.getDefaultArgumentResolvers
holds the default configuration for the argument resovlers, and we have:
RequestResponseBodyMethodProcessor
handling the@RequestBody
annotation, andServletModelAttributeMethodProcessor
handling the@ModelAttribute
, or any parameter without any annotations.
It's always just one single resolver that gets executed, even if you try using a composite.
My solution
@ControllerAdvice
@RequiredArgsConstructor
@Order(HIGHEST_PRECEDENCE)
public class ServletRequestBinderRequestBodyAdvice extends RequestBodyAdviceAdapter {
private final ServletRequest servletRequest;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
copyDefaultPropertiesThatWhereOverwritenWithNull(parameter, body);
new ExtendedServletRequestDataBinder(body).bind(servletRequest);
return body;
}
private void copyDefaultPropertiesThatWhereOverwritenWithNull(MethodParameter parameter, Object arg) {
Object argWithDefaults = instantiateClass(parameter.getParameterType());
copyPropertiesSkippingNulls(argWithDefaults, arg);
}
}
Spring MVC : post request and json object with array : bad request
I think you're looking for something like `@RequestBody. Create a class to represent your JSON data. In your case, this class will contain two member variables - globalId as a string and lines as an array of the object it represents. Then in your controller method, you will use the @RequestBody annotation on this class type so that Spring will be able to convert the JSON into object. Check the examples below.
http://www.leveluplunch.com/java/tutorials/014-post-json-to-spring-rest-webservice/
JQuery, Spring MVC @RequestBody and JSON - making it work together
http://www.techzoo.org/spring-framework/spring-mvc-requestbody-json-example.html
Spring MVC & JQuery AJAX Post only working with @ResponseBody
@ResponseBody
is needed since you are making an XHR call via JQuery. This is true for endpoints that will return a specific data format (JSON, XML) but also for endpoint that do not return any data (void
).
Otherwise, when not specified Spring require a ModelView object to be returned that will point to a specific view and can be decorated with a model hash in it.
In your case the problem could be that during JSON.stringify(test)
your are not providing a valid key-value pair in the form of: test=yourValue
For more info about Responsebody you can check this one.
Hope it helps.
Related Topics
Sorting a Collection of Objects
How to Wire One Pane to Another
Display Indeterminate Jprogressbar While Batch File Runs
Jformattedtextfield Is Not Properly Cleared
Converting Array to List in Java
Initial Bytes Incorrect After Java Aes/Cbc Decryption
How to Know If Other Threads Have Finished
Remove Diacritical Marks (Ń Ǹ Ň ñ Ṅ Ņ Ṇ Ṋ Ṉ ̈ Ɲ Ƞ ᶇ ɳ ȵ) from Unicode Chars
How to Supply Value to an Annotation from a Constant Java
How to Read a Specific Line Using the Specific Line Number from a File in Java
Java - Method Name Collision in Interface Implementation
Get a Resource Using Getresource()
Javafx Fxml Controller - Constructor VS Initialize Method
"Program to an Interface". What Does It Mean