I pass array of items from JS to spring controller. I have this model in JS:
function Row() {
this.id = 0;
this.rulingValue = '';
this.rulingType = '';
this.dateStart = '';
this.dateEnd = '';
}
I have array of Rows - var jsonData = [];
Then I fill this array. And set to
var oMyForm = new FormData();
oMyForm.append("items", jsonData);
In Spring controller I expect this array like List<Item>
#Data
public class Item {
private String id;
private String rulingValue;
private String rulingType;
private String dateStart;
private String dateEnd;
}
#RequestParam("items") List<Item> items
But my items parameter arrive as String. How can I get this array like List<Item>?
Springs preferred way to send JSON to a Controller is as body payload rather than as form parameter. To do so, you just have to do three things:
Make sure you have a JSON library in the classpath, e.g. fasterxml.jackson.
Ensure your JSON payload is sent via POST request with HTTP Content-Type "application/json"
Annotate the receiving parameter in your Controller handler method with #RequestBody, e.g.
getItems(#RequestBody List items)
A complete example can be found here: http://www.beabetterdeveloper.com/2013/07/spring-mvc-requestbody-and-responsebody.html
If you stay with sending your data as form parameter, you will have to write a custom property editor along the lines indicated here: JSON parameter in spring MVC controller. It is much harder and requires extra code.
Related
Desired request:
http://localhost:8080/values?input=[["aaa","bbb","ccc","ddd"],["abcd","abcd","abcd","abcd"]]
I would love to be able to pass the URL in some way using brackets.
However if it is not possible, how do I still pass the list of lists ?
My controller path:
#GetMapping(path = "/values/")
public String getValues(#RequestParam List<List<#Size(min=4, max=4)String>> input) {
return input.get(0).get(2);
}
which should return ccc.
This is not a good way to do this job. Instead you can pass them as request parameter and and receive them from hashMap. But since you are passing list of lists, so it would be convenient to pass them in request body. To do that you have to create a request POJO class following these steps:
public class ListRequest{
private List<List<String>> inputList;
//generate getter, setter for it
}
Now, change in your controller, replace GET method with POST:
#PostMapping(path = "/values/")
public String getValues(#RequestBody ListRequest input) {
List<List<String>> yourData=input;
System.out.println(yourData);
//operate on your data as you wish
return input.get(0).get(2);
}
Create a Pojo class with a list of list as field.
Send the values in the request body and use a post method.
In the controller method, use this Pojo object to retrieve those values.
The client side will send the request in json format. However, it looks like the value can't be got by #FormParam annotation. I tried to change the #Consumes(MediaType.APPLICATION_FORM_URLENCODED) but it didn't work.
Which kind of change shall I make on JAVA side to receive the data correctly?
For example, JSON data is
var postData = {
'uipath': 'xxx\abc\location1',
'value': 'Hello World!'
};
The JAX-RS method is
#POST
#Path(value = "/receive")
public Object getValueFromUIPath(#Context UriInfo uriInfo,
#FormParam("uipath") String uiPath,
#FormParam("value") String value) {
...
}
for your information
use consumes annotaion
json should be double quoted
and coming to the answer , you are creating json object
{
'uipath': 'xxx\abc\location1',
'value': 'Hello World!'
}
however you are suppose to consume two string fields, not an object. you have two options, whether consume object have two fields uipath and value, or send simple value rather then json object.
I'm a NanoHttpd newbie. I'm shifting my Java EE servlet code into NanoHttpd for embedded usage. Please don't recommend other embedded servers like Jetty, I'd like to use NanoHttpd in particular.
My jQuery Javascript code looks like this:
$.ajax({
type:'POST',
url:'',
traditional: true,
data: {
'prm1':'val2',
'prm2':'val2',
'array1':['array1','array2','array3']
},
success:function(result){},
error:function(xhr,err,stat){}
});
On a servlet getting parameters would look like this:
String serverval1 = request.getParameter("prm1"); //get single value
String serverval2 = request.getParameter("prm2"); //get single value
String[] params = request.getParameterValues("array1"); //get array
On NanoHttpd I can get individual values via:
String serverval1 = ihttpsession.getParms().get("prm1"); //get single value
String serverval2 = ihttpsession.getParms().get("prm2"); //get single value
String[] params = ???
How do I get array parameters in NanoHttpd?
I figured it out after seeing a few more NanoHttpd sample codes, apparently there are many ways to get the request parameters
String serverval1 = ihttpsession.getParms().get("prm1"); //get single value
String serverval2 = ihttpsession.getParms().get("prm2"); //get single value
//get parameters as array (alternative method)
Map<String,List<String>>prms=decodeParameters(ihttpsession.getQueryParameterString());
String[] array = prms.get("array1").toArray(new String[prms.get("array1").size()]);
the later method can also be used on non array parameters but will obviously contain only one value in their respective List<String> object
I have to transform a very peculiar JSON payload into POJOs manually. I thought I could put the JSON string into a String entity:
#ApiMethod(
name = "postSomething",
path = "postSomething/{id}",
httpMethod = ApiMethod.HttpMethod.POST
)
public void postSomething(#Named("id") Integer id, HttpServletRequest request, String data) {
//Parse data here...
}
When I do that, I get an error: MissingParameterNameException: Missing parameter name. Parameter type (class java.lang.String) is not an entity type and thus should be annotated with #Named.
I tried to use an #ApiTransformer but I get a similar error.
Could you please give me an example of parsing the JSON content manually?
The error message says that String data needs to have an #Named annotation, similar to Integer id.
I worked around this issue by using a Collections class instead of String and manual parsing:
#ApiMethod(
name = "postSomething",
path = "postSomething/{id}",
httpMethod = ApiMethod.HttpMethod.POST
)
public void postSomething(#Named("id") Integer id, HttpServletRequest request, HashMap<String,String> data) {
//Parse each item of data here...
}
From this, I can parse each item inside the data. The values contain a hierarchy of either other collections (List for an array, Map for a JSON entity) or String for an actual value. So by doing this I don't need to use any other JSON parsing library such as Jackson.
String is not an #Entity object so it can't be passed as a parameter (a data parameter) to the endpoints API without proper annotation (like #Name or #Nullable). Either you must remove it from the method declaration or annotate it with #Name or #Nullable.
Question is pretty self explanatory. I want to send 2 different arrays of objects through a POST form without ajax to my controller.
I changed my question to using ajax and using a get request due to the size of the params. Currently getting a 400 (Bad Request). I have no idea why. Please take a look...
I have objects:
var phone = {phoneId:"", phoneNumber:"", phoneType:""};
var schedule = {scheduleId:"", time:"", day:""};
Which I place into a javascript arrays:
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
and I use ajax to send:
var data = {
index: id,
schedules: schedules,
phones: phones
}
var url = "/myController/myUrl"
$.getJSON(url, data, function(result){
if(result.ok){
$('#messageAlertSuccess').show();
} else {
$('#messageAlertError').show();
}
});
I created wrapping classes to map them like so:
public class PhoneWrapper(){
private String phoneId;
private String phoneNumber;
private String phoneType;
}
And of course the scheduleWrapper follows the same convention.
Here's the method in my controller:
#ResponseBody
#RequestMapping(value="/myUrl", method=RequestMethod.GET)
public Result doSomething(#RequestParam("index") int index,
#RequestParam("phones") Set<PhoneWrapper> phoneWrappers,
#RequestParam("schedules") Set<ScheduleWrapper> scheduleWrappers,
Model model,
HttpSession session){
//do stuff here.
}
I am currently getting a 400. So what's wrong?
Update: here's the url that the .getJSON jquery method is building:
http://localhost:8080/myApp/myController/myUrl?index=9&schedules%5B0%5D%5BscheduleId%5D=1&schedules%5B0%5D%5BfromDay%5D=Monday&schedules%5B0%5D%5BtoDay%5D=Friday&schedules%5B0%5D%5BfromTime%5D=08%3A30%3A00&schedules%5B0%5D%5BtoTime%5D=16%3A00%3A00&schedules%5B1%5D%5BscheduleId%5D=5&schedules%5B1%5D%5BfromDay%5D=Saturday&schedules%5B1%5D%5BtoDay%5D=Monday&schedules%5B1%5D%5BfromTime%5D=09%3A00%3A00&schedules%5B1%5D%5BtoTime%5D=13%3A00%3A00&phones%5B0%5D%5BphoneId%5D=6&phones%5B0%5D%5BphoneNumber%5D=787-788-1111&phones%5B0%5D%5BphoneType%5D=PHONE&phones%5B1%5D%5BphoneId%5D=106&phones%5B1%5D%5BphoneNumber%5D=787-795-4095&phones%5B1%5D%5BphoneType%5D=FAX
I see a few things that don't look right
unless you have getters and setters in your wrappers (DTO is a better name), i don't use them for my DTOs for xhr calls, you need to change
public class PhoneWrapper(){
private String phoneId;
private String phoneNumber;
private String phoneType;
}
to have public fields vs private
public class PhoneWrapper(){
public String phoneId;
public String phoneNumber;
public String phoneType;
}
Your js arrays are not arrays but objects;
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};
Here they are as arrays
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
Make sure you naming is the same of both the js and java sides. I find it very helpful to turn on the debugging when troubleshooting these problems. log4j -
<logger name="org.springframework.web.servlet.mvc" >
<level value="debug" />
</logger>
EDIT
So after the question was updated with more info I notice that it was the same problem as Binding a list in #RequestParam
I would say that you are almost there! The first thing the you need is a wrapper to hold the two Set<> parameters since spring is not able to map a collection directly to parameters (yet?).
Also, there are two ways to handle this kind of requests:
use a json request and #Requestbody with a single javascript object in the request body an map this into a java class (automatically by spring). This means you need to change a little how the data is send down and this approach has one side effect: you cannot merge data simply by defining the parameter as a model attribute.
a second possibility is to stay with the post form submit. Also here you need to create the wrapper and use this one as a requestparam. Either one per Set<> parameter like #Sotirios mentioned in his answer or one parameter which holds both sets. Then you need to modify your submit data to send the phone and schedule information like input fields. I haven't used sets in this case but
lists and the parameter names would look like phoneWrapper[0].phoneId.
The advantage of the second approach is that you can merge the request data with existing values so you do not need to send down a complete phone information all the time.
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};
These two are not arrays (square brackets), but objects (curly brackets).
Compare with
var phones = ["phone1", "phone2", "phone3"];
var schedules = ["schedule1", "schedule2"];
and if you are to pass actual object references (phone1, phone2, phone3, schedule1 and schedule2 are object variables) then you need to use
var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];
For spring the map request parameters to Class instance fields, they have to match the name of the parameter.
So with
<input type="hidden" name="someParameter" value="123"/>
and
public class SomeClass {
private String someParameter;
// getters and setters
}
a Spring controller will be able to be injected with a SomeClass instance whose field someParameter has the value 123 that comes from the html hidden input request parameter. This is also known as a command object.
A javascript array has no meaning to either html or http.
As for the solution, I would keep your class PhoneWrapper, use javascript to populate 3 <input> elements, and change the method definition to
#RequestMapping(value=MY_URL, method=RequestMethod.POST)
public String doSomething(#RequestParam("index") int index,
PhoneWrappers phoneWrappers,
ScheduleWrappers scheduleWrappers,
Model model,
HttpSession session){
Notice there are no more array [] brackets. (You would do the same for ScheduleWrappers).