尝试使用Spring Boot和Thymeleaf验证表单时遇到问题。 from只是注册一个具有给定字段的用户。我正在使用多部分表单,因为表单也上传了一张图片,但我已经尝试使用没有它的表单,但仍然是同样的问题。
顺便说一句,我知道这个问题有很多但是没有一个能帮助我...如果表单字段正确,一切正常。但如果我输入无效字段,我会得到回复:
HTTP状态400 -
输入状态报告
消息
description客户端发送的请求在语法上是不正确的。
我只想展示一个气泡来警告那个领域。目前我在html输入标签中使用“pattern”,但用户可以将其从浏览器中删除。我可以使控制器中的进程检查失效并重定向到同一个已清理的页面,但这只是一个不舒服的解决方法。
<form class="styleweb" id="registrationform" th:action="@{/site/new_user}" method="post" enctype="multipart/form-data">
<fieldset>
<div class="styleweb">
<label for="login">Login</label> <input id="login" type="text"
placeholder="Username" th:field="${user.login}" />
<p th:if="${#fields.hasErrors('user.login')}" th:errors="*{user.login}">Incorrect stuff</p>
</div>
<div class="styleweb">
<label for="password">Password</label>
<input id="password"
type="password" placeholder="Password" th:field="${user.password}"/>
</div>
<div class="pure-control-group">
<label for="email">Email Address</label> <input id="email"
type="email" placeholder="Email Address" th:field="${user.email}"/>
</div>
<div class="pure-control-group">
<label for="foo">Profile pic</label> <input type="file" name="profilePic" id="imgInp"/>
<img id="profilepic" src="#" alt="avatar" />
</div>
<div class="styleweb">
<button type="submit" class="styleweb">Submit</button>
</div>
</fieldset>
</form>
这是控制器:
@RequestMapping(value="new_user", method = RequestMethod.GET)
public String addUserPage(Model model) {
model.addAttribute("user", new User());
return "site/user/add_user";
}
@RequestMapping(value = "new_user", method = RequestMethod.POST)
public String processAddUserWeb(@Valid @ModelAttribute(value = "user") User user,
@ModelAttribute(value = "profilePic") MultipartFile profilePic,
BindingResult result) throws LoginNotAvailableException {
if (result.hasErrors()) {
System.out.println("Form has errors");
return "elovendo/user/add_user";
}
else {
System.out.println("Form is ok");
byte[] profilePicBytes = null;
if (!profilePic.isEmpty()) try {
profilePicBytes = profilePic.getBytes();
} catch (IOException e) {
System.out.println("Error converting to bytes image file");
}
userService.addUser(user, profilePicBytes);
return "site/user/registered_successful";
}
}
用户类是:
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "userId")
private Long userId;
@NotNull(message="Login cannot be null")
@Length(min = 2, max = 20, message="Invalid login lenght")
@Pattern(regexp=Constant.loginPattern, message="Invalid login name")
private String login;
@Column(name = "password", length = 255)
@Length(min = 8, max = 255)
private String password;
private String email;
// constructor, getters and setters, ...
}
我还尝试使用Validator的实现:
public class FormValidator implements Validator {
private Pattern pattern;
private Matcher matcher;
@Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
User user = (User) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "login", "required.login");
// input string conatains numeric values only
if (user != null) {
pattern = Pattern.compile(Constant.loginPattern);
matcher = pattern.matcher(user.getLogin());
if (!matcher.matches()) {
errors.rejectValue("login", "login.invalid");
}
}
}
}
并在控制器中使用它(首先没有 @Valid 注释,但无论是否有相同的[相同错误]):
@RequestMapping(value = "new_user", method = RequestMethod.POST)
public String processAddUserWeb(@ModelAttribute(value = "user") User user,
@ModelAttribute(value = "profilePic") MultipartFile profilePic,
BindingResult result) throws LoginNotAvailableException {
FormValidator formValidator = new FormValidator();
formValidator.validate(user, result);
if (result.hasErrors()) {
System.out.println("Form has errors");
return "elovendo/user/add_user";
}
}
但也没有奏效。如果不使用 th:if =“$ {#fields.hasErrors('user.login')}(...)标签(这是愚蠢的,但我只是绝望地试图找到一个解决方案)返回:
org.springframework.beans.NotReadablePropertyException:无效 bean类的属性'login'[java.lang.String]:Bean属性 'login'不可读或getter方法无效:是吗? getter的返回类型是否与setter的参数类型相匹配? (...)。validator.FormValidator.validate(FormValidator.java:28)
在这里问这是在解决这个问题之前松开所有头发之前的最后一站,希望有人可以帮助我。 谢谢!
修改
这是我发送包含无效数据的表单帖子时的日志:
2014-08-06 14:42:01.717 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:42:01.718 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sdfd.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]
2014-08-06 14:42:01.743 DEBUG 9759 --- .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.744 DEBUG 9759 --- .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2014-08-06 14:42:01.746 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet : Successfully completed request
2014-08-06 14:42:01.748 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/error]
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.controller.MainController.errorPage()]
2014-08-06 14:42:01.751 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@503dc0cf] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:42:01.755 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet : Successfully completed request
这是包含有效数据的日志:
2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/site/new_user]
2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.web.UserWebController.addUserPage(org.springframework.ui.Model)]
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/site/new_user] is: -1
2014-08-06 14:54:25.712 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@4b34f94d] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:54:25.722 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Successfully completed request
答案 0 :(得分:6)
您需要在BindingResult
之后立即放置User user
以便能够正确处理无效数据。
因此控制器方法如下:
public String processAddUserWeb(@ModelAttribute(value = "user") User user,
BindingResult result,
@ModelAttribute(value = "profilePic") MultipartFile profilePic)
答案 1 :(得分:1)
您的大多数<input>
元素
<input id="login" type="text" placeholder="Username" th:field="${user.login}" />
<input id="password" type="password" placeholder="Password" th:field="${user.password}"/>
<input id="email" type="email" placeholder="Email Address" th:field="${user.email}"/>
没有name
属性。 name
元素需要<input>
属性作为提交的<form>
的一部分发送。所以这些都没有被发送,验证似乎也失败了。
向name
元素添加id
属性,可能与<input>
的值相同。
答案 2 :(得分:0)
BindingResult和@ModelAttribute的无效顺序 我只是改变顺序,像个魅力一样醒来...
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addUser( @ModelAttribute("SpringWeb")@Valid User user,BindingResult binding, ModelMap model) {
System.out.println(binding.toString());
if (!binding.hasErrors()) {
System.out.println("Has No Error");
model.addAttribute("username", user.getUsername());
model.addAttribute("password", user.getPassword());
model.addAttribute("address", user.getAddress());
model.addAttribute("receivePaper", user.isReceivePaper());
model.addAttribute("favoriteFrameworks", user.getFavoriteFrameworks());
model.addAttribute("gender", user.getGender());
model.addAttribute("favoriteNumber", user.getFavoriteNumber());
model.addAttribute("country", user.getCountry());
return "users";
} else {
System.out.println("Has Error");
return "error";
}
}