JSON Posting to Spring-MVC, Spring is not seeing the data - ajax

I am working on a project that the project is going to use Ajax to post JSON object to Springs-MVC. I been making a number of changes and I got it to the point where I dont get any more errors BUT I dont see the data that is getting POSTed to Spring in the object I need it in.
Here is my Spring Controller.
#RequestMapping(value="/AddUser.htm",method=RequestMethod.POST)
public #ResponseBody JsonResponse addUser(#ModelAttribute(value="user") User user, BindingResult result ){
JsonResponse res = new JsonResponse();
if(!result.hasErrors()){
res.setStatus("SUCCESS");
res.setResult(userList);
}else{
res.setStatus("FAIL");
res.setResult(result.getAllErrors());
}
return res;
}
I put a breakpoint in and my USER object never gets the data. next is a copy of my USER object:
public class User {
private String name = null;
private String education = null;
private List<String> nameList = null;
private List<String> educationList = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEducation() {
return education;
}
public void setEducation(String education) {
this.education = education;
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList) {
this.nameList = nameList;
}
public List<String> getEducationList() {
return educationList;
}
public void setEducationList(List<String> educationList) {
this.educationList = educationList;
}
and now for the javascript code that does the Ajax, JSON post:
function doAjaxPost() {
var inData = {};
inData.nameList = ['kurt','johnathan'];
inData.educationList = ['GSM','HardKnocks'];
htmlStr = JSON.stringify(inData);
alert(".ajax:" + htmlStr);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: contexPath + "/AddUser.htm",
data: inData,
dataType: "json",
error: function(data){
alert("fail");
},
success: function(data){
alert("success");
}
});
};
Please let me now if you can help?? I have to get this working ASAP... thanks

You also need to specify the header in your RequestMapping annotion found in your controller.
#RequestMapping(headers ={"Accept=application/json"}, value="/AddUser.htm", method=RequestMethod.POST)
Also, remove .htm in your URL path. htm is some kind of request type overide. Using .htm specifies the web server to handle the request as a classic html request. Using .json would specify to the webserver that the request expects to be handled as a json request.

Related

Throw custom exception from Spring controller and receive it in ajax-post error function

So, i need to add custom validation to my page, the problem is, i don't have any form, i collect and send data almost manually, here is my ajax post:
$.ajax({
type: "POST",
url: "/settings/propertyedit",
dataType: 'json',
contentType: 'application/json;charset=UTF-8',
data: {
propertyName : propName,
propertyValue : propVal,
Id : Id,
SettingId : SettingId,
},
beforeSend: function (xhr) {
xhr.setRequestHeader($.metaCsrfHeader, $.metaCsrfToken);
},
success: function (response) {
//Do some something good
},
error: function(response){
//do some something worning
}
});
And controller:
#Link(label = "property edit", family = "SettingsController", parent = "Settings")
#RequestMapping(value = "/settings/propertyedit", method = RequestMethod.POST)
#ResponseBody
public String atmpropertyedit(#RequestParam String propertyName,
#RequestParam String propertyValue,
#RequestParam Long Id,
#RequestParam Long SettingId) {
//Check if it is an error
//If correct i want to return some text in success function
//If error happens want to return some relevant text to error function
}
So, the point is, that validation is also custom, so i cant throw exception simply with try catch and if i am trying to do something like:
return new ResponseEntity<>(HttpStatus.NOT_EXTENDED);//Error type is for testing purposes
I will get 400 error even without triggering into my controller. At this point i just want some simple method to let know my ajax what has happened in my controller.
The controller can be as simple as this one, you can make it happen with custom response class which I named CommonResp and an Enum VALIDATION.
Controller - returns Response class.
#ResponseBody
public CommonResp atmpropertyedit(#RequestParam String propertyName,
#RequestParam String propertyValue,
#RequestParam Long Id,
#RequestParam Long SettingId) {
// error
if (!isValidPropertyName(propertyName)) return new CommonResp(VALIDATION.INVALID_PROPERTY_NAME);
// success
return new CommonResp(VALIDATION.OK);
}
}
CommonResp.java - will be the json response.
public class CommonResp implements Serializable {
private int code;
private String message;
public CommonResp() {
this(VALIDATION.OK);
}
private CommonResp(final int code, final String message){
this.code = code;
this.message = message;
}
public CommonResp(VALIDATION validation) {
this(validation.getCode(), validation.getMessage());
}
/* Getters and Setters */
}
VALIDATION.java
public enum VALIDATION {
OK(200, "OK"),
INVALID_PROPERTY_NAME(401, "PropertyName is not valid");
private int code;
private String message;
private VALIDATION(int code, String message) {
this.setCode(code);
this.message = message;
}
/* Getters and Setters */
}
Please let me know if there are any better implementations. (propably tons of, It's just that i don't know :P)

