我有一个简单的模型类Product,它与表现出多对一的关系ProductCategory:
Product
ProductCategory
产品类别:
@Entity @Table(name="product") public class Product { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Long id; @Column(name="name") private String name; @Column(name="description") private String description; @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="category_id") private ProductCategory category; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPdfUrl() { return pdfUrl; } public void setPdfUrl(String pdfUrl) { this.pdfUrl = pdfUrl; } public ProductCategory getCategory() { return category; } public void setCategoryId(ProductCategory category) { this.category = category; } }
ProductCategory类
@Entity @Table(name="product_category",uniqueConstraints={@UniqueConstraint(columnNames="name")}) public class ProductCategory { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Long id; @Column(name="name") private String name; @OneToMany(fetch=FetchType.LAZY, mappedBy="category") private Set<Product> products = new HashSet<Product>(0); // getters() & setters() }
我将Spring Boot与Thymeleaf结合使用,以创建通常的CRUD操作所需的表单。
这是我的html页面的基本部分,用于将新Product对象添加到数据库中。
<form action="#" th:action="/product/save" th:object="${newProduct}" method="POST"> <input type="text" th:field="*{name}" /> <input type="text" th:field="*{description}" /> <select th:field="*{category}"> <option th:each="category: ${productCategories}" th:value="${category}" th:text="${category.name}" /> </select> <button type="submit">Submit</button> </form>
问题是,当我尝试Product从控制器中插入结果对象时(我知道我没有在这里显示它,主要是因为我不认为这实际上是问题的原因),
MySQLIntegrityConstraintViolationException: Column 'category_id' cannot be null
我曾试图改变value的option到${category.id},但即使这样仍不能解决问题。
value
option
${category.id}
我实际上如何使用Thymeleaf将复杂的对象作为POST参数传递给控制器?
与我的最初想法相反,这实际上可能与我有关Controller,所以这是我的ProductController:
Controller
ProductController
@RequestMapping(value="/product/save", method=RequestMethod.POST) public String saveProduct(@Valid @ModelAttribute("newProduct") Product product, ModelMap model) { productRepo.save(product); model.addAttribute("productCategories", productCategoryRepo.findAll()); return "admin-home"; } @RequestMapping(value="/product/save") public String addProduct(ModelMap model) { model.addAttribute("newProduct", new Product()); model.addAttribute("productCategories", productCategoryRepo.findAll()); return "add-product"; }
请注意,我已将form方法更改为POST。
从百里香的角度来看,我可以确保以下代码可以正常工作。
<form method="POST" th:action="@{/product/save}" th:object="${newProduct}"> .... <select th:field="*{category}" class="form-control"> <option th:each="category: ${productCategories}" th:value="${category.id}" th:text="${category.name}"></option> </select>
只要您的控制器看起来像这样。
@RequestMapping(value = "/product/save") public String create(Model model) { model.addAttribute("productCategories", productCategoryService.findAll()); model.addAttribute("newproduct", new Product()); //or try to fetch an existing object return '<your view path>'; } @RequestMapping(value = "/product/save", method = RequestMethod.POST) public String create(Model model, @Valid @ModelAttribute("newProduct") Product newProduct, BindingResult result) { if(result.hasErrors()){ //error handling .... }else { //or calling the repository to save the newProduct productService.save(newProduct); .... } }
更新资料
您的模型应该具有正确的具有正确名称的吸气剂和吸气剂。例如,对于category您应该拥有的属性,
category
public ProductCategory getCategory(){ return category; } public void setCategory(productCategory category){ this.category = category; }
注意 - 我尚未编译此代码,我从当前的工作项目中提取了该代码,并将其名称替换为您的类名称