Handle (TaskId) Redirect in Spring MVC - spring

User's controllers needs to concatenate the task ID to be obtained in a .js that is loaded by the Architecture (me) when the view is loaded. This mechanism is necessary to tasks control. In this context:
#RequestMapping(method = RequestMethod.POST)
public String create(#Valid Vote vote, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
uiModel.addAttribute("vote", vote);
addDateTimeFormatPatterns(uiModel);
return "votes/create";
}
uiModel.asMap().clear();
vote.persist();
return "redirect:/votes/" + encodeUrlPathSegment(vote.getId().toString(), httpServletRequest) +
"**?ArcSpring.idTask=" + httpServletRequest.getParameter("ArcSpring.idTask")**;
}
Is there a way to handle this redirect in the way I can concatenate the task ID to make it transparent for users?
I tried with a customized class extending from UrlBasedViewResolver, capturing the url and adding the attributes by my own, but with no kind of success.

Related

why Spring mvc redirect not working well?

#PostMapping("/regist")
public String regist(Person person, Model model) {
Person p = new Person("name", "age");
model.addAttribute("person", p); //add person to model
model.addAttribute("hobby", "reading);
return "redirect:/info";
}
#GetMapping("/info")
public String info() {
return "result";
}
Why (person) model.addAttribute("person", p) not appended to url like (hobby) when redirecting?
Model attributes are not used for redirects. Have a look at RedirectAttributes instead.
A specialization of the Model interface that controllers can use to
select attributes for a redirect scenario. Since the intent of adding
redirect attributes is very explicit -- i.e. to be used for a redirect
URL, attribute values may be formatted as Strings and stored that way
to make them eligible to be appended to the query string or expanded
as URI variables in org.springframework.web.servlet.view.RedirectView.
This interface also provides a way to add flash attributes. For a
general overview of flash attributes see FlashMap. You can use
RedirectAttributes to store flash attributes and they will be
automatically propagated to the "output" FlashMap of the current
request.
Example usage in an #Controller:
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
if (result.hasErrors()) {
return "accounts/new";
}
// Save account ...
redirectAttrs.addAttribute("id", account.getId()).addFlashAttribute("message", "Account created!");
return "redirect:/accounts/{id}";
}
A RedirectAttributes model is
empty when the method is called and is never used unless the method
returns a redirect view name or a RedirectView.
After the redirect, flash attributes are automatically added to the
model of the controller that serves the target URL.

optional parameter in Spring MVC method

