使用 Thymeleaf 发布具有多对一关系的数据
POSTing data with many to one relationship using Thymeleaf
我有一个简单的模型 class Product
,它与 ProductCategory
:
表现出多对一的关系
产品class:
@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;
}
}
产品类别class
@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 with 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
我曾尝试将 option
的 value
更改为 ${category.id}
,但即使那样也无法解决问题。
简而言之
我如何使用 Thymeleaf 将复杂对象作为 POST 参数实际传递到控制器中?
更新
与我最初的想法相反,这实际上可能与我的 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.
从 thymeleafs 的角度来看,我可以保证下面的代码应该有效。
<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);
....
}
}
更新
您的模型应该具有正确名称的正确 getter 和 setter。例如,对于 属性 category
你应该有,
public ProductCategory getCategory(){
return category;
}
public void setCategory(productCategory category){
this.category = category;
}
注意 - 我没有编译这段代码,我从我当前的工作项目中提取了它并用你的 class 名称替换了名称
我有一个简单的模型 class Product
,它与 ProductCategory
:
产品class:
@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;
}
}
产品类别class
@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 with 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
我曾尝试将 option
的 value
更改为 ${category.id}
,但即使那样也无法解决问题。
简而言之
我如何使用 Thymeleaf 将复杂对象作为 POST 参数实际传递到控制器中?
更新
与我最初的想法相反,这实际上可能与我的 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.
从 thymeleafs 的角度来看,我可以保证下面的代码应该有效。
<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);
....
}
}
更新
您的模型应该具有正确名称的正确 getter 和 setter。例如,对于 属性 category
你应该有,
public ProductCategory getCategory(){
return category;
}
public void setCategory(productCategory category){
this.category = category;
}
注意 - 我没有编译这段代码,我从我当前的工作项目中提取了它并用你的 class 名称替换了名称