Use of Model object as a param in the request handling methods - spring-mvc

I just want to know
Why do we use Model object as a Parameter to the request handling method in the Spring MVC application?
Basic Explanation helps me a lot.

ModelAndView (or Model) is a specialized spring object to store name value pairs (kind of java Map). It is optional to have the Model Object as a parameter to the request method. However in case if your request method has anything that needs to be passed on to the View; then you need a Model.
So Model is basically a data structure that carries information from the service layer to the view layer.
You can also initialize a Model inside your request method as:
public ModelAndView listCarrier() {
HashMap<String, Object> model = new HashMap<String, Object>();
model.put("isView", request.getParameter("isView"));
return model;
}

You can add attribute to Model object and use that attribute inside your JSP like below.
#RequestMapping(method = RequestMethod.GET)
public String login(String name, Model model) {
model.addAttribute("name", name);
return "xyz";
}
and later on you can access this property in your xyz.jsp like below.
Name: ${name}
For more info refer :-Model API docs

Related

How to post List of Dictionary

I have a client ( in this case POSTMAN) that is posting collection of object. The properties of the object are not known in advance so I cannot use concrete C# model.
So I am using Dictionary<string,object> that represent a single object where Key will be the property name and Value will be the value of the property. Since client is posting collection i am using List<Dictionary<string,object>>
ISSUE
In controller's action method each dictionary has Key however corresponding value is NULL
POSTMAN
Fiddler shows
model%5B0%5D.FirstName=foo&model%5B0%5D.LastName=bar&model%5B1%5D.FirstName=james&model%5B1%5D.LastName=smith
Quick watch in model:
I tried using JObject, ExpandoObject as model with no luck
I changed the model type from List<Dictionary<string, object>> to List<Dictionary<string, string>> and it worked
[HttpPost]
public IActionResult Update([FromForm]List<Dictionary<string, string>> model)
{
return Ok();
}

Spring MVC #ModelAttribute method

Question about Spring MVC #ModelAttribute methods, Setting model attributes in a controller #RequestMapping method verses setting attribute individually with #ModelAttribute methods, which one is considered better and is more used?
From design point of view which approach is considered better from the following:
Approach 1
#ModelAttribute("message")
public String addMessage(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("addMessage - " + userName);
return "Spring 3 MVC Hello World - " + userName;
}
#RequestMapping(value="/welcome/{userName}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("printWelcome - " + userName);
return "hello";
}
Approach 2
#RequestMapping(value="/welcome/{userName}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("printWelcome - " + userName);
model.addAttribute("message", "Spring 3 MVC Hello World - " + userName);
return "hello";
}
The #ModelAttribute annotation serves two purposes depending on how it is used:
At Method level
Use #ModelAttribute at the method level to provide reference data for the model. #ModelAttribute annotated methods are executed before the chosen #RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through #ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.
In other words; a method annotated with #ModelAttribute will populate the specified “key” in the model. This happens BEFORE the #RequestMapping
At Method Parameter level
At Method Parameter level
When you place #ModelAttribute on a method parameter, #ModelAttribute maps a model attribute to the specific, annotated method parameter. This is how the controller gets a reference to the object holding the data entered in the form.
Examples
Method Level
#Controller
public class MyController {
#ModelAttribute("productsList")
public Collection<Product> populateProducts() {
return this.productsService.getProducts();
}
}
So, in the above example, “productsList” in the Model is populated before the the #RequestMapping is performed.
Method parameter level
#Controller
public class MyController {
#RequestMapping(method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("product") Product myProduct, BindingResult result, SessionStatus status) {
new ProductValidator().validate(myProduct, result);
if (result.hasErrors()) {
return "productForm";
}
else {
this.productsService.saveProduct(myProduct);
status.setComplete();
return "productSaved";
}
}
}
Look here for detailed information with examples.
One is not better then the other. They both serve another purpose.
Method: If you need the model for a particular controller to be always populated with certain attributes the method level #ModelAttribute makes more sense.
Parameter: Use it on a parameter when you want to bind data from the request and add it to the model implicitly.
To answer your question on the better approach
I would say approach 2 is better since the data is specific to that handler.

spring controller convention to use

