model attribute on a second (redirected) JSP page not working, throws error - Spring MVC - spring

My welcome page is Login.jsp. On submit it redirects to another page which enlists dummy transaction details of the logged in user.
please view this image link to see the login flow
However, when i try adding a form in the second page with a model attribute, it throws an error.
Login.jsp - form bit of code
<form:form method="POST" action="login2.html" modelAttribute="user" id="form">
<table>
<tr><td> <form:input path="user_id" placeholder="User ID:" value="" disabled="true"/></td></tr>
<tr><td><form:input path="email_id" placeholder="Email ID:" value="" /></td></tr>
<tr> <td> <form:password path="password" placeholder="Password" value="" /> </td></tr>
</table>
<input type="submit" value="Log-in"/>
</form:form>
Controller class action for login2.html
#RequestMapping(value = "/login2", method = RequestMethod.POST)
public ModelAndView login( #ModelAttribute("user") UserBean u1, BindingResult result) {
/*some code to call service class*/
/* lst is a list<Users>*/
model.put("t1", lst);
return new ModelAndView("save", model);
}
Save.jsp (redirected page)
<form:form method="POST" action="saveTransaction.html" modelAttribute="trans" id="form">
<table>
<tr>
<td><form:label path="transaction_id">Transaction ID:</form:label></td>
<td><form:input path="transaction_id" value="${i.transaction_id}" readonly="true"/></td>
</tr>
<tr>
<td><form:label path="user_id">User ID:</form:label></td>
<td><form:input path="user_id" value="${i.user_id}"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"/></td>
</tr>
</table>
</form:form>
<c:if test="${!empty t1}">
<table align="left" border="1">
<tr>
<th>transaction ID</th>
<th>User ID</th>
</tr>
<c:forEach var="i" items="${t1}">
<tr>
<td><c:out value="${i.transaction_id}"/></td>
<td><c:out value="${i.user_id}"/></td>
<td align="center">Edit | Delete</td>
</tr>
</c:forEach>
</table>
</c:if>
Controller class for action - saveTransaction.html
#RequestMapping(value = "/saveTransaction", method = RequestMethod.POST)
public ModelAndView saveTransaction( #ModelAttribute("trans") TransactionBeans t1, BindingResult result) {
/* some code */
/* lst is a list<TransactionDetails>*/
model.put("t1", lst);
return new ModelAndView("save", model);
}
TransactionBeans.java - bean class
public class TransactionBeans implements Serializable{
int user_id, transaction_id;
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public int getTransaction_id() {
return transaction_id;
}
public void setTransaction_id(int transaction_id) {
this.transaction_id = transaction_id;
}
}
This code works with the form - it enlists all the data as i have shown in above screenshot. However, it throws an error with form modelAttribute. Please note, model attributes in both forms are different, binding different tables.
Error thrown:
root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'trans' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198)
org.springframework.web.servlet.tags.form.LabelTag.autogenerateFor(LabelTag.java:129)
org.springframework.web.servlet.tags.form.LabelTag.resolveFor(LabelTag.java:119)
org.springframework.web.servlet.tags.form.LabelTag.writeTagContent(LabelTag.java:89)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
org.apache.jsp.WEB_002dINF.views.save_jsp._jspx_meth_form_005flabel_005f0(save_jsp.java:208)
org.apache.jsp.WEB_002dINF.views.save_jsp._jspx_meth_form_005fform_005f0(save_jsp.java:153)
org.apache.jsp.WEB_002dINF.views.save_jsp._jspService(save_jsp.java:93)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:439)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
So does this mean a redirected page cannot have a different model from the calling page binding another set of data?
Thanks.

