如何持久化实体类中的数据并结合数据传输对象?

Posted

技术标签:

【中文标题】如何持久化实体类中的数据并结合数据传输对象?【英文标题】:How to persist data from the entity class and combined with data transfer object? 【发布时间】:2020-09-09 21:45:17 【问题描述】:

我正在开发一项身份验证功能,但在持久化实体类中的数据时遇到了问题。我能够从数据传输对象访问密码哈希和用户名,但无法从数据库中的用户类中查看电子邮件、名字、姓氏或电话号码。下面的照片是我注册新用户时发生的情况的示例。可以看到有 4 列没有数据。

当我添加 newUser 时,我使用了一个看起来像这样的 processRegistrationForm 方法...

    @PostMapping("/register")
    public String processRegistrationForm(@ModelAttribute @Valid RegisterFormDTO registerFormDTO,
                                          Errors errors, HttpServletRequest request,
                                          Model model) 

        // a few conditionals that I removed for brevity

        User newUser = new User(registerFormDTO.getUsername(), registerFormDTO.getPassword(), registerFormDTO.getFirstName(), registerFormDTO.getLastName(), registerFormDTO.getEmail(), registerFormDTO.getPhoneNumber());
        userRepository.save(newUser);
        setUserInSession(request.getSession(), newUser);

        return "redirect:";
    

registerFromDTO

public class RegisterFormDTO extends LoginFormDTO

    private String verifyPassword;


    private String firstName;

    private String lastName;

    private String email;

    private String phoneNumber;
//getters and setters.

LoginFormDTO

public class LoginFormDTO 

    @NotNull
    @NotBlank
    @Size(min = 3, max = 20, message = "Invalid username. Must be between 3 and 30 characters.")
    private String username;

    @NotNull
    @NotBlank
    @Size(min = 5, max = 20, message = "Invalid password. Must be between 5 and 30 characters.")
    private String password;
//getters and setters

用户类..

@Entity
public class User extends AbstractEntity 

    @NotBlank
    private String username;

    @NotBlank
    private String pwHash;

    //@Column(name = "first_name")
    private String firstName;
    //@Column(name = "last_name")
    private String lastName;
    //@Column(name = "email")
    private String email;
    //@Column(name = "phone_number")
    private String phoneNumber;

    public User() 

    private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    public User(String username, String password, String firstName, String lastName, String email, String phoneNumber)
        this.username =username;
        this.pwHash = encoder.encode(password);
        this.firstName =firstName;
        this.lastName = lastName;
        this.email = email;
        this.phoneNumber = phoneNumber;
    

    public boolean isMatchingPassword(String password) 
        return encoder.matches(password, pwHash);
    
//getters and setters

最后但并非最不重要的是我的注册表单视图

<form method="post">
    <div class="form-group">
        <label>Username
            <input class="form-control" th:field="$registerFormDTO.username" />
        </label>
        <p class="error" th:errors="$registerFormDTO.username"></p>
    </div>
    <div class="form-group">
        <label>Password
            <input class="form-control" th:field="$registerFormDTO.password" type="password" />
        </label>
        <p class="error" th:errors="$registerFormDTO.password"></p>
    </div>
    <div class="form-group">
        <label>Verify Password
            <input class="form-control" th:field="$registerFormDTO.verifyPassword" type="password" />
        </label>
    </div>
    <div class="form-group">
        <label>First Name
            <input class="form-control" th:field="$registerFormDTO.firstName" type="firstName" />
        </label>
    </div>
    <div class="form-group">
        <label>Last Name
            <input class="form-control" th:field="$registerFormDTO.lastName" type="lastName" />
        </label>
    </div>

    <input type="submit" class="btn btn-primary" value="Register" />
</form>

【问题讨论】:

RegisterFormDTOprocessRegistrationForm 方法中是否包含来自表单视图的有效值? @mslowiak 我有两个正在验证的字段,没有出现任何错误。我需要向其他字段添加额外的验证注释吗? 我只是询问在调用该方法后RegisterFromDTO 实例中是否存在任何值。尤其是如果registerFormDTO.getUsername() 有一些值或者它本身就是一个空值 @mslowiak RegisterFormDTO 中存在三个值:verifyPasswordusernamepassword 所以看起来你以LoginFormDTO作为模型而不是RegisterFromDTO 呈现注册表... 【参考方案1】:

您可以使用 MapStruct 从 DTO 映射到模型。

例如:

    @Mapper
public interface EmployeeMapper 
    @Mappings(
      @Mapping(target="employeeId", source="entity.id"),
      @Mapping(target="employeeName", source="entity.name")
    )
    EmployeeDTO employeeToEmployeeDTO(Employee entity);
    @Mappings(
      @Mapping(target="id", source="dto.employeeId"),
      @Mapping(target="name", source="dto.employeeName")
    )
    Employee employeeDTOtoEmployee(EmployeeDTO dto);

“Quick Guide to MapStruct”有更多信息。

【讨论】:

请不要说“...更多在这里。”使用更具描述性的东西。以下页面帮助解释:参见“Don’t use “click here” and other common hyperlink mistakes”、“Don't use "click here" as link text”和“Links and Hypertext - Link Text and Appearance”【参考方案2】:

该表单需要包含一些内容以保存在registerFormDTO 中收集的数据。第一个是: 1.在表单标签中,添加th:action="@/register"th:object="registerFormDTO" 2. 在输入标签中,将type="text"添加到每个输入字段,并将其中type="password"type="firstName"等更改为id="password"id="firstName"等。

做这些事情可以让 Thymeleaf 连接并保存收集到的数据。

这是完整的代码。

<form th:action="@/register" th:object="$registerFormDTO" method="post">
    <div class="form-group">
        <label>Username
            <input class="form-control" type="text" th:field="$registerFormDTO.username" id="username" />
        </label>
        <p class="error" th:errors="$registerFormDTO.username"></p>
    </div>
    <div class="form-group">
        <label>Password
            <input class="form-control" type="text" th:field="$registerFormDTO.password" id="password" />
        </label>
        <p class="error" th:errors="$registerFormDTO.password"></p>
    </div>
    <div class="form-group">
        <label>Verify Password
            <input class="form-control" type="text" th:field="$registerFormDTO.verifyPassword" id="password" />
        </label>
    </div>
    <div class="form-group">
        <label>First Name
            <input class="form-control" type="text" th:field="$registerFormDTO.firstName" id="firstName" />
        </label>
    </div>
    <div class="form-group">
        <label>Last Name
            <input class="form-control" type="text" th:field="$registerFormDTO.lastName" id="lastName" />
        </label>
    </div>
    <div class="form-group">
        <label>Email
            <input class="form-control" type="text" th:field="$registerFormDTO.email" id="email" />
        </label>
    </div>
    <div class="form-group">
        <label>Phone Number
            <input class="form-control" type="text" th:field="$registerFormDTO.phoneNumber" id="phoneNumber" />
        </label>
    </div>

    <input type="submit" class="btn btn-primary" value="Register" />
</form>

【讨论】:

以上是关于如何持久化实体类中的数据并结合数据传输对象?的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2/Doctrine:如何从实体类中持久化一个实体?

实体类中的所有实例变量是不是都在数据库中持久化? [复制]

如何将 ajax 数据传递给 React 组件?

VS2015 + SQL Server 反向生成实体模型

Java Persistence with MyBatis 小结1

如何将解析器中的数据传递给函数