how to configure spring-data-rest search method path with #PathVariable - spring

I want to customize my spring-data-rest search method path by passing parameter as a path variable like follows
http://localhost:8080/orders/search/customers/{customerId}
findByCustomer(#PathVariable("customerId") Integer customer);
The search resource listh the links as follows
http://localhost:8080/orders/search/customers/%7BcustomerId%7D
How to expose search url with path params?

You can use custom handler similar to this:
#RepositoryRestController
public class OrderController {
#Autowired
OrderRepository orderRepository;
#GetMapping("/orders/search/customers/{id}")
public #ResponseBody ResponseEntity<?> getByCustomers(#PathVariable Integer customer) {
Order order = orderRepository.findOne(id);
if(order == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
Resource<Order> resource = new Resource<Order>(order);
return ResponseEntity.ok(resource);
}
}
More about this can be found here.

Use HttpServletRequest to get the request url:
findByCustomer(#PathVariable("customerId") Integer customer, HttpServletRequest request){
String request = request.getRequestURL().toString(); // StringBuffer, so use append if you want to...
[...]
}
also you can use request.getQueryString() to get the query part after ?.

Related

Access absolute path of resource when using #RequestMapping in spring boot controller

I am using #RquestMapping for mapping url to controller method.
#RestController
#RequestMapping(path = "/api/tasks")
public class TaskController { ....
and methods inside controller have /{id} with request mapping annotations.
#RequestMapping(
path = "/{taskId},
method = RequestMethod.GET
)
public Map<String, Object> methodOne(...
I want to access http method and absolute path (configured path) for that method inside.
i.e. I want to get /api/tasks/{taskId} as value (not the /api/tasks/1 if api is called for task id 1) and GET as method inside of the methodOne.
I checked the HandlerMapping but it returns actual path of resource called by client. Not the configured path for the method / resource.
Any help or guidance would be highly appreciated. Thank you.
String[] pathReqMappingAnnotationOnControllerClass = this.getClass().getAnnotation(RequestMapping.class).path();
Method method = TaskApiController.class.getMethod("getListOfTasks", HttpServletRequest.class, HttpServletResponse.class);
String[] pathReqMappingAnnotationOnControllerMethod = method.getAnnotation(RequestMapping.class).path();
String wholePath = pathReqMappingAnnotationOnControllerClass[0] + pathReqMappingAnnotationOnControllerMethod[0];
//pathReqMappingAnnotationOnControllerMethod will be empty array if method is not annotated for path
#RequestMapping(path = "/{id}", method = [RequestMethod.DELETE])
public void test(#PathVariable("id") String id, HttpServletRequest request) {
\\ Code Here
}
In the method parameter, id is the pathVariable. And request method is accessible in the request variable (Although I do not know what is the point as you are limiting it to only accept GET requests)
As suggested by #codedetector, best option is if you have request object or you can add one if you dont have it.
#RequestMapping(path = "/{taskId}, method = RequestMethod.GET)
public String methodOne(HttpServletRequest request){
String test = request.getRequestURI();
return test;
}
If you dont have request object in your method, with below code you can get any URL on your system.
import org.springframework.hateoas.mvc.ControllerLinkBuilder
...
ControllerLinkBuilder linkBuilder = ControllerLinkBuilder.linkTo(methodOn(YourController.class).getSomeEntityMethod(parameterId, parameterTwoId))
URI methodUri = linkBuilder.Uri()
String methodUrl = methodUri.getPath()
--------Edit
I am not sure why you need in this format "/api/tasks/{taskId}" as value (not the /api/tasks/1 )but i can think of using a constant use it for your #RequestMapping path parameter and then easily after getting absolute path , replace/append it with that constant.
String pathParam ="/{taskId}"
#RequestMapping(path = "/{id}", method = [RequestMethod.DELETE])
public void test(#PathVariable("id") String id, HttpServletRequest request) {
switch(id){
case 1:
method1();
break;
case 2:
method2();
break
....
....
}
}
private void method1(){};
private void method2(){};
private void method3(){};

DTO has only null with GET request params, but not POST #RequestBody

I'm trying to get my query params in a DTO like in this question but my DTO has always null value.
Is there anything wrong in my code ? I made it as simple as possible.
Queries:
GET http://localhost:8080/api/test?a=azaz => null
POST http://localhost:8080/api/test with {"a":"azaz"} => "azaz"
Controller with a GET and a POST:
#RestController
#RequestMapping(path = {"/api"}, produces = APPLICATION_JSON_VALUE)
public class MyController {
// GET: dto NOT populated from query params "?a=azaz"
#RequestMapping(method = GET, path = "test")
public #ResponseBody String test(TestDto testDto){
return testDto.toString(); // null
}
// POST: dto WELL populated from body json {"a"="azaz"}
#RequestMapping(method = POST, path = "test")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString(); // "azaz"
}
}
DTO:
public class TestDto {
public String a;
#Override
public String toString() {
return a;
}
}
Thanks !
Full Spring boot sample to illustrate it
The problem is that you are missing setter for the field.
public void setA(String a) {
this.a = a;
}
should fix it.
I'm assuming that you have done required configuration like having Jackson mapper in the class path, consume json attribute, getter and setter in DTO classes etc.
One thing missed here is, in RequestMapping use value attribute instead of path attribute as shown below
#RequestMapping(method = POST, value= "/test", consumes="application/json")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString();
}
And, make sure that you set content-type="application/json" while sending the request
I think what you are trying to do is not possible. To access the query Parameter you have to use #RequestParam("a"). Then you just get the String. To get your object this way you have to pass json as Parameter. a={"a":"azaz"}
Kind regards

