I am using spring to build a REST api with PageAble, to get numberofPages,itens...
first, i did a mapping like this
public ResponseEntity<Data> findByName(#PathVariable(value="name",required=true) String name, #RequestParam(value="page", defaultValue="0") Integer page, #RequestParam(value="qtd", defaultValue="10") Integer linesPerPage, #RequestParam(value="sort", defaultValue="nome") String sort, #RequestParam(value="direction", defaultValue="ASC") String direction)
So in my url i get for example "url?name=erick&direction=asc" but i need to change to "url?name=erick!asc"
How can i change it?
You can do this. Look at page 3 of https://www.ietf.org/rfc/rfc1738.txt
In you case,you should use #RequestParam("name") instead of #PathVariable.Then the request url will be like "url?name=erick&direction=asc"
Spring has three kinds of Annotation.
#PathVariable
This annotation means the variable is on the url.For example:
#RequestMapping("/{id}")
public void pathVariable(#PathVariable("id") Long id){}
The variable was put between the brace at the url.
#RequestParam
This annotation means the variable is part of the quest param,the request url looks like
stackoverflow.com?name=hhhh
For example:
#RequestMapping("/")
public void requestParam(#RequestParam("id")Long id){}
#RequestBody
This annotation means you will receive some data from request body.And some kind of converter,like jackson,will convert it into a properly object.For example:
#PostMapping("/")
public void requestBody(#RequestBody Example example){}
Related
I try to bind an object in Spring controller so it can be used as #PathVariable. I want to do so, since there are some #PathVariable that I want to pass. I have tried the solution from Bind Path variables to a custom model object in spring and also Is it possible to bind path variable and request param into a single object?. But both are not working.
I have created something like this in my controller.
#RestController
#RequestMapping("/buildings")
#RequiredArgsConstructor
public class BuildingController {
private final BuildingService buildingService;
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(BuildingRequestBean request) {
return this.buildingService.getRoomSections(request);
}
}
and BuildingRequestBean.java like this
#Getter
#Setter
public class BuildingRequestBean {
private String buildingId;
private String floorId;
private String roomId;
}
When I check BuildingRequestBean, the attributes is null when I call it with GET localhost:8080/buildings/a/floors/b/rooms/c/sections.
However, it will not null if I call it as #RequestParam, something like this GET localhost:8080/buildings/{buildingId}/floors/{floorId}/rooms/{roomId}/sections?buildingId=a&floorId=b&roomId=c
How to fix it so it will behave like #PathVariable rather than behave like #RequestParam?
U can get it by using #ModelAttribute
Try with this:
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(#ModelAttribute BuildingRequestBean request) {
return this.buildingService.getRoomSections(request);
}
PathVariable must be added to the function parameter
Try this :
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(#PathVariable String buildingId,#PathVariable String floorId ,#PathVariable String roomId) {
Let's say I have:
#GET
public UserList fetch(#PathParam("user") String userId) {
// Do stuff here
}
Now, let's say I have my own type for userId, let's call it UserId. Is it possible to parse that String to UserId when it is passed into the fetch method, i.e.:
#GET
public UserList fetch(#PathParam("user") UserId userId) {
// Do stuff here
}
I realize I can parse the String once I am inside the method, but it would be more convenient that my method gets the type I want.
Well you've attempted to make a GET call with a request body is what I find not very helpful. Do read Paul's answer here -
you can send a body with GET, and no, it is never useful to do so
What would be good to practice is, to make a PUT or a POST call (PUT vs POST in REST) as follows -
#POST
#Path("/some-path/{some-query-param}")
public Response getDocuments(#ApiParam("user") UserId userId,
#PathParam("some-query-param") String queryParam) {
UserId userIdInstance = userId; // you can use the request body further
Note - The ApiParam annotation used is imported from the com.wordnik.swagger.annotations package. You can similarily use FormParam,QueryParam according to your source of input.
Dropwizard is using Jersey for HTTP<->Java POJO marshalling. You could use the various annotations from Jersey #*Param (#FormParam, #QueryParam, etc.) for some of the parameters.
If you need to use map/marshall to/from Java POJOs take a look at the test cases in Dropwizard:
#Path("/valid/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ValidatingResource {
#POST
#Path("foo")
#Valid
public ValidRepresentation blah(#NotNull #Valid ValidRepresentation representation, #QueryParam("somethingelse") String xer) {
return new ValidRepresentation();
}
This defines an API endpoint responding to HTTP POST method which expects ValidRepresentation object and "somethingelse" as HTTP method query parameter. The endpoint WILL respond ONLY when supplied with JSON parameters and will return only JSON objects (#Produces and #Consumes on the class level). The #NotNull requires that object to be mandatory for the call to succeed and #Valid instructs Dropwizard to call Hibernate validator to validate the object before calling the endpoint.
The ValidRepresentation class is here:
package io.dropwizard.jersey.validation;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
public class ValidRepresentation {
#NotEmpty
private String name;
#JsonProperty
public String getName() {
return name;
}
#JsonProperty
public void setName(String name) {
this.name = name;
}
}
The POJO is using Jackson annotations to define how JSON representation of this object should look like. #NotEmtpy is annotation from Hibernate validator.
Dropwizard, Jersey and Jackson take care of the details. So for the basic stuff this is all that you need.
I have a simple servlet as follows:
#RestController
public class TestServlet {
#RequestMapping(value = "/test1")
public String test1() {
return "test1";
}
#RequestMapping(value = "/test2")
public String test2(#RequestBody TestClass req) {
return "test2";
}
public static class TestClass {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
But only the servlet not receiving parameters is working:
Works: http://localhost:8080/test1
Doesn't work: http://localhost:8080/test2?value=1234
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.lang.String
Why is the #RequestBody annotation not working? Am I missing an important piece?
One of the differences between #Controller and #RestController is that you don't have to write #RequestBody and #ResponseBody, that means that any parameter in your controller method which does not have an annotation (like #PathVariable, #ModelAttribute, ...) will implicitly have #RequestBody, and must therefore be POSTed as the HTTP entity body. So you need to send JSON/XML as part of a POST. What you have done is to send data on as part of the URL, which makes it a request parameter and not body-data, and you need #RequestParam to to extract data from the URL.
Also, I would recommend that you use the #GetMapping/#PostMapping or include the method parameter in the #RequestMapping annotation, it is highly unlikely that you want a service to be used for both POST and GET, so you should be as specific as possible in you controller method descriptions, to limit error scenarios.
The reason the second URL does not work is because when using #RequestBody the data you are sending to the endpoint needs to come through via the data attribute in the request header. When you append ?attr=value to your URL that is sending the attribute in the params header.
There are two ways to fix this:
Change your endpoint to read something like this:
public String test2(#RequestParam("value") TestClass req) {
//Endpoint code
}
Change your endpoint to read something like this:
#RequestMapping(value="test2",method=RequestMethod.POST)
public String test2(#RequestBody TestClass req){
//Endpoint code
}
and make your call similar to this (e.g. angularjs):
http.post({url:/*url*/,data:/*object to send*/});
The second option will most likely be what you want to go with because it looks like you are trying to send a json object to your endpoint and I believe you can only do that by making a POST request rather than a GET request
Just leave out the #RequestBody annotation, as this is only for POST requests.
public String test2(#Valid TestClass req) {
return "test2";
}
When you declare a controller method parameter as #RequestBody, you are wishing it to be recovered from the request body and not as a "regular" http parameter.
You could try using any kind of plugin for Firefox (RESTClient) or Chrome (PostMan) and try using one of them. You could do it using SoapUI as well.
The request should be a POST to the requested url this way:
POST http://localhost:8080/test2
You must provide http headers provinding expected Content-Type and Accept. In case of using Json, set them like this:
Content-Type: application/json
Accept: text/html (As your method returns only a String)
And then write the param to the request body. If in Json, like this:
{
"value":"the provided value"
}
I am a newbie on Spring framework and maybe this is an easy question.
I have a link as follows and attempt Spring controller handles the value"201610061023" of this link.However,my code did not work.
I know this value can be attached as a parameter or pathvariable in path but I just curious can I pass this value implicitly?
Thank you very much.
201610061023
#RequestMapping(value = "/Order")
public String requestHandlingMethod(#ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
Spring will not handle the title of the link simply because the title of the link will not be sent by the browser. To send it you can either:
add the value as parameter: 201610061023
add the value as path variable: 201610061023
add a JavaScript that will copy the title onClick into the href or send the generated URL with document.location. This can be automated, but it's pretty uncommon.
Your a-tag is wrong, you need to submit the id, there is no implicit way to submit the link-text (except a lot of java script code)!
201610061023
#RequestMapping(value = "/Order/{orderId}")
public String requestHandlingMethod(#PathVariable("orderId") long orderId, #ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
or
201610061023
#RequestMapping(value = "/Order")
public String requestHandlingMethod(#RequestParam("orderId") long orderId, #ModelAttribute("test") String name, HttpServletRequest request) {
return "nextpage";
}
See #RequestParam vs #PathVariable for the difference between this two approaches
I want to dynamically enter my spring restful url, how to do this?
first of all, before i trying to create dynamical url, i create the static one. Here is what i do :
#RequestMapping(value = "/insert/{id}/{name}/{address}", method = RequestMethod.GET,headers="Accept=application/json")
public void insertsoheaderdinamis(#PathVariable String id, #PathVariable String name, #PathVariable String address) throws ParseException {
}
above is my static url code. in the future, what i need is, i need a new pathvariable like this localhost:8080/SpringServiceJsonSample/service/updatepool/insert/{here goes id}/{here goes name}/{here goes address}/{new variable goes phone number}/{here goes age}.
i don't want to change my code, so i decided to create a dynamic url. While i read around internet.
i trying to do this :
#RequestMapping(value = "/insert/{path}/**", method = RequestMethod.GET,headers="Accept=application/json")
public void insertdynamicurl(#PathVariable("path") String path, HttpServletRequest request) throws ParseException {
}
but this won't do, even i can't get into my function while debuging it. It always give me "noHandlerFound" in my console log. How to do the dynamically url for springrestful service properly?
You can have a look at URI Template Patterns with Regular Expressions which suggests on using regular expressions in #RequestMapping annotations.
The #RequestMapping annotation supports the use of regular expressions in URI template variables. The syntax is {varName:regex} where the first part defines the variable name and the second - the regular expression. For example:
#RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}")
public void handle(#PathVariable String version, #PathVariable String extension) {
// ...
}
}
In addition to this, you can match rest of the URL string using request attribute name HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, as shown below.
#RequestMapping("/{id}/**")
public void foo(#PathVariable("id") int id, HttpServletRequest request) {
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
Shishir's approach is good, but even the regular expression will match the value only up to a first forward slash, because the default AntPathMatcher uses a forward slash as a delimiter for path variables.
This means that you'll always have to statically list the mappings with all the possible path variable combinations. However, on the side of function arguments you don't have to list all the path variables, as you can use a map that will catch all the path variables regardless of the count, and this you can use to achieve a level of generality, something like
#RequestMapping(value = {"/insert/{id}/{name}/{address}", "/insert/{id}/{name}/{address}/{phoneNumber}", "/insert/{id}/{name}/{address}/{phoneNumber}/{age}"} , method = RequestMethod.GET,headers="Accept=application/json")
public void insertsoheaderdinamis(
#PathVariable Map<String, String> pathVariables) {
// to access the values of your path variables do something like
if (pathVariables.containsKey("id")) {
String id= pathVariables.get("id");
}
// do your stuff
}