Spring SimpleFormController - Including Search Form In Success View - java

UPDATE 1/31/10: Since this thread continues to get a lot of views...I am curious if it has been of help to anyone recently? Feel free to leave comments/feedback, thanks.
I have a Spring form where I would like to reuse the search page to include the results under the search form. Currently when I do this I get the following error on loading the success view:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'searchAccounts' available as request attribute
Here is my bean configuration:
<bean name="/search.html" class="myapp.web.AccountSearchController">
<property name="sessionForm" value="true"/>
<property name="commandName" value="searchAccounts"/>
<property name="commandClass" value="myapp.service.AccountSearch"/>
<property name="validator">
<bean class="myapp.service.AccountSearchValidator"/>
</property>
<property name="formView" value="accountSearch"/>
<property name="successView" value="accountSearchResults"/>
</bean>
Here is the snippet of JSP that includes the search form:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form method="post" commandName="searchAccounts">
<table valign="top" cellspacing="0" cellpadding="0" width="500" border="0">
<tr>
<td valign="top">
<div class="border-title">Account Search</div>
<div id="navhome">
<div class="border">
<div id="sidebarhome">
<table id="form">
<tr>
<td colspan="2">Search by Account ID or Domain Name. If
values are provided for both, only accounts matching both values
will be returned.</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td align="right" valign="top"><form:label path="accountId">Account ID</form:label>:</td>
<td><form:input path="accountId" size="30"/></td>
</tr>
<c:set var="accountIdErrors"><form:errors path="accountId"/></c:set>
<c:if test="${not empty accountIdErrors}">
<tr>
<td> </td>
<td>${accountIdErrors}</td>
</tr>
</c:if>
<tr>
<td align="right" valign="top"><form:label path="domainName">Domain Name</form:label>:</td>
<td><form:input path="domainName" size="30"/></td>
</tr>
<c:set var="domainNameErrors"><form:errors path="domainName"/></c:set>
<c:if test="${not empty domainNameErrors}">
<tr>
<td> </td>
<td>${domainNameErrors}</td>
</tr>
</c:if>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td> </td>
<td><input type="submit" name="submit" value="Search">
</td>
</tr>
</table>
</div>
</div>
</div>
</td>
</tr>
</table>
</form:form>
And...here is my form controller class (less the imports):
public class AccountSearchController extends SimpleFormController {
protected final Log logger = LogFactory.getLog(getClass());
public ModelAndView onSubmit(Object command, BindException errors) throws ServletException {
String accountId = ((AccountSearch) command).getAccountId();
String domainName = ((AccountSearch) command).getDomainName();
logger.info("User provided search criteria...\n\tDomain Name: " + domainName + "\n\tAccountId: " + accountId);
//TODO do search
logger.info("returning from AccountSearch form view to " + getSuccessView());
return new ModelAndView(getSuccessView());
}
protected Object formBackingObject(HttpServletRequest request) throws ServletException {
AccountSearch accountSearch = new AccountSearch();
return accountSearch;
}
}
Thanks in advance for your help!
-aj
UPDATE:
I ported this to an annotated controller per answer below. Here is the new/working code:
#Controller
#RequestMapping("/search.html")
public class AccountSearchController {
// note: this method does not have to be called setupForm
#RequestMapping(method = RequestMethod.GET)
public String setupForm(Model model) {
AccountSearchCriteria accountSearchCriteria = new AccountSearchCriteria();
model.addAttribute("accountSearchCriteria", accountSearchCriteria);
model.addAttribute("title", "Account Search");
return "accountSearch";
}
// note: this method does not have to be called onSubmit
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("accountSearchCriteria") AccountSearchCriteria accountSearchCriteria, BindingResult result, SessionStatus status, Model model) {
new AccountSearchValidator().validate(accountSearchCriteria, result);
if (result.hasErrors()) {
return "accountSearch";
} else {
ArrayList<AccountSearchCriteria> accountSearchResults = new ArrayList<AccountSearchCriteria>();
AccountSearchCriteria rec = new AccountSearchCriteria();
rec.setDomainName("ajcoon.com");
accountSearchResults.add(rec);
AccountSearchCriteria rec2 = new AccountSearchCriteria();
rec2.setDomainName("ajcoon2.com");
accountSearchResults.add(rec2);
//TODO do search
//ArrayList<HashMap<String,String>> accountSearchResults = new AccountSearchService().search(accountId,domainName);
if( accountSearchResults.size() < 1 ){
result.rejectValue("domainName", "error.accountSearch.noMatchesFound", "No matching records were found.");
return "accountSearch";
} else if(accountSearchResults.size() > 1){
model.addAttribute("accountSearchResults", accountSearchResults);
return "accountSearch";
} else {
status.setComplete();
return "redirect:viewAccount?accountId=";
//return "redirect:viewAccount?accountId=" + accountSearchResults.get(0).getAccountId();
}
}
}
}

