I am implementing a web service using spring boot 1.3.6. In my controller, I have a method like:
#RequestMapping(value = "/employees/{id}", method = RequestMethod.PUT)
createEmployee(#PathVariable String id,
#QueryParam(required = false, value = "department") Set<String> departments)
I want to collect the request parameters in a class like:
class EmployeeParams {
public String id;
public Set<String> departments;
}
I tried using:
#RequestMapping(value = "/employees/{id}", method = RequestMethod.PUT)
createEmployee(EmployeeParams param) { ... }
But it does not work. I get the id in above class but not departments. What is the proper way of collecting the request parameters in Spring requests?
You should add a custom converter that implements Spring org.springframework.core.convert.converter.Converter<String, EmployeeParams> and register it with Spring.
See Spring documentation.
This stack overflow issue also discusses some details on adding a custom converter or formatter.
Related
I am a newbie in Spring development. I need to create a simple application, a controller that has a method that takes as parameter an object of a custom designed entity class into the project. The prototype looks like this:
#RestController
public class JobsController {
#PostMapping("/search")
public ResponseEntity<?> search() {
log.info("JobsController -> search method");
//JobSearchEntity jobSearchEntity = modelMapper.map(jobSearch, JobSearchEntity.class);
List<JobEntity> jobs = jobService.searchJobs();
//log.info(String.format("Job found: %s ", jobSearch));
return ResponseEntity.ok(jobs);
}
}
Can someone who is more advanced into this staff with Postman testing tell me how to do that , how to test a controller method which takes parameters?
You can use postman to submit parameters in JSON format after adding # requestbody annotation on the method, or submit parameters directly in form without annotation
You can use this example. Is very simple exemple.
#RestController
#RequestMapping("/root")
public class RootController {
private final RootService service;
public RootController(final RootService service) {
this.service = service;
}
#PostMapping("/exemple")
public void createRoot(#RequestBody final RootDto dto) {
service.createRoot(dto);
}
}
Then you can send request to POST host/root/exemple with your JSON.
More exampls you can find here: https://www.baeldung.com/spring-request-response-body
It seems you are missing an honest search on google about the subject.
You can make use of #RequestBody annotation to accept method arguments.
Check these page for examples --
#RequestBody and #ResponseBody annotations in Spring
https://stackabuse.com/get-http-post-body-in-spring/
https://www.twilio.com/blog/create-rest-apis-java-spring-boot
These set of playlist on youtube are very good starter course for SpringBoot -
https://www.youtube.com/c/JavaBrainsChannel/playlists
Postman Tutorial--
https://www.youtube.com/watch?v=VywxIQ2ZXw4
To get data from api is preferred to use GET method :
#RestController
public class JobsController {
#GetMapping("/search")
public ResponseEntity<?> search(#RequestParam("id") String id,#RequestParam("desc") String desc) {
log.info("JobsController -> search method");
//JobSearchEntity jobSearchEntity = modelMapper.map(jobSearch, JobSearchEntity.class);
List<JobEntity> jobs = jobService.searchJobs();
//log.info(String.format("Job found: %s ", jobSearch));
return ResponseEntity.ok(jobs);
}
}
you call this api with post man this way :
#PostMapping used usually to save new data (example : create job )
Take look on rest resource naming guide
I should migrate some code from jax-rs to spring mvc. We had a controller, which response with an object and set at the same time links in a list :
HateoasResponse.ok(content)
.selfLink(FieldPath.path("categories"), "some_controller_id", "id")
.build()
Did any one know, if there is something similar in spring mvc ?
I have checked spring-hateoas. If I use it , I should modify my models to something supported by this package (CollectionModel, EnitityModel..)
You have to make the response object extend ResourceSupport and then generate the links as follows.
org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(methodOn(YourSpringMvcController.class)
.methodWhichHasMappingTo(param1,param2,paramN))
.withRel("relationOfThisLinkToTheRequestedResource").expand();
This link can then be added to the response object using the resource add method.
for example, let's say you have a controller like the following:
#RestController
public class OrderController {
#GetMapping(value = "/orders/{orderId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Order> getOrder(#Valid #PathVariable Integer orderId) {
return getOrder(orderId);
}
#DeleteMapping(value = "/orders/{orderId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Order> deleteOrder(#Valid #PathVariable Integer orderId) {
return orderRepo.deleteOrder(orderId);
}
}
then for a request to GET orders, you would build the response like the following:
Order which is a response entity will extend ResourceSupport
public Order getOrder(int orderId){
Order order = repo.findByOrderId(orderId);
Link deleteLink = ControllerLinkBuilder.linkTo(methodOn(OrderController.class)
.deleteOrder(orderId))
.withRel("delete").expand();
order.add(deleteLink);
Link selfLink = ControllerLinkBuilder.linkTo(methodOn(OrderController.class)
.getOrder(orderId))
.withSelfRel();
order.add(selfLink);
return order;
}
Hope this helps.
I want to build a simple endpoint that returns an Order object where I can search for this order by a single query parameter or a combination of several query parameters altogether. All of these query parameters are optional and the reason is that different people will access these orders based on the different Ids.
So for example:
/order/items?itemId={itemId}&orderId={orderId}&deliveryId={deliveryId}&packetId={packetId}
#GetMapping(path = "/order/items", produces = "application/json")
public Order getOrders(#RequestParam Optional<String> itemId,
#RequestParam Optional<String> orderId,
#RequestParam Optional<String> deliveryId,
#RequestParam Optional<String> packetId) { }
I could of course also skip the Java Optional and use #RequestParam(required = false), but the question here is rather how do I escape the if-else or .isPresent() nightmare of checking whether the query params are null? Or is there an elegant way, depending on the constellation of params, to pass further to my service and Spring Data JPA repository.
To minimize the amount of parameters in your method, you could define your query parameters as fields of a class:
#Data
public class SearchOrderCriteria {
private String itemId;
private String orderId;
private String deliveryId;
private String packetId;
}
Then receive an instance of such class in your controller method:
#GetMapping(path = "/order/items", produces = "application/json")
public ResponseEntity<OrderInfo> getOrder(SearchOrderCriteria searchCriteria) {
OrderInfo order = orderService.findOrder(searchCriteria)
return ResponseEntity.ok(order);
}
And, in your service, to avoid a bunch of if-else, you could use query by example:
public OrderInfo findOrder(SearchOrderCriteria searchCriteria) {
OrderInfo order = new OrderInfo();
order.setItemId(searchCriteria.getItemId());
order.setOrderId(searchCriteria.getOrderId());
order.setDeliveryId(searchCriteria.getDeliveryId());
order.setPacketId(searchCriteria.getPacketId());
Example<OrderInfo> example = Example.of(order);
return orderRepository.findOne(example);
}
My small suggestion is avoid to use too general API, for example you can split your mapping into several endpoints eg:/order/delivery/itemId/{itemId} and /order/delivery/deliveryId/{deliveryId} and /order/delivery/packetId/{packetId} and handle which you need to call on client side.
I want to receive a Map<Timestamp, Integer> as PathVariable using Spring MVC. Is this possible?
This is my controller:
#ApiOperation(value = "Some Api", produces = MediaType.APPLICATION_JSON_VALUE)
#PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<RestResult> createApi(#RequestPart (value="image", required = false) MultipartFile banner, SomeRequest request){
RestResult result = new RestResult();
return new ResponseEntity<>(result, HttpStatus.CREATED);
}
This is my request:
#Getter
#Setter
public class SomeRequest implements Serializable {
#NonNull
private MultiValueMap<Timestamp, Integer> someValue;
}
As one of the way you could use Spring's HandlerMethodArgumentResolver and implement its supportsParameter() and resolveArgument() methods. The last one accepts the method parameter and web request, which you can use to get any required data and compose the object whatever you want.
The argument resolver is invoked before the controller method and makes the required argument transformation.
Update:
You have to register the resolver to make it active. If you use spring-boot, you just need to define it as a bean.
Hope it will help.
I'm new to Spring, and since Spring provides many ways to map an HTTP request to Java objects, I'm hoping someone could advice me how to resolve this:
I have a client that sends a request having
ContentType: application/x-www-form-urlencoded
Some of the request parmeters have names such as
"form_data[orderStatus]", "form_data[orderNumber]", etc'
I have no control over this client!
I have a java class (#Component) called MyOrder which looks as follows:
#component
#Scope("prototpe")
public class MyOrder {
private String orderStatus;
private String orderNumber;
//etc'
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
//public setter for all other properties, as the above
}
What is the simplest way to create an instance of MyOrder
populated with all values of all "form_data[]", so that I can have a controller method having a signature that includes a MyOrder parameter, such as:
public ModelAndView saveNewOrder( #RequestParam("foo") String foo,
#ModelAttribute("myOrder") MyOrder anOrder) {
//... impl'n here
}
The best solution I could think of was to use a Web Filter which would flaten request params names such as "form_data[attrib1]" to "attrib1", and then Spring would do all the work of populating the MyOrder instance.
One disadvantage of this is that the request may have both "form_data[attrib1]" and "attrib1" parameters. For example:
form_data[orderStatus]=ok
orderStatus=fail
In this case i want MyOrder.orderStatus to have the value "ok".
Any good way of utilizing Spring create MyOrder from the request?
As an alternative, that does not use the class MyOrder, is there a way to have Spring map all the form_data[] parameters and their values to a map, so that i can have the controller method below?
public ModelAndView saveNewOrder( #RequestParam("foo") String foo,
<some annotation> #Map<String,String> formFieldsOfAnOrder) {
//... impl'n here
orderStatus = formFieldsOfAnOrder.get("orderStatus");
//or at least:
orderStatus = formFieldsOfAnOrder.get("form_data[orderStatus]");
}