I can't see anywhere in your controllers the attributes "user" and "trans" passed into your models. Your views with modelAttribute seem to expect them and it is why you receive this error.
Also it would be great to see your GET method handlers as you only provide the ones associated with POST methods.
I'm maybe missing the point of what you are trying to achieve, but each view renders the model attributes you give to it.
Does-it help if I suggest the following for the controllers ?
#RequestMapping(value = "/login2", method = RequestMethod.GET)
public ModelAndView login(ModelMap model) {
model.put("user", new UserBean(0, "", ""));
return new ModelAndView("Login", model);
}
#RequestMapping(value = "/login2", method = RequestMethod.POST)
public ModelAndView loginPost( #ModelAttribute("user") UserBean u1, ModelMap model, BindingResult result) {
List<TransactionBeans> lst = service.getAll();
model.put("t1", lst);
//Display default transaction
model.put("trans", new TransactionBeans(0, 0));
return new ModelAndView("save", model);
}
#RequestMapping(value = "/saveTransaction", method = RequestMethod.POST)
public ModelAndView saveTransaction(TransactionBeans t1, ModelMap model,BindingResult result) {
service.save(t1);
List<TransactionBeans> lst = service.getAll();
model.put("t1", lst);
model.put("trans", t1);
return new ModelAndView("save", model);
}
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView edit(#RequestParam("id") String transactionId, ModelMap model) {
TransactionBeans trans = service.get(transactionId);
List<TransactionBeans> lst = service.getAll();
model.put("t1", lst);
model.put("trans", trans);
return new ModelAndView("save", model);
}
Good luck

Related

Field is always null in Spring Boot Postmapping method

