What is the difference between #ModelAttribute, model.addAttribute in spring? - java

i am new Spring learner.i'm really confused about what is the difference between two concept:
#ModelAttribute
model.addAttribute
in below there are two "user" value.Are these same thing?Why should I use like this?
Thank you all
#RequestMapping(method = RequestMethod.GET)
public String setupForm(ModelMap model) {
model.addAttribute("user", new User());
return "editUser";
}
#RequestMapping(method = RequestMethod.POST)
public String processSubmit( #ModelAttribute("user") User user, BindingResult result, SessionStatus status) {
userStorageDao.save(user);
status.setComplete();
return "redirect:users.htm";
}

When used on an argument, #ModelAttribute behaves as follows:
An #ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument’s fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually.
http://docs.spring.io/spring/docs/4.1.0.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#mvc-ann-modelattrib-method-args
That's a very powerful feature. In your example, the User object is populated from the POST request automatically by Spring.
The first method, however, simply creates an instance of Userand adds it to the Model. It could be written like that to benefit from #ModelAttribute:
#RequestMapping(method = RequestMethod.GET)
public String setupForm(#ModelAttribute User user) {
// user.set...
return "editUser";
}

Related

Differentiation of #ModelAttribute, ModelAndView mode, HttpServletRequest request

I'm new to mvc spring and I have some code from the internet like the following:
#RequestMapping(value = "/newContact", method = RequestMethod.GET)
public ModelAndView newContact(ModelAndView model) {
Contact newContact = new Contact();
model.addObject("contact", newContact);
model.setViewName("ContactForm");
return model;
}
#RequestMapping(value = "/saveContact", method = RequestMethod.POST)
public ModelAndView saveContact(#ModelAttribute Contact contact) {
contactDAO.saveOrUpdate(contact);
return new ModelAndView("redirect:/");
}
#RequestMapping(value = "/deleteContact", method = RequestMethod.GET)
public ModelAndView deleteContact(HttpServletRequest request) {
int contactId = Integer.parseInt(request.getParameter("id"));
contactDAO.delete(contactId);
return new ModelAndView("redirect:/");
}
My question is,
what is the purpose of using and using in any case with # ModelAttribute, ModelAndView mode and HttpServletRequest request?
Thanks you.
Please check https://stackoverflow.com/a/33422321/3530898. I my opinion ModelAttribute is used usually with form transport objects (i.e. bean classes whose fields contain the form data), ModelAndView is used when you want to set view name and model object in a single method of a controller. Both ModelAndView and Model uses HttpServletRequest internally, Spring has added wrapper classes over HttpServletRequest to make development easier for developer. But sometime you need HttpServletRequest class for instance, when you want to capture a query parameter in an Ajax call etc

Get #RequestMapping value of different method in same controller

Using Spring Boot, I have a couple methods in my RegisterController which handles new user registration.
The createNewUser method is responsible for saving the new user to the database and sending a confirmation e-mail containing a link that has a unique token.
The confirmUser method handles processing the GET request for the confirmation link.
Is there a way for the createNewUser method to get the #RequestMapping value assigned to confirmUser? I'd like to use this value to generate the confirmation link instead of hard coding it.
// Process form input data
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ModelAndView createNewUser(#Valid User user, BindingResult bindingResult) {
}
// Process confirmation link
// Link in confirmation e-mail will be /registerConfirmation?token=UUID
#RequestMapping(value="/registerConfirmation", method = RequestMethod.GET)
public ModelAndView confirmUser( #RequestParam("token") String token) {
}
I don't know of a way to get it from the #RequestMapping value but you have a couple of different options.
Option 1: Create a constant for the mapping and use that which allows you to reference it in both methods.
private final static String REGISTER_CONF_VAL = "/registerConfirmation";
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ModelAndView createNewUser(#Valid User user, BindingResult bindingResult) {
}
// Process confirmation link
// Link in confirmation e-mail will be /registerConfirmation?token=UUID
#RequestMapping(value=REGISTER_CONF_VAL, method = RequestMethod.GET)
public ModelAndView confirmUser( #RequestParam("token") String token) {
}
Option 2: Less ideal, but if you add registerConfirmation to your config file, you can access it like:
#RequestMapping(value="${register.conf.val}", method = RequestMethod.GET)
public ModelAndView confirmUser( #RequestParam("token") String token) {
}
The reason this isn't ideal is because you probably don't want it to be different from environment to environment. That said, it would work.
If you need to generate the link based on user request, you can use the Path Variable in the controller. U can get the path variable and use some mechanism to validate the path as well.
Replace registerConfirmation with {registerConfirmation} and in the method, use #PathVariable annotation to get the path. Use the variable to check if the path is valid.

Use of getFlashAttributes() in Spring's RedirectAttributes

