Spring Boot: Ошибка конвертации данных при передаче списка размеров и изображений в контроллер
Делаю обучающий проект на Spring, сайт по продаже одежды. В данный момент делаю админку, а именно фору для добавления нового товара. У меня есть форма на Thymeleaf, которая отправляет список размеров и загружает изображения для создания товара. Однако, при передаче данных в контроллер возникает ошибка MethodArgumentNotValidExceptio и статус 400.
Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.List' for property 'sizes'; Failed to convert from type [java.lang.String] to type [java.lang.Long] for value [S]
Failed to convert property value of type 'java.util.ArrayList' to required type 'java.util.List' for property 'images'; Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'OnlineStoreWemalpa.com.OnlineStore.model.ProductImage' for property 'images[0]': no matching editors or conversion strategy found
Форма Thymleaf
<form th:action="@{/api/v1/admin/product-create}" method="post" enctype="multipart/form-data">
<label>Размеры в наличии:</label>
<div>
<input type="checkbox" name="sizes" value="XS"> XS
<input type="checkbox" name="sizes" value="S"> S
<input type="checkbox" name="sizes" value="M"> M
<input type="checkbox" name="sizes" value="L"> L
<input type="checkbox" name="sizes" value="XL"> XL
</div>
<label for="images">Фото товара:</label>
<input type="file" id="images" name="images" multiple>
<button type="submit">Создать товар</button>
</form>
Контроллер
@GetMapping("/product-create")
public String showCreateProductForm(Model model) {
model.addAttribute("product", new Product()); // Добавляем пустого пользователя в модель
return "product-create"; // Отображаем форму для создания нового пользователя
}
// Обработка формы создания нового пользователя
@PostMapping("/product-create")
public String createProduct(
@ModelAttribute Product product,
@RequestParam("images") List<MultipartFile> images,
@RequestParam(value = "sizes", required = false) List<String> sizes,
RedirectAttributes redirectAttributes) {
try {
// Загружаем изображения и создаем объекты ProductImage
List<ProductImage> productImages = new ArrayList<>();
for (MultipartFile file : images) {
if (!file.isEmpty()) {
String imageUrl = fileUploadService.uploadFile(file);
ProductImage productImage = new ProductImage();
productImage.setImageUrl(imageUrl);
productImage.setProduct(product); // Устанавливаем продукт для изображения
productImage.setIsPrimary(false); // По умолчанию ставим, что это не главное изображение
productImages.add(productImage);
}
}
// Преобразуем размеры из строки в объекты ProductSize
List<ProductSize> productSizes = new ArrayList<>();
if (sizes != null) {
for (String size : sizes) {
ProductSize productSize = new ProductSize();
productSize.setSize(size); // Устанавливаем размер
productSize.setProduct(product); // Устанавливаем продукт для размера
productSizes.add(productSize);
}
}
// Устанавливаем список изображений и размеров в продукт
product.setImages(productImages);
product.setSizes(productSizes);
// Сохраняем продукт с изображениями и размерами
service.saveProductWithImagesAndSizes(product); // Нужно создать метод для сохранения
redirectAttributes.addFlashAttribute("success", "Товар успешно создан!");
} catch (Exception e) {
redirectAttributes.addFlashAttribute("error", "Ошибка при создании товара: " + e.getMessage());
}
return "redirect:/api/v1/admin/product-admin";
}
Модель Product
@Data
@Entity
@Table(name = "product")
public class Product {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false, length = 255)
private String name;
@Column(name = "decsription")
private String decsription;
@Column(name = "price", nullable = false)
private BigDecimal price;
@Column(name = "gender")
private String gender;
@Column(name = "clothing_type", nullable = false)
private String clothingType;
@Column(name = "custom")
private Boolean custom;
@ManyToOne
@JoinColumn(name = "print_type_id")
private PrintType printType;
@ManyToOne
@JoinColumn(name = "material_id")
private Material material;
@ManyToOne
@JoinColumn(name = "color_id")
private Color color;
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<ProductSize> sizes = new ArrayList<>();; // Связь с размерами продукта
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<ProductImage> images = new ArrayList<>(); // Связь с изображениями продукта
Модель ProductImage
@Data
@Entity
@Table(name = "product_image")
public class ProductImage {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@Column(name = "image_url", nullable = false)
private String imageUrl;
@Column(name = "is_primary")
private Boolean isPrimary; // Флаг для главного изображения
}
Модель ProductSize
@Data
@Entity
@Table(name = "product_size")
public class ProductSize {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@Column(name = "size", nullable = false)
private String size;
}