There are 2 formats for writing controller handlers in spring.
Could someone help summarizing what determines the format to be used.
Also whats the format of preference?
Being a new-bie,this would help being on teh right track.
Option 1:
#RequestMapping(value=".....", method=RequestMethod.GET)
public String loadFormPage(Model m) {
m.addAttribute("subscriber", new Subscriber());
return "formPage";
}
#RequestMapping(value="....", method=RequestMethod.POST)
public String submitForm(#ModelAttribute Subscriber subscriber, Model m) {
m.addAttribute("message", "Successfully saved person: " + subscriber.toString());
return "formPage";
}
Option 2:
#RequestMapping(value=".....")
public ModelAndView personPage() {
return new ModelAndView("person-page", "person-entity", new Person());
}
#RequestMapping(value=".....")
public ModelAndView processPerson(#ModelAttribute Person person) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("person-result-page");
modelAndView.addObject("pers", person);
return modelAndView;
}
A controller method in Spring can support zero-to-many input parameters, and the principal mechanisms in Spring for specifying input parameters are the #RequestParam and the #ModelAttribute annotations.
The #RequestParam annotation is used to bind individual request parameters, like string and integers, to method parameters in the controller.
The #ModelAttribute annotation is used to bind complex objects, like domain objects, data transfer objects and/or form backing objects, to method parameters in a controller.
The annotaton is determined by the variable type.
primitive variables will be annotated with #RequestParam
complex variables will be annotated with #ModelAttribute
The annotation name is derived from the variable name
A controller method in Spring can also output model data, and the principal mechanism in Spring for specifying output model data is the ModelAndView object.
In the event that there isn't any data to be returned by the method, the controller method can simply return a String that represents the view that should be rendered.
If the controller method does return data, then a ModalAndView object needs to be instantiated and each output variable is added as a model attribute to the ModelAndView object.

spring auto populate user details for every request

I have a spring MVC based web application. Currently in my web page i am showing the user first name and last name after user logs in. The way i am doing this is, for every HttpServletRequest that comes into #Controller#RequestMapping, i get the Principal object and get the user details from it, then populate the ModelMap with firstname and lastname attribute. For example here is the sample code
#Autowired
private SecurityDetails securityDetails;
#RequestMapping(method = RequestMethod.GET)
public String showWelcomePage(HttpServletRequest request,
HttpServletResponse response, ModelMap model, Principal principal)
{
securityDetails.populateUserName(model, principal);
... lot of code here;
return "home";
}
public boolean populateUserName(ModelMap model, Principal principal) {
if (principal != null) {
Object ob = ((Authentication)principal).getPrincipal();
if(ob instanceof MyUserDetails)
{
MyUserDetails ud = (MyUserDetails)ob;
model.addAttribute("username", ud.getFirstName() + " " + ud.getLastName());
}
return true;
}
else
{
logger.debug("principal is null");
return false;
}
}
My problem is i am having to call the populateUserName method for every RequestMapping. Is there a elegant way, like populating this in Interceptor method, which will result in this method being called just in one place for entire application?
Its good that you want to prevent duplication of code. Here is how you can do it.
Create a custom HandlerInterceptor http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/HandlerInterceptor.html
Post handle is the only method of interest for us, for the others return defaults.
In the post handle method, you have access to the model and view returned from your controller, go ahead and add whatever you want.
The Principal will not be available directly here, you will have to look it up using some code like SecurityContextHolder.getContext().getAuthentication().getPrincipal()
Wire the handler interceptor to intercept all or some of your controllers.
Hope this helps.
You can use either Servlet Filters or Spring Interceptors.
BTW, where do you populate the Principal from?
In any case, thats where you should do this populating stuff.

What does it mean when Spring MVC #Controller returns null view name?

I downloaded the code for the Spring MVC 3 Showcase. One thing puzzles me (well, more than one), why does this (edited for concision) sample return null?
#Controller
#RequestMapping("/form")
public class FormController {
#RequestMapping(method=RequestMethod.POST)
public String processSubmit(#Valid FormBean form,
BindingResult result,
WebRequest webRequest,
HttpSession session, Model model) {
if (result.hasErrors()) {
return null;
} else {
session.setAttribute("form", form);
return "redirect:/form";
}
}
}
If a controller returns a null view name, or declares a void return type, Spring will attempt to infer the view name from the request URL.
In your case, it will assume the view name is form, and proceed on that assumption.
It does this using an implementation of RequestToViewNameTranslator, the default implementation of which is DefaultRequestToViewNameTranslator, the javadoc for which explains the exact rules it applies.
AnnotationMethodHandlerAdapter.invokeHandlerMethod() takes care of invoking handler methods. Here, a ModelAndView will be retrieved via ServletHandlerMethodInvoker.getModelAndView().
In your case, getModelAndView() gets provided the handler method's null return value. The getModelAndView() method checks for the return value's type, but as in Java null is never an instanceof any class, that method's logic will create a new ModelAndView. A new ModelAndView has initially its view property set to null.
Then later back up the call stack, in DispatcherServlet.doDispatch(), there is a test if the ModelAndView object has a View associated with it ( mv.hasView() ). Because view == null, doDispatch()'s logic calls mv.setViewName(getDefaultViewName(request)). It delegates to the registered RequestToViewNameTranslator, whose default implementation is DefaultRequestToViewNameTranslator. This subclass translates the request URI into a view name, in your case form.
Later in doDispatch(), via render() -> resolveViewName(), this sample's ViewResolvers are provided with the view name form. Only one ViewResolver, InternalResourceViewResolver is used in this sample. Also, this InternalResourceViewResolver was configured in src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml to add the prefix /WEB-INF/views/ and the suffix .jsp to the view name. So in total, it will create a View using the JSP file /WEB-INF/views/form.jsp. Luckily, a JSP file exists at exactly this location.

Resources