I'm trying to create links between two existing objects using form with checkboxes, e.g. categories of products and products itself. The link between them is one-to-many and is managed by Hibernate. However, I'm struggling to pass my objects between controllers with JSP.
I have CategoryViewController with form-init method:
...
@RequestMapping("/details")
@Transactional(readOnly=true)
public ModelAndView showCategoryDetails(@RequestParam Integer categoryId, @ModelAttribute CategoryProductAssignment assignmentModel, Model model) {
Category category = categoryService.getCategory(categoryId);
Set<Product> categoryProducts = category.getProducts();
List<Product> allProducts = productService.getProducts();
model.addAttribute("categoryProducts", categoryProducts);
model.addAttribute("allProducts", allProducts);
model.addAttribute("category", category);
assignmentModel.setCategory(category);
return new ModelAndView("categoryDetails");
}
...
In this method I form the list of all available products, products already assigned to category and category itself and sets it in a model.
Also, I have a jsp which uses previous model and creates this form:
...
<form:form method="post" action="assignProducts.html" commandName="categoryProductAssignment">
<form:hidden path="category.id" />
<tr>
<td><form:checkboxes path="products" items="${allProducts}" itemValue="id" itemLabel="name"/></td>
<td>${product.name}</td>
<br>
</tr>
<input type="submit" value="ok">
</form:form>
...
And also I have another CategoryAssignController, which processes form after submit:
...
@InitBinder
public void bindForm(final WebDataBinder binder) {
binder.registerCustomEditor(List.class, "products", new ProductCollectionEditor<ProductService>(productService, List.class));
binder.registerCustomEditor(Category.class, new CategoryEditor<CategoryService>(categoryService));
}
@RequestMapping(value = "/category/assignProducts", method = RequestMethod.POST)
public String assignProducts(@ModelAttribute CategoryProductAssignment assignmentModel) {
Category category = assignmentModel.getCategory();
Integer id = category.getId();
List<Product> products = assignmentModel.getProducts();
categoryService.addProducts(category, products);
return "redirect:/categoryDetails.html?categoryId=" + id;
}
...
The problem what I'm facing is to transfer Category and Products objects from one controller to another. I don't want to store it in session, so I need to pass them via jsp.
I have no problems with List formed with checkboxes. To do this I've created ProductCollectionEditor.class:
public class ProductCollectionEditor<T extends ProductService> extends CustomCollectionEditor {
private final T service;
public ProductCollectionEditor(final T service, final Class<List> collectionType) {
super(collectionType, true);
this.service = service;
}
@Override
protected Object convertElement(final Object element) {
try {
Product product = service.getProduct(Integer.valueOf(element.toString()));
return product;
} catch (NumberFormatException e) {
return null;
}
}
}
and registered it
binder.registerCustomEditor(List.class, "products", new ProductCollectionEditor<ProductService>(productService, List.class));
in my CategoryAssignController using @InitBinder.
However, I can't do the same with Category for some reason. I've created CategoryEditor:
public class CategoryEditor<T extends CategoryService> extends PropertyEditorSupport {
private final T service;
public CategoryEditor(final T service) {
super();
this.service = service;
}
@Override
public void setValue(Object value) {
Category category = service.getCategory(Integer.valueOf(value.toString()));
setValue(category);
}
}
and registered it
binder.registerCustomEditor(Category.class, new CategoryEditor(categoryService));
in my CategoryAssignController using @InitBinder.
Important note: I don't want to pass ids as Strings and find\get objects manually in Controller\Services.
As I can guess, when Spring sees "category.id" coming from form
<form:hidden path="category.id" />
it automatically constructs Category object and sets id in there. So, in this case, inside of CategoryEditor.setValue method I already have Category object created. But, if I change editor registration line to following:
binder.registerCustomEditor(String.class, "category.id",new CategoryEditor<CategoryService>(categoryService));
method CategoryEditor.setValue is not called at all.
So, the main questions of this post: what am I doing wrong and what is the best approach \ best practice to do what I need?
Thanks.
Aucun commentaire:
Enregistrer un commentaire