In the client side, I am using jQuery to submit a number of pairs to the server.
But the number of entries is variable.
For example:
1: 1.55
2: 2.33
3: 5.66
In the server side, how should I design the Controller so that it could take the POST data and store it in a List / Map?
Something like:
#RequestMapping ("/submitdata")
public #ResponseBody String changeData (???) {
// changes to database
return "Success";
}
EDIT:
I got the answer:
#RequestMapping ("/submitdata")
public #ResponseBody String changeData (#RequestParam Map <String, String> params) {
for (Map.Entry<String, String> entry: params.entrySet()) {
System.out.println ("Key = " + entry.getKey() + " Value = " + entry.getValue());
}
// changes to database
return "Success";
}
You can use #RequestParam annotation to grab POST data
you can use
#ResponseBody Map<String,String> udpateIdentification(HttpServletResponse response, #ModelAttribute("jspObject") Test test,BindingResult result)
The values will be get bind to the ModelAttribute if you have used that in your JSP
Related
We have a requirement to read data after '?' in service-url in Spring boot REST API.
For example, We exposed a service called sampleService and GET URL for this is
http://www.myservices.com/api/sampleServce
And clients will pass the data as http://www.myservices.com/api/sampleServce?dynamicdata
So we have to read that "dynamicdata" in my sample service and process.
Please let me know the possibilities.
GET: http://localhost:8080/api/foos?id=abc here the query string is id=abc . Now to extract the value of id, you can use the code something like this.
#GetMapping("/api/foos")
#ResponseBody
public String getFoos(#RequestParam String id) {
return "ID: " + id;
}
GET: http://www.myservices.com/api/sampleServce?dynamicdata is incorrect. Either it should be http://www.myservices.com/api/sampleServce/dynamicdata (PathVariable) or http://www.myservices.com/api/sampleServce?title=dynamicdata (RequestParam)
GET: http://www.myservices.com/api/sampleServce/dynamicdata to extract dynamicdata, you can use code something like
#GetMapping("/api/sampleServce/{id}")
#ResponseBody
public String getFooById(#PathVariable String id) {
return "ID: " + id; // here id = "dynamicdata"
}
GET: http://www.myservices.com/api/sampleServce?title=dynamicdata to extract title, you can use code something like
#GetMapping("/api/sampleServce")
#ResponseBody
public String getFoos(#RequestParam String title) {
return "title: " + title; // title="dynamicdata"
}
dynamicdata is path param, it cannot be placed after ?. It should be something like this:
http://www.myservices.com/api/dynamicdata/sampleServce
Check when and how to use query or path parameters
Accept dynamic data through request param:
#GetMapping("/api/sampleServce")
public void test(#RequestParam Map<String, String> dynamicdata) {
System.out.println(dynamicdata.keySet()); //http://localhost:9001/dag-backend/api/sampleServce?test&test11
Optional<String> data = dynamicdata.keySet().stream().findFirst();
String value = data.isPresent() ? data.get() : null;
System.out.println(value); //http://localhost:9001/dag-backend/api/sampleServce?test
}
URLs:
http://www.myservices.com/api/sampleServce?dynamicdata
http://www.myservices.com/api/sampleServce?dynamicdata&12344&1212
http://www.myservices.com/api/sampleServce?$999900&124434&234
You can add an HttpServletRequest object to your mapped method signature:
#RequestMapping("/api/sampleServce")
public Object sampleServce (HttpServletRequest request) {
//print everything after the question mark:
System.out.println("queryString: " + request.getQueryString());
//print key value pairs:
Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
String paramName = params.nextElement();
String paramValue = request.getParameter(paramName);
System.out.println("name: " + paramName);
System.out.println("value: " + paramValue);
}
return request.getQueryString();
}
I have in front end a form where the user selects the year and one or more months from a list of months. These params will be sent to Controller as Get Method.
Given an URL like this:
..../{year}/{months}/excel/
Where months would be a variable list of the months selected, i.e [01,02,10].
How I receive all parameters in the Controller?
Here's my controller so far:
#RequestMapping(value = "/{year}/{months}/excel/", method = RequestMethod.GET, produces = EXCEL_FORMAT_HEADER)
public #ResponseBody
ModelAndView getRankingByYearExcel(#PathVariable("year") Integer year,
#RequestParam Map<String, Object> months)
{...}
I did it like this and worked, declaring months as array of Strings:
#RequestMapping(value = "/{year}/excel/", method = RequestMethod.GET, produces = EXCEL_FORMAT_HEADER)
public #ResponseBody
ModelAndView getRankingByYearExcel(#PathVariable("year") Integer year,
#RequestParam String[] months)
And in URL sent variable months as array of strings:
../2016/excel/?months=1,3,12
Thanks for guiding me in this direction
I would change the #RequestParam Map<String, Object> months to #RequestParam String months You can then split the months based on comma.
String[] monthsList = months.split(",");
The monthsList array will have all the user selected values.
Here is how you bind all URI template variable to Map and use.
First of all, You need to change #RequesetParam to #PathVariable
example1:
#RequestMapping("{id}/messages/{msgId}")
public String handleRequest4 (#PathVariable Map<String, String> varsMap, Model model) {
model.addAttribute("msg", varsMap.toString());
return "my-page";
}
example2:
#GetMapping("/request4/{name}/{age}/address/{city}/{country}")
#ResponseBody
public String handler(#PathVariable Map<String, String> params) {
StringBuilder builder = new StringBuilder();
builder.append("URL parameters - <br>");
for (Entry<String, String> entry : params.entrySet()) {
builder.append(entry.getKey() + " = " + entry.getValue() + "<br>");
}
return builder.toString();
}
For more information see doc1 or see doc2
I know that this is an easy one if I am not using Jersey and would use something like this:
Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Parameter Name - "+paramName+", Value - "+request.getParameter(paramName));
}
params = request.getHeaderNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Header Name - "+paramName+", Value - "+request.getHeader(paramName));
}
params = request.getAttributeNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Attribute Name - "+paramName+", Value - "+request.getAttribute(paramName));
}
I am also aware that I can do this and be done with it.
#FormParam("location") String location
But what if I do want to dump all the contents of the form submitted via POST?
The problem is that I am using Jersey as the implementation of JAX-RS and using the code above outputs this:
Attribute Name - org.glassfish.jersey.server.spring.scope.RequestContextFilter.REQUEST_ATTRIBUTES, Value - org.glassfish.jersey.server.spring.scope.JaxrsRequestAttributes#11e035a
Attribute Name - org.glassfish.jersey.message.internal.TracingLogger, Value - org.glassfish.jersey.message.internal.TracingLogger$1#16e45c8
I am guessing that my data is contained here: JaxrsRequestAttributes I am not sure though.
I know I am missing something here. This isn't supposed to be difficult isn't it?
UPDATE
As suggested Sotirios,
This is the code get the dump of the form.
try {
InputStream is = request.getInputStream();
int i;
char c;
while((i=is.read())!=-1)
{
// converts integer to character
c=(char)i;
// prints character
System.out.print(c);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
In order for this to work, I had to remove #FormParam in my parameter and leave out #Context HttpSerlvetRequest request.
Are there no other way to output this in a more elegant way with out the need to remove #FormParam? Maybe get the values from JaxrsRequestAttributes?
I tried to create a variable JaxrsRequestAttributes but it's a default class a can not access it directly.
Based on Sotirios comment's, here's the answer:
Here's the method signature
public Response authenticateUser(MultivaluedMap<String, String> form)
Iterator<String> it = form.keySet().iterator();
while(it.hasNext()){
String theKey = (String)it.next();
System.out.println("Parameter Name - "+theKey+", Value - "+form.getFirst(theKey));
}
System.out.println(form);
The HttpServletRequest can be accessed using :
#Context
private HttpServletRequest request;
Isn't that enough?
My function looks like this:
#PUT
#Path("property/{uuid}/{key}/{value}")
#Produces("application/xml")
public Map<String,ValueEntity> updateProperty(#Context HttpServletRequest request,
#PathParam("key") String key,
#PathParam("value") String value,
#PathParam("uuid") String uuid) throws Exception {
...
}
I have to modify it, so it accepts indefinite(or many) list of key-value pairs from REST call, something like
#Path("property/{uuid}/{key1}/{value1}/{key2}/{value2}/{key3}/{value3}/...")
Is it possible to store them in an array or list, so I do not list dozens of #PathParams and parameters, to avoid this:
#PathParam("key1") String key1,
#PathParam("key2") String key2,
#PathParam("key3") String key3,
Might be a good opportunity to rethink this design. By using /s, we are in a way signifying, with each / that we are trying to locate a different resource. Key/Value pairs (in the context of the URL) are mainly for query parameters or matrix parameters.
If /property/{uuid} is the path to a main resource, and we just want to offer some parameters to the client for accessing this resource, then we could allow matrix parameters or query parameters
Matrix Parameters (in a request url) will look something like
/12345;key1=value1;key2=value2;key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getMatrix(#PathParam("uuid") PathSegment pathSegment) {
StringBuilder builder = new StringBuilder();
// Get the {uuid} value
System.out.println("Path: " + pathSegment.getPath());
MultivaluedMap matrix = pathSegment.getMatrixParameters();
for (Object key : matrix.keySet()) {
builder.append(key).append(":")
.append(matrix.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See PathSegment
Query Parameters (in a request url) might look something like
/12345?key1=value1&key2=value2&key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getQuery(#PathParam("uuid") String uuid,
#Context UriInfo uriInfo) {
MultivaluedMap params = uriInfo.getQueryParameters();
StringBuilder builder = new StringBuilder();
for (Object key : params.keySet()) {
builder.append(key).append(":")
.append(params.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See UriInfo
The difference is that Matrix parameters can be embedded into path segments, while query parameters must be placed at the end of the URL. You can also notice a little difference in syntax.
Some Resources
Query String (Wikipedia)
When to use query parameters versus matrix parameters?
URL matrix parameters vs. request parameters
UPDATE
Also looking at the PUT in you method signature, it appears you are trying update a resource using the path as the values for which you are trying to update, as I don't see any parameters in your method for an entity body. When PUTting, you should be sending the representation in the the entity body, not as as path segments or parameters.
A workaround:
#Path("/foo/bar/{other: .*}
public Response foo(#PathParam("other") VariableStrings vstrings) {
String[] splitPath = vstrings.getSplitPath();
}
VariableStrings class:
public class VariableStrings {
private String[] splitPath;
public VariableStrings(String unparsedPath) {
splitPath = unparsedPath.split("/");
}
}
Path segment sequence to vararg array in JAX-RS / Jersey?
Another example where you map the optional parameter to a Map:
#GET
# Produces({"application/xml", "application/json", "plain/text"})
# Path("/location/{locationId}{path:.*}")
public Response getLocation(#PathParam("locationId") int locationId, #PathParam("path") String path) {
Map < String, String > params = parsePath(path);
String format = params.get("format");
if ("xml".equals(format)) {
String xml = "<location<</location<<id<</id<" + locationId + "";
return Response.status(200).type("application/xml").entity(xml).build();
} else if ("json".equals(format)) {
String json = "{ 'location' : { 'id' : '" + locationId + "' } }";
return Response.status(200).type("application/json").entity(json).build();
} else {
String text = "Location: id=" + locationId;
return Response.status(200).type("text/plain").entity(text).build();
}
}
private Map < String, String > parsePath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
String[] pathParts = path.split("/");
Map < String, String > pathMap = new HashMap < String, String > ();
for (int i = 0; i < pathParts.length / 2; i++) {
String key = pathParts[2 * i];
String value = pathParts[2 * i + 1];
pathMap.put(key, value);
}
return pathMap;
}
In Java, I am implementing a server where client can pass some data (Key-value pairs) using post query. I have decided to make a REST Service and I am planning to use JAX-RS along with Jetty.
I have no previous knowledge about the keys to be send here. Is there any way to browse over all the KV pairs POSTed by client? I know that if key is known we could retrieve data as in -
#Path("/testpath")
public class test {
#POST
#Path("/level1")
public Response getData(
#FormParam("key1") String val1,
#FormParam("key2") int val2) {
return Response.status(200)
.entity("getData is called, Key1 : " + val1 + ", Key2 : " + val2)
.build();
}
}
In the above example, I could have N of different keys!
I am planning to use vanilla JAX-RS without Jersey, or RESTeasy. However I am open to the options when not possible in JAX-RS!
Use MultiValuedMap :
#Path("/testpath")
public class test {
#POST
#Path("/level1")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces("text/plain")
public Response getData(MultiValuedMap<String, String> params) {
StringBuilder sb = new StringBuilder("getData is called, ");
for(String param : params.keySet()) {
sb.append(param + " : " + params.getFirst(param) + ", ");
}
return Response.status(200).entity(sb.toString()).build();
}
}