首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Spring的Thymeleaf表单中的空字段,其他字段很好

使用Spring的Thymeleaf表单中的空字段,其他字段很好
EN

Stack Overflow用户
提问于 2022-02-14 19:33:47
回答 1查看 1.7K关注 0票数 0

我对Spring Boot比较陌生。目前,我正在使用用户注册系统制作Spring应用程序,但我遇到了一个问题。表单中的一些字段在后端注册为‘null’,尽管请求已正确发布。

我有一个HTML/ Thymeleaf表单,它提交8个字段来创建一个“User”对象。以下是表格:

代码语言:javascript
复制
<form th:action="@{/users/register_attempt}" th:object="${user}"
      method="post" style="max-width: 600px; margin: 0 auto;">
    <div class="m-3">
        <div class="form-group row">
            <label class="col-4 col-form-label">DOB: </label>
            <div class="col-8">
                <input type="text" th:field="*{dob}" class="form-control" th:required="required" />
            </div>
        </div>
        <div class="form-group row">
            <label class="col-4 col-form-label">First Name: </label>
            <div class="col-8">
                <input type="text" th:field="*{name}" class="form-control" th:required="required" />
            </div>
        </div>

        <div class="form-group row">
            <label class="col-4 col-form-label">Surname: </label>
            <div class="col-8">
                <input type="text" th:field="*{surname}" class="form-control" th:required="required" />
            </div>
        </div>

        <div class="form-group row">
            <label class="col-4 col-form-label">PPSN: </label>
            <div class="col-8">
                <input type="text" th:field="*{ppsn}" class="form-control" th:required="required" />
            </div>
        </div>
        <div class="form-group row">
            <label class="col-4 col-form-label">Address: </label>
            <div class="col-8">
                <input type="text" th:field="*{address}" class="form-control" th:required="required" />
            </div>
        </div>
        <div class="form-group row">
            <label class="col-4 col-form-label">Phone Number: </label>
            <div class="col-8">
                <input type="number" th:field="*{phone}" class="form-control"  />
            </div>
        </div>

        <div class="form-group row">
            <label class="col-4 col-form-label">E-mail: </label>
            <div class="col-8">
                <input type="email" th:field="*{email}" class="form-control" th:required="required" />
            </div>
        </div>
        <div class="form-group row">
            <label class="col-4 col-form-label">Password: </label>
            <div class="col-8">
                <input type="password" th:field="*{password}" class="form-control"
                       required minlength="6" maxlength="10" th:required="required"/>
            </div>
        </div>

        <div>
            <button type="submit" class="btn btn-primary">Sign Up</button>
        </div>
    </div>
</form>

下面是表单代码要模仿的模型:

代码语言:javascript
复制
public class User {
@Id
@GeneratedValue
private Long id;

@NotBlank
private String dob;
@NotBlank
private String name;
@NotBlank
private String surname;
@NotBlank
private String ppsn;
@NotBlank
private String address;
@NotBlank
private String phone;
@NotBlank
@Column(unique = true)
private String email;

private String nextApptId;

private String dose1Date;

private String dose2Date;

private String lastLogin;
@NotBlank
private String password;

public User() {
    super();
}

public User(String dob, String name, String surname, String ppsn, String address, String phone, String email, String password) {
    super();
    this.dob = dob;
    this.name = name;
    this.surname = surname;
    this.ppsn = ppsn;
    this.address = address;
    this.phone = phone;
    this.email = email;
    this.password = password;
}
 public Long getId() {
    return id;
}

public String getDob() {
    return dob;
}

public String getName() {
    return name;
}

public String getSurname() {
    return surname;
}

public String getPpsn() {
    return ppsn;
}

public String getAddress() {
    return address;
}

public void setAddress(String address) {
    this.address = address;
}

public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getNextApptId() {
    return nextApptId;
}

public void setNextApptId(String apptId) {
    this.nextApptId = apptId;
}

public String getDose1Date() {
    return dose1Date;
}

public void setDose1Date(String dose1Date) {
    this.dose1Date = dose1Date;
}

public String getDose2Date() {
    return dose2Date;
}

public void setDose2Date(String dose2Date) {
    this.dose2Date = dose2Date;
}

public String getLastLogin() {
    return lastLogin;
}

public void setLastLogin(String lastLogin) {
    this.lastLogin = lastLogin;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}
}

但由于某些原因,我无法确定前四个字段--即道布(出生日期)、姓名、姓氏和PPSN --在服务器端实例化用户对象时产生了一个空错误,例如:

代码语言:javascript
复制
     `Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 4 errors<EOL>
Field error in object 'user' on field 'dob': rejected value [null]; codes [NotBlank.user.dob,NotBlank.dob,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.dob,dob]; arguments []; default message [dob]]; default message [must not be blank] `.