Spring - Stop redirection on error

I have a page to manage users and I would like to stay on the page if any error occurs when clicking save.
The only cases I found online where to do with validation.
Also my page requires the userId to be posted so I don't think returning the name of the original page in the controller would work. Also I would loose the changes made in the page.
What I am trying to achieve is stay in the same page, showing a message to the user.
Here is my controller:
#RequestMapping(method = RequestMethod.POST)
public String editUser(#RequestParam("userId") String userId, final Map<String, Object> model) {
User user = spiService.getUser(userId);
model.put("user", user);
configureRoles(model, user);
return "edituser";
}
#RequestMapping(path = "/updateUser", method = RequestMethod.POST)
public String updateUser(#RequestParam("userJson") String userRoles, #RequestParam("userId") String userId, final Map<String, Object> model) throws IOException {
User user = spiService.getUser(userId);
try {
addRoles(JsonUtil.getField(userRoles, "addedRoles"), user.getRoles(), userId);
removeRoles(JsonUtil.getField(userRoles, "removedRoles"), user.getRoles(), userId);
} catch (Exception ex) {
// What now?
}
return "users";
}
Instead of redirecting you can use Ajax calls in your controller. For that you have to create one AjaxPojoClass for exampleAjaxResponseBody as your convenience.
For example
$.ajax({
type : "POST",
contentType : "application/json",
url : "/yourUrl",
data : JSON.stringify(data),
dataType : 'json',
success : function(data) {
window.location.replace("/successUrl")
},
error : function(e) {
display(e);
},
});
AjaxController
#Controller
public class AjaxController {
#ResponseBody
#RequestMapping(value = "/yourUrl")
public AjaxResponseBody getSearchResultViaAjax(#RequestBody SearchCriteria search) {
AjaxResponseBody result = new AjaxResponseBody();
//logic
return result;
}
}
you can use ajax to submit your request.

#ResourceMapping that accepts JSON from Ajax request

