Retrieving multiple model attributes from jsp page (Spring) - java

In ReservationController.java I have the following method, which gets a reservation object from new-reservation.jsp
#PostMapping("/addBookToReservation")
public String addBookToReservation(Model model,
#Valid #ModelAttribute("reservation") Reservation reservation,
BindingResult result,
RedirectAttributes redirectAttributes) {
if(result.hasErrors()) {
return "reservation/new-reservation";
}
redirectAttributes.addFlashAttribute("reservation", reservation);
return "redirect:/book/add-book";
}
and sends it to BookController.java, where another method adds another attribute to the model
#GetMapping("/book/add-book")
public String showAddBookForm(Model model) {
model.addAttribute("book", new Book());
Reservation reservation = (Reservation) model.getAttribute("reservation");
System.out.println(reservation); //prints the object I passed it!
return "/book/add-book";
}
and returns the following add-book.jsp
<form:form action="/addBook" modelAttribute="book" method="post">
<div>
<div>
<form:label path="title">Title</form:label>
<form:input type="text" id="title" path="title" />
<form:errors path="title" />
</div>
...
</div>
<div>
<input type="submit" value="Add book">
</div>
</form:form>
Now, when I handle the form's action addBook
#PostMapping("/addBook")
public String addBook(#Valid #ModelAttribute Book book,
BindingResult result,
Model model) {
if (result.hasErrors()) {
return "book/add-book";
}
Reservation reservation = (Reservation) model.getAttribute("reservation");
System.out.println(reservation); // reservation is null!!
return "somewhere/else";
}
and I try to retrieve the reservation object from the model I get a null.
How can I pass my reservation object through the JSPs I've showed you before?

try adding #SessionAttributes for the model attribute on top of the controller and remove the session attribute when done
#SessionAttributes("reservation")

Related

PostMapping not attaching Vehicle object to Customer Object - returning NULL

So, my issue is that my Vehicle ID is being passed to the GET mapping and it populates if I print statement and on the JSP. But when I try and set it to my Customer object, which has Vehicle variable, it keeps coming back null, like it's creating a new Vehicle object when you submit.
I've tried creating a "model" (Customer_And_Vehicle) class that has both variables, and the vehicle is still being nulled.
Using the vehicleOne attributes and calling the ID in the Post Mapping works. The vehicle does get passed through and attached to the customer.
The vehicle ID is getting passed through the requestID in the GETmapping.
CustomerController
#GetMapping("/buy-vehicle")
public String addCustomer(Model model, #RequestParam String id, HttpSession session) {
Vehicle vehicle = vehicleService.getVehicle(id);
//Vehicle vehicle = vehicleService.findById(id);
model.addAttribute("vehicle", vehicle);
//model.addAttribute("customer", new Customer());
Customer_And_Vehicle cv = new Customer_And_Vehicle();
cv.setVehicle(vehicle);
cv.setCustomer(new Customer());
model.addAttribute("cv", cv);
System.out.println(vehicle);
return "buy-vehicle";
}
#PostMapping("/buy-vehicle")
public String handleBuyVehicle(Model model, #ModelAttribute("customer") Customer customer, #ModelAttribute("vehicleOne") Vehicle vehicle,
#ModelAttribute("cv") Customer_And_Vehicle cv, HttpSession session) {
//Vehicle vehicleOne = vehicleService.findById("123");
//vehicleOne.setBought(true);
model.getAttribute("customer");
model.getAttribute("vehicle");
//model.addAttribute("vehicle", vehicleService.getVehicle(vehicle.getId()));
//model.addAttribute("vehicleOne", vehicleService.findById("123"));
//cv.getVehicle().setBought(true);
customer.setEmail(cv.getCustomer().getEmail());
customer.setfName(cv.getCustomer().getfName());
//customer.setVehicle(vehicleOne);
//customer.setAmountSpent(vehicleOne.getPrice());
customerService.addCustomer(customer);
return "index";
}
If I specify which ID("123") - in vehicleOne - in the Post Mapping, the vehicle does get passed through and attached to the customer.
/buy-vehicle
<body>
<form:form modelAttribute="cv" action="/buy-vehicle"
method="post">
<div>
<label for="inputFirstName">First Name</label>
<form:input path="customer.fName" type="text" id="inputFirstName" />
</div>
<div>
<label for="inputLastName">Last Name</label>
<form:input path="customer.lName" type="text" id="inputLastName" />
</div>
<div>
<label for="inputEmail">Email</label>
<form:input path="customer.email" type="email" id="inputEmail" />
</div>
<div>
<label for="inputPassword">Password</label>
<form:input path="customer.password" type="password" id="inputPassword" />
</div>
<button type="submit">work</button>
</form:form>
</body>
index - to show printout on local
<body>
Work please
<div>
Auto list
</div>
<div>${customer.vehicle.id}</div>
<div>${vehicleOne }</div>
<div>${customer.fName}</div>
<div>${customer.amountSpent}</div>
<div>${cv}</div>
<div>${cv.customer}</div>
<div>${cv.vehicle}</div>
<div>Create Account</div>
</body>
Screenshot of vehicle getting passed to buy-vehicle
Screenshot of index printout

