尝试重构以下控制器的代码:
@PutMapping("products/{productId}")
public ProductResponse updateProduct(@PathVariable("productId") Long productId, @RequestBody ProductForm productForm) {
Optional<Product> foundProductOpt = productRepository.findById(productId);
Product foundProduct = foundProductOpt.orElseThrow(() -> new EntityNotFoundException("productId" + productId + "not found."));
//would like to refactor code below!!
foundProduct.setProductTitle(productForm.getProductTitle());
foundProduct.setProductPrice(productForm.getProductPrice());
foundProduct.setProductDescription(productForm.getProductDescription());
foundProduct.setProductImage(productForm.getProductImage());
productRepository.save(foundProduct);
return new ProductResponse(null, "product updated");
}
我只是将表单对象中的值传递给实体对象。考虑创建方法但不想在实体中编写方法,因此不确定其他解决方案是什么。
根据要求,以下是我的产品和表单对象。我想使用表单对象进行验证,然后将数据传输到Product对象。
Product.java
package com.assignment.restapi.domain;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Min;
import java.util.Date;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long productId;
private String productImage;
private String productTitle;
private String productDescription;
private Integer productPrice;
//https://stackoverflow.com/questions/49954812/how-can-you-make-a-created-at-column-generate-the-creation-date-time-automatical/49954965#49954965
@CreationTimestamp
private Date createdAt;
@UpdateTimestamp
private Date updatedAt;
// default constructor
public Product() {
}
// parameterized constructor-User enetered value goes here to set the fields of the instantiated object.
public Product(String productImage, String productTitle, String productDescription, Integer productPrice, Date createdAt) {
this.productImage = productImage;
this.productTitle = productTitle;
this.productDescription = productDescription;
this.productPrice = productPrice;
this.createdAt = createdAt;
}
// getter methods are used to retrieve a value from an object.
// setter methods are used to set a new value to an object.
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProductImage() {
return productImage;
}
public void setProductImage(String productImage) {
this.productImage = productImage;
}
public String getProductTitle() {
return productTitle;
}
public void setProductTitle(String productTitle) {
this.productTitle = productTitle;
}
public String getProductDescription() {
return productDescription;
}
public void setProductDescription(String productDescription) {
this.productDescription = productDescription;
}
public Integer getProductPrice() {
return productPrice;
}
public void setProductPrice(@Min(value = 1, message = "値段は0以上の値を設定してください。") Integer productPrice) {
this.productPrice = productPrice;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
ProductForm.java
package com.assignment.restapi.web.view;
import com.assignment.restapi.domain.Product;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
public class ProductForm {
String productImage;
@NotBlank(message = "Product title is necessary")
@Size(max = 100, message = "Product title has to be less than 100 letters")
String productTitle;
@Size(max = 500, message = "Product title has to be less than 500 letters")
String productDescription;
@Min(value = 1, message = "price has to have a value larger than 1")
Integer productPrice;
public ProductForm() {
}
public ProductForm(String productImage, String productTitle, String productDescription, Integer productPrice) {
this.productImage = productImage;
this.productTitle = productTitle;
this.productDescription = productDescription;
this.productPrice = productPrice;
}
public String getProductImage() {
return productImage;
}
public void setProductImage(String productImage) {
this.productImage = productImage;
}
public String getProductTitle() {
return productTitle;
}
public void setProductTitle(String productTitle) {
this.productTitle = productTitle;
}
public String getProductDescription() {
return productDescription;
}
public void setProductDescription(String productDescription) {
this.productDescription = productDescription;
}
public Integer getProductPrice() {
return productPrice;
}
public void setProductPrice(Integer productPrice) {
this.productPrice = productPrice;
}
//turns productForm into Product object.
public Product convertToProduct() {
//step by step debug mode, new object constructor function in Product.java gets called.
//setter methods get called and values of the ProductForm object gets passed and becomes the new value of the Product object.
Product product = new Product();
product.setProductTitle(this.productTitle);
product.setProductImage(this.productImage);
product.setProductDescription(this.productDescription);
product.setProductPrice(this.productPrice);
return product;
}
}
答案 0 :(得分:2)
使用Apache commons-beanutils ::
如果两个类中都有相同的字段名称,这将有效。
@PutMapping("products/{productId}")
public ProductResponse updateProduct(@PathVariable("productId") Long productId, @RequestBody ProductForm productForm) {
Optional<Product> foundProductOpt = productRepository.findById(productId);
Product foundProduct = foundProductOpt.orElseThrow(() -> new EntityNotFoundException("productId" + productId + "not found."));
org.apache.commons.beanutils.BeanUtils.copyProperties(foundProduct, productForm);
productRepository.save(foundProduct);
return new ProductResponse(null, "product updated");
}
答案 1 :(得分:0)
您可以使用copyProperties(Object dest, Object orig)
中的 BeanUtils将属性值从原始bean复制到目标bean 所有属性名称相同的情况。
对于您的控制器代码,它看起来像这样(如果对象具有Date属性并且没有值,则需要注意):
BeanUtils.copyProperties(foundProduct,productForm);
您也可以直接在控制器方法中使用Product
作为对象参数,但我认为它不符合您的代码设计
答案 2 :(得分:0)
而不是在productId
中发送@PathVariable
而不是在身体中发送它自己。使用Product
中的@RequestBody
代替ProductForm
。
还在@NotNull,@NotBlank
等产品实体中添加验证,然后使用@Valid
验证产品请求正文。
最后保存Product对象。由于产品具有id
(产品ID),因此存储库的save()方法将对数据库执行更新命令。
所以找代码就是这样:
@PutMapping("/products")
public ProductResponse updateProduct(@Valid @RequestBody Product product) {
Optional<Product> productOptional = productRepository.findById(product.getId());
Product existingProduct = productOptional
.orElseThrow(() -> new EntityNotFoundException("productId" + product.getId() + "not found."));
productRepository.save(product);
return new ProductResponse(null, "product updated");
}