Simple JSP-Spring 3 dropdown list not working - spring

I know this should be pretty easy but I'm stuck after trying several things.
I'm only trying to display in my jsp a basic dropdown list. Spring version is 3 so I want everything to work with annotations.
JSP form with dropdown list:
<form:form method="post" commandName="countryForm">
<table>
<tr>
<td>Country :</td>
<td><form:select path="country">
<form:option value="Select" label="Select" />
</form:select>
</td>
<tr>
<td colspan="3"><input type="submit" /></td>
</tr>
</table>
</form:form>
CountryForm.java is a plain object with a single String attribute "country", with its getters and setters.
Controller who deals with the GET request is the following:
#Controller
public class CountryFormController {
#RequestMapping(value = "MainView", method = RequestMethod.GET)
public String showForm(Map model) {
CountryForm cform = new CountryForm();
model.put("countryForm", cform);
return "MainView";
}
}
However, when I redirect to the JSP "MainView" I get the typical error:
org.apache.jasper.JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'countryForm' available as request attribute
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:502)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:424)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
What am I doing wrong?

The select tag in the Spring TagLib needs to be provided with a collection, map or array of options. I'm not sure what you would like these to be so I will make some assumptions.
You need to include a collection, map or array of objects in your controller. Ideally you would have a Country class and create new instances for a set of countries. For the example to work with your code, I just created a static list of countries. Add the list to your model and then modify the select tag, setting the options to ${countries}. Assuming country is a field of type String on CountryForm with appropriate get/set methods, the country should data-bind to field when the form is submitted.
Controller
#Controller
public class CountryFormController {
#RequestMapping(value = "MainView", method = RequestMethod.GET)
public String showForm(Map model) {
List<CountryForm> cfs = new ArrayList<CountryForm>();
cfs.add("United States");
cfs.add("Canada");
model.put("countries", cfs);
model.put("countryForm", cform);
return "MainView";
}
}
JSP
<form:select path="countryForm.country" options="${countries}"/>

I have sample code at GitHub, try it an let me know. Look at landing.jsp and UserController
<form:select path="users[${status.index}].type" >
<form:option value="NONE" label="--- Select ---"/>
<form:options itemValue="name" itemLabel="description" />
</form:select>
HTH

Related

Why do I lose information after submit a form with Spring MVC?

As I say int the title I loose information in the object that comes back from JSP to Controller.
From my Controller I pass a ModelAndView with an object of class Historic.
In the JSP page I have access to all of the values of this object, but when I submit I just get part of this information, some looses on the way on.
Controller:
#GetMapping("/tt")
public ModelAndView index(Model model) {
HistoricBO historic = new HistoricBO();
// ... I fulfill this object ...
return new ModelAndView("tt", "historic", historic);
}
In JSP I have access to all the information that I passed.
I use the values in two different ways. The first one (information that later I won't be able to recover) is:
<form:form method="POST" action="/addInput" modelAttribute="historic">
....
<form:label path="userHistoric[0].user.name" />
<form:input path="userHistoric[0].user.name" disabled="true" />
Being userHistoric a list inside HistoricBO object.
And the other way that I use the object values is daoing loop to the registers and show them. I can have these values after submit:
c:forEach items="${historic.userHistoric[0].periods[0].registers}" var="reg" varStatus="rog">
...
<td class="tab-odd">
<form:input path="userHistoric[0].periods[0].registers[${rog.index}].hours[0]" class="monin" type="number" />
</td>
The method that catch the submit is as follows:
#PostMapping("/addInput")
public String savePeriod(
#ModelAttribute("historic") HistoricBO inputs,
BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "error";
}
...
And here the object inputs only has setted the hours values, the rest of the object is empty.
Can you please why is the info loosing and how to solve it?
Thanks
Remove disabled="true" and use readonly="true" or readonly="readonly" instead like below.
<form:input path="userHistoric[0].user.name" readonly="readonly" />
Disabled values will not be submitted with the form.
See this values-of-disabled-inputs-will-not-be-submitted and demo here.

Spring MVC: (If is possible) search form on submit event generate a URI instead of URL pattern format

I have a #Controller with the following #RequestMapping annotation
#RequestMapping(value={"somevalue"},
method=RequestMethod.GET,
produces=MediaType.TEXT_HTML_VALUE)
public String findOneById(#PathVariable String id, Model model){
model.addAttribute(findOneById(id));
return "some view";
}
Observe it uses #PathVariable, based on URI, it works around /persons/{id}, for example for:
/persons/100
/persons/200
it retrieves an expected person.
that #RequestMapping method works fine when:
I put the URL/URI in the same Web Browser address bar (.../persons/200)
when I generate a report of items including for each one a link to see the details (.../persons/200).
I am trying to create a search form such as follows:
<body>
<spring:url var="findOne" value="/persons/" >
</spring:url>
<form action="${findOne}" method="get">
<table>
<tr>
<td><label for="id"><spring:message code="persona.id.label"/></label></td>
<td><input name="id" id="id" value=""/></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="search"/></td>
</tr>
</table>
</form>
</body>
My problem is, when I press submit the form always generates/creates the URL to do the search in the format /persons?id=100. I know it is normal and is expected.
But just being curious and of course if is possible:
Question:
What would be the new configuration to generate a URI pattern such as /persons/100 instead of /persons?id=100 when I press the submit button?
I want avoid create a new #RequestMapping method working around with a #RequestParam (it for ?id=100). It to complement the #RequesMapping method working with #PathVariable (it for /100) version.
Thanks

