首页 > 解决方案 > Spring 验证器未检测到错误

问题描述

此代码正在创建一个 hmtl 表单,您可以在其中选择一些 chekcboxes 并设计一个 Taco。我正在尝试执行模型字段验证,但它不起作用。例如,如果名称的输入字段框为空或根本没有选中任何复选框,则此代码应该返回错误。控制器中的错误变量虽然从未捕获任何错误。可能会发生什么。此代码是 Spring in Action 书中的复制粘贴示例,因此我不确定为什么它不起作用。

模型

@Data
public class Taco {

 @NotNull
 @Size(min=5, message = "Name must be at least 5 characters long")
 private String name;
 @Size(min=1, message = "You must choose at least 1 ingredient")
 private List<String> ingredients;
}

控制器

@Slf4j
@Controller
@RequestMapping("/design")
public class DesignTacoController {

@GetMapping
public String showDesignFromModel(Model model){
    List<Ingredient> ingredients = Arrays.asList(
            new Ingredient("FLTO","Flour Tortilla", WRAP),
            new Ingredient("COTO","Corn Tortilla", WRAP),
            new Ingredient("GRBF","Ground Beef", PROTEIN),
            new Ingredient("CARN","Carnitas", PROTEIN),
            new Ingredient("TMTP","Diced Tomatoes", VEGGIES),
            new Ingredient("LETC","Lettuce", VEGGIES),
            new Ingredient("CHED","Cheddar", CHEESE),
            new Ingredient("JACK","Monterrey Jack", CHEESE),
            new Ingredient("SLSA","Salsa", SAUCE),
            new Ingredient("SRCR","Sour Cream", SAUCE)
    );


    Type[] types = Ingredient.Type.values();
    for (Type type : types){
        model.addAttribute(type.toString().toLowerCase(),
                ingredients.stream()
                        .filter(e -> e.getType() == type)
                        .collect(Collectors.toList()));

    }
    model.addAttribute("design",new Taco());
    return "design";
}

@PostMapping
public String processDesign(@Valid Taco design , Errors errors){
    if(errors.hasErrors()){
        System.out.println("Many errors " + errors);
        return "design";
    }
    System.out.println("Process design: " + design);
    System.out.println("No errors " + errors);
    log.info("Process design: " + design);
    return "redirect:/orders/current";
}
}

看法

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org">

<head>
   <title>Taco Cloud</title>
   <link rel="stylesheet" th:href="@{/styles.css}" />
</head>

<body>
<h1>Design your taco!</h1>
<img th:src="@{/images/TacoCloud.png}" alt="Taco Cloud Logo"/>
<form method="POST" th:object="${design}">
    <div class="grid">
        <div class="ingredient-group" id="wraps">
           <h3>Designate your wrap:</h3>
           <div th:each="ingredient : ${wrap}">
               <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
               <span th:text="${ingredient.name}">INGREDIENT</span><br/>
           </div>
        </div>
        <div class="ingredient-group" id="proteins">
            <h3>Pick your protein:</h3>
            <div th:each="ingredient : ${protein}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="cheeses">
            <h3>Choose your cheese:</h3>
            <div th:each="ingredient : ${cheese}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="veggies">
            <h3>Determine your veggies:</h3>
            <div th:each="ingredient : ${veggies}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="sauces">
            <h3>Select your sauce:</h3>
            <div th:each="ingredient : ${sauce}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
    </div>
    <div>
        <h3>Name your taco creation:</h3>
        <input type="text" th:field="*{name}"/>
        <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Error</span>
        <br/>
        <button>Submit your taco</button>
    </div>
</form>
</body>


</html>

标签: springspring-bootspring-mvc

解决方案


当验证不起作用时,通常有一件事是不正确的。类路径上没有javax.validationAPI 的实现。仅向validation-apifrom添加依赖项javax.validation将无济于事,因为这只是 API 而不是实际实现。

您还需要添加一个实现,例如hibernate-validator

现在在 Spring Boot 的早期版本(2.3 之前)中,spring-boot-starter-web作为依赖项添加时会自动包含验证。但是在较新的版本(2.3+)中,这已被删除。您现在需要显式包含 spring-boot-starter-validation启动器依赖项。这包括 API 和实现。

话虽这么说,也可能是在类路径上拥有 Jakarta Validation API 以及它的实现(如hibernate-validator版本 7 或更高版本),而不是 Java Validation API。Spring 或 Spring Boot(尚)不支持 Jakarata Validation API(或大多数 JakartaEE API)。因此,即使您的类路径中有它,它也不起作用,您需要 Java Validation API 之一。


推荐阅读