JSP or Spring MVC controller display same info several times - java

I have controller which adds Computer assigned to User by admin. User can have several assigned Computers and it is implemented through Spring MVC Multiple Selection. But I’ve little issue with displaying of info after updating. It shows as many users in List of users as many computers were assigned. I think problem not in JSP and debuggers shows nothing so I’ll very appreciate your help.
Here is my AdminUserUpdateController.java
#Controller
public class AdminUserUpdateController {
#InitBinder("userForm")
private void initBinder(WebDataBinder binder) {
binder.setValidator(updateValidator);
binder.registerCustomEditor(Set.class, "computers", new CustomCollectionEditor(Set.class) {
#Override
protected Object convertElement(Object element) {
String pcName = null;
if (element instanceof String && !((String) element).equals("")) {
try {
pcName = (String) element;
Set<Computer> computerSet = new LinkedHashSet<>();
computerSet.add(computerService.getComputerByName(pcName));
new UserForm().setComputers(computerSet);
} catch (NumberFormatException e) {
logger.info("Error in element");
logger.info("Element was " + ((String) element));
}
}
return pcName != null ? computerService.getComputerByName(pcName) : null;
}
});
}
...............
#RequestMapping(value = "/adminEdit/{userId}", method = RequestMethod.GET)
public String updateView(#PathVariable("userId") Integer userId,
UserForm userForm,
ModelMap model) {
userForm.setUser(userService.getUserById(userId));
model.addAttribute("userForm", userForm);
model.addAttribute("computers", computerService.getAllComputers());
return "adminUserUpdate";
}
#RequestMapping(value = "adminEdit.do/{userId}", method = RequestMethod.POST)
public ModelAndView updateUserProcess(#ModelAttribute(value = "userForm")
UserForm userForm,
#PathVariable("userId") Integer userId,
BindingResult result, Model model) {
User user = userService.getUserById(userId);
model.addAttribute("computers", computerService.getAllComputers());
model.addAttribute("userForm", userForm);
updateValidator.validate(userForm, result);
return updatingUser(user, model, userForm);
}
private ModelAndView updatingUser(User user, Model model,
UserForm userForm) {
if (isEmailExists(userForm, user)) {
model.addAttribute("errorMsg", "Email is already in use!");
return new ModelAndView("adminUserUpdate");
}
fillForm(userForm, user);
user = userForm.getUser();
userService.updateUser(user);
return new ModelAndView("redirect:/adminPage", "user", user);
}
private void fillForm(UserForm userForm, User user) {
userForm.setUserId(user.getUserId());
userForm.setLogin(user.getLogin());
userForm.setRegDate(user.getRegDate());
// userForm.setComputers(computer);
userForm.setRole(roleService.findByName(user.getRole().getRoleName()));
}
}
And here it is my JSP
<!--BEGIN OF USERS TABLE-->
<div align="center">
<table border=1>
<thead align="center">
<tr>
<th>User Id</th>
<th>Login</th>
<th>Name</th>
<th>Password</th>
<th>Email</th>
<th>Regsiter Date</th>
<th>PC Assigned</th>
<th colspan=2>Action</th>
</tr>
</thead>
<tbody align="center">
<tr>
<c:forEach items="${members}" var="user">
<td><c:out value="${user.userId}"/></td>
<td><c:out value="${user.login}"/></td>
<td><c:out value="${user.name}"/></td>
<td><c:out value="${user.password}"/></td>
<td><c:out value="${user.email}"/></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${user.regDate}"/></td>
<td>
<c:choose>
<c:when test="${user.computers!= null && !user.computers['empty']}">
<c:forEach items="${user.computers}" var="comp">
<c:out value="${comp.pcName}"/>
</c:forEach>
</c:when>
<c:otherwise>
<p class="h3_error">No PC Assigned</p>
</c:otherwise>
</c:choose>
</td>
<td>Update</td>
<td>Delete</td>
</tr>
</c:forEach>
</tbody>
</table>
<br>
</div>
<!--END OF USERS TABLE-->

Related

How to get a list of objects from a JSP in a Controller

