Ни BindingResult, ни обычный целевой объект для имени компонента «продукт», доступного в качестве атрибута запроса

#spring #spring-boot #spring-mvc #post #get

Вопрос:

Кажется, я не могу найти ошибку в своем коде. Все мои импортные товары в порядке. Все кажется в порядке, но когда я нажимаю кнопку добавить новое, я получаю сообщение об ошибке «Ни BindingResult, ни обычный целевой объект для имени компонента «продукт», доступного в качестве атрибута запроса«. Кроме того, если я изменю имя компонента на продукты в своем запросе на сопоставление Get и Post, а также внесу те же изменения в файл добавления, это сработает.

Вот мой add.html файл:

 <!doctype html>
 
 <nav th:replace="/fragments/nav :: nav-admin"></nav>

<div class="container">

    <h1 class="display-2">Add a product</h1>
    <a href="/admin/products" class="btn btn-primary mt-4 mb-4">Back to Products</a>
    
    <div th:if="${message}" th:text="${message}" th:class="${'alert '   alertClass}"></div>

    <form method="post" th:object="${product}" th:action="@{/admin/products/add}" enctype="multipart/form-data">

        <div th:if="${#fields.hasErrors('*')}" class="alert alert-danger">
            There are errors
        </div>
    
        <div class="form-group">
            <label for="">Name</label>
            <input type="text" class="form-control" th:field="*{name}" placeholder="Name">
            <span class="error" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
        </div>
        
        <div class="form-group">
            <label for="">Description</label>
            <textarea th:field="*{description}" rows="10" class="form-control" placeholder="Description"></textarea>
            <span class="error" th:if="${#fields.hasErrors('description')}" th:errors="*{description}"></span>
        </div>

        <div class="form-group">
            <label for="">Image</label>
            <input type="file" class="form-control" th:name="file" th:id="file">
            <img class="mt-2" src="#" alt="" id="imgPreview1">
        </div>

        <div class="form-group">
            <label for="">Price</label>
            <input type="text" class="form-control" th:field="*{price}" placeholder="20 or 20.99">
            <span class="error" th:if="${#fields.hasErrors('price')}" th:errors="*{price}"></span>
        </div>

        <div class="form-group">
            <label for="">Category</label>
            <select th:field="*{categoryId}" class="form-control">
                <option th:value="0">Choose a category</option>
                <option th:each="cat: ${categories}" th:value="${cat.id}" th:text="${cat.name}"></option>
            </select>
            <span class="error" th:if="${#fields.hasErrors('categoryId')}" th:errors="*{categoryId}"></span>
        </div>

        <button class="btn btn-danger mt-4 mb-4">Add</button>

    </form>

</div>

<div th:replace="/fragments/footer"></div>
 

Моя модель называется Products.java, а вот код контроллера для GET и POST для добавления

 @GetMapping("/add")
public String add(Products product, Model model) {
    
    List<Category> categories = categoryRepo.findAll();
    model.addAttribute("categories", categories);

    return "admin/products/add";
}

@PostMapping("/add")
public String add(@Valid Products product, BindingResult bindingResult, 
                    MultipartFile file, RedirectAttributes redirectAttributes, 
                    Model model) throws IOException {

    List<Category> categories = categoryRepo.findAll();

    if (bindingResult.hasErrors()) {
        model.addAttribute("categories", categories);
        return "admin/products/add";
    }

    boolean fileOK = false;
    byte[] bytes = file.getBytes();
    String filename = file.getOriginalFilename();
    Path path = Paths.get("src/main/resources/static/media/"   filename);

    if (filename.endsWith("jpg") || filename.endsWith("png") ) {
        fileOK = true;
    }

    redirectAttributes.addFlashAttribute("message", "Product added");
    redirectAttributes.addFlashAttribute("alertClass", "alert-success");

    String slug = product.getName().toLowerCase().replace(" ", "-");

    Products productExists = productRepo.findBySlug(slug);

    if (! fileOK ) {
        redirectAttributes.addFlashAttribute("message", "Image must be a jpg or a png");
        redirectAttributes.addFlashAttribute("alertClass", "alert-danger");
        redirectAttributes.addFlashAttribute("product", product);
    }
    else if ( productExists != null ) {
        redirectAttributes.addFlashAttribute("message", "Product exists, choose another");
        redirectAttributes.addFlashAttribute("alertClass", "alert-danger");
        redirectAttributes.addFlashAttribute("product", product);
    } else {
        product.setSlug(slug);
        product.setImage(filename);
        productRepo.save(product);
        Files.write(path, bytes);
    }
    return "redirect:/admin/products/add";
}
 

Ответ №1:

Вам нужно добавить в модель в методе сопоставления get атрибут с именем «продукт», представляющий форму. Учебник по форме Spring MVC

 @GetMapping("/add")
public String add(Model model) {

   List<Category> categories = categoryRepo.findAll();
   model.addAttribute("categories", categories);
   model.addAttribute("product", new Products());
   return "admin/products/add";
}