I am working on an app written in java and angular. The request goes from angular with params and I need to read the params in the rest services. The angular piece is fixed (I cannot change it), but I can update the java code as needed.
My issue: I cannot read the params in my java services method. The value is always null.
angular code:
alert("params : "+JSON.stringify(params, null, 2));
return $http.get(url, {
params: params
}).success(function (data) {
// success criteria
});
The params looks like this based on the alert statement:
{
"start": 0,
"end": 100,
"type": "asdf",
"name": null,
"values": [],
"locs": [],
"test1": "Val"
}
My java code looks like this:
#GET
#Path("valuesList")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_XML)
public String getValues(#RequestParam("type")String type) throws Exception {
System.out.println("type ================"+type);
}
The type is null. I want to read all the values, but for now I am just using the type for testing. I also tried various #Consumes values, but nothing helps.
I think I need to change the #RequestParam, but not sure to what though. Thanks for any pointers.
Just wanted to post the solution - I had to update the #RequestParam to #QueryParam. The updated method call is below
public String getValues(#QueryParam("type")String type) throws Exception {
System.out.println("type ================"+type);
}
Related
I try to build my first api. I got problem when i want to register new user. The problem is when i want to send request from postman. I using also SwaggerUI, so when i use Post Request to my end point /registration in SwaggerUI by textfields always i got http status 201 so its works good. Problem is when i want to make Mock to this controller or when i want to send new user in postman request but not always. I show you in example
If i use postman -> post: localhost:8080/registration -> Raw -> JSON
{
"email": "testtest#gmail.com",
"id": 0,
"password": "Test1234567 ",
"username": "testtest"
}
Then i got message
{
"status": "BAD_REQUEST",
"timestamp": "01-03-2021 11:44:26",
"message": "Value cannot be empty!",
"debugMessage": null,
"subErrors": null
}
So its should be good because i used catch exception. But Value isnt empty, so whats happend?I dont know.
But when i go to x-www-form-urlencoded and there i put keys: email, username and password then, user is created!
Another, when im put this same info to Swagger then also my user is created.
Below i add my code from controller and test.
#Test
void shouldCreateNewUser() throws Exception {
UserRegistrationDto user = new UserRegistrationDto( null,"seba12345", "lelelele1908#gmail.com", passwordEncoder.encode("Respeck123"));
mockMvc.perform(post("/registration")
.header("header1", "1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andExpect(status().isCreated());
}
#PostMapping("/registration")
public ResponseEntity<UserRegistrationDto> registerUser(UserRegistrationDto userRegistrationDto) {
HttpHeaders headers = new HttpHeaders();
userService.save(userRegistrationDto);
return new ResponseEntity<>(userRegistrationDto, headers, HttpStatus.CREATED);
}
You need #RequestBody in your controller method to tell Spring that you want the content of the request body:
#PostMapping("/registration")
public void post(#RequestBody MyDTO dto) {
...
}
I would like to send datas (in json form) from frontend to backend using POST, but requestparameter is null.
Angular:
this.http.post('api/example', { mydata: JSON.stringify(data) },
{ "headers": { header: "text/html;charset=UTF-8" } }).subscribe(Response => console.log(Response);
});
JSON.stringify(data) looks like this:
[
["num1","num2","num3","num4","num5", "num6"],
["test6","test2","test1","test5","test4", "test3"]
]
This is just an example, the data will be dynamic, so sometimes I will have more or less columns and rows.
Spring backend:
#RequestMapping(value = "/api/example", method = RequestMethod.POST)
public #ResponseBody void postExample(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession();
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
request.setCharacterEncoding("UTF-8");
String mydata = request.getParameter("mydata");
System.out.println(mydata);
...
}
mydata is null, when I print out. I don't know why.
What I tried:
change "text/html" to "application/json" and "application/*" and "text/plain" (and wanted to convert the text to json at backend, but still null parameter)
I would like to use "getParameter" instead of using #RequestBody annotation.
How can I get the json data from frontend and use it in backend?
Edit:
Originally I didn't want to use #RequestBody, but if I want to use it, how can I use it for getting these json arrays?
for using #RequestBody you'll need a Java data structure matching your JSON,
e.g. a nested array
#PostMapping(path="/api/example")
public void postExample(#RequestBody ArrayList<ArrayList<String>> body) {
//....
}
Test case (from question above)
[
["num1","num2","num3","num4","num5", "num6"],
["test6","test2","test1","test5","test4", "test3"]
]
You need to use .getReader(), instead of the .getParameter() method, since you need to retrieve the body of the request not some parameter.
I am working with an API which basically allows for the navigation of a file-system. I am trying to access data from within the returned JSON by the API in order to perform a function on it.
Below is the code I am using the access the API. I have tried to use unmarshal to
convert the JSON returned to a Map.
from("timer://foo?fixedRate=true&period=120000")
.log("Checking for files")
.setHeader("Authorization", simple(myHttp.getAuth()))
.setHeader("CamelHttpMethod", constant("GET"))
.to(myHttp.getFullRequest())
.unmarshal(new JacksonDataFormat(Map.class)).log("${body}");
Which returns this data to me:
{
objects=[
{
name=file1.csv,
type=file
},
{
name=dir1,
type=directory,
},
{
name=dir2,
type=directory
},
{
name=dir3,
type=directory
},
{
name=dir4,
type=directory
}]
}
I want to access the array under "objects" in order to check whether any files exist inside this directory. So far, I only tried to log the data under objects and therefore I have used this code:
.unmarshal(new JacksonDataFormat(Map.class)).log("${body.objects}");
Using ${body.objects}, I'm still unable to access the data inside the MAP. I expected something like this to be returned:
[{
name=file1.csv,
type=file
},
{
name=dir1,
type=directory,
},
{
name=dir2,
type=directory
},
{
name=dir3,
type=directory
},
{
name=dir4,
type=directory
}]
but instead I get this error:
Method with name: objects not found on bean: {objects=[{name=file1.csv,type=file},{name=dir1,type=directory,},{name=dir2,type=directory},{name=dir3,type=directory},{name=dir4,type=directory}]} of type: java.util.LinkedHashMap. Exchange[ID-IT1289-1529914067957-0-1]
Am I accessing the returned MAP after using unmarshall incorrectly? What is the correct syntax I must I use if so?
I have seen other examples of unmarshalling... but I cannot understand completely. I've noticed many examples use a class with the structure of the JSON. Is this necessary? If my body is currently of type: java.util.LinkedHashMap, I expect it shouldn't be a problem to access but I cannot seem to find the way.
Thanks in advance
The best way to do this is to create a class matching your Json Structure.
class RestResponse {
List<FileNameType> objects;
//Getters and Setters
}
class FileNameType {
String name;
String type;
//Getters and setters.
}
Then change your route like this
from("timer://foo?fixedRate=true&period=120000")
.log("Checking for files")
.setHeader("Authorization", simple(myHttp.getAuth()))
.setHeader("CamelHttpMethod", constant("GET"))
.to(myHttp.getFullRequest())
.unmarshal().json(JsonLibrary.Jackson, RestResponse.class)
.to(....);
The last part I have left it blank, here you can add a processor to verify your logic. You can get the RestResponse object from exchange.getIn().getBody(). Some thing like this will do
........
.unmarshal().json(JsonLibrary.Jackson, RestResponse.class)
.process(exchange -> {
RestResponse response = exchange.getIn().getBody(RestResponse.class);
// Do your logic here.
})
You might need to add this dependency
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>yourcamelversion</version>
</dependency>
My problem is similar to the following posts:
JSON ajax POST to Spring Portlet Controller #ResourceMapping conversion issue and #ResourceMapping that accepts JSON from Ajax request
I have tried the Tipps there, but without success.
I have the following Technologies in place:
liferay-portal 6.2 CE
custom portlet-plugin for liferay based on spring 3.0.7
kendo-ui for jsp
On the client-side I produce a stringified json-Object with the functionality of kendo-ui for jsp, which is submitted in the request body. Currently it contains just some filter-parameters (but it can also contain additional parameters for server-side paging, sorting, grouping,..).
In Firefox developer tools the request-body (payload) looks like following:
{
"filter" : {
"logic" : "and",
"filters" : [{
"field" : "name",
"value" : ""
}, {
"field" : "city",
"value" : ""
}, {
"field" : "zip",
"value" : ""
}, {
"field" : "country",
"value" : ""
}
]
}
}
On the server-side I have a POJO for that structure. I tested this in a Spring Web MVC Servlet enviroment with success. Using #RequestBody and Jackson the deserialization of the JSON Object works.
Working in liferay-portlet enviroment I cannot use #RequestBody and httpServletRequest.
The Controller looks like following:
#ResourceMapping(value = "test")
public void searchProviderTest(ResourceRequest request, ResourceResponse response,
#ModelAttribute("filter") DataSourceRequest dataSourceRequest) {
LOGGER.info(">>>>>> JsonOjekt per Parameter übergeben: " + request.getParameter("filter"));
LOGGER.info(">>>>>>>> DatasourceRequest: " + dataSourceRequest);
}
The DataRequestObject has no values. I see all the attributes, but they are empty. And there is no request parameter "filter" (as exspected)
Here is my DataSourceRequest-Object (abstract):
public class DataSourceRequest {
private int page;
private int pageSize;
private int take;
private int skip;
private List<SortDescriptor> sort;
private List<GroupDescriptor> group;
private List<AggregateDescriptor> aggregate;
private HashMap<String, Object> data;
private FilterDescriptor filter;
public DataSourceRequest() {
filter = new FilterDescriptor();
data = new HashMap<String, Object>();
}
...(getters and setters)
public static class FilterDescriptor {
private String logic;
private List<FilterDescriptor> filters;
private String field;
private Object value;
private String operator;
private boolean ignoreCase = true;
public FilterDescriptor() {
filters = new ArrayList<FilterDescriptor>();
}
...(getters and setters)
Im am searching for a solution since a few weecks, but I do not get the JSON-Object converted (deserialized?) to the DataSourceRequest-Object using the portlet-controller. I even do not have an idea how to access the JSON-String in the request-body (payload) from the portlet-controller.
Following the second mentioned post, the nested objects might be the problem. I contacted the kendo-ui support with the question, how I can submit the request to get the format described in the post. But they told me, that is not possible (e.g. using parameterMap-attribute of the datasource object)and I have to solve it on the server-side.
The first post describes a solution with #ModelAttribute, but then I get only the empty object-and when I try to get the JSON with #RequestParam I get an error, that the parameter is not in the request (I think because it is in the body)
I was thinking about setting up an additional RESTFul API, based on Spring Web MVC Servlet - I even tried it and it works- but I am not sure if that is really meaningful, because liferay already has a RESTFul -API.
Is there a way to convert the JSON Object to an JAVA Object inside the Portlet Controller ? or Do I need the additional API?
Any tips are welcome!!
I had the same problem while serializing and deserializing Json with Liferay. The solution for me was to send the json as a parameter in a form-data. That way a I was able to retrive the Json with the following method:
String paramJson = ParamUtil.getString(request, "myJson");
And then make use of Gson api to deserialize:
new Gson().fromJson(paramJson, MyPOJO.class);
You won't have so many troubles with Gson.
You can also use Gson to serialize objects in the return of your services, this will avoid problems with nested objects witch Liferay doesn't serialize properly.
This code show how to send the Json as request body:
The request will be processed by method 'serveResource' in a MVCPortlet.
var portletUrl = Liferay.PortletURL.createResourceURL();
portletUrl.setPortletId(<portletId>);
portletUrl.setResourceId('publicar'); // Any identifier
var formData = new FormData();
formData.append(<portlet-namespace> + 'myJson', JSON.stringify(object));
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', callbackSuccess, false);
xhr.open('POST', urlPortlet);
xhr.send(formData);
To share my experience hera are the steps:
in JS set contentType to application/x-www-form-urlencoded. Thats the code for kendo-ui (uses jQuery Ajax in Background)
<kendo:dataSource-transport-parameterMap>
function parameterMap(options,type) {
if(type==="read"){
return "osdeFilter=" + encodeURIComponent(JSON.stringify(options));
} else {
return "osdeModels=" + encodeURIComponent(JSON.stringify(options.models));
}
}
</kendo:dataSource-transport-parameterMap>
Get the Parameter and in my case use Jackson manualy to deserialize the JSON String
#ResourceMapping(value = "test")
public void searchProviderTest(ResourceRequest request, ResourceResponse response)
throws JsonParseException, JsonMappingException, IOException {
String osdeFilter = URLDecoder.decode(request.getParameter("osdeFilter"),"UTF-8");
LOGGER.info(">>>>>> JsonOjekt per Parameter übergeben: " + request.getParameter("osdeFilter"));
ObjectMapper objectMapper = new ObjectMapper();
DataSourceRequest dataSourceRequest = objectMapper.readValue(osdeFilter, DataSourceRequest.class);
LOGGER.info(">>>>>>>> DatasourceRequest: " + dataSourceRequest);
}
Differ from #giovani I do not need to submit the portlet-namespace. To achieve that, you must add the following configuration to liferay-portlet.xml
<requires-namespaced-parameters>false</requires-namespaced-parameters>
I'm trying to build a very basic REST API using Spring.
My URL endpoints are:
GET /notes
GET /notes/{noteId}
POST /notes
PUT /notes/{noteId}
DELETE /notes/{noteId}
All these endpoints work perfectly fine as expected except the PUT request which I want to run to update an item.
The problem is that data is not being received via PUT, where as it works fine for POST.
Here's my controller; I've tested it by adding a method identical to the update method but using POST and that works fine. I don't know why?
package notes;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/notes")
public class NotesController {
...
#RequestMapping(value="/{noteId}", method=RequestMethod.PUT)
public Response update(#PathVariable Integer noteId, Note note) {
return new Response("Note Updated", note);
}
#RequestMapping(value="/{noteId}", method=RequestMethod.POST)
public Response updateWithPost(#PathVariable Integer noteId, Note note) {
return new Response("Note Updated", note);
}
...
}
Using postman, I've tested POST http://127.0.0.1:8080/notes/5 and the response was:
{
"message": "Note Updated",
"note": {
"id": null,
"title": "Hello World detail content",
"text": "Hello World",
"createdAt": "72, Mar 2015",
"updatedAt": "72, Mar 2015"
}
}
But for PUT http://127.0.0.1:8080/notes/5 with exactly same data the response was:
{
"message": "Note Updated",
"note": {
"id": null,
"title": "",
"text": "",
"createdAt": "72, Mar 2015",
"updatedAt": "72, Mar 2015"
}
}
Update Request
For both PUT & POST request I'm sending the same test data:
title: Hello World
text: Hello World detail content
Response Class
package notes;
public class Response {
private String message;
private Note note;
public Response(String text) {
setMessage(text);
}
public Response(String text, Note note) {
setMessage(text);
setNote(note);
}
//...getters/setters
}
Note Class
package notes;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Note {
private Integer id = null;
private String title = "";
private String text = "";
private Date createdAt = new Date();
private Date updatedAt = new Date();
public Note() {}
public Note(String title, String text) {
this.setTitle(title);
this.setText(text);
}
//...getters/setters
}
ApplicationConfig
package notes;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#EnableWebMvc
#Configuration
public class ApplicationConfig {
}
I don't know why this is not working?
This is a limitation of the Servlet Spec and the inner workings of Spring for populating model attributes.
First, the spec says
3.1.1 When Parameters Are Available
The following are the conditions that must be met before post form data will be populated to the
parameter set:
The request is an HTTP or HTTPS request.
The HTTP method is POST.
The content type is application/x-www-form-urlencoded.
The servlet has made an initial call of any of the getParameter family of methods on the request object. If the conditions are not met
and the post form data is not included in the parameter set, the post
data must still be available to the servlet via the request object's
input stream. If the conditions are met, post form data will no longer
be available for reading directly from the request object's input
stream.
Second, your handler methods' second parameter, the one of type Note, is actually considered a model attribute, as if it was implicitly annotated with #ModelAttribute. As such, it is processed by Spring's ModelAttributeMethodProcessor. This HandlerMethodArgumentResolver uses the getParameter (and its family of methods) for populating the created instance's fields.
Since this is a PUT request, the parameters are not retrievable through getParameter. However, they are still accessible through the request body, but Spring doesn't go there for model attributes.
You can do the conversion yourself. But I suggest you change your request content to JSON or XML for PUT and use #RequestBody annotated parameters.
There is a long standing request to add parameters for PUT requests.
Don't know if it's the case here (or if it is even relevant nowadays, haven't worked with REST-stuff for a while), but I've hit a problem in the past where Jetty and Tomcat handled PUT-requests differently (the application itself was using Spring MVC similarly as your code), the other expected the parameters to be in the URL and the other wanted them in the body, like with POST.
Apparently the HTTP-spec isn't very precise on this, so different containers can handle it differently. More information here.