I have some issues with my code. I try to get a list of object from a jsp in my controller to send it to my service with a POST
When I try to get the list in my controller with the annotation #ModelAttribute it return me an empty list. Here my controller class and my jsp
Controller
#GetMapping("/OvedraftsCustomer")
public String getOverdraftsCustomers(ModelMap model){
List<AccountDTO> overdraftAccounts = overdraftService.getOverdraftAccounts();
model.addAttribute("overdraftAccounts",overdraftAccounts);
return "agios/displayOverdraftCustomers";
}
#PostMapping("/agioDetails")
public String getOverDraftDetails(#ModelAttribute("account") ArrayList<AccountDTO> account, BindingResult binding, ModelMap model) throws ParseException {
model.addAttribute("accounts",account);
logger.info("taille : " + account.size());
return "redirect:agiosInfo";
}
JSP
<table class="w3-table-all w3-hoverable">
<tr class="w3-hover-blue w3-blue">
<th>Nom</th>
<th>Prénom </th>
<th>iban</th>
<th>email</th>
<th>Découvert Autorisé</th>
<th>Découvert actuel</th>
<th>Taux débiteurs</th>
</tr>
<c:forEach items="${overdraftAccounts}" var="overdraftAccounts">
<tr class="w3-hover-blue">
<td><c:out value="${overdraftAccounts.getCustomer().getName()}" /></td>
<td><c:out value="${overdraftAccounts.getCustomer().getSurname()}" /></td>
<td><c:out value="${overdraftAccounts.getIban()}" /></td>
<td><c:out value="${overdraftAccounts.getCustomer().getEmail()}" /></td>
<td><c:out value="${overdraftAccounts.getCustomer().getAgioParameters().getAuthorizedOverdraft()}" /></td>
<td><c:out value="${overdraftAccounts.getOldBalances().get(overdraftAccounts.getOldBalances().size()-1).getBalance()}" /></td>
<td><c:out value="${overdraftAccounts.getCustomer().getAgioParameters().getBorrowingRate()}" /></td>
</tr>
</c:forEach>
</table>
</br>
</br>
<form method="POST" action="/agioDetails" modelAttribute="account">
<c:forEach var="test" items="${accounts}" varStatus="status">
<form:input path="accounts[${status.index}].getIban()" name="iban" id="iban" value="test.getIban()" />
<form:input path="accounts[${status.index}].getBalance()" name="balance" id="balance" value="test.getBalance()" />
<form:input path="accounts[${status.index}].oldBalances()" name="oldBalances" id="oldBalances" value="test.getOldBalances()" />
<form:input path="accounts[${status.index}].getCustomer()" name="customer" id="customer" value="test.getCustomer()" />
<form:input path="accounts[${status.index}].getAgios()" name="agios" id="agios" value="test.getAgios()" />
</c:forEach>
</br>
<table align="center">
<tr>
<td colspan="2"><input class="w3-button w3-padding-large w3-blue" type="submit" value="Consulter le détail"/></td>
</tr>
</table>
</form>
Currently, I am just trying to get the list in my controller from my jsp therefore I just try to see if my list is not empty in my controller. If anyone can help me with this issue and explain what i have done wrongly please..
Hi I think your way of making a post request to your controller is little bit messy, so I'll recommend that you try to do this:
First in your java Create a Entity class for your Details,
e.g.
Details.java
public class Details {
private String iban;
private Integer balance;
private Integer oldBalances;
private String customer;
private String agios;
public String getIban() {
return iban;
}
public void setIban(String iban) {
this.iban = iban;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public Integer getOldBalances() {
return oldBalances;
}
public void setOldBalances(Integer oldBalances) {
this.oldBalances = oldBalances;
}
public String getCustomer() {
return customer;
}
public void setCustomer(String customer) {
this.customer = customer;
}
public String getAgios() {
return agios;
}
public void setAgios(String agios) {
this.agios = agios;
}
#Override
public String toString() {
return "Details [iban=" + iban + ", balance=" + balance + ", oldBalances=" + oldBalances + ", customer="
+ customer + ", agios=" + agios + "]";
}
}
and add this id to your button"btnSubmit" and put this to your javascipt(I'm using jquery)
var details = {};
$("#btnSubmit").click(function(){
details.iban = $("#iban").val();
details.balance = $("#balance ").val();
details.oldBalances = $("#oldBalances").val();
details.customer = $("#customer ").val();
details.agios = $("#agios ").val();
$.ajax({
method: "POST",
headers: {
"Content-Type":"application/json"
},
url: "/agioDetails",
data: JSON.stringify(details ),
success: function( result ) {
alert("okay");
}
});
})
and do this to your controller
#PostMapping(value = "/agioDetails", consumes = "application/json")
ModelAndView getRecord(#RequestBody Details details) throws SQLException, Exception {
System.out.println(details);
ModelAndView mv = new ModelAndView("index");
return mv;
}
the datas should have been passed to your java cotroller without errors.

After submitting a form go back to previous page (Spring/Hibernate)

I have a restaurant edit page located "/restaurant/edit/{id}". From that page I can (among other things) add tables to the restaurant by pressing an "Add tables" button. That button takes me to another page located "/restaurant/edit/{id}/table". The question is, after I have added the table - how do I get back to the previous page by pressing a button? Right now my contoller is returning "editRestaurant.jsp" which is the right value, but I don't know how to pass that same restaurant id as well. I hope you understand what I mean.
My RestaurantTableController.java:
#Controller
public class RestaurantTableController {
#Autowired
private RestaurantService restaurantService;
#Autowired
private RestaurantTableService restaurantTableService;
#RequestMapping(value="restaurant/{id}/table", method = RequestMethod.GET)
public String addRestaurantTable(Model model, #PathVariable Long id) {
model.addAttribute("table", new RestaurantTable());
return "newTable";
}
#RequestMapping(value = "restaurant/{id}/table", method = RequestMethod.POST)
public String addRestaurantTableAction(#PathVariable Long id, #ModelAttribute ("table") RestaurantTable table, BindingResult result) {
RestaurantTableFormValidator restaurantTableFormValidator = new RestaurantTableFormValidator();
restaurantTableFormValidator.validate(table, result);
if (result.hasErrors()) {
return "newTable";
}
restaurantService.mergeRestaurant(id, table);
return "editRestaurant";
}
}
My "newTable.jsp":
<body>
<jsp:include page="../fragments/menu.jsp"/>
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Add New Table</h2>
<form:form method="POST" modelAttribute="table">
<table>
<tr>
<td>Table size:</td>
<td><form:input path="tableSize" /></td>
<td><form:errors path="tableSize" cssClass="error"/></td>
</tr>
<tr>
<td>Table number:</td>
<td><form:input path="tableNumber" /></td>
<td><form:errors path="tableNumber" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" onclick="goback()"/>
</td>
</tr>
</table>
</form:form>
</section>
</div>
<jsp:include page="../fragments/footer.jsp"/>
</body>
Relevant methods in RestaurantController.java:
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
model.addAttribute("restaurant", restaurant);
return "editRestaurant";
}
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.POST, params="submit")
public String editRestaurant(#ModelAttribute ("restaurant") Restaurant restaurant, BindingResult result) {
RestaurantFormValidator restaurantFormValidator = new RestaurantFormValidator();
restaurantFormValidator.validate(restaurant, result);
if (result.hasErrors()) {
return "editRestaurant";
}
restaurantService.updateRestaurant(restaurant);
return "redirect:/bookings";
}
"editRestaurant.jsp":
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Edit</h2>
<form:form method="POST" modelAttribute="restaurant" >
<table>
<tr>
<td>Restaurant:</td>
<td><form:input path="restaurantName" /></td>
<td><form:errors path="restaurantName" cssClass="error"/></td>
</tr>
<tr>
<td>Address:</td>
<td><form:input path="address" /></td>
<td><form:errors path="address" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Submit" name="submit"/>
</td>
</tr>
<tr>
<c:forEach items="${restaurant.table}" var="item">
<td>${item.toString()}</td>
</c:forEach>
</tr>
<tr>
<td>Add Table</td>
</tr>
</table>
</form:form>
<div>
Back to List
</div>
</section>
</div>
After successful POST you should do a redirect.
Something like this:
return "redirect:/restaurant/edit/" + restaurant.getId();
or
return new RedirectView("/restaurant/edit/" + restaurant.getId(), false);
There is a different method you can use to return the model that will include the parameter. I believe this may solve your problem.
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
return new ModelAndView("editRestaurant", "restaurant", restaurant);
}