I'm searching how I can interprete a JSON parameter in my #ResourceMapping in Spring Portlet MVC. When I add #RequestBody, I got the message: #RequestBody is not supported... Really stuck on this one.
I have this:
View side:
<portlet:resourceURL var="getTest" id="ajaxTest" ></portlet:resourceURL>
<p>
<button onClick="executeAjaxTest();">Klik mij!</button>
<button onClick="$('#ajaxResponse').html('');">Klik mij!</button>
</p>
<p>
<h3>Hieronder het antwoord:</h3>
<h4 id="ajaxResponse"></h4>
</p>
<script>
function executeAjaxTest() {
var jsonObj = {
user: "Korneel",
password: "testpassword",
type: {
testParam: "test",
}
}
console.debug(JSON.stringify(jsonObj));
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:JSON.stringify(jsonObj),
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
}
</script>
Controller side:
#ResourceMapping(value="ajaxTest")
#ResponseBody
public void ajaxTestMethod(ResourceRequest request, ResourceResponse response) throws IOException, ParseException {
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
How can I use the spring magic to auto map this JSON data to my own model?
Note: It's Spring Portlet MVC, not regular Spring MVC..
#ResponseBody annotation is not supported out of the box in Spring MVC portlet framework, but you can implement #ResponseBody handling yourself.
We do it by implementing custom view type and model and view resolver.
Implement custom model and view resolver (ModelAndViewResolver), let's say JsonModelAndViewResolver.
In resolveModelAndView method, check whether controller method has #ResponseBody annotation (or more specific condition to identify JSON output - e.g. annotation + required supported mime type).
If yes, return your custom View implementation - let's say SingleObjectJson view (extending AbstractView).
Pass your to-be-serialized object to the view instance.
The view will serialize the object to JSON format and write it to the response (by using Jackson, Gson or other framework in renderMergedOutputModel method).
Register the new resolver as AnnotationMethodHandlerAdapter.customModelAndViewResolvers.
You need to build your json object like this:
var jsonObj = {
user: "Korneel",
password: "testpassword",
"type.testParam" : "test"
};
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:jsonObj,
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
In your Controller you should use the #ModelAttribute annotation:
#ModelAttribute(value = "jsonObj")
public JsonObjCommand obtenerJsonObjCommand() {
JsonObjCommand jsonObjCommand = new JsonObjCommand();
return jsonObjCommand;
}
#ResourceMapping(value = "ajaxTest")
public void ajaxTestMethod(
ResourceRequest request,
ResourceResponse response,
#ModelAttribute(value = "jsonObj") JsonObjCommand jsonObjCommand)
throws IOException, ParseException {
LOGGER.debug("USER: " + jsonObjCommand.getUser());
LOGGER.debug("Password: " + jsonObjCommand.getPassword());
LOGGER.debug("TestParam: " + jsonObjCommand.getType().getTestParam());
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
Don't forget your beans:
public class JsonObjCommand {
private String user;
private String password;
private TypeJson type;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public TypeJson getType() {
return type;
}
public void setType(TypeJson type) {
this.type = type;
}
}
public class TypeJson {
private String testParam;
public String getTestParam() {
return testParam;
}
public void setTestParam(String testParam) {
this.testParam = testParam;
}
}
According to the documentation, #RequestBody is only supported in Servlet environments, not Portlet environments (same for #ResponseBody). So it seems you can't use that functionality.

receiving json and deserializing as List of object at spring mvc controller

My code is as below:
controller
#RequestMapping(value="/setTest", method=RequestMethod.POST, consumes="application/json")
public #ResponseBody ModelMap setTest(#RequestBody List<TestS> refunds, ModelMap map) {
for(TestS r : refunds) {
System.out.println(r.getName());
}
// other codes
}
TestS pojo
public class TestS implements Serializable {
private String name;
private String age;
//getter setter
}
Json request
var z = '[{"name":"1","age":"2"},{"name":"1","age":"3"}]';
$.ajax({
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
});
It's giving this error
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.air.cidb.entities.TestS
I am using spring 3.1.2 and jackson 2.0.4
Edit: I want to receive list of TestS objects at my controller method, and process them. I am not able to find if I am sending wrong json or my method signature is wrong.
Here is the code that works for me. The key is that you need a wrapper class.
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
A PersonWrapper class
public class PersonWrapper {
private List<Person> persons;
/**
* #return the persons
*/
public List<Person> getPersons() {
return persons;
}
/**
* #param persons the persons to set
*/
public void setPersons(List<Person> persons) {
this.persons = persons;
}
}
My Controller methods
#RequestMapping(value="person", method=RequestMethod.POST,consumes="application/json",produces="application/json")
#ResponseBody
public List<String> savePerson(#RequestBody PersonWrapper wrapper) {
List<String> response = new ArrayList<String>();
for (Person person: wrapper.getPersons()){
personService.save(person);
response.add("Saved person: " + person.toString());
}
return response;
}
The request sent is json in POST
{"persons":[{"name":"shail1","age":"2"},{"name":"shail2","age":"3"}]}
And the response is
["Saved person: Person [name=shail1, age=2]","Saved person: Person [name=shail2, age=3]"]
This is not possible the way you are trying it. The Jackson unmarshalling works on the compiled java code after type erasure. So your
public #ResponseBody ModelMap setTest(#RequestBody List<TestS> refunds, ModelMap map)
is really only
public #ResponseBody ModelMap setTest(#RequestBody List refunds, ModelMap map)
(no generics in the list arg).
The default type Jackson creates when unmarshalling a List is a LinkedHashMap.
As mentioned by #Saint you can circumvent this by creating your own type for the list like so:
class TestSList extends ArrayList<TestS> { }
and then modifying your controller signature to
public #ResponseBody ModelMap setTest(#RequestBody TestSList refunds, ModelMap map) {
#RequestMapping(
value="person",
method=RequestMethod.POST,
consumes="application/json",
produces="application/json")
#ResponseBody
public List<String> savePerson(#RequestBody Person[] personArray) {
List<String> response = new ArrayList<String>();
for (Person person: personArray) {
personService.save(person);
response.add("Saved person: " + person.toString());
}
return response;
}
We can use Array as shown above.
Solution works very well,
public List<String> savePerson(#RequestBody Person[] personArray)
For this signature you can pass Person array from postman like
[
{
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
}, {
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
}
]
Don't forget to add consumes tag:
#RequestMapping(value = "/getEmployeeList", method = RequestMethod.POST, consumes="application/json", produces = "application/json")
public List<Employee> getEmployeeDataList(#RequestBody Employee[] employeearray) { ... }
I believe this will solve the issue
var z = '[{"name":"1","age":"2"},{"name":"1","age":"3"}]';
z = JSON.stringify(JSON.parse(z));
$.ajax({
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
});
For me below code worked, first sending json string with proper headers
$.ajax({
type: "POST",
url : 'save',
data : JSON.stringify(valObject),
contentType:"application/json; charset=utf-8",
dataType:"json",
success : function(resp){
console.log(resp);
},
error : function(resp){
console.log(resp);
}
});
And then on Spring side -
#RequestMapping(value = "/save",
method = RequestMethod.POST,
consumes="application/json")
public #ResponseBody String save(#RequestBody ArrayList<KeyValue> keyValList) {
//Saving call goes here
return "";
}
Here KeyValue is simple pojo that corresponds to your JSON structure also you can add produces as you wish, I am simply returning string.
My json object is like this -
[{"storedKey":"vc","storedValue":"1","clientId":"1","locationId":"1"},
{"storedKey":"vr","storedValue":"","clientId":"1","locationId":"1"}]

Spring 3 MVC - Advanced Data Binding - Form Request with List of Simple Objects

I've read through all of the Spring 3 Web docs: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/spring-web.html but have been completely unable to find any interesting documentation on binding more complicated request data, for example, let's say I use jQuery to post to a controller like so:
$.ajax({
url: 'controllerMethod',
type: "POST",
data : {
people : [
{
name:"dave",
age:"15"
} ,
{
name:"pete",
age:"12"
} ,
{
name:"steve",
age:"24"
} ]
},
success: function(data) {
alert('done');
}
});
How can I accept that through the controller? Preferably without having to create a custom object, I'd rather just be able to use simple data-types, however if I need custom objects to make things simpler, I'm fine with that too.
To get you started:
#RequestMapping("/controllerMethod", method=RequestMethod.POST)
public String doSomething() {
System.out.println( wantToSeeListOfPeople );
}
Don't worry about the response for this question, all I care about is handling the request, I know how to deal with the responses.
EDIT:
I've got more sample code, but I can't get it to work, what am I missing here?
select javascript:
var person = new Object();
person.name = "john smith";
person.age = 27;
var jsonPerson = JSON.stringify(person);
$.ajax({
url: "test/serialize",
type : "POST",
processData: false,
contentType : 'application/json',
data: jsonPerson,
success: function(data) {
alert('success with data : ' + data);
},
error : function(data) {
alert('an error occurred : ' + data);
}
});
controller method:
public static class Person {
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
String name;
Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#RequestMapping(value = "/serialize")
#ResponseBody
public String doSerialize(#RequestBody Person body) {
System.out.println("body : " + body);
return body.toString();
}
this renders the following exception:
org.springframework.web.HttpMediaTypeNotSupportedException:
Content type 'application/json' not
supported
If the doSerialize() method takes a String as opposed to a Person, the request is successful, but the String is empty
Your jQuery ajax call produces the following application/x-www-form-urlencoded request body (in %-decoded form):
people[0][name]=dave&people[0][age]=15&people[1][name]=pete&people[1][age]=12&people[2][name]=steve&people[2][age]=24
Spring MVC can bind properties indexed with numbers to Lists and properties indexed with strings to Maps. You need the custom object here because #RequestParam doesn't support complex types. So, you have:
public class People {
private List<HashMap<String, String>> people;
... getters, setters ...
}
#RequestMapping("/controllerMethod", method=RequestMethod.POST)
public String doSomething(People people) {
...
}
You can also serialize data into JSON before sending them and then use a #RequestBody, as Bozho suggests. You may find an example of this approach in the mvc-showcase sample.
if you have <mvc:annotation-driven> enabled then:
#RequestMapping("/controllerMethod", method=RequestMethod.POST)
public String doSomething(#RequestBody List<Person> people) {
System.out.println( wantToSeeListOfPeople );
}
(List<Person> might not be the structure you would like to obtain, it's just an example here)
You can try setting the Content-Type of $.ajax to be application/json, if it doesn't work immediately.
Have a look at Jackson's spring integration. It is incredible easy to use and powerful.
A question/answer on SO that can help guide on this:
Spring 3.0 making JSON response using jackson message converter

Resources