In my Spring web application, I have an API that accepts requests with application/x-www-form-urlencoded content type.
#RequestMapping(value = "/do-it", method = {RequestMethod.POST})
public String test(#ModelAttribute("request")RequestDTO request,HttpServletRequest
httpServletRequest, Map<String, Object> model, RedirectAttributes redirectAttributes){
.....
}
My RequestDTO has following fields in it.
public class RequestDTO {
private String paramOne;
private String paramTwo;
// standard getters and setters
}
This implementation works fine, all the request params get mapped to the request dto as expected. However, now I have this requirement to accept the requests with the fields in following pattern.
param_one, param_two
I understand that, using #JsonProperty annotation on the fields in my request dto is not gonna work in my case since the request is not in the type of application/json.
The only way I have found to solve the issue is creating new setters like following (which looks ugly in my opinion when it comes to naming convention).
public void setParam_one(String param_one) {
this.paramOne = param_one;
}
Can some one help me to find a better way to get this done? I cannot change the param names in original request dto.
Thank you..!
I was able to get this done. Thanks to #neetash for guiding me.
Everything I needed to have was a Custom HandlerMethodArgumentResolver to map the post request body data to the object that I wanted to get.
I followed following linked tutorial to implement it. It contains every single thing someone needs to know to create a HandlerMethodArgumentResolver.
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/
Related
I have the following method and I need to pass List<UUID> to this Controller method.
#GetMapping("/product/{productUuidList}")
public ResponseEntity<ApiResponse<List<ProductDTO>>> getProductList(
#RequestParam List<UUID> productUuidList) {
// code omitted
}
If I pass the list parameters by separating comma, it is ok. But, I want to pass these list parameters as Json array. When I try to pass uuid parameters in Postman as shown below, I get "productUuidList parameter is missing" error.
{
"productUuidList": ["c849bcbb-c26c-4299-9ca4-dcde56830f5f", "398ec0f8-86c8-400a-93cb-caf47c1ac92d"]
}
So, how should I properly pass uuid array to this Controller method without changing #GetMapping to #PostMapping ?
It won't work like this. Here you are sending a JSON object that looks like this java POJO :
public class MyUUIDWrapper{
private List<UUID> productUuidList;
// GETTERS/SETTERS
}
So Spring is expecting to retrieve a MyUUIDWrapper object in the RequestBody
If you change your code like this it should work :
public ResponseEntity<ApiResponse<List<ProductDTO>>> getProductList(
#RequestParam MyUUIDWrapper uuids) {
NB : If you have troubles deserializing UUIDs (I've never done it before), change List to List. Not the smartest or most beautiful solution, but you can still convert them later in your controller ;)
I would like to know a simple solution for receiving images and simple data in a single post using Spring. I am a beginner in Java so I would like to know the easy way. I've used several backend frameworks and I've encountered this problem in all of them.
I have the following problem:
I was receiving a multipart/form-data like this
public CasaVenda storeCasaVendaOld(#RequestParam("dormitorios") Integer dormitorios, #RequestParam("preco") Double preco, #RequestParam("foto_1") MultipartFile foto_1){
I receive some numbers along with an image. This is a typical first attempt of beginner's implementation.Validate will require code to be writeen in the controller and I have to receive far more parameters than described here, so it's a bad implementation.
I thought about receiving a model
public CasaVenda storeCasaVenda(#Valid #RequestBody CasaVenda casa)
Now I can validate using annotations and so. The problem is with the file. Is there a simple solution to receive the file in one post request or should I split the process of seding the overall data and the files spareted? I mean I can make the process of the resource creation two steps, first it enters the overall data and afterwards it includes the photos.
Its pretty easy to define an object:
public class MyObject {
private Integer dormitorios;
private Double preco;
...
getters/setters/constructors/etc.
...
// I'm not sure whether you can place a MultipartFile here as well to process image,
// however it doesn't make sense to validate it anyway
}
Then you can use this object in the controller, it will map all the query params to the fields of the object automatically by spring:
public CasaVenda storeCasaVendaOld(MyObject myObject) {
}
Now, you can place Validation annotations inside MyObject and it will be validated, just do not use #RequestParam annotation before the object...
In my spring boot application a request comes from the client with the following URL.localhost:8080/api/invoice?invoiceNo=1234&invoiceDate=050218&invoiceNo=6543&invoiceDate=060218
How can I get the values for the request property invoiceNo and invoiceDate. I know we can always use some delimiter while building the URL and fetch it.
I would like to know if there is any springboot way for achieving this.
Any help is much appreciated.
Now when I try request.getParameter("invoiceNo") I get only the first parameter.
use List
public void invoice(#RequestParam(name="invoiceNo") List<String> invoiceNos, #RequestParam(name="invoiceDate") List<String> invoiceDates) {
In spring you can get query parameters by using the annotation #RequestParam inside controller's endpoint method like this:
#GetMapping("/invoice")
public CustomResponse getInvoiceData(
#RequestParam(value="invoiceNo") List<Long> invoiceNoList,
#RequestParam(value="invoiceDate", required = false) List<Date> invoiceDateList){
...
}
You can see another values that this annotation can get (like required, default, etc..) in the docs
As #maruthi mentioned request.getParameterValues("invoiceNumber") is one way. Another way is to add #RequestParam(value="invoiceNo", required=false) List<String> invoiceNo as the controller method parameter.
I have the following code:
#RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Void> flagDevice (#RequestBody List<MobileDeviceData> devicedataList, #RequestHeader(value="special_code") String specialCode) {
// Implementation details
}
Each instance of MobileDeviceData that gets created needs to have a param field filled in with the RequestHeader special_code.
How would I go about doing this so that it is fully populated by the time the flagDevice method body gets called?
Thanks in advance.
This is non trivial.
An HttpMessageConverter is already provided that deserializes the JSON, that's the MappingJackson2HttpMessageConverter. It has access to request headers. You could extend that class to also use the headers for deserialization (this is extremely difficult to do generically, as opposed to only for MobileDeviceData).
You could use Spring AOP, intercept the method, retrieve the arguments, cast to the appropriate types, and assign the value yourself.
The solution I would go for is the simplest: do it yourself in the handler method. Loop the the List and use a corresponding setter to set the specialCode for each MobileDeviceData.
Another option is to define your own HandlerMethodArgumentResolver specifically for List<MobileDeviceData> parameters that need to be constructed from header vales.
I'm thinking the answer here is probably no, but just in case.
I'm doing something like this:
#RequestMapping(value="data.json", params="query=overview")
public String getOverview(#RequestBody MyRequest myRequest) {
[...]
return "overview";
}
#RequestMapping(value="data.json", params="query=detail")
public String getDetail(#RequestBody MyRequest myRequest) {
[...]
return "detail";
}
and the client is POSTing JSON data, which is deserialized by Jackson on the way in and bound to the MyRequest parameter, all working nicely.
However, I don't like the query type having to be specified in the URL of the requests. What I would like is to include the query parameter in the JSON object and use that to drive the #RequestMapping. Is this possible?
If not, I guess I will implement a single mapping and have that method delegate to others based on the incoming data, but that feels like a step in the wrong direction.
What you are trying to do does not work out of the box.
If you don't like the param why don't you add the qualifier to the URL like so:
#RequestMapping("/overview/data.json")
#RequestMapping("/detail/data.json")
If you absolutely need the functionality you mention, you could implement a custom RequestMappingHandlerMapping that would do what you want by extending that class as is done here.
It's not possible if you remove the params. You have to have something distinct between the two mappings. If you are intent on getting rid of the params, best you could do is have a single method/mapping and call your services or whatever other logic you have according to what the value of query is in your MyRequest object.
#RequestMapping(value="data.json")
public String getOverviewOrDetail(#RequestBody MyRequest myRequest) {
if (myRequest.getQuery().equalsIgnoreCase("overview")) {
[...]
return "overview"
} else if(myRequest.getQuery().equalsIgnoreCase("detail")) {
[...]
return "detail"
}
}
Since both methods are unmarshalling to the same object, you don't really need two separate methods/mappings.