您好,我无法使用Thymeleaf和Spring Boot(+Spring data)将一个对象作为另一个对象的属性发送给POST请求。
在这种情况下,我很难理解Spring Boot controller是如何传递和处理数据的。
传递基本数据类型(以字符串形式)很容易由控制器管理,并转换为适当的数据类型服务器端。
但当我需要将复杂对象数据类型作为属性传递时,问题就来了:
这是用户类:
//Import...
public class User implements Serializable {
@Id
@Column(name="c_Username", length=64, unique = true, nullable = false)
private String username;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "c_Role")
private Role role;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "c_Team")
@JsonManagedReference
private Team team;
@Column(name="e_Email", unique = true, length=128, nullable = false)
@Email
private String email;
@Column(name="x_Name", nullable = false, length=32)
private String name;
@Column(name="x_Surame", nullable = false, length=64)
private String surname;
@Column(name="x_Description", nullable = false, length=128)
private String description;
@Column(name="i_Cost", nullable = false)
private double cost;
@Column(name="x_Time", nullable = false, length=5)
private String time;
@Column(name="h_Password", nullable = false, length=128)
private String passwordHash;
@Column(name="f_Enabled", nullable = false)
private boolean enabled;
//... hashcode & equals
}
这是单个用户更新的映射:
@PostMapping("/updateuser")
public void updateUser(@Valid User user){
System.out.println(user); //For debugging reason
//find object and validate if it exists.. or return error response
utentiService.saveUser(user);
}
这是一个Javascript函数,通过它,我只需点击一个按钮,就可以对编辑过的表的每一行(每一行代表一个用户)进行post请求。(您必须通过复选框检查行,但我发现在location.reload()之后复选框不会重置,我将稍后尝试修复此问题)
function saveUsers(){
for (let index in tableRowList){
if(tableRowList[index]){
let data = new FormData(document.getElementById("form"+index));
for (let value of data.values()) {
console.log(value);
}
fetch("/updateuser", {method: 'POST', body: data})
.then(response => console.log(response));
}
}
fetch("/users")
.then(() => window.location.reload());
}
这是生成表中每一行的html代码。
表格得到了很好的生成,每一个值都在每个表格单元格中,读取工作正常。
<tr th:each="user,iter : ${listaUtenti}" th:id="riga+${iter.index}">
<form th:action="@{/updateuser}" th:id="form+${iter.index}" th:object="${user}" method="post">
<td>
<input type="hidden" th:id="pass + ${iter.index}" name="passwordHash" value="fake">
<input th:onclick="'selezionaRigaTabella(\'' + ${iter.index} + '\');'" type="checkbox" class="tablecheckbox">
</td>
<td>
<input class="input has-background-primary-light has-text-primary is-primary" th:id="username + ${iter.index}" name="username" type="text" th:value="${user.username}" th:placeholder="${user.username}" maxlength="64" required readonly>
</td>
<td>
<div class="select">
<select th:id="role + ${iter.index}" name="role" th:selected="${user.role.roleName}" class="width110">
<option name="role" th:each="role : ${listaRuoli}" th:selected="${user.role.roleName == role.roleName}" th:value="${role}" th:text="${role.roleName}"></option>
</select>
</div>
</td>
<td>
<input class="input" th:id="name + ${iter.index}" name="name" type="text" th:value="${user.name}" th:placeholder="${user.name}" maxlength="32" required>
</td>
<td>
<input class="input" th:id="surname + ${iter.index}" name="surname" type="text" th:value="${user.surname}" th:placeholder="${user.surname}" maxlength="64" required>
</td>
<td>
<input class="input" th:id="description + ${iter.index}" name="description" type="text" th:value="${user.description}" th:placeholder="${user.description}" maxlength="128" required>
</td>
<td>
<input class="input" th:id="email + ${iter.index}" name="email" type="email" th:value="${user.email}" th:placeholder="${user.email}" maxlength="128" required onresize="this.style.width = ((this.value.length + 1) * 8) + 'px';">
</td>
<td>
<div class="select">
<select th:id="team + ${iter.index}" name="team" th:selected="${user.team.teamName}" class="width110">
<option th:each="team : ${listaTeams}" th:selected="${user.team.teamName == team.teamName}" th:value="${team}" th:text="${team.teamName}"></option>
</select>
</div>
</td>
<td>
<input class="input" th:id="cost + ${iter.index}" name="cost" type="text" th:value="${user.cost}" th:placeholder="${user.cost}" required>
</td>
<td>
<input class="input" th:id="time + ${iter.index}" name="time" type="text" th:value="${user.time}" th:placeholder="${user.time}" minlength="5" maxlength="5" required>
</td>
<td>
<div class="select">
<select th:id="enabled + ${iter.index}" name="enabled" class="width80">
<option th:selected="${user.enabled}" value="true">yes</option>
<option th:selected="${!user.enabled}" value="false">no</option>
</select>
</div>
</td>
</form>
</tr>
问题是我不知道如何在用户对象中传递对象团队和角色。
目前,它们是从thymeleaf生成的。
这是表单从生成的HTML(基本上是字符串“ClassName(attribute1=Value,attribute2=Value)”)发出post请求时发送的值的一个示例
<select id="team0" name="team" class="width110" selected="selected">
<option value="Team(teamName=AMM, teamDesc=Administration)" selected="selected">AMM</option>
<option value="Team(teamName=ANA, teamDesc=Analytics)">ANA</option>
<option value="Team(teamName=DEV, teamDesc=Developers)">DEV</option>
</select>
错误是在服务器端,我只为实际上是对象的两个属性(团队和角色)获取空值,我必须禁用非空约束才能使其工作。
我不知道控制器如何在他的方法中实例化对象。
我对thymeleaf很陌生,你知道这个对象传递/绑定应该如何工作吗?
我尝试在select标记上使用th:字段,但它在编译时会出错。
我的临时修复程序只传递这些对象(角色和团队)的密钥,从请求体读取它们,通过服务检索它们,并为请求在post映射方法中实例化的对象用户手动设置它们。
虽然这给了我很多响应/错误逻辑的可能性,但我在问自己是否有可能自动正确实例化post-mapping方法的用户对象。
谢谢