【问题标题】:ThymeLeaf - POST Table Data (ArrayList) to Another ControllerThymLeaf - 将表数据(ArrayList)发布到另一个控制器
【发布时间】:2019-10-25 04:09:27
【问题描述】:

我很难在 Thymeleaf POST 中绑定 ObjectList。

我正在尝试使用 Spring 5 和 ThymeLeaf 实现以下要求

1. User uploads a Excel File
2. Display data in HTML Table (For Java Script Data Validation)
3. Allow User to Delete Invalid Rows  (from Inmemory User Specific ArrayList)
4. Display Remaining Values
5. POST valid remaining values to Server

我打算在每一行中添加一个删除按钮,.还有一个提交按钮,用于将所有剩余的行保存在 DB 中。

如何将 eachRowList 转发到另一个控制器(用于删除操作和数据库保存)。

@PostMapping("/load-excel")
public ModelAndView loadFile(@RequestParam("fileName") MultipartFile file,
         @RequestParam("selectedApplicationName") String selectedApplicationName,RedirectAttributes redirectAttr,Model model) {

        List<EachRowinExcel> eachRowList = fileReaderService.convertExceltoObjList();
        ....

        modelAndView.addObject("eachRowList", eachRowList);

        return modelAndView;
}



 <tr th:each="eachRow : ${eachRowList}">
              <td th:text="${eachRow.column1}"></td>
              <td th:text="${eachRow.column2}"></td>
              <td th:text="${eachRow.column3}"></td>
              <td th:text="${eachRow.column4}"></td>
              <td th:text="${eachRow.column5}"></td>
              <td th:text="${eachRow.column6}"></td>
              <td th:text="${eachRow.column7}"></td>
              <!-- Special Columns -->
              <th:block th:each="customColumnValue:${eachRow.customColumnsList}">
                <td th:text="${customColumnValue}"></td>
              </th:block> 

            </tr>

更新 1:

修改后的视图

<form action="#" th:action="@{/access/delete}" th:object="${form}" method="post">
    <table id="accessRequestDataTable"  class="display compact" style="width:100%">
      <thead>
        <tr>
          <!-- Headers -->       
        </tr>
      </thead>
      <tbody>
     <tr th:each="eachRow, iter : ${form.eachRowList}">
          <td  th:text="${eachRow.accessReqeustCounter}" th:field="*{eachRowList[__${iter.index}__].accessReqeustCounter}"></td>
          <td  th:text="${eachRow.accessReqeustID}" th:field="*{eachRowList[__${iter.index}__].accessReqeustID}"></td>
          <td  th:text="${eachRow.accessRequestType}" th:field="*{eachRowList[__${iter.index}__].accessRequestType}"></td>
          <td  th:text="${eachRow.userProfile}" th:field="*{eachRowList[__${iter.index}__].userProfile}"></td>
          <td  th:text="${eachRow.userFinalName}" th:field="*{eachRowList[__${iter.index}__].userFinalName}"></td>
          <td  th:text="${eachRow.userLoginName}" th:field="*{eachRowList[__${iter.index}__].userLoginName}"></td>
          <td  th:text="${eachRow.userEmail}" th:field="*{eachRowList[__${iter.index}__].userEmail}"></td>

          <td>              
            <button class="btn btn-danger btn-sm" 
            type="submit" value="submit">Delete</button>             
          </td>
        </tr>        

      </tbody>
    </table>
  </form>

POST 控制器

@RequestMapping(value = "/access/delete", method = RequestMethod.POST)
public ModelAndView deleteUserFromTable(@ModelAttribute("form") EachRowListWrapper eachRowListWrapper){
    System.out.println(eachRowListWrapper.getEachRowList().size());
    ModelAndView modelAndView = new ModelAndView();
    eachRowListWrapper.getEachRowList().remove(0);
    modelAndView.setViewName("access-table");
    return modelAndView;        
}

更新 2

对列标题采用了类似的方法。我在包装类中有另一个 List 对象。 它在初始加载时工作,但在从 POST 控制器返回后缺少标头。

  <thead>
    <tr>              
      <th scope="col">User Name</th>
      <th scope="col">Login</th>
      <th scope="col">Email</th>
      <th:block th:each="key, iter : ${form.customColumns}">
        <th th:text="${key}" scope="col"></th>
        <input type="hidden" th:field="${form.customColumns[__${iter.index}__]}" />
      </th:block> 
      <th scope="col">Action</th>
    </tr>
  </thead>

最终更新:

显然 th:field 输入标签不会绑定在 thead 部分(它不应该有输入字段 LoL)。在表格开始之前我移动它后一切正常。

【问题讨论】:

    标签: spring thymeleaf


    【解决方案1】:

    您需要将您的表格放在一个表单中,这将确定将在其 th:object 字段中发送到控制器的内容。这在 spring 中称为命令对象。让我们假设您的“eachRowList”列表位于名为“form”的命令对象内。

    <form method="post"
            th:action="@{/mappingInYourController}"
            th:object="${form}">
    <!-- Here goes your table -->
    </form>
    

    您还必须指定将哪些数据放置在您在 th:object 中定义的对象内,以便将其发送到控制器。这是通过输入 th:fields 以下列方式完成的(其中一行的示例):

    <tr th:each="eachRow, iter : ${form.eachRowList}">
    <!-- ... -->
    <td> <input th:value="${eachRow.column1}" th:field="*{eachRowList[__${iter.index}__].column1}"/>
    </td>
    

    请注意,当您使用 *{} 访问属性时,您将引用您定义为表单的 th:object 的属性。

    现在,例如,如果您使用按钮提交表单,您的控制器将能够接收其中包含 eachRowList 列表的命令对象“form”,并且列表的元素将是表格输入中的元素.如果您不希望此输入可在表格中内联编辑,您可以这样做:

    th:readonly="true"
    

    【讨论】:

    • 感谢您在本 Jorge 上的宝贵时间。我已经尝试过你的输入,但我在 POST 方法中得到空值。我已经添加了修改后的代码。
    • 我的错,那些 th:field 标签必须在输入元素内。我会更新答案,希望它现在可以正常工作。同样对于每一行的删除按钮,您很可能希望使用按钮 formaction 属性来更改每个按钮的操作,这样您就可以告诉控制器您选择删除哪个条目。为此,您也可以在操作上使用 [${iter.index}] 部分。
    • 哇!!非常感谢。工作完美。几乎完成,除了表头。我已经添加了更新 3。我错过了什么吗?
    • 您使用的是“th:field="${form..."。首先,对于 th:fields,您应该使用 *{},而不是 ${} 语法。其次,这是因为 * {} 指的是表单的 th:object。由于在您的示例中此 th:object 称为“表单”,因此您无需使用 *{} 再次引用它,仅在使用 ${} 时。语法为 th:field="*{customColumns[__${iter.index}__]}"。
    • 我之前确实尝试过,正如你提到的,然后将其更改为显式引用。无论如何,两者都没有工作。 “表单”包装类可以包含多个列表作为成员吗?
    【解决方案2】:

    对于您的提交按钮,您需要一个围绕表格的表单。一个可行的解决方案是隐藏输入字段来保存每个td 的数据。

    <input type="hidden" th:field="${eachRow.column1}"/>
    

    提交表单后,您可以访问控制器中输入字段保存的数据并将其保存在数据库中。

    【讨论】:

    • 感谢您的输入 Happy 。我使用了隐藏属性。
    猜你喜欢
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多