Spring form path with multiple model attributes with the same property name - forms

The problem is that I have a spring form and 2 #ModelAttribute params with the same properties in my controller. The 'commandName' parameter of the the form is set to one of my modelAttributes names. I was surprised that the maps the property not only to the model attribute specified with 'commandName', but also to the second one.
I haven't found the exact solution here, except the similar to mine: Spring-form multiple forms with same model atribute name properties
But in my case I can't see any 'strange things', I have one form, one Model attribute to bind this form, and one model attribute to have accsess to controller scoped #SessionAttribute.
I've also tried to use form's 'modelAttribute' parameter (Actually I can't see any difference between them), but it didn't help.
My code example:
view.jsp:
<form:form name="form" action="/myAction" method="POST" commandName="model1">
<form:input path="property"/>
....
<input type="submit" value="Submit"/>
</form:form>
Controller.java
#SessionAttributes("model2")
class Controller {
#RequestMapping(value = "/myAction", method = POST)
public String submitEditSite(final #ModelAttribute(value = "model1") Model1 model1,
final #ModelAttribute(value = "model2") Model2 model2) {
....
return "redirect:/home";
}
}
Model1.java Model2.java
class Model1 {
private String property;
}
class Model2 {
private String property;
}
Where am I wrong?

If I understand you correctly you want to prevent the setting of any property on model2, right?
Then this should do:
#InitBinder("model2")
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields("*");
}

Related

ZK: loading value/text into selectbox

I have a selectbox and want to load the value and text into the template, similar to an HTML dropdown box. I am using ZK framework with Java on the back end.
<selectbox id="buListbox" model="${$composer.buModel}" >
<template name="model">
<label value="${each}" />
</template>
</selectbox>
When using ZK, you don't need the value to identify the selected object like in HTML.
When using the MVC pattern, binding a model via model attribute, the selected item is also stored in that model and can be retrieved in java via model.getSelection().
Furthermore, a model is not restricted to lists of String, but it can hold any object type you want. In the template section, you can display any property of that object. Then the properties' toString() method is used to get the value which is displayed. This also applies to ${each} itself.
Example:
Assuming your model is a ListModelList of type ValueType:
public class ValueType {
private String value;
private String text;
public ValueType(String value, String text) {
this.value=value;
this.text=text;
}
public String getText() {
return this.text;
}
public String getValue() {
return this.value;
}
}
private ListModelList<ValueType> typesModel;
public ListModelList<ValueType> getTypesModel() {
return typesModel;
}
You than can use the selectbox's model/template to display it's text property:
<selectbox id="typesSelectbox" model="${$composer.typesModel}">
<template name="model">
${each.text}
</template>
</selectbox>
In java, you then get the selected item via typeModel.getSelection() .
Here you can find a working ZKFiddle example.

Difference between modelAttribute and commandName attributes in form tag in spring?

In Spring 3, I have seen two different attribute in form tag in jsp
<form:form method="post" modelAttribute="login">
in this the attribute modelAttribute is the name of the form object whose properties are used to populate the form. And I used it in posting a form and in controller I have used #ModelAttribute to capture value, calling validator, applying business logic. Everything is fine here. Now
<form:form method="post" commandName="login">
What is expected by this attribute, is it also a form object whose properties we are going to populate?
If you look at the source code of FormTag (4.3.x) which backs your <form> element, you'll notice this
/**
* Set the name of the form attribute in the model.
* <p>May be a runtime expression.
*/
public void setModelAttribute(String modelAttribute) {
this.modelAttribute = modelAttribute;
}
/**
* Get the name of the form attribute in the model.
*/
protected String getModelAttribute() {
return this.modelAttribute;
}
/**
* Set the name of the form attribute in the model.
* <p>May be a runtime expression.
* #see #setModelAttribute
*/
public void setCommandName(String commandName) {
this.modelAttribute = commandName;
}
/**
* Get the name of the form attribute in the model.
* #see #getModelAttribute
*/
protected String getCommandName() {
return this.modelAttribute;
}
They are both referring to the same field, thus having same effect.
But, as the field name indicates, modelAttribute should be preferred, as others have also pointed out.
OLD WAY = commandName
...
<spring:url value="/manage/add.do" var="action" />
<form:form action="${action}" commandName="employee">
<div>
<table>
....
NEW WAY = modelAttribute
..
<spring:url value="/manage/add.do" var="action" />
<form:form action="${action}" modelAttribute="employee">
<div>
<table>
..
I had the same question a while ago, I can't remember the exact differences but from research I ascertained that commandName was the old way of doing it and in new applications you should be using modelAttribute
commandName = name of a variable in the request scope or session scope that contains the information about this form,or this is model for this view. Tt should be a been.
In xml based config, we will use command class to pass an object between controller and views. Now in annotation we are using modelattribute.

Spring MVC form:checkbox not working

I am having an issue with the Spring form:checkbox tag.
I currently have a JSP page with a form:checkbox tag bound to a Java boolean field. When I put a tick in the checkbox and submit the form the value is false.
Here is the checkbox on my JSP:
<form:checkbox id="field_termsandconditions" path="agreeTermsAndConditions" />
My GET controller:
#RequestMapping(value = "/page1.htm", method = RequestMethod.GET)
public String getPage(HttpServletRequest request, ModelMap model) {
model.addAttribute("MyObject", new MyObject());
return getURL(request);
}
My POST controller:
#RequestMapping(value = "/page1.htm", method = RequestMethod.POST)
public String processPage(HttpServletRequest request,
HttpServletResponse response,
ModelMap model,
MyObject myObject,
BindingResult bindingResult) {
System.out.println(myObject.isAgreeTermsAndConditions);
}
myObject.isAgreeTermsAndConditions is always false when it hits the POST controllers even when checked!
Any ideas?
This might be a little late to answer, but maybe it will help some other person.
When you auto-generate getter and setters for boolean values it is very often generated without 'is' prefix.
For instance, in the case mentioned above the generated setter for 'isAgreeTermsAndConditions' property might be the following: 'setAgreeTermsAndConditions()', note there is no 'is' prefix in the method. The same true for the getters as well.
Since property getter and setters names are used find and bind to the model property, the checkbox might be not shown on the UI or not working properly if there are property name and getters/setters mismatch.
Make sure the property 'isAgreeTermsAndConditions' has the following getters/setters method names: getIsAgreeTermsAndConditions()/setIsAgreeTermsAndConditions(...)

