Thymeleaf 表单不将对象返回给控制器类方法

Posted

技术标签:

【中文标题】Thymeleaf 表单不将对象返回给控制器类方法【英文标题】:Thymeleaf's form dont return the object to controller class's method 【发布时间】:2020-07-20 05:00:25 【问题描述】:

我有一个带有 JPA/Hibernate 的 SpringBoot-MVC Java 应用程序,它使用 H2 数据库来存储数据,我正在尝试通过 Web 浏览器读取和更改该数据库的行。我阅读成功,但带有百里香叶的编辑页面表单不会将我更改的对象发送到控制器类。

处方集:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>Cadastro de Clientes</title>
<link href="/webjars/bootstrap/4.5.0/css/bootstrap.min.css"
    rel="stylesheet"></link>
<script src="/webjars/jquery/3.5.1/jquery.min.js"></script>
<script src="/webjars/bootstrap/4.5.0/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="panel panel-default">
        <div class="panel-heading">
            <strong>Edicao de Clientes</strong>
        </div>
        <div class="panel-body">
            <form class="form-horizontal" th:object="$customer"
                th:action="@/save" method="post" style="margin: 10px">
                <div class="form-group">
                    <fieldset>
                        <div class="form-group row">
                            <div class="alert alert-danger" th:if="$#fields.hasAnyErrors()">
                                <div th:each="detailedError : $#fields.detailedErrors()">
                                    <span th:text="$detailedError.message"></span>
                                </div>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-1">
                                <input type="hidden" class="form-control input-sm"
                                    th:field="*id" readonly="readonly" style="display: none;" />
                            </div>
                            <div class="col-md-1">
                                <label>CÓD. DO CLIENTE</label> <input type="text"
                                    class="form-control input-sm" th:field="*customerId"
                                    readonly="readonly" />
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('companyName')? 'has-error'">
                                <label>RAZAO SOCIAL</label> <input type="text"
                                    class="form-control input-sm" th:field="*companyName"
                                    autofocus="autofocus" placeholder="Informe o texto"
                                    maxlength="50" />
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('tradeName')? 'has-error'">
                                <label>NOME FANTASIA</label> <input type="text"
                                    class="form-control input-sm" th:field="*tradeName"
                                    maxlength="150" placeholder="Informe o texto" />
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('sectorId')? 'has-error'">
                                <label>SETOR</label> <input type="text"
                                    class="form-control input-sm" th:field="*sectorId" />
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('neighborhood')? 'has-error'">
                                <label>BAIRRO</label>
                                <textarea class="form-control input-sm"
                                    th:field="*neighborhood" placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('place')? 'has-error'">
                                <label>LOGRADOURO</label>
                                <textarea class="form-control input-sm" th:field="*place"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('neighborhood')? 'has-error'">
                                <label>NUMERO</label>
                                <textarea class="form-control input-sm" th:field="*placeId"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('city')? 'has-error'">
                                <label>CIDADE</label>
                                <textarea class="form-control input-sm" th:field="*city"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('visitDay')? 'has-error'">
                                <label>DIA DE VISITA</label>
                                <textarea class="form-control input-sm" th:field="*visitDay"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('region')? 'has-error'">
                                <label>REGIAO</label>
                                <textarea class="form-control input-sm" th:field="*region"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('latitude')? 'has-error'">
                                <label>LATITUDE</label>
                                <textarea class="form-control input-sm" th:field="*latitude"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-md-2"
                                th:classappend="$#fields.hasErrors('longitude')? 'has-error'">
                                <label>LONGITUDE</label>
                                <textarea class="form-control input-sm" th:field="*longitude"
                                    placeholder="Informe o texto"></textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <button type="submit" class="btn btn-sm btn-primary">Salvar</button>
                            <a th:href="@/" class="btn btn-sm btn-default">Cancelar</a>
                        </div>
                    </fieldset>
                </div>
            </form>
        </div>
    </div>
</body>
</html>

应接收公式对象的方法:

package com.br.aloi.planner.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

import com.br.aloi.planner.model.Customer;
import com.br.aloi.planner.service.CustomerService;

@Controller
public class CustomerController 

    @Autowired
    private CustomerService service;

(...)

    @PostMapping("/save")
    public ModelAndView save(@Valid Customer customer, BindingResult result) 
        if (result.hasErrors()) 
            return edit(customer.getId());
        
        service.save(customer);
        return findAll();
    


对象正在向控制器类上的save 方法返回空值。否则,当我在浏览器中选择数据库的一行并单击“编辑”时,编辑页面将打开以进行编辑,其中创建的对象属性恰到好处。

【问题讨论】:

【参考方案1】:

在向 Thymeleaf 请求对象之前,您必须通过模型传递对象,以便 Thymeleaf 拥有它。

将以下内容添加到您的控制器方法中:

@ModelAttribute("customer")
public Customer thisPartCanBeCalledWhatever() 
    return new Customer(); 

确保 Customer 类具有 getter、setter 和默认构造函数。

【讨论】:

@GetMapping("/edit/id") public ModelAndView edit(@PathVariable("id") Integer id) ModelAndView mv = new ModelAndView("/customerEdit"); mv.addObject("客户", service.findById(id));返回 mv; 我使用编辑方法中的 addObject 发送对象。没有错吗? 好吧,您的代码似乎是这样认为的,它返回 null :) 唯一知道的方法是尝试我的建议,看看它是否有帮助。也尝试在主题文件中显示客户对象以进行调试。重要的是,无论如何,当该页面加载时,客户对象已经在模型中,我不知道您的代码中是否是这种情况。用我的方法,我们可以确保这一点。 按照您的命令,我重新检查了我的模型类,发现唯一的 'id customer.Id' 没有声明 setter,只有 getter。解决问题。非常感谢阿斯加罗夫,对不起我的无知。 不要无知,忘记getter或setter是很常见的,很高兴它成功了:)【参考方案2】:

按照 J Asgarov 的建议,我重新检查了我的模型,并重新创建了所有属性的 getter 和 setter。重建项目后,帖子立即返回对象。毕竟代码是正确的,我的新手令人不安 毕竟。谢谢!!

【讨论】:

以上是关于Thymeleaf 表单不将对象返回给控制器类方法的主要内容,如果未能解决你的问题,请参考以下文章

Thymeleaf 表单未提交给 Spring 引导控制器

处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法

@ModelAttribute 使用 thymeleaf 返回空值

使用 Thymeleaf 为嵌套对象创建表单的问题

Thymeleaf 将对象集作为对象的成员传递给控制器

spring thymeleaf - 从 html 表中删除对象并将 id 传递给控制器