try to use (throws Exception instead of ..)
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
AccountSearch accountSearch = new AccountSearch();
System.out.println("inside formBackingObject");
return accountSearch;
}
It looks like your formBackingObject Method is not executed. rerun the code with the above change and see log console to see if the method is executed.
--
You should be using annotation instead of extending controller. Spring 3.0 will deprecate the controller hierarchy.

Related

How to have add and remove buttons in html form handle by spring 5 controller?

I am using Spring 5 and Hibernate 5.
I have got form like below in jsp file:
<form:form action="addUser" method="post" modelAttribute="user">
<table>
<tr>
<td>Name</td>
<td>
<form:input path="name" /> <br />
<form:errors path="name" cssClass="error" />
</td>
</tr>
<tr>
<td>Email</td>
<td>
<form:input path="email" /> <br />
<form:errors path="email" cssClass="error" />
</td>
</tr>
<tr>
<td colspan="1"><button type="submit">Submit</button></td>
<td colspan="1"><button type="???delete???">Remove</button></td>
</tr>
</table>
</form:form>
And UserController.java like below:
#Controller
public class UserController {
#Autowired
private UserService userService;
#GetMapping("/")
public String userForm(Locale locale, Model model) {
model.addAttribute("users", userService.list());
return "editUsers";
}
#ModelAttribute("user")
public User formBackingObject() {
return new User();
}
#PostMapping("/addUser")
public String saveUser(#ModelAttribute("user") #Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("users", userService.list());
return "editUsers";
}
userService.save(user);
return "redirect:/";
}
}
Right now I have got a submit button which allow me to save name and email of the user.
I would like to add button REMOVE which would also relay on the same form but will instead of adding new user will be removing existing user.
Could you tell how can I do it?
Maybe the first option is to add some attribute like action, but then I need to handle it in controller and I don't know how?
Thank you.
It can be done by changing the form action dynamically based on the button click using some javascript.
<script>
$('#addBtn').click(function(){
$("#userForm").submit();
});
$('#removeBtn').click(function(){
$('#userForm').attr('action', '<your remove action>');
$("#userForm").submit();
});
<script>
<form:form action="addUser" method="post" modelAttribute="user" id="userForm">
...
<td colspan="1"><button type="button" id='addBtn'>Submit</button></td>
<td colspan="1"><button type="button" id='removeBtn'>Remove</button></td>
...
</form:form>

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);
}

No output info on .JSP from MySQL DB, Spring MVC, Hibernate, JAVA

I'm trying to output some information from table users on my JSP page, but there is no output there.
Here is my controller method:
#Autowired
private UsersService usersService;
#RequestMapping(value="/user**")
public String getUserProfile( ) {
ModelAndView mav = new ModelAndView("userInfo");
List<Users> userInfo = usersService.userInfo("Oleg");
mav.addObject("userInfo", userInfo);
return "user";
}
Here is my DAO method
#SuppressWarnings("unchecked")
#Override
public List<Users> userInfo(String username) {
Transaction tx = sessionFactory.getCurrentSession().beginTransaction();
Session session = this.sessionFactory.getCurrentSession();
String query = "select users.username, users.name, users.surname, users.email, users.gender, users.age, users.weight, users.height, users.sport, users.place from users where users.username LIKE '%s'";
List<Users> userInfo = session.createSQLQuery(String.format(query,username)).list();
tx.commit();
return userInfo;
}
Here is my Service layer method
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>User Profile Page</title>
</head>
<body>
<br />
<br />
<br />
<h1>User profile page !!!</h1>
<c:url var="logoutUrl" value="j_spring_security_logout" />
<form action="${logoutUrl}" method="post">
<input type="submit" value="Log out" /> <input type="hidden"
name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:forEach var="users" items="${userInfo}">
<table>
<tr>
<td>Username</td>
<td>${users.username}</td>
</tr>
<tr>
<td>First Name</td>
<td>${users.name}</td>
</tr>
<tr>
<td>Last Name</td>
<td>${users.surname}</td>
</tr>
<tr>
<td>Email</td>
<td>${users.email}</td>
</tr>
<tr>
<td>Gender</td>
<td>${users.gender}</td>
</tr>
<tr>
<td>Age</td>
<td>${users.gender}</td>
</tr>
<tr>
<td>Weight</td>
<td>${users.weight}</td>
</tr>
<tr>
<td>Height</td>
<td>${users.height}</td>
</tr>
<tr>
<td>Sport</td>
<td>${users.sport}</td>
</tr>
<tr>
<td>Place</td>
<td>${users.place}</td>
</tr>
</table>
</c:forEach>
</body>
</html>
When i'm starting my project and opening my JSP, i have no output from my DB. Help pls!