I am learning spring MVC and come across these methos in spring contrller MVC 3.1
ControllerClass(){
#RequestMapping(....)
public String show( Model uiModel) {
return ".....";
}
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.POST)
public String update(#Valid Contact contact, BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes, Locale locale,
#RequestParam(value="file", required=false) Part file) {
if (bindingResult.hasErrors()) {
...........
return ".....";
}
parameters like BindingResult , Model ,
HttpServletRequest , RedirectAttributes , Locale ,
#RequestParam(value="file", required=false) Part are optional but I wonder where I can find these optional parameter and under which situation it can appear in method.
Parameter:
BindingResult - imagine you have an registration-form and you would pre validate the user input, then you can use the BindingResult.
Model - After the user is registered, he wants to edit his own profile he goes to a edit site, in this site you would show the data from the user. Here you can search for the user and add the user-object to the model and in the template you can read the values from the model-attribute.
HttpServletRequest provides request information.
#RequestParam(value="file", required=false) from Spring:
annotated parameters for access to specific Servlet request parameters. Parameter values are converted to the declared method argument type
Imagine you have a table of users and you would edit one of these, you select an entry and there you can send the userId as a requestparam.
There is a similar attribute, it's called #PathVariable the main difference, the #PathVariable is mandatory. The #RequestParam is optional respectively for this exist a "fallback/default value".
The #PathVariable is a part from the url:
#RequestMapping(value = "/{login}/edit", method = RequestMethod.GET)
public ModelAndView editUserByLogin(#PathVariable("login") final String login, final Principal principal) {}
The other two I have not used yet.

Can't access Model attributes during validation

I'm using Spring 3.1 and have web pages using validation. The field-level validation, and the display of errors, works OK. My problem is with Model attributes not being available during the validation form display.
Let's say I've code:
#RequestMapping(value="/edit", method=RequestMethod.GET)
public String getEdit(#RequestParam("id") Long id, Model model) {
model.addAttribute("mytitle", "Hello There");
return "editObject"
}
#RequestMapping(value="/edit", method=RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("object") MyData object, BindingResult result) {
if(result.hasErrors()) {
return "editObject";
}
[snip]
}
If I have an error the hasErrors() is detected and short-circuits to the map "editObject". However, the model attributes aren't available.
What do I use here? I tried adding a Model reference to the postEdit parameter list and adding in again things like the "mytitle" attribute.
Thanks,
Jerome.
When postEdit controller render the editObject view, you are in a new request, so you are loosing the model (previously set for getEdit action).
What you need to do it re-set any values needed in a new model:
#RequestMapping(value="/edit", method=RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("object") MyData object, BindingResult result, Model model) {
if(result.hasErrors()) {
model.addAttribute("mytitle", "Hello There");
model.addAttribute("object", object);
return "editObject";
}
If you need to keep those attributes for different views you can store them in a session for example (so that you won't have to re-set them for each new request).

Spring preprocess request in another controller method

In one of my controllers I have:
#RequestMapping(value = "search", method = RequestMethod.GET)
public ModelAndView searchUsers(HttpSession session, HttpServletRequest request) {
UiUserSearchCriteria userSearchCriteria = (UiUserSearchCriteria) session
.getAttribute("UsersController_userSearchCriteria");
if (null == userSearchCriteria) {
userSearchCriteria= defaultUserSearchCriteria;
}
// Here be dragons
return searchUsers(userSearchCriteria, new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria"), session, request);
}
#RequestMapping(value = "search", method = RequestMethod.POST)
public ModelAndView searchUsers(
#ModelAttribute("userSearchCriteria") UiUserSearchCriteria userSearchCriteria,
BindingResult bindingResult, HttpSession session, HttpServletRequest request) {
userSearchCriteriaValidator.validate(userSearchCriteria, bindingResult);
if (bindingResult.hasErrors()) {
// Here be dragons
return new ModelAndView("searchUsers");
}
ModelAndView result = new ModelAndView("redirect:listUsers");
PagedListHolder<UiUser> userList = new PagedListHolder<UiUser>(
usersService.searchUsers(userSearchCriteria));
userList.setPageSize(10);
userList.setSort(defaultSort);
userList.resort();
session.setAttribute("UsersController_userList", userList);
session.setAttribute("UsersController_userSearchCriteria", userSearchCriteria);
return result;
}
The logic is simple: when the user navigates to search page I actually perform a search with default criteria and return him a list (this is the result of requirements changing, huh).
I found a problem in this code, accidentally. When default search criteria is not valid the behavior is: navigate to search -> populate search criteria with invalid criteria -> call another method (the second one, with POST) -> perform validation -> errors are not empty, so return searchUsers view. But the BindingResult bindingResult is actually syntethic, from previous method (new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")). So I got an error No binding result is bound to session (I agree with this).
I cannot have #ModelAttribute and BindingResult parameters (that, which are bound by Spring) pair in GET method to call POST with them.
So what is the best solutions for this?
I think you can simply associate your new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria") with an appropriate Spring model attribute name, this way:
BindingResult bindingResult = new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")
model.addAttribute(BindingResult.MODEL_KEY_PREFIX + "userSearchCriteria", bindingResult);
This is the default Spring MVC behavior of binding the validation results of a specific model attribute and should help you avoid the No binding result.. error

Session Handling in Spring MVC 3.0

I am using session.setAttribute to store user object after login. In next controller, I have #SessionAttribute for the same user and #ModelAttribute for same object to be used in the method mapped to a RequestMapping. After login if I click any link in the user home page it give
HttpSessionRequiredException: Session attribute '' required - not found in session
I am not sure what I am doing wrong. I went through many article and question in this site as well but could find any solution. The user object which I am storing in session stores user's account details which are required in all the controller to get different information from DB. I using SessionAttribute is wrong should I use HttpSession instead in all the controller and get the object from session manually or there is a proper way to handle in spring 3.0. Please note that this user object is not backing any form just login, but contains many other details.
As help would be good.
Have a look at my (non-perfect) use of session data:
#Controller
#SessionAttributes("sharedData")
public class RegistrationFormController {
#Autowired
private SharedData sharedData; // bean with scope="session"
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.GET)
public ModelAndView newForm() {
final ModelAndView modelAndView = new ModelAndView("registrationForm");
modelAndView.addObject("registrationForm", new RegistrationForm());
// I want to render some data from this object in JSP:
modelAndView.addObject("sharedData", sharedData);
return modelAndView;
}
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.POST)
public String onRegistrationFormSubmitted(HttpServletRequest request,
#ModelAttribute("registrationForm") RegistrationForm registrationForm, BindingResult result) {
if (result.hasErrors()) {
return "registrationForm";
}
// Perform business logic, e.g. persist registration data
return "formSubmitted";
}
}

Resources