How to get modelAttribute values that are not in form, in Spring

I have an hibernate entity object. I need to update this object, so I passed this object to a form. In the form i will change some values and the others are constant. And I can not show these constant values to the client, so they should pass to next page via another method except from diplaying them explicity in a html form.
Here is my object obtained in controller and passed to the view:
#GetMapping("/update")
public String update(#RequestParam("dataId") int id, Model md){
Doctor dr = doctorService.getById(id);
/*for example lets say this doctor object has following properties
dr.setId(3);
dr.setName("James");
dr.setUserId(7);
*/
md.addAttribute("doctor", dr);
return "object-form";
}
Here is my form in view :
<form:form action="save" modelAttribute="doctor" method="post">
<form:errors path="name"></form:errors>
<form:input path="name" placeholder="Doktor İsmi" class="form-control" />
<form:hidden path="id" />
<input type="submit" value="Save doc" />
</form:form>
From form, only name and id values are coming, however, the userId is null. I need to get this userId without post.
Here is my post-process controller that I handle the object:
#PostMapping(value="/save")
public String save(#Valid Doctor dr, BindingResult bindingResult){
doctorValidator.validate(dr, bindingResult);
if (bindingResult.hasErrors()) {
return "object-form";
}
else{
doctorService.save(dr);
return "redirect:list";
}
}
I don't know how can achieve this r even there is way for it. I searched on Google but I did not find any solution.
Thank a lot,,
You can get previous doctor object from db and get the user ID from there like below:
#PostMapping(value="/save")
public String save(#Valid Doctor dr, BindingResult bindingResult){
Doctor prevDr = doctorService.getById(dr.getId());
dr.setUserId(prevDr.getUserId());
doctorValidator.validate(dr, bindingResult);
if (bindingResult.hasErrors()) {
return "object-form";
}
else{
doctorService.save(dr);
return "redirect:list";
}
}

Customize items in form select

In my registration form, I have a field that give to users the possiblity to choose roles. But, I want to, only, show two roles : USER and MODERATOR.
But, I don't know how to proceed.
this registration form jsp :
<div class="row">
<div class="form-group col-md-12">
<label style="color:#ffffff;" class="col-md-3 control-lable" for="userProfiles">Roles</label>
<div class="col-md-7">
<form:select path="userProfiles" items="${roles}" multiple="true" itemValue="id" itemLabel="type" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userProfiles" class="help-inline"/>
</div>
</div>
</div>
</div>
I have an enum : UserProfileType
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
}
And this is how it look :
This my controller, the part responsible of registration
//new user
#RequestMapping(value = "/registrationForm", method = RequestMethod.GET)
public String newUser(User user, ModelMap model) {
//User user = new User();
model.addAttribute("user", user);
model.addAttribute("loggedinuser", getPrincipal());
return "registrationForm";
}
//save user
#RequestMapping(value = { "/registrationForm" }, method = RequestMethod.POST)
public String saveUser1(#Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registrationForm";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registrationForm";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
//return "success";
return "registrationsuccess";
}
I am using spring mvc/security and hibernate.
Thanks in advance
The data to be displayed by the page should be provided and manipulated by the controller. Filter the roles in your controller before handing over to the view.
Depending on how you are adding attributes to the model you can do it as foLlows (or any equivalent way as Spring MVC is flexible)
You could create methods in your Enum class to return the filtered values according to yours needs:
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
public static List<UserProfileType> getAdminRoles(){
return Arrays.asList(UserProfileType.USER , UserProfileType.MODERATOR);
}
}
#ModelAttribute("roles")
public List<UserProfileType> roles(){
return UserProfileType.getAdminRoles();
}
You can also filter the roles in the view but its not recommended to have control logic in your view
<form:select path="userProfiles"multiple="true" class="form-control input-sm">
<c:forEach items="${roles}" var = "role">
<c:if test="${role.type eq 'USER' or role.type eq 'MODERATOR'}">
<form:option value="${role.id}" label="${role.type}"/>
</c:if>
</c:forEach>
</form:select>

