在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull
, @Max
, @ZipCode
, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
hibernate validator实现了bean validator的规范,中文文档地址如下:http://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html/validator-usingvalidator.html
在具体spring boot场景下,我总结了一下几个场景,作为分享
1、自定义一个校验注解MobileValidation,能够校验手机号格式是否正确
首先定义一个注解,然后实现一个validator即可。下面是代码实例:
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Documented @Constraint(validatedBy = MobileValidator.class) @Target({METHOD,FIELD,PARAMETER}) @Retention(RUNTIME) public @interface MobileValidation { String message() default "手机号格式不正确"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
import com.jeeplus.common.utils.StringUtils; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class MobileValidator implements ConstraintValidator<MobileValidation, String> { public static final String MOBILE_REGEX = "^1[23456789]\d{9}$"; @Override public void initialize(MobileValidation constraintAnnotation) { } @Override public boolean isValid(String value, ConstraintValidatorContext context) { return isMobile(value); } public static Boolean isMobile(String mobile) { Boolean flag = false; if (StringUtils.isBlank(mobile)) { return flag; } flag = mobile.matches(MOBILE_REGEX); return flag; } }
然后在需要校验的地方,使用MobileValidation 即可
2、在controller的入口请求方法里做参数校验
例如如下一个函数中,在进入业务之间必须校验传入手机号必须符合规则。
@RequestMapping(value = {"/sendRegisterSms"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8") public void sendRegisterSms(HttpServletRequest request, @NotBlank @MobileValidation @RequestParam(required = true) String mobile, @RequestParam(required = true) String imageCode ) throws BusinessException { }
使用的时候需要在controller添加
@RestControllerAdvice @Configuration public class GlobalExceptionAdvice { @ExceptionHandler(value = ConstraintViolationException.class) public AjaxJson handleValidationException(ConstraintViolationException e) { StringBuffer errorBuffer = new StringBuffer(); for(ConstraintViolation<?> s:e.getConstraintViolations()){ errorBuffer.append(s.getMessage()+";") ; } return getAjaxJson(ErrorCode.PARAM_ERROR,errorBuffer.toString()); } }
3、对整个bean进行validate
HibernateValidator类库来源https://github.com/springside/springside4/wiki/HibernateValidator。代码只是提供思路,具体的可运行代码自己需要处理。
protected boolean beanValidator(Model model, Object object, Class<?>... groups) { try{ BeanValidators.validateWithException(validator, object, groups); }catch(ConstraintViolationException ex){ List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": "); list.add(0, "数据验证失败:"); addMessage(model, list.toArray(new String[]{})); return false; } return true; }
4、校验场景比较复杂时候,可以使用分组
参考https://blog.csdn.net/lklihaikunkun/article/details/80605425即可
5、如果分组也解决不了你的问题,你只能完全定制了。
参考https://medium.com/@crb3/spring-boot-conditional-validation-example-2dd23af22539