How to pass checkbox values to the controller in Spring MVC

I have a jsp page with list of functions. Here in controller I get this list from database and pass it to jsp.
#RequestMapping(value = "/functionlist", method = RequestMethod.GET)
public ModelAndView functionList(Model model) throws Exception {
ModelAndView mv = new ModelAndView("functionList");
mv.addObject("functionList", getFunctionsFromDB());
return mv;
}
In my jsp page I create table using this list of functions
<table id="table">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<c:choose>
<c:when test="${not empty functionList}">
<c:forEach var="function" items="${functionList}">
<tr>
<td><input name="id" value="${function.id}" hidden></td>
<td>${function.name}</td>
<td>
<input type="checkbox" id="${function.id}" value="${function.action}"></td>
</tr>
</c:forEach>
</c:when>
</c:choose>
</tbody>
</table>
<button type="submit" name="save">Save</button>
I also give function id to checkbox id.
My Function entity is the following
public class Function {
private Integer id;
private String name;
private Boolean action;
...
}
I want to press button Save and get in controller "/functionlist/save" my list of checkbox values.
Try to add form like this to your jsp page
<form:form id="yourForm" action="/functionlist/save" method="POST" modelAttribute="functionList">
<c:forEach items="${functionList}" varStatus="status" var="function">
<tr>
<td>${function.name}</td>
<td>
<form:checkbox path="functionList[${status.index}].action"/>
</td>
</tr>
</c:forEach>
<input type="submit" value="submit" />
</form:form>
and in Controller you should have a method like this
#RequestMapping(value = { "/functionlist/save" }, method = RequestMethod.POST)
public String savePerson(#ModelAttribute("functionList")List<Function> functionList) {
// process your list
}
If this does not work, you can try to wrap you list.
public class FunctionListWrapper {
private List<Function> functionList;
public FunctionListWrapper() {
this.functionList = new ArrayList<Function>();
}
public List<Function> getFunctionList() {
return functionList;
}
public void setFunctionList(List<Function> functionList) {
this.functionList = functionList;
}
public void add(Function function) {
this.functionList.add(function);
}
}
in controller instead of passing list, pass wrapper
FunctionListWrapper functionListWrapper=new FunctionListWrapper();
functionListWrapper.setFunctionList(userService.getFunctionList());
mv.addObject("functionListWrapper", functionListWrapper);
For more details please take a look at this questions: question 1 and question 2
First you need to add name attribute to your checkbox inputs.You can get these in
an array on controller with same name as your name attribute.eg-
#RequestMapping(value = "/functionlist", method = RequestMethod.GET)
public ModelAndView functionList(Model model,#RequestParam("checkboxname")String[] checkboxvalues) throws Exception {
ModelAndView mv = new ModelAndView("functionList");
mv.addObject("functionList", getFunctionsFromDB());
return mv;
}
few things.
First you should think about a form object, which is the exchange entity between the view and the controller. The form entity will be something similar to the followng:
public class Form {
private List<Function> functions;
//getters & setters
}
secondly, since you are using Spring MVC, you should leverage the <%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %> library. Consequently, your form will be:
<form:form commandName="form" action="/your/url">
<c:forEach items="${form.functions }" var="function" varStatus="status">
<tr>
<td><form:hidden path="functions[${status.index }].id"></td>
<td>${function.name}</td>
<td>
<form:checkbox path="functions[${status.index }].action" id="${function.id}" value="${function.action}"/>
</td>
</tr>
</c:forEach>
</form:form>
and finally the controller will be something like
#RequestMapping(value="/your/url", method=RequestMethod.POST)
public String postForm(#ModelAttribute("form") FormForm form)
{
//cool stuff here
}
please note that the proper HTTP method is POST, not GET. Yup, I know things work also with GET it's definitely a deprecated strategy.
In addition, figure out how I referred the list of Function in the Form. I used the variable function in the foreach statement when I had to display data, I referred the list when I had to bind the Form object for transferring data to the controller. Last but not least, I haven't tried the code. I wrote it on the fly just to give you hints about how to do it properly.
One last thing. Since you pass the Form to the JSP, you don't need anymore to fill the Model with the attribute you used. Just fill the form with your data and use it to diaplay them in the view. Just like this ${form.stuff.you.want}

<option> returning emptyin UI form:select of spring mvc3

I've a list of values to be passed from my controller to the jsp page. I've the below controller:
#RequestMapping(value="/addClient.do", method = RequestMethod.GET)
protected ModelAndView Submit(HttpServletRequest request, HttpServletResponse response) throws Exception {
MyForm = new MyForm();
MyForm.setClientList(MyService.getClientList(/*"30-JUN-15"*/));
System.out.println("Size of list : "+MyForm.getClientList().size()); //-- Displayed as 10 which is correct
ModelAndView model = new ModelAndView("feeMaintenance");
model.addObject("clientForm",MyForm);
model.addObject("selectedMenu", "MenuSelected");
model.addObject("clientsList",MyForm.getClientList());
return model;
}
And my jsp form is as below:
<body>
<form:form method="post" modelAttribute="clientForm" action="${userActionUrl}">
<tr> <td align="left">
<form:select path="clientList">
<form:option value="-" label="------Select Client ------">
<form:options items="${clientsLists}">
</form:options></form:option></form:select>
</tr> </td>
</form>
</body>
I've removed the additional unrelated code. The drop down only shows ----Select Client--- even though the controller shows the correct values of the clientList. Unable to figure out whats missing.
if MyForm.getClientList() is successfully return list of client data than
rewrite this line into jsp page.
you write key name into controller is clientsList and you write this into jsp page is clientsLists this is wrong.
I hope this is work.
try this code.
model.addObject("country", projectservice.getallCountry());
**Note:**itemLabel name is same as property name into pojo class and also itemValue name.

Spring MVC form not backed by a model object

I am pretty new to Spring MVC so please be easy on me.
I am having difficulties to understand how to achieve the following requirements in Spring MVC:
JSP list form, to list users from the database (service, repository thing are working properly).
Form is not backed by a model attribute object. This is a list/find form!
I need to list users matching some criteria taken from several "filter" fields like:
Region (dropdown list)
Is user archived? (yes/no dropdown list)
userList.jsp
<spring:url value="strFormAction" var="/rest/security/user/list" />
<form:form id="userListForm" method="GET" action="${strFormAction}" modelAttribute="user">
<form:select id="strRegionId" path="${strRegionId}" cssClass="form-control" onchange="updateUsersList('1');">
<spring:message var="strSelectRegionLabel" code="select.region" />
<form:option value="0" label="${strSelectRegionLabel}" />
<form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>
<form:select id="strArchived" path="${strArchived}" cssClass="form-control">
<spring:message var="strYesLabel" code="yes" />
<form:option value="true" label="${strYesLabel}"/>
<spring:message var="strNoLabel" code="no" />
<form:option value="false" label="${strNoLabel}"/>
</form:select>
<table>
...
<c:forEach items="${users}" var="user">
...rows generated here...
</c:forEach>
...
</table>
</form:form>
UserController.java
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList( #ModelAttribute("user") User user,
#RequestParam(value = "strRegionId", required = false) String strRegionId,
#RequestParam(value = "strArchived", required = false) String strArchived,
#RequestParam(value = "strSortBy", required = false) String strSortBy,
Model model) {
int intRegionId = strRegionId != null && strRegionId.equals("0") == false ? Integer.valueOf(strRegionId) : 0;
boolean booArchived = strArchived != null && strArchived.length() > 0 ? Boolean.valueOf(strArchived) : false;
int intSortBy = strSortBy != null && strSortBy.length() > 0 ? Integer.valueOf(strSortBy) : 1;
List<Region> regions = this.locationService.lstRegions();
model.addAttribute("strRegionId", String.valueOf(intRegionId));
model.addAttribute("strArchived", String.valueOf(booArchived));
model.addAttribute("strSortBy", String.valueOf(intSortBy));
List<User> users = this.securityService.listUsersByRegionAndArchiveState(intRegionId, booArchived, intSortBy);
model.addAttribute("user", new User());
model.addAttribute("users", users);
model.addAttribute("regions", regions);
return "user/userList";
}
It seems like I can't use the Spring form taglib at all without providing a modelAttribute in the form. I have then placed a dummy modelAttribute from my controller, but now I get:
javax.servlet.ServletException: javax.servlet.jsp.JspException: org.springframework.beans.NotReadablePropertyException: Invalid property '0' of bean class [spring4base.model.security.User]: Bean property '0' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
As I said earlier, that page is not meant to be backed by any specific POJO. This is a search page, that must return a list of users (User entity bean) based on filters selected previously (region, archived state). Form must submit on itself every time a dropdown is changed (user chooses a region, submit is done on the same mapping, and then the users list reloads with only users from that specific region).
I'm coming from Struts 1 in which we needed to create ActionForm for every single page. From what I read from the documentation, forms are not necessary these days so I am really looking forward into fixing that issue.
Any help would be greatly appreciated.
I would just create helper class containing your search criteria, for instance:
public class UserSearchCriteria {
private String regionId;
private Boolean archived;
private String sortBy;
// Getters and setters
}
Then I would modify your controller method like so (some code is missing, but this should give you the idea).
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList(#ModelAttribute("searchCriteria") UserSearchCriteria userSearchCriteria, Model model) {
// Retrieve users and perform filtering based on search criteria
List<User> users = this.securityService.listUsers(searchCriteria);
model.addAttribute("users", users);
model.addAttribute("regions", regions);
return "user/userList";
}
And then you would use your filtering form like this:
<spring:url value="/rest/security/user/list" var="formAction" />
<form:form id="userListForm" method="GET" action="${formAction}" modelAttribute="searchCriteria">
<form:select path="regionId" cssClass="form-control" onchange="updateUsersList('1');">
<spring:message var="strSelectRegionLabel" code="select.region" />
<form:option value="0" label="${strSelectRegionLabel}" />
<form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>
<form:select path="archived" cssClass="form-control">
<spring:message var="strYesLabel" code="yes" />
<form:option value="true" label="${strYesLabel}"/>
<spring:message var="strNoLabel" code="no" />
<form:option value="false" label="${strNoLabel}"/>
</form:select>
You had several errors in the form in your snippet. For example the path attribute takes String containing name (or path) of the property to bind to, you were passing it some variable. Also you had value and var switched in your <spring:url> I think.
Try it, it's not complete solution but hopefully it will give you some directions on how to implement this. If you run into any problems, leave a comment and I'll update the answer.

Resources