I want to bind my HTML table with all fields to Java code in Spring Boot.
Therefore, I have annotated my method with Postmapping, too.
I was already able to show all the fields in Thymeleaf and I was also able to set the checkBox value ( true / false ) accordingly.
This is my Thymeleaf HTML code:
<form action="#" th:action="#{/mitarbeiterverwaltung}" th:object="${users}" method="post">
<fieldset>
<table border="1" align="center">
<thead>
<tr>
<!-- <th:text = "#{mitarbeiterverwaltung.active}>Active ( Tick ) / Passive</th>-->
<th>Active ( Tick ) / Passive</th>
<th>ID</th>
<th>Username</th>
<th>Anzeigename</th>
<th>Dienstnummer</th>
</tr>
</thead>
<tbody>
<tr th:each="user, itemStat : *{users}">
<td><input th:field="*{users[__${itemStat.index}__].isActive}"
th:checked="${user.isActive}"
class="checkBox"
type="checkBox"
name="checkBox"
/></td>
<td><input th:field="*{users[__${itemStat.index}__].id}"
readonly/></td>
<td><input th:field="*{users[__${itemStat.index}__].username}"
readonly/></td>
<td><input class="anzeigename"
type="text"
name="anzeigename"
th:field="*{users[__${itemStat.index}__].anzeigename}"
th:id="${itemStat.index}"
readonly/></td>
<td><input class="dienstnummer"
type="text"
name="dienstnummer"
th:field="*{users[__${itemStat.index}__].dienstnummer}"
th:id="${itemStat.index}"
readonly/></td>
</tr>
</tbody>
</table>
<br />
<div style="text-align:center;">
<input type="submit" id="submitButton" th:value="Speichern"/>
</div>
</fieldset>
And this is my Java code, where the field isActive of UserCreationDto is always null.
#PostMapping
public String updateActivePassiveUser(#ModelAttribute UserCreationDto userTableSettings,
#RequestParam("checkBox") String checkBoxName, BindingResult result, Model model, Errors errors) {
logger.info("Method {} called in {}", new Object() {}.getClass().getEnclosingMethod().getName(), this.getClass().getName());
if (errors.hasErrors()) {
logger.error("Error in {}", new Object() {}.getClass().getEnclosingMethod().getName());
return "error";
}
List<Benutzer> users = userManagementServiceImpl.getAllUsers();
userManagementServiceImpl.updateActivePassiveUser(1, 0);
return "redirect:/mitarbeiterverwaltung?success";
}
Here is a picture of the field in Java code where the method is annotated with #PostMapping
And so does my #RequestMapping look like:
This is my #RequestMapping method:
#RequestMapping
public String showUserManagement(Model model) {
logger.info("Method {} called in {}", new Object() {}.getClass().getEnclosingMethod().getName(), this.getClass().getName());
List<Benutzer> users = userManagementServiceImpl.getAllUsers();
userForm = userManagementServiceImpl.saveUserForm(users);
model.addAttribute("users", userForm);
return "mitarbeiterverwaltung";
}
My UserCreationDto where all the fields get added to a list:
public class UserCreationDto {
private List<User> users = new ArrayList<>();
public void addUser(User user) {
this.users.add(user);
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
And my simple POJO class with all the fields
#Data
public class User {
//#SafeHtml prevents XSS ( Cross-Site Scripting )
#SafeHtml
private String username;
private String password;
private String anzeigename;
private String dienstnummer;
private long id;
private Boolean isActive;
}
The other fields like anzeigename, dienstnummer, id, and username are filled within my Java code, however, isactive is always null.
Maybe, someone can tell me what I am doing wrong here.
Thank you very much in advance.
I think you have to many options set. You don't need th:checked:
<input th:field="*{users[__${itemStat.index}__].isActive}"
class="checkBox"
type="checkBox"
name="checkBox" />
I found another way now, but it is not really nice.
#PostMapping
public String updateActivePassiveUser(#Valid #ModelAttribute("userForm") UserCreationDto userTableSettings,
#RequestParam List<String> searchValues, BindingResult result, Model model, Errors errors) {
The field searchValues contains all the checkBoxes that are ticked.
This is my view:
<td><input type="checkbox"
name="searchValues"
th:value="${user.id}"
th:checked="${user.isActive}"
/>
Now, the only problem that I am having is how to update my column that is of type Boolean in Postgresql?
For accomplishing this task I call this:
userRepo.updateActivePassiveUser(new Boolean("False"), id);
#Modifying
#Query(value = "UPDATE benutzer SET active = :active WHERE id = :id", nativeQuery = true)
#Transactional
void updateActivePassiveUser(#Param("active") Boolean active, #Param("id") long id);
However, the value in my database never changes.
Maybe, someone could give me a last hint, please!

Spring 4 mvc RedirectView with BindingResult errors and RedirectAttributes and ModelAttribute

I have controller (POST|GET) and jsp view form (add person)
how can I make a redirect if I have a mistake - to see errors on the page in the fields INPUT ? bindingResult.hasErrors() == true ?
if ok i see success FlashAttribute
if i have error i see FlashAttribute error but i don't see mistake fields INPUT
#RequestMapping(
value = "/addUserProfile",
method = RequestMethod.GET
)
public ModelAndView addUserProfile() {
ModelAndView modelAndView = new ModelAndView(VIEW_ADD_USER_PROFILE);
return modelAndView;
}
#ModelAttribute("userProfile")
UserProfile userProfile() {
return new UserProfile();
}
and view addUserProfile.jsp
<form:form id="data" action="/addUserProfile" method="POST" modelAttribute="userProfile" commandName="userProfile">
<p><pre><code>${errorMessage}</code></pre></p>
<p><pre><code>${id}</code></pre></p>
<p><pre><code>${successMessage}</code></pre></p>
<table>
<tr>
<td><form:label path="phone">phone</form:label></td>
<td><form:input path="phone"/></td>
<td><form:errors path="phone" cssClass="error"/></td>
</tr>
<tr>
<td><form:label path="firstname">firstname</form:label></td>
<td><form:input path="firstname"/></td>
<td><form:errors path="firstname" cssClass="error"/></td>
</tr>
<!--submit -->
<tr>
<td><input type="submit" value="submit"/></td>
</tr>
</table>
</form:form>
Howto redirect to
#RequestMapping(
value = "/addUserProfile",
method = RequestMethod.POST
)
public RedirectView addUserProfile(HttpServletRequest request,
#Valid #ModelAttribute("userProfile") UserProfile userProfile,
BindingResult bindingResult,
RedirectAttributes redirectAttrs) {
RedirectView redirectView = new RedirectView(request.getRequestURI());
if (bindingResult.hasErrors()) {
redirectAttrs.addFlashAttribute("errorMessage","error");
redirectView.setContextRelative(true);
} else {
redirectAttrs.addFlashAttribute("successMessage","success");
long id = userService.add(userProfile);
redirectAttrs.addFlashAttribute("id",id);
}
return redirectView;
}
Validate object form
public class UserProfile {
#NotEmpty
#Size(min = 9, max = 20)
private String phone;
#NotEmpty
#Size(min = 3, max = 20)
private String firstname;
}

Spring MVC #Valid not working when form is binded to a list

I am trying to do form validations on a Spring MVC form binded to a list of objects. The validations are not working. Please let me know if I am missing something
#Component
public class Customer{
#NotEmpty private int custId;
#NotEmpty private List<Order> orders;
//Getters & Setters...
}
#Component
public class Order{
#NotEmpty private String id;
#NotEmpty private String orderName;
//Getters & Setters...
}
//JSP - custFormBean is set as a model attribute
<form:form method="post" action="/submitOrder.htm" modelAttribute="custFormBean">
<table class="activity" width="600px" bgcolor="#FCF4DE">
<c:forEach items="${custForm.orders}" var="order" varStatus="status">
<tr>
<td>
<c:out value="${order.id}" />
</td>
</tr>
<tr>
<td>
<form:password path="orders[${status.index}].orderName" name="name" />
</td>
<td><form:errors path="orders[${status.index}].orderName" cssClass="errorMessage" /></td>
</tr>
</c:forEach>
<tr></tr>
<tr>
<td align="center" colspan="2">
<input type="submit" id="orderSubmit" class="formButton" value="OK" />
</td>
</tr>
</table>
</form:form>
//Controller
#Controller
#SessionAttributes("custFormBean")
public class CustomerController {
#RequestMapping(value = "/order.htm", method=RequestMethod.GET)
public String getOrder(ModelMap model, HttpServletRequest request) {
nextPage = "order"
try {
Customer custBean = custService.getCustOrders(...);
model.addAttribute("custFormBean", custBean);
} catch (ServiceException e) {
log.error("ServiceException when calling getChallengeQuestionLists", e);
}
return nextPage;
}
#RequestMapping(value = "/submitOrder.htm", method=RequestMethod.POST)
public String submitOrder(#Valid #ModelAttribute("custFormBean") Customer custBean, BindingResult result, Model model, HttpServletRequest request){
String nextPage = "success";
if(result.hasErrors()) {
//This is not working - The custBean is populated with the values entered in the form but if I leave the fields empty the validation is not kicking in.
log.debug("Validation errors...");
nextPage = "error";
}
return nextPage;
}
}
Please let me know if I am missing something
From Hibernate Validator javadoc of #NotEmpty:
Check that a String is not empty (not null and length > 0) or that a
Collection (or array) is not empty (not null and length > 0)
I think your list is not null and has length > 0 although all of them are blanks. So according to this the validator probably kicked it and yielded correct result.
You may need to write custom validator that checks there's at least a non-blank element in the list?

spring mvc requestmapping issues

i'm working in a spring mvc app (im new in spring mvc).
this is my controller:
#Controller
#RequestMapping("/prueba2")
public class controller2 {
Stock stock=new Stock();
List stockList=new ArrayList<Stock>();
ApplicationContext appContext = new ClassPathXmlApplicationContext("spring/config/BeanLocations.xml");
StockBo stockBo = (StockBo)appContext.getBean("stockBo");
#RequestMapping(method = RequestMethod.GET)
public Stock returnCustomer(ModelMap model) {
stock=stockBo.findByStockCode("7668");
model.addAttribute("miStock", stock);
return stock;
}
#RequestMapping(method = RequestMethod.GET)
public #ResponseBody
List<Stock>returnAll(ModelMap model) {
stockList=stockBo.findAll();
System.out.println("lista objetos--->"+stockList.toString());
model.addAttribute("listaStock", stockList);
return stockList;
}
public StockBo getStockBo() {
return stockBo;
}
public void setStockBo(StockBo stockBo) {
this.stockBo = stockBo;
}
}
this is my view:
<%# taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<h1>Message : "Por fin funciona!!!"</h1>
<table border="1">
<tr>
<th>Codigo Stock</th>
<th>Nombre Stock</th>
</tr>
<tr>
<td>${miStock.stockCode}</td>
<td>${miStock.stockName}</td>
</tr>
</table>
<h1>Tabla con lista de stock</h1>
<table>
<tr>
<th>Codigo Stock</th>
<th>Nombre Stock</th>
</tr>
<c:forEach items="${listaStock}" var="stock">
<tr>
<td>
${stock.stockCode}
</td>
<td>
${stock.stockName}
</td>
</tr>
</c:forEach>
</table>
<ul>codigo stock
<c:forEach items="${listaStock}" var="stock">
<li> <c:out value="${stock.stockCode}"></c:out> </li>
</c:forEach>
</ul>
</body>
</html>
what i want to do is to show 2 tables in the same JSP, i dont want to go to a different page to show each table, but i dont understand very well how to use the "requestmapping" to make it work.. now is just showing me the first table.
If you need access to the stock list as well as the individual stock item in the same JSP, then just add the stock list to the model.
#RequestMapping(method = RequestMethod.GET)
public Stock returnCustomer(ModelMap model) {
stock = stockBo.findByStockCode("7668");
model.addAttribute("miStock", stock);
model.addAttribute("listaStock", stockBo.findAll()); // Add the list to model
return stock;
}
Alternatively you can set it as a separate method which will save on duplication if it's used in many methods within the same controller.
#RequestMapping(method = RequestMethod.GET)
public Stock returnCustomer(ModelMap model) {
stock = stockBo.findByStockCode("7668");
model.addAttribute("miStock", stock);
return stock;
}
#ModelAttribute("listaStock")
public List<Stock> getAllStock() { // Called and set by Spring automatically
return stockBo.findAll();
}

why value of ModelMap attribute getting changed in jsp?

i have a controller given below:
#Controller
#SessionAttributes("user")
public class UserController {
#Autowired
AdminDaoInterface adminDao;
#Autowired
UserValidator userValidator;
#RequestMapping(value="userdetails.htm",method=RequestMethod.GET)
public String userDetails(ModelMap model) {
UserCommand userDetailsCmd = new UserCommand();
model.addAttribute("userDetailsCmd", userDetailsCmd);
return "UserDetails"; // will go to UserDetails.jsp
}
#RequestMapping(value="userdetails.htm",method = RequestMethod.POST)
public String userDetailsSubmit(
#ModelAttribute("userDetailsCmd") UserCommand userDetailsCmd,
Errors errors, ModelMap model){
//user will contains details of user found from database.
User user=adminDao.getUserOnId(userDetailsCmd.getUserId());
if(user==null) {
errors.rejectValue("userId", "user.not.exists");
return "UserDetails";
}
model.addAttribute("user",user);
return "ChangeUserDetails"; // will go to ChangeUserDetails.jsp
}
#RequestMapping(value="changeuserdetails.htm",method = RequestMethod.POST)
public String changeUserDetails(
#ModelAttribute("userDetailsCmd") UserCommand userDetailsCmd,
#ModelAttribute("user") User user){
// some stuff...
// BOTH user and userDetailsCmd OBJECTS HAVE A FIELD "userType"
// HERE user.userType SHOULD CONTAIN VALUE COLLECTED FROM DB (already
// existing value)
// AND userDetailsCmd.userType SHOULD CONTAIN VALUE SELECTED IN JSP IN
//ORDER TO UPDATE EXISTING VALUE of user.userType.
...
//BUT WHEN I SET VALUE OF userDetailsCmd.userType IN JSP, WHY VALUE OF
// user.userType GOT CHANGED ALWAYS TO THAT VALUE???
...
// somewhere later in code i m setting user.userType to
//userDetailsCmd.userType to update value.
adminDao.updateUser(user);
return "ChangeUserSuccess";
}
}
ChangeUserDetails.jsp is:
<form:form method="post" action="changeuserdetails.htm" commandName="userDetailsCmd">
<table>
<tr>
<td>User Id :</td>
<td>${user.userId}</td>
</tr>
<tr>
<td>Project :</td>
<td>${user.projectId} </td>
<td>Change To:</td>
<td>
<form:select path="projectId">
<form:option value="-1" label="SELECT"/>
<form:options items="${projectList}" itemValue="pid"
itemLabel="projectName"/>
</form:select>
</td>
</tr>
<tr>
<td>User Type :</td>
<td>${user.userType}</td>
<td>Change To:</td>
<td>
<form:select path="userType">
<form:option value="not changed" label="SELECT"/>
<form:option value="admin" label="Admin" />
<form:option value="user" label="User" />
</form:select>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Change User Details"/>
</td>
</tr>
</table>
</form:form>
why value of user.userType always got changed when i set/change value of command object userDetailsCmd (userDetailsCmd.userType) in jsp?
is this because both have same attribute name (userType)?
EDIT:
UserCommand class (command object)is :
public class UserCommand{
private String userId;
private String password;
private int projectId;
private String userType;
private int listUserId;
private List usersList;
//PLUS getters and setters for these fields...
}
And User class (a POJO )is:
public class User{
private String userId;
private String password;
private int projectId;
private String userType;
//PLUS getters and setters for these fields...
}
#InitBinder("user")
public void userBinding(DataBinder binder) {
binder.setDisallowedFields("userType");
}
Add this to your controller and the userType field of the User object will not get populated.

Resources