java 如何将列表中的字段绑定到Thymeleaf表单?[Bean属性不可读]

2ul0zpep  于 2023-03-28  发布在  Java
关注(0)|答案(1)|浏览(119)

我有一个对象,它可以有两个或三个重复的字段集。似乎最简单的处理方法是使用列表和一个表单,该表单将随着列表的大小而扩展或收缩。
不幸的是,我一直收到一个错误,提示Thymeleaf无法识别我试图绑定到主表单对象的变量。这个问题在this article中得到了解决,但由于某种原因,我无法得到相同的结果。
∮我所尝试的∮

DTO

package nathanLively.subAlignerjava.DTO;

import lombok.Builder;
import lombok.Data;
import nathanLively.subAlignerjava.Models.Enums.UnitsEnum;
import nathanLively.subAlignerjava.Models.PreAlignment;
import nathanLively.subAlignerjava.Models.Speaker;
import nathanLively.subAlignerjava.Models.UserAlignment;
import nathanLively.subAlignerjava.Models.UserAlignmentSource;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Data
@Builder
public class UserAlignmentDTO {
    private UnitsEnum units;
    private List<UserAlignmentSourceDTO2> userAlignmentSources;

    public UserAlignment toUserAlignment(PreAlignment preAlignment) {
        Set<UserAlignmentSource> userAlignmentSourceList = userAlignmentSources.stream()
                .map(UserAlignmentSourceDTO2::toUserAlignmentSource)
                .collect(Collectors.toSet());

        UserAlignment userAlignment = UserAlignment.builder()
                .preAlignment(preAlignment)
                .userAlignmentSources(userAlignmentSourceList)
                .distanceUnit(units)
                .build();

        return userAlignment;
    }
}
package nathanLively.subAlignerjava.DTO;

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import nathanLively.subAlignerjava.Models.Enums.UnitsEnum;
import nathanLively.subAlignerjava.Models.PreAlignment;
import nathanLively.subAlignerjava.Models.PreAlignmentSource;
import nathanLively.subAlignerjava.Models.Speaker;
import nathanLively.subAlignerjava.Models.UserAlignmentSource;

@Data
@Builder
public class UserAlignmentSourceDTO2 {

    private String modelName;
    private Integer count;
    private Float distance;

    public UserAlignmentSource toUserAlignmentSource() {

        UserAlignmentSource userAlignmentSource = UserAlignmentSource.builder()
//                .speaker(speaker)
                .count(count)
                .distance(distance)
                .build();

        return userAlignmentSource;
    }
}

控制器

package nathanLively.subAlignerjava.Controllers;

import lombok.RequiredArgsConstructor;
import nathanLively.subAlignerjava.DTO.UserAlignmentDTO;
import nathanLively.subAlignerjava.DTO.UserAlignmentSourceDTO;
import nathanLively.subAlignerjava.DTO.UserAlignmentSourceDTO2;
import nathanLively.subAlignerjava.Models.*;
import nathanLively.subAlignerjava.Models.Enums.UnitsEnum;
import nathanLively.subAlignerjava.Services.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@Controller
@RequiredArgsConstructor
@RequestMapping("/align")
public class AlignController {

    @Autowired
    private final BrandService brandService;

    @Autowired
    private final SpeakerModelService speakerModelService;

    @Autowired
    private final DspPresetService dspPresetService;

    @Autowired
    private final UserAlignmentService userAlignmentService;

    @Autowired
    private final SpeakerService speakerService;

    @Autowired
    private final PreAlignmentService preAlignmentService;

    // Show pre-alignments
    @GetMapping("/pre-alignments")
    public String showPreAlignments(Model model) {

        // Show pre-alignments in model
        model.addAttribute("preAlignments", preAlignmentService.findAll());

        return "pre-alignments";
    }

