我正在努力提高 Java Spring,但在练习过程中我不明白一些东西。我有一个名为 CreateApplicationType.html 的 HTML 表单。人们可以在这里创建一个新的 ApplicationType 对象以供服务器处理并存储在数据库中。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Create Application Type</title>
</head>
<body>
<h2>Create Application Type</h2>
<table>
<form th:action="@{/applicationType/save}" method="post" th:object="${applicationType}" enctype="application/x-www-form-urlencoded">
<tr>
<td><label>Application Type: </label></td>
<td><input type="text" th:field="*{applicationType}" placeholder="Application Type"/></td>
</tr>
<tr>
<td><label>Application Type Abbreviation: </label></td>
<td><input type="text" th:field="*{applicationTypeAbbreviation}" placeholder="Application Type Abbreviation"/></td>
</tr>
<tr>
<td><label>Application Type Description: </label></td>
<td><input type="text" th:field="*{applicationTypeDescription}" placeholder="Application Type Description"/></td>
</tr>
<tr>
<td><label>Application Type is Public?</label></td>
<td><input type="checkbox" th:field="*{isPublic}" placeholder="Application Type is Public?"/></td>
</tr>
<tr>
<td><label>TODO: Application Type Steps: </label></td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</form>
</table>
</body>
</html>
这是我的ApplicationType实体类:
package org.foam.civ.model.application;
import lombok.*;
import javax.persistence.*;
import java.util.List;
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="ApplicationType")
public class ApplicationType {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, unique = true)
private String applicationType;
@Column
private String applicationTypeAbbreviation;
@Column
private String applicationTypeDescription;
@Column
private Boolean isPublic;
@OneToMany(cascade=CascadeType.ALL)
private List<ApplicationStep> applicationSteps;
}
这是我的 ApplicationTypeController RESTController 类中的相关函数:
@PostMapping(value = "/save")
public void saveApplicationType(@ModelAttribute ApplicationType applicationType){
System.out.println(applicationType.toString());
applicationTypeService.saveApplicationType(applicationType);
}
当我测试填写字段并提交时,出现以下错误:
Failed to convert value of type 'java.lang.String' to required type 'org.foam.civ.model.application.ApplicationType'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'Cool Application Type'; nested exception is java.lang.NumberFormatException: For input string: "CoolApplicationType"
org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'org.foam.civ.model.application.ApplicationType'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'Cool Application Type'; nested exception is java.lang.NumberFormatException: For input string: "CoolApplicationType"
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:79)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
...
...
我的模型中唯一的 Long 是 id 字段,它是由数据库自动生成的。因此 Spring 必须尝试将客户端的 applicationType 字段映射到 ApplicationType 对象上的 id 字段。该 id 是由数据库自动生成的,因此我不想将其包含为提交字段或在服务器端为其绑定值。
我在这里做错了什么?有没有办法告诉 Spring 不要绑定到 id 字段,因为它是由数据库自动生成的?我是否需要某种仅包含客户端要使用的字段的 ApplicationTypeDTO 类?然后我可以在保存之前将该 DTO 转换为服务器端的 ApplicationType 对象吗?
您遇到的问题是由于 Thyme leaf 为整个 ApplicationType 对象生成表单字段,包括 id 字段,该字段是一个 Long。当您提交表单时,Spring 尝试将提交的值绑定到 ApplicationType 对象,但它遇到了 id 字段不匹配的情况。
要解决此问题,您可以从 Thyme leaf 模板的表单中排除 id 字段。更新 CreateApplicationType.html 文件中的表单字段以排除 id 字段。
使用数据传输对象(DTO)将客户端发送的数据与服务器使用的实际实体分开是一个很好的做法。您可以创建一个仅包含表单所需字段的 ApplicationTypeDTO 类,然后在保存之前将其转换为服务器端的 ApplicationType 实体。
以下是如何创建 ApplicationTypeDTO 的示例:
@数据 公共类 ApplicationTypeDTO {
private String applicationType;
private String applicationTypeAbbreviation;
private String applicationTypeDescription;
private Boolean isPublic;
}
尝试修改控制器方法以接受 ApplicationTypeDTO 而不是 ApplicationType 作为:
@PostMapping(值=“/保存”) 公共无效 saveApplicationType(@ModelAttribute ApplicationTypeDTO applicationTypeDTO){ // 将DTO转换为实体并保存 ApplicationType applicationType = ConvertDTOToEntity(applicationTypeDTO); applicationTypeService.saveApplicationType(applicationType); }
私有应用程序类型convertDTOToEntity(ApplicationTypeDTO applicationTypeDTO) { // 从 DTO 创建并返回一个 ApplicationType 实体 // 您可以使用 ModelMapper 等映射库或手动复制字段 // 为了简单起见,我们假设这里有一个手动副本 ApplicationType applicationType = new ApplicationType(); applicationType.setApplicationType(applicationTypeDTO.getApplicationType()); applicationType.setApplicationTypeAbbreviation(applicationTypeDTO.getApplicationTypeAbbreviation()); applicationType.setApplicationTypeDescription(applicationTypeDTO.getApplicationTypeDescription()); applicationType.setIsPublic(applicationTypeDTO.getIsPublic()); 返回应用程序类型; }