How to loop the key and value(which is in UserDefinedClass) of Hashmap in ModelAndView to JSP using JSTL

I am having a problem showing my key and value from my HashMap in which the value is in User Defined Class here is the error that shows
Student.class:
class Student
{
private String name;
private int age;
//getter and setter
}
My CONTROLLER:
#RequestMapping(value = "/showStudent", method = RequestMethod.GET)
public ModelAndView retrievesession(HttpSession session)
{
ModelAndView mav = new ModelAndView("ShowStudent");
Map<String,ArrayList<Student>> classList = new HashMap<String,ArrayList<Student>>();
ArrayList<Student> student = new ArrayList<Student>();
String nameUser = (String) session.getAttribute("name");
String trackUser = (String) session.getAttribute("track");
if(nameUser.equals("Kakashi") && trackUser.equals("Konoha"))
{
student.add(new Student("Naruto",12));
student.add(new Student("Sasuke",13));
classList.put("Ninja", student);
mav.addObject("classList", classList);
}
else if(nameUser.equals("Goku") && trackUser.equals("Earth"))
{
student.add(new Student("Gohan",25));
student.add(new Student("Goten",13));
classList.put("Fighter", student);
mav.addObject("classList", classList);
}
else if(nameUser.equals("Ryuk") && trackUser.equals("Killer"))
{
student.add(new Student("Kira",22));
student.add(new Student("L",21));
classList.put("Reaper", student);
mav.addObject("classList", classList);
}
return mav;
}
My JSP:
<h3>Name: ${name}</h3>
<h3>Track: ${track}</h3><br/><br/><br/>
<h3>Your student from ${classList.key}</h3>
<c:if test="${not empty classList}">
<table>
<c:forEach items="${classList}" var="classList">
<tr>
<td>${classList.value.name}</td>
<td>${classList.value.age}</td>
</tr>
</c:forEach>
</table>
</c:if>
I don't know if I'm doing it correctly, it is just showing the values that I am having a problem with, and also can I add an else statement, so if the session is null it will return to the login page?
Iterating over the map you'll get one more collection you need to iterate in another loop before you can get properties of the object.
<table>
<c:forEach items="${classList}" var="list">
<tr><td><h3>Your student from ${list.key}</h3></td></tr>
<tr><td>
<table>
<c:forEach items="${list.value}" var="student">
<tr>
<td>${student.name}</td>
<td>${student.age}</td>
</tr>
</c:forEach>
</table>
</td></tr>
</c:forEach>
</table>
Use the code as:-
<h3>Name: ${name}</h3>
<h3>Track: ${track}</h3><br/><br/><br/>
<h3>Your student from ${classList.key}</h3>
<c:if test="${not empty classList}">
<table>
<c:forEach items="${classList}" var="class">
<tr>
<td>${class.name}</td>
<td>${class.age}</td>
</tr>
</c:forEach>
</table>

