spring MVC request param auto mapping complex object - java

I have seen similar answer here:
Spring MVC: Complex object as GET #RequestParam
Spring map GET request parameters to POJO automatically
I really can't find document of this because this auto mapping is not even done by any annotation. (it doesn't even need #RequestParam in fact)
1) so far I only see simple mapping, the object contain all primitive data, how about if my request is a complicated JSON object which contain several level of attributes (a object contain other objects)? Will the auto-mapping still work?
2) so far I only see Spring controller can take in one auto-map object, can I let it auto-map more than one object? For example:
public #ResponseBody List<MyObject> myAction(MyObject myObject,
MyObject2 myObject2) { ... }
Anyone know where is the document to describe how the mapping work behind the scene? Based on my second question, if Spring allow to do such thing, what if I have same attributes name in MyObject and MyObject2, how the mapping will do?

If you do things like this:
public #ResponseBody List<MyObject> myAction(#RequestBody MyObject myObject) { ... }
Of course you can only have one body in your http request.
As long as you have Jackson in your classpath (spring boot will add this automatically) your objects will be marshalled correctly.
If the JSON in your body is incorrect you will get a 400 (Invalid Request) returned.

Related

Spring Boot Controller Multiple parameters (<List> and multipart file) object

Hello i am looking if i can handle with only one RestController method multiple params...
with controllers method it could be done... but i couldnt find project with 2 like that.
#PostMapping(value ="upload")
public upload(#RequestParam MultipartFile file,#RequestParam List<String> myParams ){
some code here ....
return;
}
I am just wondering if is also a good practise ... having two deferent type of objects in same controller and if its possible,,, any idea????
Simple answer: Yes, that's possible.
But as you asked for good practice, here's some context:
It is very helpful to understand how HTTP actually transports data.
If your request uses GET as request method, parameters are added to the URL as a query string. That could look like this: http://example.com/index?param1=value1&param2=value2
In this case, Spring maps the key-value pairs from the query string to your method arguments. But this will only work for text.
If you're using POST, the data is sent inside the request body. How that is encoded depends on the media type of your data. For example, the default media type application/x-www-form-urlencoded would encode the data to the same query string as above.
If you want to upload mixed-type form data like a file/blob along with some textual parameters, your data should be encoded with multipart/form-data.
As long as the request body contains a key-value format, Spring Boot will still be able to distinguish and map the parameters via #RequestParam (If the keys don't differ from your attribute names, you don't even need to assign a name to the value attribute).
I highly recommend you to take a look at the #RequestBody and #RequestPart annotations as i think it often is best practice to use a model class (DTO) for the whole request body (or rather the form, semantically), especially if there are a lot of parameters to process.
You will need to specify the names of the variables.
#PostMapping(value ="upload")
public upload(
#RequestParam(value = "file") MultipartFile file,
#RequestParam(value = "myParams") List<String> myParams
){
some code here ....
return;
}

Spring Test MVC : How to use object as Request Parameters