    // Add pre-alignment to user alignment
    @GetMapping("/pre-alignment/{id}")
    public String showUserAlignment(@PathVariable("id") Long preAlignmentId, Model model) {

        // Find pre-alignment and add to model
        PreAlignment preAlignment = preAlignmentService.findById(preAlignmentId);
        model.addAttribute("preAlignment", preAlignment);

        // Initialize UserAlignmentSourceDTO2
        int numberOfPreAlignmentSources = preAlignment.getPreAlignmentSources().size();
        List<UserAlignmentSourceDTO2> userAlignmentSourceDTO2s = new ArrayList<>();
        for (int i = 0; i < numberOfPreAlignmentSources; i++) {
            UserAlignmentSourceDTO2 userAlignmentSourceDTO2 = UserAlignmentSourceDTO2.builder()
                    .modelName(preAlignment.getPreAlignmentSources().get(i).getSpeaker().getSpeakerModel().getName())
                    .build();
            userAlignmentSourceDTO2s.add(userAlignmentSourceDTO2);
        }

        // Initialize UserAlignmentDTO and add to model
        UserAlignmentDTO userAlignmentDTO = UserAlignmentDTO.builder()
                .userAlignmentSources(userAlignmentSourceDTO2s)
                .build();
        model.addAttribute("userAlignmentDTO", userAlignmentDTO);

        // Show distance units in model
        model.addAttribute("units", List.of(UnitsEnum.METERS, UnitsEnum.FEET));

        return "user-alignment";
    }

    // Create UserAlignment and calculate result
    @PostMapping("/calculate/{id}")
    public String calculateUserAlignment(@PathVariable("id") Long preAlignmentId, @ModelAttribute("userAlignmentDTO") UserAlignmentDTO userAlignmentDTO, Model model) {

        // Find pre-alignment
        PreAlignment preAlignment = preAlignmentService.findById(preAlignmentId);
//        preAlignment.getPreAlignmentSources().get(0)

        // Convert UserAlignmentDTO to UserAlignment
        UserAlignment userAlignment = userAlignmentDTO.toUserAlignment(preAlignment);

        // Calculate result
//        userAlignment.calculateResult();

        // Save user alignment
        userAlignmentService.save(userAlignment);

        // Show result
        model.addAttribute("userAlignment", userAlignment);

        return "result";
    }

Thymeleaf模板

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout}"
      th:with="activeMenuItem='align'"
      xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>User Alignment</title>
</head>
<body>
<div layout:fragment="page-content">
    <h1>User-Alignment</h1>
    <form id="source-form"
          th:object="${userAlignmentDTO}"
          th:action="@{/align/calculate/{id}(id=${preAlignment.id})}"
          method="post">
        <th:block th:each="source,iter : *{userAlignmentSources}">
            <label th:text="${iter.index + 1} + '.'"></label>
            <label>Total [[${source.modelName}]] in array:</label>
            <input type="number"
                   th:field="*{userAlignmentSources[__${iter.index}__].count}">
            <label>Distance from [[${source.modelName}]] to FOH:</label>
            <input type="number"
                   th:field="*{userAlignmentSources[__${iter.index}__].distance}">
        </th:block>
        <label>Unit</label>
        <select th:field="*{units}">
            <option th:each="unit : ${units}"
                    th:text="${unit.fullName}"
                    th:value="${unit}">meters
            </option>
        </select>
        <button type="submit">Align</button>
    </form>

</div>
</body>
</html>

期望

我的期望是,当用户单击Align按钮时,表单将发送到端点并持久化到数据库。

错误

Invalid property 'userAlignmentSources[0]' of bean class [nathanLively.subAlignerjava.DTO.UserAlignmentDTO]: Illegal attempt to get property 'userAlignmentSources' threw exception
jm81lzqq

jm81lzqq1#

看起来我错过了Thymeleaf的正确NoArgs构造函数。

@NoArgsConstructor
@AllArgsConstructor

来自chatGPT:
根据错误消息,UserAlignmentSourceDTO2类似乎没有默认构造函数。这意味着Thymeleaf在尝试将表单数据绑定到UserAlignmentDTO对象时无法创建此类的示例。

相关问题