Actually I've googled to see how we can pass data from one controller to another in Spring MVC and I found that using flash attributes do the job.
It consists on declaring one controller with RequestMapping=GET and an other with RequestMapping=POST. I have tested this code in my controller and it worked.
#RequestMapping(value ="/ajouter", method = RequestMethod.POST)
public String add(#ModelAttribute User user,final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/account";
}
and the other:
#RequestMapping(value ="/account", method = RequestMethod.GET)
public String addAccount(#ModelAttribute("user") User user,#ModelAttribute Account account) {
System.out.println(user.getId());
return "account";
}
But I have another case: I have two JSPpages:
The first will add a user into the database. I want to recuperate the id of the user just inserted to set it as a foreign key for the account (after submitting the page for adding a user, a second page for adding an account appears).
I've tested this code:
This controller will insert a user into the database and recuperate the user which has been just inserted.
#RequestMapping(value ="/addUser", method = RequestMethod.POST)
public String add(#ModelAttribute User user,final RedirectAttributes redirectAttributes) {
this.userService.insertData(user);
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/account";
}
and this controller will insert an account into the database, but can not recuperate the user id of the user just inserted.
#RequestMapping(value= "/ajouterCompte", method = RequestMethod.POST)
public String addCompte(#ModelAttribute("account") Account compte,#ModelAttribute("user") User user){
System.out.println(user.getId()); //this code shows 0
System.out.println(compte.getPwd());
String hashPassword = passwordEncoder.encode(compte.getPwd());
System.out.println(hashPassword);
compte.setPwd(hashPassword);
compte.setId(user.getId());
this.compteService.insertCompte(compte);
return "redirect:/users";
}
I guess that the problem is that the 2 controllers are declared with a method method = RequestMethod.POST when it should be one GET and an other POST. But in this case how can I recuperate the id of the user so that it could be inserted into the database?
When I declare the second controller with GET, the insertion of the database fails!
Need your help please :(
The object which are set as flash attributes are only available for the first request after those have been set. (As also explained in the reference guide).
Assuming that in your account controller you have a GET based method for /account pre-populate the Account with the information at that point.
public String account(#ModelAttribute("user") User user, Model model) {
Account account = new Account();
account.setId(user.getId());
model.addAttribute("account", account);
return "account";
}
Now you can either annotate your controller with #SessionAttribute("account") to have the Account stored in the session in between requests. If so then you have to modify your POST handling method to include a SessionStatus object and after storing call setComplete() on it.
public String addCompte(#ModelAttribute("account") Account compete, SessionStatus sessionStatus){
...
sessionStatus.setComplete();
return "redirect:/users";
}
Or store the pre-filled information in hidden form fields so that it gets passed along with the following request and the Account can be reconstructed.
<form:hidden path="id" />
Related
#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.
Using - Spring Boot, Thymeleaf
I have following code under controller class:
public class HotelController {
private HotelService hotelService;
private HotelRepository hotelRepository;
#Autowired
public HotelController(HotelService hotelService,HotelRepository hotelRepository) {
this.hotelService = hotelService;
this.hotelRepository = hotelRepository;
}
#GetMapping("/index")
public String searchHotel(Model model) {
Hotel hotel = new Hotel();
model.addAttribute("searchObject",hotel);
model.addAttribute("cityList", hotelRepository.findListOfCities());
model.addAttribute("hotelList", hotelRepository.findListOfHotels());
return "search_hotel";
}
#PostMapping("/availabilityResult")
public String afterClickingSearch(#ModelAttribute("searchObject") Hotel hotel,Model model) {
if(hotelService.searchHotelResult(hotel)==null)
return "failure_page";
else {
model.addAttribute("hotelRoom_TypePriceGST",hotelService.findHotelPriceandRoomType(hotel.getCity(),hotel.getHotel()).split(","));
model.addAttribute("total", hotelService.findTotal(hotel.getCity(), hotel.getHotel()));
return "booking_confirmation";
}
}
#GetMapping("/navUserRegisterPage")
public String userRegisterPage(Model model){
User user = new User();
model.addAttribute("userObj", user);
return "user_registerForm";
}
#PostMapping("/reserveUser")
public String reserveUserHandler(#ModelAttribute("userObj") User user,#ModelAttribute("searchObject") Hotel hotel,Model model) {
System.out.println(hotel.getHotel());
System.out.println(user.getGuest_name());
model.addAttribute("hotelName", hotel.getHotel());
model.addAttribute("userName", user.getGuest_name());
return "confirmation_page";
}
}
I can find hotel value(usig hotel.getHotel()) under handler method- public String afterClickingSearch()
But when I try to find the hotel value(using hotel.getHotel()) under handler method -reserveUserHandler(); I get null as value.
Please help with how can I retrieve hotel value under reserveUserHandler() method.
It appears as though you have a Hotel backed form on the "search_hotel" page and the action goes to afterClickingSearch(). You can access the Hotel model attribute in afterClickingSearch() because you are submitting the attributes of the Hotel in your form. When you transition to "booking_confirmation" and other pages it's not apparent that you are passing the hotel's id to maintain state.
You have a few options, some more elegant than others. You can pass around the hotel's id via a request parameter. A second option is to include a hidden Hotel id in all forms from which reserveUserHandler() is reachable, making sure each form is initialized with the id, and lookup the hotel by id in reserveUserHandler(). A third option, which I wouldn't recommend, is to make Hotel or Hotel id a session attribute. See this for more information on session attributes. When you use session attributes you need to be wary of multiple browser tabs and how unique state is maintained across each tab.
I have a form that has 10+ field inputs that will get updated by a user. On submit I need to update the object (by id) and any/all fields that were modified in the form (utilizing Spring Data JPA & Repositories). I believe I can do this by passing the #ModelAttribute as a method argument tied to my object, but I don't quite fully understand this yet. Here's my Controller
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("User") User user, #PathVariable Long id, Model model) {
user = userRepo.findOne(id); //Spring Repository method to find user by ID
// Here is where you'd set all fields of the User object including those modified in the form
model.addAttribute("user", user);
userRepo.save(user); //Updates user in database
return "success";
}
I'm looking for a method that would do the exact same thing as:
user.setName(user.getName());
user.setAddress(user.getAddress));
//etc.
Without explicitly calling each set method (the number of field inputs will grow).
Thanks mates
If you have a form and you´re using ModelAndAttribute you just need to set the id attribute to be send to the Controller
<form:input id="id" path="id"/>
<form:input id="name" path="name"/>
<form:input id="address" path="address"/>
Then in your controller you just need to do what you´re just doing
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("User") User user, #PathVariable Long id, Model model) {
user = userRepo.findOne(id); //Spring Repository method to find user by ID
// Here is where you'd set all fields of the User object including those modified in the form
model.addAttribute("user", user);
userRepo.save(user); //Updates user in database
return "success";
}
BUT, if you´re doing this request by Ajax you will need to load the again the entity User to set the new entity in your form with the new Id.
You can take a look to JQuery load to load the form element again.
Or if the save is done by HTTP Request you must refresh the page after save so you need to return again the ModelAndView with the entity user already update with an id
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("User") User user, #PathVariable Long id, Model model) {
user = userRepo.findOne(id); //Spring Repository method to find user by ID
userRepo.save(user); //Updates user in database
ModelAndView mav = new ModelAndView(yourview);
mav.setObject("user", user);
return mav;
}
I would like to call a method of my Spring Controller only one time per user session.
#RequestMapping(value = "/user.html")
public String getUser(Model model) {
doSomethingAtEachCall();
doSomethingOnlyOneTimePerSession(); // call only first time user access to this page
return "user";
}
How can I do that (properly) ?
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";
}
}