In order to access the redirect attributes in the redirected method, we utilize the model's map, like this :
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model map) {
String some = (String) map.asMap().get("some");
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
But, why can't we access them in this way :
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(RedirectAttributes redAttr) {
String some = redAttr.getFlashAttributes().get("some");
}
If the only purpose of adding flashAttributes is that they become available to the model in the redirected method, what's the purpose of getFlashAttributes() ?
RedirectAttributes are for setting flash attributes before redirection. They are merged into model after the redirection so there is no reason to access them again via RedirectAttributes again as you have suggested.
Being able to work with the attributes just like with a map might be useful. You can check what have you set (containsKey, isEmpty, ...). However the use of the wildcard generic parameter Map<String, ?> getFlashAttributes() prevents writing into map and it is strange why they have used it instead of a plain Object parameter.

Can I add value in a BindingResult before checking Errors in Spring?

Can I add value in a BindingResult before checking Errors in Spring?
#InitBinder("memberrequest")
public void initMemberRequestBinder(WebDataBinder binder) {
binder.setValidator(new MemberRequestValidator());
}
#PreAuthorize("isAuthenticated()")
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveRequest(#Valid #ModelAttribute("memberrequest") MemberRequest mr, BindingResult result, HttpSession session) {
session.setAttribute("phone", mr.getPhonenumber());
mr.setWelfare((String)session.getAttribute("welfare"));
mr.setSchool((String)session.getAttribute("school"));
mr.setTitle((String)session.getAttribute("title"));
mr.setDistrict((String)session.getAttribute("district"));
mr.setName((String)session.getAttribute("name"));
mr.setFile((String)session.getAttribute("file"));
mr.setQueue((String)session.getAttribute("queue"));
mr.setRequestor(getUser());
mr.setSchool_id((String)session.getAttribute("school_id"));
mr.setBorough_id((String)session.getAttribute("borough_id"));
mr.setRetiree((String)session.getAttribute("retiree"));
if (result.hasErrors()) {
LOGGER.debug("Pages had errors on it... returning to input page");
return new ModelAndView("w-question");
} else {
I have the above code in my Spring controller but the issue is that I need to take some values out of the session and move them into the BindingResult (Bean) before Validator runs on it..
Can this be done someone? the issues is some of the values I keep in the session.. please me know if this can be dont and how is the best way to do it..
In your controler define method for creating your model atribute and annotate it with #ModelAttribute annotation.
Actually you will not modify the binding result object itself but the validation target and then you can change your validator behavior to change binding result as you need.
#ModelAttribute("memberrequest")
public MemberRequest getMemberRequest(HttpSession session) {
MemberRequest mr = new MemberRequest();
mr.setWelfare((String)session.getAttribute("welfare"));
mr.setSchool((String)session.getAttribute("school"));
mr.setTitle((String)session.getAttribute("title"));
mr.setDistrict((String)session.getAttribute("district"));
mr.setName((String)session.getAttribute("name"));
mr.setFile((String)session.getAttribute("file"));
mr.setQueue((String)session.getAttribute("queue"));
mr.setRequestor(getUser());
mr.setSchool_id((String)session.getAttribute("school_id"));
mr.setBorough_id((String)session.getAttribute("borough_id"));
mr.setRetiree((String)session.getAttribute("retiree"));
return mr;
}
this method will be called before the binding ocures, but have in mind that this method will be called before each controler method wich is using #ModelAttribute("memberrequest") as parameter.

2 Request Handlers for POST (ResponseBody + "Normal")

I like to implement a REST-API into my SpringMVC application. At the moment, I have one method to handle POST-Requests, which "returns" a rendered ViewScript.
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
return "success";
}
It would be nice, to add a second method with the #ResponseBody Annotation for POST-Requests, e.g. to send a JSON-Response.
Furthermore, the old Method still has to exists, to handle "normal" Requests.
But a code like this doesn't work:
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
return "success";
}
#RequestMapping(method=RequestMethod.POST)
#ResponseBody
public Object add(User user, Model model)
{
// [...]
return myObject;
}
With this code, I'm getting a 405 (Method Not Allowed) Error from Tomcat. How can I fix this?
As it stands, Spring has no way to differentiate between these two requests: same URL, same request method.
You can further differentiate by mimetype:
#RequestMapping(method=RequestMethod.POST, headers="content-type=application/json")
Although there are several mimetypes associated with JSON :/ The headers value takes an array, however, so you can narrow/widen it as necessary.
See the headers docs.
Dont USE TWO ANNOTATION. It is a poor option. Just have one more method without annotation. But the method from the old method by checking the below condition.
JUST PASS ONE MORE ARGUMENT FROM UI by query parameter(request="JSON_Request").
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
if(request="JSON_Request") {
newMethod(user, model);
}
return "success";
}
private Object newMethod(User user, Model model)
{
// [...]
return myObject;
}

Categories