其他四个字段,地址、电话、电子邮件和密码似乎运行得很好。

据我所知,这不是一个错误问题(如果结果是这样的话,请原谅我)。我使用Burp截获了Post请求,以检查字段的内容是否从表单中输入到请求中,并为我的User类中的字段提供了正确的名称,实际上它们都在其中。

我认为这意味着问题来自后端控制器代码是如何基于模型解释这个post请求的,但我并不真正知道如何或从何处开始。以下是当前控制器:

代码语言:javascript
复制
@GetMapping("/register")
    public String startRegistration(Model model) {
        model.addAttribute("user", new User());
        return "register";
    }  

@PostMapping("/register_attempt")
    public String registerAttempt(@Valid User newUser) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encodedPassword = passwordEncoder.encode(newUser.getPassword());
        newUser.setPassword(encodedPassword);
        userRepository.save(newUser);
        return "registered_successfully";
    }

编辑:对持久化问题的进一步调试和澄清

从Post中删除@Valid注释并使用老式的print语句显示相同的结果--前四个字段为null,原因不明显。

代码语言:javascript
复制
    @PostMapping("/register_attempt")
public String registerAttempt(@ModelAttribute("user") User newUser) {
    System.out.println("Saving user ");
    System.out.println("Name " + newUser.getName());
    System.out.println("Last Name " + newUser.getSurname());
    System.out.println("PPSN " +newUser.getPpsn());
    System.out.println("DOB " +newUser.getDob());
    System.out.println("email " +newUser.getEmail());
    System.out.println("address " +newUser.getAddress());
    System.out.println("encrypted password " +newUser.getPassword());
    System.out.println("Phone num " +newUser.getPhone());
    userRepository.save(newUser);
    System.out.println("User saved");
    return "registered_successfully";
}

使用以下虚拟数据:

它将此Post请求发送到后端:

这些打印报表的结果:

代码语言:javascript
复制
Saving user 
name null
last Name null
ppsn null
dob null
email foo@bar.com
address Here and there
password password
Phone num 987654321

这些错误信息是:

代码语言:javascript
复制
javax.validation.ConstraintViolationException: Validation failed for classes [app.model.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='must not be blank', propertyPath=surname, rootBeanClass=class app.model.User, messageTemplate='{javax.validation.constraints.NotBlank.message}'}
    ConstraintViolationImpl{interpolatedMessage='must not be blank', propertyPath=dob, rootBeanClass=class app.model.User, messageTemplate='{javax.validation.constraints.NotBlank.message}'}
    ConstraintViolationImpl{interpolatedMessage='must not be blank', propertyPath=name, rootBeanClass=class app.model.User, messageTemplate='{javax.validation.constraints.NotBlank.message}'}
    ConstraintViolationImpl{interpolatedMessage='must not be blank', propertyPath=ppsn, rootBeanClass=class app.model.User, messageTemplate='{javax.validation.constraints.NotBlank.message}'}
]

如果你有任何洞察力,这可能会发生,我将非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-15 07:18:00

Thymeleaf模板中有th:object="${user}",所以我必须假设控制器中的@GetMapping方法使用addAttributeUser实例添加到Model中。

在您的@PostMapping中,还应该使用@ModelAttribute

代码语言:javascript
复制
@PostMapping("/register_attempt")
public String registerAttempt(@Valid @ModelAttribute("user") User newUser) {
  ...

您还需要为每个字段设置setter。我看到User没有setName(String name),没有setDob(String dob),.

其他一些小窍门:

  1. 不要在控制器方法本身中创建BCryptPasswordEncoder实例。当您使用Spring时,这应该是一个应用程序范围的单例(在Spring中称为bean )。在应用程序中添加一个类,例如ReservationSystemApplicationConfiguration,它声明如下:
代码语言:javascript
复制
@Configuration
public class ReservationSystemApplicationConfiguration {
  @Bean
  public PasswordEncoder passwordEncoder() {
     return new BCryptPasswordEncoder();
  }
}

然后,在控制器中插入密码编码器:

代码语言:javascript
复制
@Controller
@RequestMapping("...")
public class MyController {

  private final PasswordEncoder passwordEncoder;

  public MyController(PasswordEncoder passwordEncoder) {
    this.passwordEncoder = passwordEncoder;
  }

  @PostMapping("/register_attempt")
  public String registerAttempt(@Valid @ModelAttribute("user") User newUser) {
    String encodedPassword = passwordEncoder.encode(newUser.getPassword());
    newUser.setPassword(encodedPassword);
    userRepository.save(newUser);
    return "registered_successfully";
  }
}
  1. 控制器不应直接调用存储库,而应在两者之间使用服务。
  2. 最好使用不同的对象来映射表单数据并将数据存储到数据库中。有关如何做到这一点的更多信息,请参见用Thymeleaf处理表单
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71117330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档