Null fields after form submit in Spring

I've got a Product with a Rating rating attribute. I've got a product update form (updateStart method) which doesn't contain the rating field (since I don't want it to be editable).
The problem is that when I submit the form (with update method), the rating is automatically set to null.
So I tried to add the Rating to the form model in updateStart, retrieving it in the update method, but it keeps being rewritten as well.
I tried to set a #SessionAttributes("rating") annotation in the controller. This time the rating value is kept, but Spring creates a new entry in the database, cloned from the other rating object, and attaches it to the Product.
#Controller
#SessionAttributes("rating")
#RequestMapping("/products")
public class ProductsController {
#RequestMapping("/update_start")
public String updateStart(#RequestParam("id") Long id, Model model) throws BusinessException {
Product product = productService.findProductById(id);
System.out.println("RATING A START "+product.getRating().getAbsoluteRating());
List<Category> categories = productService.findAllCategories();
model.addAttribute("categories", categories);
model.addAttribute("product", product);
model.addAttribute("id", id);
model.addAttribute("rating",product.getRating());
return "products.updateform";
}
#RequestMapping(value="/update", method = RequestMethod.POST)
public String update(#ModelAttribute("rating") Rating rating, #ModelAttribute Product product, BindingResult bindingResult) throws BusinessException {
System.out.println("RATING A UPDATE "+rating.getAbsoluteRating());
validator.validate(product, bindingResult);
List<Image> images = imageService.getProductImages(product.getId());
product.setRating(rating);
productService.updateProduct(product,images,sellerid);
return "redirect:/products/viewsforsellers.do";
}
}
What can I do?
EDIT: I'd prefer to avoid placing a hidden input field with ratingId in my form.
In the form include a hidden input with the name and value specified for the Rating. The value should include
<form>
<input name="product.rating" value="${product.rating.id}"/>
<!-- Other fields -->
</form>
Now when the request comes over the wire it should include a Rating specified by id for the product.
#RequestMapping(value="/update", method = RequestMethod.POST)
public String update(#ModelAttribute Product product, BindingResult bindingResult) throws BusinessException {
//implementation
}
#ModelAttribute should attempt to bind this parameter to the Product however it is not aware of what a Rating is. This is where a Converter comes into play. A Converter is used during databinding to tell Spring MVC how to map a field of type String to a field of type Rating.
public class StringToRatingConverter implements Converter<String, Rating> {
public Rating convert(String source) {
//Use the source String to convert to rating
//Possibly via database call or enum conversion, pending ratings type and definition
//Ultimately the code needs to return the appropriate object of type Rating
return rating; //The above implementation will create the rating object.
}
}
The StringToRatingConverter must then be registered in the dispatcher configuration file.
<!-- Register Converters - Used for data binding-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="fully.qualified.path.to.StringToRatingConverter"/>
</list>
</property>
</bean>
The first time I encountered this scenario, I captured it in a post on my blog, which you may be helpful.
You should add "types" element to your #SessionAttributes("rating") annotation in order properties of attributes to be kept; e.g.
#SessionAttributes(types = Rating.class, names = "rating")

Spring Mvc/Jpa-OneToMany : How to display a list of class associated to another one

I've got a class Module with a OneToMany binding with a class Sequence.
My aim is to show the list of Modules, and by clicking on one of them, display the associated list of Sequences
But it doesn't work, I have a HTTP 500 error.
Here there is my controller :
#RequestMapping(value="formation", method = RequestMethod.GET)
public ModelAndView allModules() {
List<Module> allModules = moduleService.findAll();
return new ModelAndView("formation", "modules", allModules);
}
#RequestMapping(value="sequences/{module}", method = RequestMethod.GET)
public String displaySequences(#PathVariable ("module") Module module, Model model) {
List<Sequence> allSequences = sequenceService.findByModule(module);
model.addAttribute("sequences", allSequences);
return "sequences";
}
and the jsp which show the list of modules to return the list of sequences
<c:forEach items="${modules}" var="module">
<ul>
<li>${module.titre}
<br/>
</li>
</ul>
</c:forEach>
So, where does my error come from?
It works when I do that:
#RequestMapping(value="/sequences/{moduleId}", method = RequestMethod.GET)
public String displaySequences(#PathVariable ("moduleId") Long moduleId, Model model) {
Module module = moduleService.findById(moduleId);
model.addAttribute("module", module);
return "sequences";
}
and I change the link with :
<a href="sequences/${module}">${module.titre}
but I'd like to understand my error.
The reason why you weren't able to display sequences is Spring doesn't know how to parse this
/cmap-web/sequences/com.almerys.jpa.tomcatspring.Module#12b0f0ae
into Module instance.
You can read on this in Spring docs here in the section's 16.3.2.2 URI Template Patterns last paragraph. I paste it here for convenience.
A #PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. You can also register support for parsing additional data types. See Section 16.3.3.14, “Method Parameters And Type Conversion” and Section 16.3.3.15, “Customizing WebDataBinder initialization”.