spring mvc 中使用validator
添加依赖:
需要两个JAR包:hibernate-validator.jar 和validation-api.jar
org.hibernate hibernate-validator true org.jboss.logging jboss-logging com.fasterxml classmate
定义bean对象
public class SwaggerUser implements Serializable{ private static final long serialVersionUID = 1L; @NotBlank private String name; @Min(value=1) @Max(value=150) private int age; @NotNull(message="用户ID不能为空") private Long id; //省略geter/seter方法}
三种验证方式
第一种只使用@Validated 或者
/** * 1.只使用@Validated 或者 @Valid 注解时,当验证不通过会返回400,并且抛出"org.springframework.validation.BindException"异常 * 这种交互不利于前端获取校验信息,可以配合BindingResult对校验结果进行封装之后再返回给前端。 * @param user * @return * @author zhaowg3 * @Date 2017年4月19日 */ @RequestMapping(value="useValidated", method=RequestMethod.POST) public ResponseEntity useValidated(@RequestBody @Valid SwaggerUser user) { return ResponseEntity.ok(null); }
当验证不通过会返回400,并且抛出"org.springframework.web.bind.MethodArgumentNotValidException"异常,如果是使用spring boot,抛出的异常回统一交给org.springframework.boot.autoconfigure.web.BasicErrorController处理,返回spring boot固定的错误格式。
如果想要修改spring boot固定的错误格式,例如当报500,404,400等错误时,返回自定义的错误信息,可以自定义通用错误处理器代替spring boot自己的BasicErrorController.
参考
第二种使用@Validated 或者 同时配合使用BindingResult
/** * 2.使用@Validated 或者 @Valid 同时配合使用BindingResult,对校验结果进行封装之后再返回给前端,方便交互 * @param user * @param bindingResult * @return * @author zhaowg3 * @Date 2017年4月19日 */ @RequestMapping(value="useValidatedAndBindingResult", method=RequestMethod.POST) public ResponseEntity useValidated(@RequestBody(required=false) @Valid SwaggerUser user,BindingResult bindingResult) { if(bindingResult.hasErrors()){ //自定义错误返回格式 ListerrorMsg = new ArrayList<>(); //获取第一个校验失败的错误下信息 //bindingResult.getFieldError(); //获取校验失败的所有字段的错误信息 List fieldErrors = bindingResult.getFieldErrors(); for (FieldError fieldError : fieldErrors) { errorMsg.add(fieldError.getField()+" "+fieldError.getObjectName()+" "+fieldError.getDefaultMessage()); } return ResponseEntity.ok(errorMsg); } return ResponseEntity.ok(null); }
这样验证失败的信息将会放到BindingResult中,然后自己从中获取错误信息,自定义错误格式。
注意:每一个@Valid后面必须跟一个BindingResult,验证失败的放到紧跟他的BindingResult中
第三种将validation逻辑封装成工具类。
1.获取Validator
/** * 两种方式获取Validator: * 1.使用Autowired * 2.使用 * private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); *
*/ @Autowired protected Validator validator;
2.创建BeanValidators工具类
/** * JSR303 Validator(Hibernate Validator)工具类. * * ConstraintViolation中包含propertyPath, message 和invalidValue等信息. * 提供了各种convert方法,适合不同的i18n需求: * 1. List, String内容为message * 2. List , String内容为propertyPath + separator + message * 3. Map * * 详情见wiki: https://github.com/springside/springside4/wiki/HibernateValidator * @author calvin * @version 2013-01-15 */public class BeanValidators { // private static Validator validator = Validation.buildDefaultValidatorFactory() // .getValidator(); /** * 调用JSR303的validate方法, 验证失败时抛出ConstraintViolationException. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static void validateWithException(Validator validator, Object object, Class ... groups) throws ConstraintViolationException { Set constraintViolations = validator.validate(object, groups); if (!constraintViolations.isEmpty()) { throw new ConstraintViolationException(constraintViolations); } } /** * 辅助方法, 转换ConstraintViolationException中的Set 中为List . */ public static List extractMessage(ConstraintViolationException e) { return extractMessage(e.getConstraintViolations()); } /** * 辅助方法, 转换Set 为List */ @SuppressWarnings("rawtypes") public static List extractMessage(Set constraintViolations) { List errorMessages = Lists.newArrayList(); for (ConstraintViolation violation : constraintViolations) { errorMessages.add(violation.getMessage()); } return errorMessages; } /** * 辅助方法, 转换ConstraintViolationException中的Set 为Map . */ public static Map extractPropertyAndMessage(ConstraintViolationException e) { return extractPropertyAndMessage(e.getConstraintViolations()); } /** * 辅助方法, 转换Set 为Map . */ @SuppressWarnings("rawtypes") public static Map extractPropertyAndMessage(Set constraintViolations) { Map errorMessages = Maps.newHashMap(); for (ConstraintViolation violation : constraintViolations) { errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage()); } return errorMessages; } /** * 辅助方法, 转换ConstraintViolationException中的Set 为List . */ public static List extractPropertyAndMessageAsList(ConstraintViolationException e) { return extractPropertyAndMessageAsList(e.getConstraintViolations(), " "); } /** * 辅助方法, 转换Set 为List . */ @SuppressWarnings("rawtypes") public static List extractPropertyAndMessageAsList(Set constraintViolations) { return extractPropertyAndMessageAsList(constraintViolations, " "); } /** * 辅助方法, 转换ConstraintViolationException中的Set 为List . */ public static List extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) { return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator); } /** * 辅助方法, 转换Set 为List . */ @SuppressWarnings("rawtypes") public static List extractPropertyAndMessageAsList(Set constraintViolations, String separator) { List errorMessages = Lists.newArrayList(); for (ConstraintViolation violation : constraintViolations) { errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage()); } return errorMessages; }}
3.在Controller中使用
/** * 3.将validation逻辑封装成工具类,使用工具类对dto进行校验,然后根据校验结果做响应的处理 * @param user * @return * @author zhaowg3 * @Date 2017年4月19日 */ @RequestMapping(value="/useValidator", method=RequestMethod.POST) public ResponseEntity useValidator(@RequestBody SwaggerUser user) { ValidationResult validationResult = beanValidatorFail(user); if(validationResult.isHasError()){ return ResponseEntity.ok(validationResult.getErrorMsg()); } return ResponseEntity.ok(null); } /** * 服务端参数有效性验证是否失败 * @param object 验证的实体对象 * @param groups 验证组 * @return 验证成功:返回false;验证失败:返回true并将错误信息添加到 errMsgs 中 */ privateValidationResult beanValidatorFail(T object, Class ... groups) { //ValidationResult为自己封装的对象 ValidationResult validationResult = new ValidationResult(); try{ BeanValidators.validateWithException(validator, object, groups); }catch(ConstraintViolationException ex){ List errMsgs = BeanValidators.extractPropertyAndMessageAsList(ex, ": "); validationResult.setHasError(true); validationResult.setErrorMsg(errMsgs); } return validationResult; }