我正在尝试在带有@Valid注释的Spring REST控制器中使用Hibernate验证。
但验证没有发生。
以下是Maven构建所说的内容:
java.lang.AssertionError:期望的状态:< 400>但是:< 201>
在尝试发布包含无效字段值的表单时,我应该收到错误的请求http状态,而是表单发布很好并且资源已创建。
我的验证测试尝试发布缺少的电子邮件值和太短的登录名值:
@Test
public void testValidation() throws Exception {
HttpHeaders httpHeaders = Common.createAuthenticationHeaders("stephane" + ":" + PASSWORD);
MvcResult resultPost = this.mockMvc.perform(
post("/admin").headers(httpHeaders)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content("{ \"firstname\" : \"" + admin0.getFirstname() + "\", \"lastname\" : \"" + admin0.getLastname() + "\", \"email\" : \"" + admin0.getEmail() + "\", \"login\" : \"" + admin0.getLogin() + "\", \"password\" : \"" + admin0.getPassword() + "\", \"passwordSalt\" : \"" + admin0.getPasswordSalt() + "\" }")
).andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.firstname").value(admin0.getFirstname()))
.andExpect(jsonPath("$.lastname").value(admin0.getLastname()))
.andExpect(jsonPath("$.email").value(""))
.andExpect(jsonPath("$.login").value("short"))
.andExpect(jsonPath("$.password").value(admin0.getPassword()))
.andExpect(jsonPath("$.passwordSalt").value(admin0.getPasswordSalt()))
.andExpect(header().string("Location", Matchers.containsString("/admin/")))
.andReturn();
}
我还有一个异常处理类:
@ControllerAdvice
public class AdminExceptionHandler {
@ExceptionHandler(AdminNotFoundException.class)
@ResponseBody
public ResponseEntity<ErrorInfo> adminNotFoundException(HttpServletRequest request, AdminNotFoundException e) {
String url = request.getRequestURL().toString();
String errorMessage = localizeErrorMessage("error.admin.not.found", new Object[] { e.getAdminId() });
return new ResponseEntity<ErrorInfo>(new ErrorInfo(url, errorMessage), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseEntity<ErrorFormInfo> methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
String url = request.getRequestURL().toString();
String errorMessage = localizeErrorMessage("error.admin.invalid.form.argument");
ErrorFormInfo errorFormInfo = new ErrorFormInfo(url, errorMessage);
BindingResult result = e.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
errorFormInfo.getFieldErrors().addAll(populateFieldErrors(fieldErrors));
return new ResponseEntity<ErrorFormInfo>(errorFormInfo, HttpStatus.BAD_REQUEST);
}
public List<ErrorFormField> populateFieldErrors(List<FieldError> fieldErrorList) {
List<ErrorFormField> errorFormFields = new ArrayList<ErrorFormField>();
StringBuilder errorMessage = new StringBuilder("");
for (FieldError fieldError : fieldErrorList) {
errorMessage.append(fieldError.getCode()).append(".");
errorMessage.append(fieldError.getObjectName()).append(".");
errorMessage.append(fieldError.getField());
errorFormFields.add(new ErrorFormField(fieldError.getField(), localizeErrorMessage(errorMessage.toString())));
errorMessage.delete(0, errorMessage.capacity());
}
return errorFormFields;
}
private String localizeErrorMessage(String errorCode) {
return localizeErrorMessage(errorCode, null);
}
private String localizeErrorMessage(String errorCode, Object args[]) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage(errorCode, args, locale);
return errorMessage;
}
}
请注意,其他一些测试会触发AdminNotFoundException。
但是没有触发MethodArgumentNotValidException。
这是控制器类:
@Controller
@ExposesResourceFor(Admin.class)
@RequestMapping("/admin")
public class AdminController {
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<Admin> add(@RequestBody @Valid Admin admin, UriComponentsBuilder builder) {
AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin()));
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri());
Admin createdAdmin = adminResourceAssembler.toResource(adminCreatedEvent.getEventAdmin());
ResponseEntity<Admin> responseEntity = new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED);
return responseEntity;
}
}
依赖项的版本是Spring的3.2.5.RELEASE和hibernate-validator的5.1.1.Final和javax.el-api的3.0.0
当针对Tomcat 7服务器手动运行并发出curl post请求时,会出现同样的问题:
mvn clean install tomcat7:run -DskipTests
curl -H "Accept:application/json" --user joethebouncer:mignet http://localhost:8080/learnintouch-rest/admin -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d "{ \"firstname\" : \"Stephane\", \"lastname\" : \"Eybert\", \"email\" : \"\", \"login\" : \"short\", \"password\" : \"mignet\", \"passwordSalt\" : \"7bc7bf5f94fef7c7106afe5c3a40a2\" }"
有任何线索吗?
以下是整个源代码,以防有人想要尝试运行此Maven构建: http://www.learnintouch.com/learnintouch-data.tar.gz http://www.learnintouch.com/learnintouch-rest.tar.gz
亲切的问候,
Stephane Eybert
答案 0 :(得分:2)
您是否尝试过使用Hibernate Validator 4.2.0.Final? Hibernate Validator 5是bean验证API 1.1(JSR 349)的参考实现,它与JSR 303的规范不同。
我认为Spring Framework 3.2仅支持JSR 303,因为我无法从其参考手册中找到有关bean验证API 1.1的任何信息。
答案 1 :(得分:1)
我尝试了您的代码,按照您提到的相同步骤进行,验证 正确发生。
这是我使用完全相同的curl命令回复的响应:
{"url":"http://localhost:8080/learnintouch-rest/admin","message":"The admin form arguments were invalid.","fieldErrors":[{"fieldName":"login","fieldEr
ror":"Length.admin.login"},{"fieldName":"email","fieldError":"NotEmpty.admin.email"}]}
我建议您尝试清除maven存储库并从头开始构建项目。
我还应该提一下,在testValidation()
集成测试中,您使用的admin0
对象实际上是有效的,因此它通过验证是有道理的:)