Neither BindingResult nor plain target object for bean name when running application

index.jsp
<f:form action="emp_change.htm" method="POST" commandName="index">
<div id="login_box">
<div id="form_val">
<div class="label">Username:</div>
<div class="control"><f:input path="emailId" /></div>
<div style="clear:both;height:0px;"></div>
<div class="label">Password:</div>
<div class="control"><f:input path="password" type="password" /></div>
<div style="clear:both;height:0px;"></div>
<div id="msgbox"></div>
<div id="login_foot">
<input type="submit" name="action" id="login" value="Login" class="send_button" />
</div>
</div>
</div>
</f:form>
AdminInfoControl.java
#Controller
public class AdminInfoControl {
private AdminInfoService service;
#RequestMapping(value = "/emp_change", method = RequestMethod.POST)
public String doActions(#ModelAttribute JtAdminInfo emp, BindingResult result, #RequestParam String action, Map<String, Object> map) {
service = new AdminInfoService();
JtAdminInfo empResult = new JtAdminInfo();
switch (action.toLowerCase()) {
case "login":
JtAdminInfo search = service.getFindAdmin(emp.getEmailId());
empResult = search != null ? search : new JtAdminInfo();
break;
}
map.put("index", empResult);
map.put("empList", service.getAll());
return "index";
}
}
I'm getting following error :
Neither BindingResult nor plain target object for bean name 'emp_change' available as request attribute
Anyone please help me to correct this. Please let me know, if information is not sufficient.
Just answered on almost the same question.. You are obtaining emp_change as a model attribute in doActions method but you didn't set it as a model attribute previously. So, set your emp_change as a model attribute in some method that e.g. shows your index.jsp page. Something like this:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showIndex() {
ModelAndView mav = new ModelAndView("index");
mav.addObject("emp_change", new JtAdminInfo ());
return mav;
}
I have added following method in my controller and works fine.
#RequestMapping("/index")
public String setupForm(Map<String, Object> map) {
map.put("index", new JtAdminInfo());
return "index";
}

Edit form validation with Spring MVC

I use Spring MVC and Spring form validation in my project.
There is class named Group in object model and I created form for editing it.
Form
<spring:url var="saveGroup" value="/teacher/groups/save"/>
<form:form action="${saveGroup}" method="post" modelAttribute="group">
<form:hidden path="id"/>
<div id="nameDiv" class="control-group">
<form:label path="title">Title:</form:label>
<form:input path="title"/>
<form:errors path="title"/>
</div>
<div id="specDiv" class="control-group">
<form:label path="title">Specialty:</form:label>
<form:select path="specialty">
<form:options items="${specialties}" itemValue="id" itemLabel="title"/>
</form:select>
</div>
<div class="center">
<spring:url var="groups" value="/teacher/groups"/>
<input class="btn btn-primary" type="submit" value="Save"/>
<a class="btn" href="${groups}"> Cancel </a>
</div>
</form:form>
Controller
#Controller
#RequestMapping("/teacher/groups")
public class GroupsController {
#Autowired
private GroupService groupService;
#Autowired
private SpecialtyService specialtyService;
#ModelAttribute("group")
public Group setGroup(Long id) {
if (id != null) {
return groupService.read(id);
} else {
return new Group();
}
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Specialty.class, "specialty",
new SpecialtyEditor(specialtyService));
binder.setValidator(new GroupValidator());
}
#RequestMapping("")
public ModelAndView groups() {
return new ModelAndView("teacher/groups/list", "groups",
groupService.list());
}
#RequestMapping("/edit")
public ModelAndView editGroup() {
return new ModelAndView("teacher/groups/edit", "specialties",
specialtyService.list());
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return "forward:/teacher/groups/edit";
}
groupService.update(group);
return "redirect:/teacher/groups";
}
}
I want to set the adequate behavior of my form in the case of failed validation. I.e. it should save its state but only show validation error message (as when using javascript to validate).
I thought that "forward:/teacher/groups/edit" will again forward request to editGroup() with saved objects group and result. But when I failed validation form just reloads and show start state of edited group: no errors and no saved changes.
How can I do that correctly?
Thanks!
I solved problem by not forwarding request to other method but sending answer to user immediately. Now it works and looks like:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return new ModelAndView("/teacher/groups/edit", "specialties", specialtyService.list());
}
groupService.update(group);
return new ModelAndView("redirect:/teacher/groups");
}

Categories