我尝试为我的应用程序创建一个注册页面,当我按下“提交”按钮时,出现此错误:
Exception evaluating SpringEL expression: "#fields.hasErrors('firstName')"
据我了解,Thymleaf使用POJO的getter进行验证,这意味着找不到firstName属性。对于注册,我将DTO用于用户实体,将DTO仅用于注册。如果我使用用户实体,则不会出现此错误。我在做什么错了?
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Registration Form</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/registration.css}"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form autocomplete="on" action="register.html" th:action="@{/user/register}"
th:object="${user}" method="post" class="form-horizontal"
role="form">
<h2>Registration Form</h2>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}"
class="validation-message"></label>
<input type="text" th:field="*{firstName}" placeholder="Name"
class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}"
class="validation-message"></label>
<input type="text" th:field="*{lastName}"
placeholder="Last Name" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('username')}" th:errors="*{username}"
class="validation-message"></label>
<input type="text" th:field="*{username}"
placeholder="Username" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="text" th:field="*{emailAddress}" placeholder="Email"
class="form-control"/> <label
th:if="${#fields.hasErrors('emailAddress')}" th:errors="*{emailAddress}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('phoneNumber')}" th:errors="*{phoneNumber}"
class="validation-message"></label>
<input type="text" th:field="*{phoneNumber}"
placeholder="Phone Number" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="password" th:field="*{password}"
placeholder="Password" class="form-control"/> <label
th:if="${#fields.hasErrors('password')}" th:errors="*{password}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="password" th:field="*{confirmPassword}"
placeholder="Confirm Password" class="form-control"/> <label
th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<button type="submit" class="btn btn-primary btn-block">Register User</button>
</div>
</div>
<h2><span class="text-success" th:utext="${successMessage}"></span></h2>
</form>
</div>
</div>
</div>
</body>
</html>
RegisterUserDto
@PasswordMatches
public class RegisterUserDto {
private Long id;
@NotNull(message = "This field can't be null")
@NotEmpty(message = "This field can't be empty")
private String firstName;
@NotNull(message = "This field can't be null")
@NotEmpty(message = "This field can't be empty")
private String lastName;
@NotNull(message = "This field can't be null")
@NotEmpty(message = "This field can't be empty")
private String username;
@NotNull(message = "This field can't be null")
@NotEmpty(message = "This field can't be empty")
@ValidEmail
private String emailAddress;
@NotNull(message = "This field can't be null")
@NotEmpty(message = "This field can't be empty")
@ValidPhoneNumber
private String phoneNumber;
@ValidPassword
private String password;
private String confirmPassword;
//getters and setters
控制器
@GetMapping("/register")
public ModelAndView registration(){
ModelAndView modelAndView = new ModelAndView();
RegisterUserDto user = new RegisterUserDto();
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
@PostMapping("/register")
public ModelAndView createNewUser(@Valid RegisterUserDto user,
BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmailAddress());
if (userExists != null) {
bindingResult
.rejectValue("emailAddress", "error.user",
"There is already a user registered with the email provided");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("register");
} else {
userService.createUser(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.setViewName("register");
}
return modelAndView;
}
用户实体
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "username",
unique = true)
private String username;
@Column(name = "email_address",
unique = true)
private String emailAddress;
@Column(name = "phone_number")
private String phoneNumber;
@Column(name = "password")
private String password;
@Column(name = "notification_type",
insertable = false)
private String notificationType = "email";
@Column(name = "date_created")
private Date dateCreated;
@Column(name = "is_active",
insertable = false)
private Boolean active = false;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserGroup> groups;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Message> messages = new ArrayList<>();
@OneToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
mappedBy = "userId",
orphanRemoval = true)
private VerificationToken verificationToken;
@OneToMany(mappedBy = "createdBy",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true)
private List<Group> createdGroups = new ArrayList<>();
//getters and setters