【问题标题】:Spring MVC + Thymeleaf divs on the page are not generated页面上的 Spring MVC + Thymeleaf div 未生成
【发布时间】:2021-03-13 06:47:52
【问题描述】:

我是 Spring 新手,我正在尝试使用 Spring MVC 和 Thymeleaf 制作 Web 应用程序。我有带有表单的页面来创建自定义比萨饼和相应的控制器。用户可以输入披萨的名称,所以我添加了输入验证。在我输入无效名称之前一切正常,但是当我返回页面的新视图时,带有我的复选框的 div 不会出现,它们只是不会生成。刷新后我的模型似乎是空的,但我不明白如何调试它,我在 intellij 想法中的快捷方式不起作用。

创建披萨控制器:

@Slf4j
@Controller
@RequestMapping("/create")
public class CreatePizzaController {
    @GetMapping
    public String showCreationForm(Model model){
        List<Ingredient> ingredients = Arrays.asList(
                new Ingredient("CLS22", "Classic base 22cm", Ingredient.Type.BASIC),
                new Ingredient("CLS30", "Classic base 30cm", Ingredient.Type.BASIC),
                new Ingredient("PEPE", "Pepperoni", Ingredient.Type.MEAT),
                new Ingredient("HAM", "Ham", Ingredient.Type.MEAT),
                new Ingredient("CHMPG", "Champignons", Ingredient.Type.VEGGIES),
                new Ingredient("CUCU", "Cucumbers", Ingredient.Type.VEGGIES),
                new Ingredient("PARM", "Parmesan cheese", Ingredient.Type.CHEESE),
                new Ingredient("MOZ", "Mozzarella cheese", Ingredient.Type.CHEESE),
                new Ingredient("BARBS", "Barbecue sauce", Ingredient.Type.SAUCE),
                new Ingredient("TOMAS", "Tomato sauce", Ingredient.Type.SAUCE)
                );

        Ingredient.Type[] types = Ingredient.Type.values();
        for(Ingredient.Type type: types){
            model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));
        }
        model.addAttribute("create", new Pizza());
        return "create";
    }

    @PostMapping
    public String processCreation(@Valid @ModelAttribute("create") Pizza pizza, BindingResult result){
        if(result.hasErrors()){
            return "create";
        }
        //Save creation...
        log.info("Processing creation: " + pizza);
        return "redirect:/orders/current";
    }

    private List<Ingredient> filterByType(List<Ingredient> ingredients, Ingredient.Type type) {
        List<Ingredient> filtered = new ArrayList<>();
        for (Ingredient ingredient:ingredients){
            if(ingredient.getType() == type){
                filtered.add(ingredient);
            }
        }
        return filtered;
    }
}

创建.html:

<!DOCTYPE html>
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" th:href="@{/styles/style.css}" />
</head>
<body>
<h3>Create your pizza:</h3>
<img th:src="@{/images/pizza_logo.jpg}" width="200" height="200"/>

<form method="post" th:object="${create}">
    <div class="grid">
        <div class="ingredient-group" id="basics">
            <h3>Choose the basic: </h3>
            <div th:each="ingredient : ${basic}">
                <input name="ingredients" type="radio" checked th:value="${ingredient.id}"/>
                <span class="checktext" th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="meat">
            <h3>Choose meat: </h3>
            <div th:each="ingredient : ${meat}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span class="checktext" th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="veggies">
            <h3>Choose vegetables: </h3>
            <div th:each="ingredient : ${veggies}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span class="checktext" th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="sauce">
            <h3>Choose sauce: </h3>
            <div th:each="ingredient : ${sauce}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span class="checktext" th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
        <div class="ingredient-group" id="cheese">
            <h3>Choose cheese: </h3>
            <div th:each="ingredient : ${cheese}">
                <input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
                <span class="checktext" th:text="${ingredient.name}">INGREDIENT</span><br/>
            </div>
        </div>
    </div>
    <div class="submit-button">
        <h3>Name your pizza:</h3>
        <input class="submit-field" type="text" th:field="*{name}" />
        <span class="validationError"
              th:if="${#fields.hasErrors('name')}"
              th:errors="*{name}">Error</span>
        <br/>
        <button>Submit your pizza</button>
    </div>
</form>
</body>
</html>

page before invalid input

pafe after invalid input

full code on github

【问题讨论】:

    标签: spring spring-boot spring-mvc thymeleaf


    【解决方案1】:

    你的问题在这里:

    @PostMapping
    public String processCreation(@Valid @ModelAttribute("create") Pizza pizza, BindingResult result){
        if(result.hasErrors()){
            return "create";
        }
        //Save creation...
        log.info("Processing creation: " + pizza);
        return "redirect:/orders/current";
    }
    

    您需要在返回“create”之前再次添加模型属性。 Thymeleaf 并不正确,模型只是缺少属性并且无法填充复选框。这样的事情应该可以工作:

    @GetMapping
    public String showCreationForm(Model model){
        addCreationFormModelAttributes(model, new Pizza());
        return "create";
    }
    
    @PostMapping
    public String processCreation(Model model, @Valid @ModelAttribute("create") Pizza pizza, BindingResult result){
        if(result.hasErrors()){
            addCreationFormModelAttributes(model, pizza);
            return "create";
        }
        //Save creation...
        log.info("Processing creation: " + pizza);
        return "redirect:/orders/current";
    }
    
    private static addCreationFormModelAttributes(Model model, Pizza pizza) {
        List<Ingredient> ingredients = Arrays.asList(
                new Ingredient("CLS22", "Classic base 22cm", Ingredient.Type.BASIC),
                new Ingredient("CLS30", "Classic base 30cm", Ingredient.Type.BASIC),
                new Ingredient("PEPE", "Pepperoni", Ingredient.Type.MEAT),
                new Ingredient("HAM", "Ham", Ingredient.Type.MEAT),
                new Ingredient("CHMPG", "Champignons", Ingredient.Type.VEGGIES),
                new Ingredient("CUCU", "Cucumbers", Ingredient.Type.VEGGIES),
                new Ingredient("PARM", "Parmesan cheese", Ingredient.Type.CHEESE),
                new Ingredient("MOZ", "Mozzarella cheese", Ingredient.Type.CHEESE),
                new Ingredient("BARBS", "Barbecue sauce", Ingredient.Type.SAUCE),
                new Ingredient("TOMAS", "Tomato sauce", Ingredient.Type.SAUCE)
        );
    
        Ingredient.Type[] types = Ingredient.Type.values();
        for(Ingredient.Type type: types){
            model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));
        }
        model.addAttribute("create", pizza);
    }
    

    【讨论】:

    • 这可行,但现在我的错误消息没有显示:错误
    • @SlavaUgnachyov 查看我修改后的帖子。现在应该可以正常工作了。
    • 这行得通,但现在我很困惑它是如何工作的
    • 这是因为每次在 processCreationreturn "create" 之前,我们都会在 addCreationFormModelAttributes 方法中创建新的 Pizza 对象?
    • addCreationFormModelAttributes 只是为了避免重复代码。在这两种情况下(新表单提交和绑定错误后重复提交表单),模型都需要包含 (1) 成分和 (2) Pizza 对象。对于新的表单提交 (showCreationForm),它需要一个新的 Pizza 对象。对于重复提交 (processCreation),它使用模型中已经存在的 Pizza 对象,现在部分由用户填写(有错误)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 2017-07-24
    • 2016-10-23
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多