I am trying to write Spring MVC Tests to test Spring controllers.
Currently if I wanted to test a controller method with this signature:
#RequestMapping(value = "/new/save", method = RequestMethod.POST)
#Transactional
public String postGateway(#Valid GatewayForm gatewayForm, BindingResult bindingResult, RedirectAttributes flash, Model model)
I would use MockMVC in this manner to populate the GatewayForm object parameter:
mvc.perform(
post("/new/save")
.sessionAttr("account", account)
.param("serialNumber", "SN1QRTY334V")
.param("branchId", "1")
.param("model", "1")
.param("templateId", "1")
The problem with this is that I can only set String/primitive values onto the GatewayForm object using the .param(String, String) method.
So there are object instance variables on the GatewayForm above that I cannot set. I have seen other people instead post a JSON string of the object, but this would require changing the implementation of the controller methods to consume "application/json" which I do not want to do.
Can anybody advise?
As the comments to the question state that strings are essentially the input for HTTP requests parameters, the goal is to convert your form object into an accepted string.
Looking at the spring-mvc-test-utils library there are multiple strategies to converting an object into a String. However, the default strategy for converting an object into a String within the source code is to use:
String.valueOf(Object object)
For example my use case was to pass a List as parameters into my integration test. My controller accepts an object with attributes:
public class MyObjectThatTheControllerExpects {
List<SomeEnum> listOfEnums;
Long id
...
Therefore, my integration test posts the parameters like so:
mvc
.perform(
post("/some/endpoint")
.param("listOfEnums", String.valueOf(SomeEnum.SOMEENUMCONSTANT), String.valueOf(SomeEnum.SOMEOTHERENUMCONSTANT))
.param("id", "100")
I am sure this may not be appropriate for more complex classes. However, for this trivial case it works.
Hope it helps!

binding and working of spring form with the back end object in SpringMVC

I am new to SpringMvc. Could anyone please explain the binding and working of spring form with the back end object in SpringMVC.
some of the doubts are
Consider the scenario, there is a form which will take user details and it will be persisted to db
1) I have seen a controller which creates User's instances and adding the attribute to ModelMap. What is the use of that?
#Controller
#RequestMapping("/form.html")
public ModelAndView form(ModelMap map){
User user= new User();
map.addAttribute("user",user);
return new ModelAndView("form","command",map);
}
2) What is the use of command here? in the form page, this 'user' object will be available?
*form.jsp
<form:form.... action="formprocess.html" commandName="user"/>
(If I want to use 'user' should it have been already created as above?)
3) Why do we use #ModelAttribute? Why do we use Model instead of ModelMap?
#Controller
#RequestMapping("/formprocess.html")
public String form(#ModelAttribute("user"User user,Model model){
model.addAttribute("username",user.getUserName());
return "formprocess";
}
could anyone please explain or provide a link which has sufficient explanations
Regarding ModelMap, model map is used to pass certain data from you controller to the view which you delegate from that controller. You add attributes from controller and later on get attributes from view page.
Regarding commandName, commandName="user" this is something that the controller uses to map the form fields to a particular bean or POJO fields. So you do not have to manually get all the request parameters and set it yo pojos when a form is submitted and controller receives the event.
Regarding #ModelAttribute, since you use #ModelAttribute("user") as method parameter, spring container will look for a a command name user from request object and map it's properties to the pojos defined in #ModelAttribute viz in your case User class.
Regarding difference between Model and ModelMap :
ModelMap subclasses LinkedHashMap, and provides some additional conveniences to make it a bit easier to use by controllers
addAttribute can be called with just a value, and the map key is then inferred from the type.
The addAttribute methods all return the ModelMap, so you can chain method called together, e.g. modelMap.addAttribute('x', x).addAttribute('y',y)
The addAttribute methods checks that the values aren't null
The generic type of ModelMap is fixed at Map<String, Object>, which is the only one that makes sense for a view model.
So nothing earth-shattering, but enough to make it a bit nicer than a raw Map. Spring will let you use either one.
You can also use the Model interface, which provides nothing other than the addAttribute methods, and is implemented by the ExtendedModelMap class which itself adds further conveniences.

Spring MVC - Is it possible to receive a strongly typed request object on a GET?

I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}

What annotations and configuration I should make to parse JSON object

I have a request(POST or GET), having one variable "data" (coming from Xcode)
now data have assigned JSON object
data={"method":"Auth","action":"login"}
now I have a bean having exactly these two fields(i.e. method,action)
now in Spring controller I have method "login".
I want this method to be invoked based on value in "action" of the request JSON object.
Now, I'm not getting what exactly types of annotation i should use.
Please help..
You need to add Jackson to the classpath, and add <mvc:annotation-driven> to your Spring context, then Spring will automatically register a MappingJacksonHttpMessageConverter for JSON Objects.
Now Annotate your method like this:
#ResponseBody
#RequestMapping("/some/path")
public YourResponseObject someName(#RequestBody YourRequestObject data){
// do something here
}
(Both YourRequestObject and YourResponseObject will be automatically converted to and from JSON, but this works only for POST requests AFAIK)

Categories

Resources