简体   繁体   中英

Spring valid annotation not working in controller

I have a problem: my post form working fine and the controller related to the post method does receive objects from HTML post form but @Valid annotation does nothing. In BindingResult object there is no error even though it should be there

The problem is in : itemAddControllerPost()

package orchowski.tomasz.ecommercedemo.controller.item;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import orchowski.tomasz.ecommercedemo.command.ItemCommand;
import orchowski.tomasz.ecommercedemo.converter.ItemCommandToItem;
import orchowski.tomasz.ecommercedemo.converter.ItemToItemCommand;
import orchowski.tomasz.ecommercedemo.domain.Item;
import orchowski.tomasz.ecommercedemo.security.permision.PermissionStoreItemCreate;
import orchowski.tomasz.ecommercedemo.security.permision.PermissionStoreItemRead;
import orchowski.tomasz.ecommercedemo.services.ItemService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.List;
import java.util.Optional;

@Slf4j
@Controller
@RequestMapping("/item")
@RequiredArgsConstructor
public class ItemController {

    private final ItemService itemService;
    private final ItemCommandToItem commandToItem;
    private final ItemToItemCommand itemToCommand;

    @PermissionStoreItemCreate
    @GetMapping("/create")
    public String itemAddController(Model model) {
        model.addAttribute("item", new ItemCommand());
        return "item/itemform";
    }

    @PermissionStoreItemCreate
    @PostMapping("/create/new")
    public String itemAddControllerPost(@ModelAttribute("item") @Valid ItemCommand itemCommand, BindingResult bindingResult) {
        log.debug("Posting new item object");
        if (bindingResult.hasErrors()) {
                bindingResult.getAllErrors().forEach(objectError -> log.error(objectError.toString()));
            log.debug("Binding error");
            return "redirect:/item/create";
        }
        Item save = itemService.save(commandToItem.convert(itemCommand));
        log.debug("New item object persisted to db \n " + save.toString());
        return "redirect:/item/" + save.getId() + "/show";
    }

    @PermissionStoreItemRead
    @GetMapping("/show")
    public String itemRead(Model model, HttpServletRequest request, @RequestParam(defaultValue = "0") Integer pageNo,
                           @RequestParam(defaultValue = "10") Integer pageSize) {
        ///item/show?pageNo=2&pageSize=20

        if (pageNo < 0 || pageSize <= 0) {
            return "redirect:/item/show?pageNo=0";
        }
        model.addAttribute("pageNumber", pageNo);
        model.addAttribute("pageSize", pageSize);

        List<Item> itemList = itemService.findAll(pageNo, pageSize);
        if (itemList.size() == 0) {
            return "redirect:/item/show?pageNo=" + (pageNo - 1);
        }
        model.addAttribute("items", itemList);
        System.out.println(itemList);
        return "item/show";
    }

    @GetMapping("/{id}/show")
    @PermissionStoreItemRead
    public String showItem(Model model,@PathVariable Long id) {
        Optional<Item> byId = itemService.findById(id);
        model.addAttribute("item", byId.orElseThrow(() -> new RuntimeException("Item id " + id + " not found")));
        return "item/showProduct";
    }
}

my command object

package orchowski.tomasz.ecommercedemo.command;


import lombok.*;
import javax.validation.constraints.*;


@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ItemCommand {

    private Long id;

    @Size(min = 20, max = 1000,message = "Description must contains at least 20 characters and less than 1000")
    @NotBlank
    private String description;

    @Min(value = 0, message = "Price have to be greater than 0")
    @NotNull
    private Double price;

    @Min(value = 0, message = "Stock have to be at least 0")
    @NotNull
    private Integer stock;

}

html form


    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    <head>
        <meta charset="UTF-8">
        <title>store</title>
        <link th:rel="stylesheet" th:href="@{/webjars/bootstrap/5.0.1/css/bootstrap.min.css}">
        <link th:rel="stylesheet" th:href="@{/css/default.css}">
    </head>
    <body>
    
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <nav th:replace="fragments/navbar :: nav"></nav>
            </div>
        </div>
    
        <form th:object="${item}" th:action="@{/item/create/new}" method="post">
            <div class="row">
                <div class="mb-3">
                    <!--description            -->
                    <label for="description" class="form-label">Description of product</label>
                    <textarea class="form-control" id="description" name="description"></textarea>
                </div>
            </div>
            <div class="row">
                <div class="col-sm-3">
                    <!--price            -->
                    <label for="price">Price of product</label>
                    <input type="text" class="form-control" id="price" name="price">
                </div>
                <div class="col-sm-3">
                    <!--stock            -->
                    <label for="stock">Stock item</label>
                    <input type="text" class="form-control" id="stock" name="stock">
                </div>
            </div>
            <div class="row">
                <button type="submit" class="btn btn-primary">Submit</button>
            </div>
        </form>
    
    </div>
    
    
    <script th:src="@{/webjars/jquery/3.0.0/jquery.min.js}"></script>
    <script th:src="@{/webjars/popper.js/2.9.2/umd/popper.js}"></script>
    <script th:src="@{/webjars/bootstrap/5.0.1/js/bootstrap.js}"></script>
    </body>
    </html>

To check the code on GitHub please click here

Try:

import javax.validation.Valid;

https://docs.oracle.com/javaee/7/api/javax/validation/Valid.html

Instead of:

import jakarta.validation.Valid;

(an ambiguous import!;)


Useful read: https://www.google.com/search?q=spring+valild ( @javax.validation.Valid vs. @org.springframework.validation.annotation.Validated )


Further read:

JSR 303


jakarta.validation.Valid : ??? ( SpringBoot with Jakarta Validation Api not validating with @Valid Annotation , https://www.google.com/search?q=jakarta.validation.Valid (looks obsolete !???)) Check your class path/dependency tree!


Actually I found no/few samples, where the import statements is explicitly mentioned, but it is "clear" that spring supports JSR 303 (ie javax.validation.* and rather not jakarta.validation.* ..)

Problem has been solved!

I change hibernate dependency in pom.xml from

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>7.0.1.Final</version>
        </dependency>

to

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.5.Final</version>
</dependency>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM