Spring MVC #ModelAttribute method - spring-mvc

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.

Related

get or pass values from jsp to spring mvc controller with #RequestParam("VIEW") annotation

Hi everyone I'm trying to get or pass the values from my JSP to my controller because I want to write a method whose main function will be to save a new user in the database but I got an error like this:
(((java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/myPath] versus [VIEW])))
I guess this two annotations, first in the class declaration #RequestMapping("VIEW") and the second in the method declaration for save the new user
#RequestMapping(value="/saveUser", method = RequestMethod.POST)
are in conflict by the use of the same annotation in tow times at the same controller but I have to say that I´ve been tried to remove the #RequestMapping annotation in the class declaration and after that, I get a different error like this:
(((java.lang.IllegalStateException: No portlet mode mappings specified - neither at type nor at method level)))
I don't know if I can use as many necessary controllers for differents operations as I will need, if I can, I will be happy to know the correct way to implement with this technique
Here is my controller:
#Controller
#RequestMapping("VIEW")
public class UsersController {
User currentUser = null;
#RenderMapping
public ModelAndView view(RenderRequest request, RenderResponse response)throws Exception {
ModelAndView modelView = new ModelAndView();
UserDTO usuarioAdd = new UserDTO();
//blah, blah, blah...
return modelView;
}
#RequestMapping(value="/saveUser", method=RequestMethod.POST)
public void saveUser(HttpServletRequest request) {
logger.info("***SAVE USER***);
System.out.println("***SAVE USER***);
}
}

Spring MVC #Validation with Marker Interface in Generic Controller Method

I have a Spring MVC survey application where the Controller method called by each form POST is virtually identical:
#PostMapping("/1")
public String processGroupOne (
Model model,
#ModelAttribute("pageNum") int pageNum,
#ModelAttribute(GlobalControllerAdvice.SESSION_ATTRIBUTE_NAME) #Validated(SurveyGroupOne.class) SurveyCommand surveyCommand,
BindingResult result) {
if (result.hasErrors()) {
LOG.debug(result.getAllErrors().toString());
model.addAttribute("pageNum", pageNum);
return "survey/page".concat(Integer.toString(pageNum));
}
pageNum++;
model.addAttribute("pageNum", pageNum);
return "redirect:/survey/".concat(Integer.toString(pageNum));
}
The only difference is what part of the SurveyCommand object is validated at each stop along the way. This is designated by the marker interface passed to the #Validated() annotation. The marker interfaces (SurveyGroupOne, SurveyGroupTwo, etc) are just that, markers:
public interface SurveyGroupOne {}
public interface SurveyGroupTwo {}
...
and they are applied to properties of objects in the SurveyCommand object:
public class Person {
#NotBlank(groups = {
SurveyGroupTwo.class,
SurveyGroupThree.class})
private String firstName;
#NotBlank(groups = {
SurveyGroupTwo.class,
SurveyGroupThree.class})
private String lastName;
...
}
My question: how can I make the method generic and still use the marker interface specific to the page being processed? Something like this:
#PostMapping("/{pageNum}")
public String processGroupOne (
Model model,
#PathVariable("pageNum") int pageNum,
#ModelAttribute(GlobalControllerAdvice.SESSION_ATTRIBUTE_NAME)
#Validated(__what goes here??__) SurveyCommand surveyCommand,
BindingResult result) {
if (result.hasErrors()) {
LOG.debug(result.getAllErrors().toString());
model.addAttribute("pageNum", pageNum);
return "survey/page".concat(Integer.toString(pageNum));
}
pageNum++;
model.addAttribute("pageNum", pageNum);
return "redirect:/survey/".concat(Integer.toString(pageNum));
}
How can I pass the proper marker interface to #Validated based solely on the pageNum #PathVariable (or any other parameter)?
Because #Validated is an annotation, it requires its arguments to be available during compilation and hence static. You can still use it but in this case you will have N methods, where N is a number of steps. To distinguish one step from another you can use params argument of #PostMapping annotation.
There is also another way where you need to inject Validator to the controller and invoke it directly with an appropriate group that you need.

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

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

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.

Resources