I think It is easy for a lot of peoples but I don't know what I'm doing wrong.
My controller:
#RequestMapping(value = "/novo", method = RequestMethod.GET)
public ModelAndView novoTimeSheet() {
Usuario usuario1 = new Usuario(1L,"Leandro1","ltsiciliano1#gmail.com");
Usuario usuario2 = new Usuario(2L,"Leandro2","ltsiciliano2#gmail.com");
Usuario usuario3 = new Usuario(3L,"Leandro3","ltsiciliano3#gmail.com");
List<Usuario> usuarioList = new ArrayList<Usuario>();
usuarioList.add(usuario1);
usuarioList.add(usuario2);
usuarioList.add(usuario3);
Map<String, Object> model = new HashMap<String, Object>();
model.put("usuarios", usuarioList);
return new ModelAndView("timesheetcrud/novo", "timesheetcruddto", model);
}
It's working:
<td>Usuário :</td>
<td>
<select id="usuarios" name="usuarios">
<c:forEach items="${timesheetcruddto.usuarios}" var="usuario">
<option value="${usuario.id}"><c:out value="${usuario.nome}"/></option>
</c:forEach>
</select>
</td>
But I'd like to use spring tag and I put this:
<td>Usuário :</td>
<td>
<td>
<form:select id="id_usuario" path="usuarios">
<form:option value="0" label="--- Select ---" />
<form:options items="${usuarioList}"/>
</form:select>
</td>
</td>
It isn't work:
<td>
<form:select id="id_usuario" path="usuarios">
<form:option value="0" label="--- Select ---" />
<form:options items="${usuarios}"/>
</form:select>
</td>
And It's wrong:
org.springframework.beans.NotReadablePropertyException: Invalid property 'usuarios' of bean class [java.util.HashMap]: Bean property 'usuarios' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
I'd like to know what's benefit to use spring tags instead of JSTL.
Thanks
usuarios is a list .. for a form, you need to bind an object
object will have a list with getters and setters.
object.setUsuarioList(usariolist);
model.put("object", object);
and then
<form:options items="${object.usuarioList}"/>
You can do like this
<form:select path="usuarioList">
<form:options items="${usuarios}" />
</form:select>
You can improve your code like
`<form:select path="usuarioList">
<form:option value="NONE" label="--- Select ---"/>
<form:options items="${usuarios}" />
</form:select>
`
Also please change your variable name for more suitable one like
List<Usuario> usuarios= new ArrayList<Usuario>();
usuarios.add(usuario1);
usuarios.add(usuario2);
usuarios.add(usuario3);
Map<String, Object> model = new HashMap<String, Object>();
model.put("UserList", usuarios);
It looks much good than earlier
Related
I have simple form where user can choose a value from select. I am not sure how it works but if there are the selects pointing to the same filed in POJO class value is not overridden but two values are separated by comma. Why this is happening? Is there any String concatenation behid the scenes?
It looks like this:
<form:form action="processForm" modelAttribute="student">
First Name : <form:input path="firstName"/>
<br><br>
Last Name : <form:input path="lastName"/>
<br><br>
Country : <form:select path="country">
<form:option value="Brazil" label="Brazil" />
<form:option value="France" label="France" />
<form:option value="Germany" label="Germany"></form:option>
<form:option value="India" label="India"></form:option>
<form:option value="" label="Select" />
</form:select>
<br><br>
Country : <form:select path="country">
<form:options items="${student.countryOptions}" />
</form:select>
<br><br>
<input type="submit" value="Submit">
</form:form>
#Controller
#RequestMapping("/student")
public class StudentController {
#Value("#{countryOptionsID}")
private Map<String, String> countryOptionsProperties;
#Value("#{favoriteLanguageID}")
private Map<String, String> favoriteLanguageProperties;
#RequestMapping("/showForm")
public String showForm(Model theModel) {
theModel.addAttribute("student", new Student());
// add the country options to the model
theModel.addAttribute("theCountryOptions", countryOptionsProperties);
theModel.addAttribute("theFavoriteLanguageOptions", favoriteLanguageProperties);
return "student-form";
}
#RequestMapping("/processForm")
public String processForm(#ModelAttribute("student") Student theStudent) {
System.out.println("Student Details : " + theStudent);
return "student-confirmation";
}
#RequestMapping("/processFormA")
public String processFormA(Student student) { //without using #ModelAttribute
System.out.println("without using #ModelAttribute Student Details : " + student);
return "student-confirmation";
}
}
and properties are like:
BR=Brazil
FR=France
CO=Colombia
IN=India
LK=Sri Lanka
If you fill out the model in the controller:
theModel.addAttribute("theCountryOptions", countryOptionsProperties);
It means that in the view you could get this object:
Country :
<form:select path="country">
<form:options items="${theCountryOptions}" />
</form:select>
${products} contains a List<Product>. Product is a #Entity, has an equals method that compares by id. There is no converter or formatter registered for Product (other than Spring Data's DomainClassConverter but that doesn't seem to kick in for this case):
This works:
<form:select path="productFrom">
<form:option value="" label="-" />
<form:options items="${products}" itemValue="id" itemLabel="name"/>
</form:select>
This (needed for optgroup-ing, but simplified here) does not select the correct value:
<form:select path="productFrom">
<form:option value="" label="-" />
<c:forEach items="${products}" var="product">
<form:option value="${product.id}">${product.name}</form:option>
</c:forEach>
</form:select>
After debugging SelectedValueComparator I found that it tries to compare a candidateValue of type Long to a boundValue of String. I could work this around by creating a toString() method in product that returns the id as String. (Or I could have modified the equals() method to handle Long.)
Still, I have a bad feeling that I'm doing something wrong here.
In the end I solved this by adding a new method to Product:
public String getIdString() {
return id == null ? "" : id.toString();
}
and changing the option definition:
<form:option value="${product.idString}">${product.name}</form:option>
Still not sure I'm doing this the right way, any tips are appreciated.
I am using Spring.AjaxEventDecoration to dynamically populate a drop down on my JSP but it is throwing an error as it cannot bind to the original model. I have been researching this for a while and I do not think this is possible but it seeems like it should be hence this post.. Help me out somebody!
OK My controller dumbed down looks like this,
#Controller
#RequestMapping(value = "/cis/crimeProperty/")
public class CrimePropertyController
{
#RequestMapping(value = "/manageView", method = RequestMethod.GET)
public ModelAndView managePropertyDetails(Long propertyId) throws DAOException
{
Map<String, Object> model = new HashMap<String, Object>();
CrimePropertyVO crimePropertyVO = new CrimePropertyVO();
model.put("crimePropertyVO", crimePropertyVO);
return new ModelAndView("cis.crime.property.edit", model);
}
#RequestMapping(value = "/changeItemList", method = RequestMethod.POST)
public ModelAndView retrieveItemList(String propertyClass)
{
Map<String, Object> model = new HashMap<String, Object>();
..call service to get list of items from class..
model.put("propertyItemList", propertyItemList);
return new ModelAndView("/cis/property/crime_property_item", model);
}
}
I am using tiles so my tile definition looks like this,
<definition name="cis.crime.property.edit" template="/WEB-INF/jsp/cis/property/manage_crime_property.jsp">
<put-attribute name="itemListFrag" value="/WEB-INF/jsp/cis/property/crime_property_item.jsp"/>
My (manage_crime_property.jsp) JSP looks like so,
<form id= "changeList" action="${pageContext.request.contextPath}/smvc/cis/crimeProperty/changeItemList" method="post">
<select id="propertyClassChange" path="propertyClass">
<option value="" label="-Please Select-"/>
<option value="CLO" label="CLOTHING"/>
<option value="TOL" label="TOOLS"/>
</select>
</form
<form:form modelAttribute="crimePropertyVO" action="${pageContext.request.contextPath}/smvc/cis/crimeProperty/saveProperty" method="post">
<table class="genericOutlinedTable" style="width: 100%;">
<tr>
<td><b>Item</b></td>
<td>
<tiles:insertAttribute name="itemListFrag" flush="true" ignore="false"/>
</td>
</tr>
<tr>
<td><b>Make</b></td>
<td><form:input path="propertyMake" size="20" maxlength="20"/></td>
<td><b>Model</b></td>
<td><form:input path="propertyModel" size="15" maxlength="15"/></td>
</tr>
</form:form>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
elementId:'propertyClassChange',
event:'onchange',
formId:'changeList',
params: {fragments: 'itemListFrag'}
}));
My (crime_property_item.jsp) JSP fragment looks like this,
<span id="itemListFrag">
<form:select path="propertyItem">
<form:option value="" label="-Please Select-">
<c:forEach var="itemList" items="${propertyItemList}">
<form:option value="${itemList.propertyCode}" label="${itemList.propertyCode}" />
</c:forEach>
</form:select>
</span>
Its all configured correctly and when I change the first drop down it calls my controller changeItemList method which returns my JSP frag and list of items to make up the options but I get a server error ...
Neither BindingResult nor plain target object for bean name propertyItemavailable as request attribute
I've tried having just the options tags in my frag but that doesn't work and I've tried using the spring:bind tag and normal select but can't get that to work either.
Many Thanks in advance for any help with this.
I have a controller which sets few values to a model and sends to jsp. In jsp i need to show those values(as labels) along with additional values from user as input values. When i submit the jsp i only get valid values that user has entered and the values set earlier by controller is null.
JSP
<form:form
action="${pageContext.request.contextPath}/admin/deviceAction.html"
modelAttribute="deviceData">
<table class="gridtable" width="500px">
<tr>
<td>Device Name : </td>
<td>${deviceData.deviceName}</td>
</tr>
<tr>
<td>Model Name : </td>
<td>${deviceData.modelName}</td>
</tr>
<tr>
<td>Serial No : </td>
<td>${deviceData.serialNo}</td>
</tr>
<tr>
<td>Device Id : </td>
<td>${deviceData.deviceId}</td>
</tr>
<tr>
<td>Status : </td>
<td>${deviceData.statusCode}</td>
</tr>
<tr>
<td>Action : <span class="required">*</span></td>
<td>
<form:select path="deviceAction" >
<form:option value="" label="--- Select ---" />
<form:options items="${model.actionList}" />
</form:select>
</td>
</tr>
</table>
<input type="submit" value="Submit" id="btn_submit">
</form:form>
Controller:
public ModelAndView beforeSubmit() {
ModelAndView modelView = new ModelAndView();
DeviceData deviceData = new DeviceData();
deviceData.setDevicePk("123");
deviceData.setAccessToken("abcwetrwertewrtetr");
deviceData.setDeviceId("deferterterterterwtetetertg");
deviceData.setDeviceName("test");
deviceData.setEnrolledDate("7-8-13");
deviceData.setModelName("test1");
deviceData.setSerialNo("test2dsfgdfgdfg");
deviceData.setStatusCode("test3");
List<String> actionList = getActionList();
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("actionList", actionList);
modelView.addObject("deviceData", deviceData);
modelView.addObject("model", model);
modelView.setViewName("admin/tokenSearchResult");
}
public ModelAndView afterSubmit() {
#ModelAttribute("deviceData") DeviceData deviceData, BindingResult result) {
logger.info("#################device datas are : " + deviceData.getDevicePk() + "###### " + deviceData.getDeviceAction());
return new ModelAndView();
}
deviceData.getDevicePk() is null
Only the drop down value is having valid value. Other values displayed in the screen are received as null.
Edit:
Till now i have found only one solution:
<form:input path="deviceName" readonly="true" />
But this way UI does not looks good. The editable and non editable values mixup in the screen. Looking for a better answer
Finally i am using hidden parameters to solve the problem.
Example:
<td>${deviceData.deviceName}</td>
is replaced by:
<td><form:hidden path="deviceName"</td>
By this way it helps me to avoid any css work(which i am not much comfortable)
If anyone get a better solution kindly post it here
You need to make them into form inputs using the Spring form tags in much the same way as you have for the form:select. If they are not editable by the user, you can always disable them.
You can simple hide those input. For example :
<input type="hidden" name="VehSeriesModelId" value="${vehDetailsVM.id }">
This way, you can get the data to the controller and the user will also not be able to edit the value. On the other hand, your form will also not show it :)
I receive the exception
Failed to convert property value of
type [java.lang.String] to required
type [beans.Product] for property
product; nested exception is
java.lang.IllegalArgumentException:
Cannot convert value of type
[java.lang.String] to required type
[beans.Product] for property product:
no matching editors or conversion
strategy found
in the Errors errors object even before my DetailProductValidator starts validating through the validate method.
I don't understand why Spring does that. I don't have any input field that is mapped directly to the product property/object. I just use the product object's properties in the jsp. For example, I use:
<form:options items="${dpBackObj.product.colorMap}"/>
<!-- or -->
${dpBackObj.product.priceInDollars}
but I never use:
<form:input path="product"/>
Can anyone please explain why this happens? And maybe inform me of a simple solution?
The bean configuration for the controller is:
<!-- DETAIL PRODUCT FORM CONTROLLER -->
<bean id="productDetailFormController" name="/detail.htm /addToCart.htm"
class="detailProduct.DetailProductFormController">
<property name="sessionForm" value="true" />
<property name="commandName" value="dpBackObj" />
<property name="commandClass" value="detailProduct.DetailProductBackingObject" />
<property name="validator">
<bean class="detailProduct.DetailProductValidator" />
</property>
<property name="formView" value="detail" />
<property name="successView" value="redirect:/viewCart.htm" />
<property name="cartService" ref="cartServiceImpl"/>
</bean>
The backing object for the DetailProductFormController is:
public class DetailProductBackingObject {
private String quantityOverflowError;
private Product product;
private int quantity;
private ShoppingCart shoppingCart;
private long sizeId;
private long colorId;
public DetailProductBackingObject() {
this.product = new Product();
this.sizeId = -1;
this.colorId = -1;
}
//getters and setters
}
If you need some other info, I will provide. I am using Spring 2.5.5.
Kind Regards,
Despot
EDIT1 (due to request from axtavt):
<form:form method="post" commandName="dpBackObj">
<table width="730" border="0" cellspacing="0" cellpadding="0">
<c:if test="${!empty dpBackObj.quantityOverflowError}">
<tr>
<td>
<c:out value="${dpBackObj.quantityOverflowError}"/>
</td>
</tr>
</c:if>
<spring:bind path="dpBackObj.*">
<c:if test="${not empty status.errorMessages}">
<div class="val-summary text-error" id="errorDivId">
<div style="" class="val-summary text-error" id="errorDivId">
<fmt:message key="detail.error.header"/>
<ul>
<c:forEach items="${status.errorMessages}" var="error">
<li><c:out value="${error}"/></li>
</c:forEach>
</ul>
</div>
</div>
</c:if>
</spring:bind>
<tr>
<td width="310" align="left" valign="top">
<img src="${imagesPath}/${dpBackObj.product.largeImageUrl}" alt="${dpBackObj.product.description}" />
</td>
<td width="420" align="left" valign="top">
<div id="tls_detPName">
<c:out value="${dpBackObj.product.name}"></c:out>
</div>
<div >
<strong class="numeric">${dpBackObj.product.priceInDollars}</strong>
</div>
<div id="tls_detPDescLong">
${dpBackObj.product.largeDescription}
<br />
</div>
<div >
<table cellpadding="2" border="0">
<tr>
<td align="right">
<label for="p_sizes" class="label"><fmt:message key="viewCart.Size"/></label>
</td>
<td>
<form:select path="sizeId" >
<form:option value="-1" label="x"/>
<form:options items="${dpBackObj.product.sizeMap}"/>
</form:select>
</td>
</tr>
<tr>
<td align="right">
<label for="p_colors" class="label"><fmt:message key="viewCart.Color"/></label>
</td>
<td>
<form:select path="colorId" >
<form:option value="-1" label="y"/>
<form:options items="${dpBackObj.product.colorMap}"/>
</form:select>
</td>
</tr>
</table>
</div>
<div id="tls_addToCart">
<div >
<label for="quantityId" class="label"><fmt:message key="viewCart.Quantity"/>:</label>
<form:input path="quantity" onkeypress="return checkForNumber(this, event)" maxlength="10" size="3" id="quantityId" cssClass="textbox-center"/>
<input type="image" name="addToCartButtonName" src="${imagesPath}/addToCartBtn.jpg" />
</div>
</div>
</td>
</tr>
</table>
</form:form>
EDIT2 (due to JacobM's request):
This is my Validator:
public class DetailProductValidator implements Validator {
public boolean supports(Class clazz) {
return DetailProductBackingObject.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
DetailProductBackingObject detailProductBackingObject = (DetailProductBackingObject) obj;
if (detailProductBackingObject.getSizeId() == -1) {
errors.rejectValue("sizeId", "error.detail.jsp.choose.size", null, "Input size.");
}
}
}
When I reach the line DetailProductBackingObject detailProductBackingObject = I already have the error.
The converting of the request parameters to the backing object properties happens in http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html . This is what Spring says about the conversion:
Populating using request parameters
and PropertyEditors: Upon receiving a
request, any BaseCommandController
will attempt to fill the command
object using the request parameters.
This is done using the typical and
well-known JavaBeans property
notation. When a request parameter
named 'firstName' exists, the
framework will attempt to call
setFirstName([value]) passing the
value of the parameter. Nested
properties are of course supported.
For instance a parameter named
'address.city' will result in a
getAddress().setCity([value]) call on
the command class.
It's important to realise that you are
not limited to String arguments in
your JavaBeans. Using the
PropertyEditor-notion as supplied by
the java.beans package, you will be
able to transform Strings to Objects
and the other way around. For instance
setLocale(Locale loc) is perfectly
possible for a request parameter named
locale having a value of en, as long
as you register the appropriate
PropertyEditor in the Controller (see
initBinder() for more information on
that matter.
Validators: After the controller has
successfully populated the command
object with parameters from the
request, it will use any configured
validators to validate the object.
Validation results will be put in a
Errors object which can be used in a
View to render any input problems.
Since I can't see anything wrong with the form, the only possible reason I can imagine is that you have a parameter named product in the URL of your form page.
If so, you can change your URLs or use DataBinder.setDisallowedFields() to disable the attempt to bind that parameter.