Map #CookieValue, #RequestHeader etc. to POJO in Spring Controller

I have a bunch of params in my controller and want to map all of them to a separate POJO to keep readability. There is also a #CookieValue, #RequestHeader I need to evaluate and aim for a solution to also map them to that POJO. But how?
I saw a possible solution on a blog but it doesn't work, the variable stays null.
Controller:
#RequestMapping(path = MAPPING_LANGUAGE + "/category", produces = MediaType.TEXT_HTML_VALUE)
#ResponseBody
public String category(CategoryViewResolveModel model) {
doSomething();
}
And my POJO is this:
public class CategoryViewResolveModel {
private String pageLayoutCookieValue;
public CategoryViewResolveModel() {
}
public CategoryViewResolveModel(
#CookieValue(value = "SOME_COOKIE", required = false) String pageLayoutCookieValue) {
this.pageLayoutCookieValue = pageLayoutCookieValue;
}
... some other RequestParams, PathVariables etc.
}
According to the documentation it's not possible for #CookieValue and #RequestHeader.
This annotation is supported for annotated handler methods in Servlet
and Portlet environments.
Take a look at:
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/
instead of using getParameter to access request parameters you can use getHeader to retrieve the header value and so define your CategoryViewResolveModel just as you were requesting

Spring MVC parse web url Object

I have a GET request in the format below
http://www.example.com/companies?filters=%7B%22q%22%3A%22aaa%22%7D
After decode it is
filters={"q":"aaa"}
I have created an Object named Filters as below
public class Filters {
private String q;
//getter setter....
}
and in my controller
#RequestMapping(method = RequestMethod.GET)
public List<CompanyDTO> getCompanies(Filters filters) {
filters.getQ();
//do things
}
However, the filters.getQ() is null.
Am I doing something incorrect here?
You need to associate the request parameter to the method argument. Add #RequestParam to your method i.e.
#RequestMapping(method = RequestMethod.GET)
public List<CompanyDTO> getCompanies(#RequestParam(value="filters") Filters filters) {
filters.getQ();
//do things
}
Instead of #RequestParam, use #RequestBody
Instead of String filters=%7B%22q%22%3A%22aaa%22%7D, pass JSON object as parameter http://www.example.com/companies?filters={"q":"aaa"}

how to capture multiple parameters using #RequestParam using spring mvc?

Suppose a hyperlink is clicked and an url is fired with the following parameter list myparam=myValue1&myparam=myValue2&myparam=myValue3 . Now how can I capture all the parameters using #RequestParam in spring mvc?
My requirement is I have to capture all the params and put them in a map.
Please help!
#RequestMapping(value = "users/newuser", method = RequestMethod.POST)
public String saveUser(#RequestParam Map<String,String> requestParams) throws Exception{
String userName=requestParams.get("email");
String password=requestParams.get("password");
//perform DB operations
return "profile";
}
You could use RequestParam in the above mentioned manner.
It seems you can't get
Map<String,String>
because all your params have same name "myparam"
Try this instead:
public ModelAndView method(#RequestParam("myparam") List<String> params) { }
To get all parameters at once try this:
public ModelAndView postResultPage(#RequestParam MultiValueMap<String, String> params)
This feature is described in the #RequestParam java doc (3. Paragraph):
Annotation which indicates that a method parameter should be bound to a web request parameter. Supported for annotated handler methods in Servlet and Portlet environments.
If the method parameter type is Map and a request parameter name is specified, then the request parameter value is converted to a Map assuming an appropriate conversion strategy is available.
If the method parameter is Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.
As of Spring 3.0, you can also use MultiValueMap to achieve this:
A rudimentary example would be:
public String someMethod(#RequestParam MultiValueMap<String,String> params) {
final Iterator<Entry<String, List<String>>> it = params.entrySet().iterator();
while(it.hasNext()) {
final String k = it.next().getKey();
final List<String> values = it.next().getValue();
}
return "dummy_response";
}
If anyone is trying to do the same in Spring Boot, use RequestBody in place of RequestParam
Spring mvc can support List<Object>, Set<Object> and Map<Object> param, but without #RequestParam.
Take List<Object> as example, if your object is User.java, and it like this:
public class User {
private String name;
private int age;
// getter and setter
}
And you want pass a param of List<User>, you can use url like this
http://127.0.0.1:8080/list?users[0].name=Alice&users[0].age=26&users[1].name=Bob&users[1].age=16
Remember to encode the url, the url after encoded is like this:
http://127.0.0.1:8080/list?users%5B0%5D.name=Alice&users%5B0%5D.age=26&users%5B1%5D.name=Bob&users%5B1%5D.age=16
Example of List<Object>, Set<Object> and Map<Object> is displayed in my github.
You can use for multiple Params as such
public String saveUser(#RequestParam("email") String userName, #RequestParam("password") String password) throws Exception{
//your code
//perform DB operations
return "profile";
}
For params with same name, you can use MultiValueMap<String ,String>. Then all the values would be present as List
You can use multiple #RequestParam annotations as shown below.
#RequestParam(value="myparam1", required = true) <Datatype> myparam1,
#RequestParam(value = "myparam2", required = false) <Datatype> myparam2,

Resources