Form validation with form:options

Form:Options working pretty well, but if I submit wrong data in Form, form:options in newContact.jsp shows the first element of departmentList as selected.
ContactController:
#RequestMapping(value="/saveContact", method=RequestMethod.GET)
public ModelAndView newuserForm(){
ModelAndView mav = new ModelAndView("newContact");
// Contact contact = new Contact();
// Department department = new Department();
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
mav.addObject("username", name);
mav.addObject("newContact", new Contact());
// mav.addObject("department", department);
mav.addObject("departmentList", departmentService.listDepartment());
//mav.getModelMap().put("newContact", contact);
return mav;
}
#RequestMapping(value="/saveContact", method=RequestMethod.POST)
public String create(#ModelAttribute("newContact")Contact contact, BindingResult result, SessionStatus status,Map<String, Object> map)
{
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
map.put("departmentList", departmentService.listDepartment());
map.put("username", name);
contactFormvalidator.validate(contact, result);
if (result.hasErrors())
{
return "newContact";
}
contactService.addContact(contact);
status.setComplete();
//return "redirect:/showContacts.do";
return "newContactSuccess";
}
newContact.jsp:
<%#include file="header.jsp"%>
<div id="menu">
<div id="subMenu"></div>
</div>
<div id="main">
<h2>Contact Manager</h2>
<form:form method="post" action="saveContact.do" commandName="newContact" >
<table>
<tr>
<td><form:label path="firstname">
<spring:message code="label.firstname" />
</form:label></td>
<td><form:input path="firstname" /></td>
<td><form:errors path="firstname" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="lastname">
<spring:message code="label.lastname" />
</form:label></td>
<td><form:input path="lastname" /></td>
<td><form:errors path="lastname" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="email">
<spring:message code="label.email" />
</form:label></td>
<td><form:input path="email" /></td>
<td><form:errors path="email" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="telephone">
<spring:message code="label.telephone" />
</form:label></td>
<td><form:input path="telephone" /></td>
<td><form:errors path="telephone" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td><form:label path="department">
<spring:message code="label.department" />
</form:label></td>
<td><form:select path="department" >
<form:option label="**SELECT**" value="0"></form:option>
<form:options items="${departmentList}" itemValue="id" itemLabel="name"></form:options>
</form:select> </td>
<td><form:errors path="department" cssStyle="color:red"></form:errors> </td>
</tr>
<tr>
<td colspan="2"><input type="submit"
value="<spring:message code="label.addcontact"/>" /></td>
</tr>
</table>
</form:form>
</div>
<%# include file="footer.jsp"%>
ContactFormValidator:
package pl.ivmx.contact.validator;
import java.util.regex.*;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import pl.ivmx.contact.form.Contact;;
//#Component("contactFormValidator")
public class ContactFormValidator implements Validator{
#Override
public boolean supports(Class clazz) {
return Contact.class.isAssignableFrom(clazz);
}
#SuppressWarnings("unchecked")
#Override
public void validate(Object obj, Errors errors) {
Contact contact = (Contact) obj;
Pattern p = Pattern.compile("[a-zA-Z]*[0-9]*#[a-zA-Z]*.[a-zA-Z]*");
Matcher m = p.matcher(contact.getEmail());
boolean b = m.matches();
if (b != true) {
errors.rejectValue("email", "error.is.not.valid",
"Email does not Valid ");
}
if (contact.getFirstname() == null || contact.getFirstname().length() < 3) {
errors.rejectValue("firstname", "error.empty.field",
"Please Enter First Name");
}
if (contact.getLastname() == null || contact.getLastname().length() < 4) {
errors.rejectValue("lastname", "error.empty.field",
"Please Enter Last Name");
}
if (contact.getTelephone() == 0 || String.valueOf(contact.getTelephone()).trim().length() < 2 ||
String.valueOf(contact.getTelephone()).trim().length() > 9) {
errors.rejectValue("telephone", "error.empty.field",
"Please Enter Telephone");
}
if (contact.getDepartment() == null) {
errors.rejectValue("department", "error.empty.field",
"Please select department");
}
}
}
Instead of returning String in your submit method return ModelAndView ...
#RequestMapping(value="/saveContact", method=RequestMethod.POST)
public ModelAndView create(#ModelAttribute("newContact")Contact contact, BindingResult result, SessionStatus status,ModelMap map)
{
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
map.addAttribute("departmentList", departmentService.listDepartment());
map.addAttribute("username", name);
contactFormvalidator.validate(contact, result);
if (result.hasErrors())
{
return new ModelAndView("newContact",map);
}
contactService.addContact(contact);
status.setComplete();
//return new ModelAndView("redirect:/showContacts.do");
return new ModelAndView("newContactSuccess");
}

Neither BindingResult nor plain target object for bean name 'index' available as request attribute

I have a problem when trying to access the controller.
Here is my controller:
#Controller
#RequestMapping("/index.htm")
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
public String showForm(Map model) {
model.put("index", new LoginForm());
return "index";
}
#RequestMapping(method = RequestMethod.POST)
public String processForm(LoginForm loginForm, BindingResult result,
Map model) {
if (result.hasErrors()) {
HashMap<String, String> errors = new HashMap<String, String>();
for (FieldError error : result.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
model.put("errors", errors);
return "index";
}
List<User> users = userService.getUsers();
loginForm = (LoginForm) model.get("loginForm");
for (User user : users) {
if (!loginForm.getEmail().equals(user.getEmail()) || !loginForm.getPassword().equals(user.getPassword())) {
return "index";
}
}
model.put("index", loginForm);
return "loginsuccess";
}
}
Here is my form:
<form:form action="index.htm" commandName="index">
<table border="0" cellspacing="12">
<tr>
<td>
<spring:message code="application.loginForm.email"/>
</td>
<td>
<form:input path="email"/>
</td>
<td class="error">
<form:errors path="email"/>
</td>
</tr>
<tr>
<td>
<spring:message code="application.loginForm.password"/>
</td>
<td>
<form:password path="password"/>
</td>
<td class="error">
<form:errors path="password"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
On form submit I am getting this exception:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'index' available as request attribute.
What am I doing wrong here?
It's because you're only doing this bit down at the bottom
model.put("index", loginForm);
If you return from the validation error, or from a success, there is no backing object in the model map named "index" so your form tag that has commandName="index" pitches a fit.
A common solution is to simply do this
#ModelAttribute("index")
public LoginForm getLoginForm() {
return new LoginForm();
}
Then there will always be one present, and you can take adding it out of the GET method.

Categories