Spring JSP passing variables

I want to handle simple form. Here's form from my signUp.jsp, where from I receive my data
<form:form method="POST" commandName="user-entity" action="process.html">
<table>
<tr>
<td><form:label path="userName">Name:</form:label></td>
<td><form:input path="userName" /></td>
</tr>
<tr>
<td><form:label path="label">Age:</form:label></td>
<td><form:label path="label"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit"/>
</td>
<td></td>
<td></td>
</tr>
</table>
</form:form>
And part of my result.jsp
<p>User's name is ${user.userName}. The age is ${user.age}.</p>
And UserController.java
#Controller
public class UserController {
#RequestMapping(value = "/signUp")
public ModelAndView signUpPage() {
return new ModelAndView("signUp", "user-entity", new User());
}
#RequestMapping(value = "/process")
public ModelAndView processUser(#ModelAttribute User user) {
ModelAndView model = new ModelAndView();
model.setViewName("result");
model.addObject("user", user);
return model;
}
}
As the result I get
User's name is ${user.userName}. The age is ${user.password}.
and i have no idea why. Where might be the problem?
Missing
<%# page isELIgnored="false"%> in result.jsp
Solution brought from here

Showing error message on JSP using BindingResult

I am new to Spring.
I am trying to show error messages on jsp for the wrong user and password by using BindingResult. But the error messages are not showing.
Please suggest me what I is wrong in the below code.
JSP
<script type="text/javascript">
function loginUser() {
$('#loginForm').submit();
}
</script>
</head>
<body>
<form:form action="login.test" id="loginForm" commandName="loginForm" method="POST">
<div class="brand_area"></div>
<div class="content_area">
<table style="top: 360px; position: relative; margin-left: 333px;">
<tr id="uNameID">
<td class="label">User Name:</td>
<td><form:input id="userNameID" path="userName" class="textInput" /></td>
<td><form:errors path="userName" class="error"/></td>
</tr>
<tr id="pID">
<td class="label">Password:</td>
<td><form:password id="passwordID" path="password" class="textInput" /></td>
<td><form:errors path="password" class="error"/></td>
</tr>
<tr>
<td></td>
<td><span id="saveButton" class="loginButton"
onclick="loginUser()"> <span>Login</span>
</span></td>
</tr>
</table>
</div>
</form:form>
Controller
#RequestMapping(value = "login.test", method = RequestMethod.POST)
public String processForm( LoginForm loginForm, BindingResult result, ModelMap model, HttpSession session) throws SQLException {
String resultedPage;
model.addAttribute("l_nodes", reportService.getAllLiveNodes());
model.addAttribute("s_nodes", reportService.getAllStaticReportNodes());
User user = userService.getUserByName( loginForm.getUserName() );
if( user != null ){
session.setAttribute("userID", user.getUserID());
if( loginForm.getPassword().equals( user.getPassword() ) ){
resultedPage = "home/userHome";
}else{
result.rejectValue( "password", "login.passwordNotValid");
resultedPage = "redirect:login.test";
}
}else{
result.rejectValue( "userName", "login.userNotValid");
resultedPage = "redirect:login.test";
}
return resultedPage;
}
Thanks
In case anyone else research the same...
Add the hasBindErrors tag to your JSP:
<spring:hasBindErrors name="loginForm">
<c:forEach var="error" items="${errors.allErrors}">
<b><spring:message message="${error}" /></b>
<br/>
</c:forEach>
</spring:hasBindErrors>
Well, i generally send back the values using the Model object.
May be this answer might help you.

Categories