赞
踩
前端的校验是必须的,这个很简单,因为客户体验。后台的校验更是必须的,关键在于如何与目前我们的分层思想(控制层、业务层、持久层)综合起来考虑。在每层都要进行校验吗?还是只在是某个特定层做就可以了?是否有好的校验框架(如前端的jquery校验框架、springmvc校验框架)?总之校验框架还是有很多的,原理不就是对后端接收的数据进行特定规则的判断,那我们怎么制定规则,有怎么去检验呢?
1、表现层验证:SpringMVC提供对JSR-303的表现层验证;
2、业务逻辑层验证:Spring3.1提供对业务逻辑层的方法验证(当然方法验证可以出现在其他层,但笔者觉得方法验证应该验证业务逻辑);
3、DAO层验证:Hibernate提供DAO层的模型数据的验证(可参考hibernate validator参考文档的7.3. ORM集成)。
4、数据库端的验证:通过数据库约束来进行;
5、客户端验证支持:JSR-303也提供编程式验证支持。2. Hibernate Validator 的作用
- 验证逻辑与业务逻辑之间进行了分离,降低了程序耦合度;
- 统一且规范的验证方式,无需你再次编写重复的验证代码;
- 你将更专注于你的业务,将这些繁琐的事情统统丢在一边。
Hibernate Validator 的使用
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-validator</artifactId>
- <version>6.0.9.Final</version>
- </dependency>
- <dependency>
- <groupId>javax.el</groupId>
- <artifactId>javax.el-api</artifactId>
- <version>3.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.glassfish</groupId>
- <artifactId>javax.el</artifactId>
- <version>3.0.1-b08</version>
- </dependency>
-
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>${lombok.version}</version>
- </dependency>
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class MyAccount {
- private String id;
-
- @NotNull
- @Length(max = 20)
- private String userName;
-
- @NotNull
- @Pattern(regexp = "[A-Z][a-z][0-9]")
- private String passWord;
-
- @DateTimeFormat(pattern = "yyy-MM-dd")
- private Date createTime;
-
- private String alias;
-
- @Max(10)
- @Min(1)
- private Integer level;
-
- private Integer vip;
- }
api访问
- @PostMapping("/mytest")
- @ResponseBody
- public Object myTest(@RequestBody @Valid MyAccount account) {
- return account;
- }
封装工具
- public class ValidationUtil {
- /**
- * 开启快速结束模式 failFast (true)
- */
- private static Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
-
- /**
- * 校验对象
- *
- * @param t bean
- * @param groups 校验组
- * @return ValidResult
- */
- public static <T> ValidResult validateBean(T t, Class<?>... groups) {
- ValidResult result = new ValidationUtil().new ValidResult();
- Set<ConstraintViolation<T>> violationSet = validator.validate(t, groups);
- boolean hasError = violationSet != null && violationSet.size() > 0;
- result.setHasErrors(hasError);
- if (hasError) {
- for (ConstraintViolation<T> violation : violationSet) {
- result.addError(violation.getPropertyPath().toString(), violation.getMessage());
- }
- }
- return result;
- }
-
- /**
- * 校验bean的某一个属性
- *
- * @param obj bean
- * @param propertyName 属性名称
- * @return ValidResult
- */
- public static <T> ValidResult validateProperty(T obj, String propertyName) {
- ValidResult result = new ValidationUtil().new ValidResult();
- Set<ConstraintViolation<T>> violationSet = validator.validateProperty(obj, propertyName);
- boolean hasError = violationSet != null && violationSet.size() > 0;
- result.setHasErrors(hasError);
- if (hasError) {
- for (ConstraintViolation<T> violation : violationSet) {
- result.addError(propertyName, violation.getMessage());
- }
- }
- return result;
- }
-
- /**
- * 校验结果类
- */
- @Data
- public class ValidResult {
- /**
- * 是否有错误
- */
- private boolean hasErrors;
-
- /**
- * 错误信息
- */
- private List<ErrorMessage> errors;
-
- public ValidResult() {
- this.errors = new ArrayList<>();
- }
-
- public boolean hasErrors() {
- return hasErrors;
- }
-
- public void setHasErrors(boolean hasErrors) {
- this.hasErrors = hasErrors;
- }
-
- /**
- * 获取所有验证信息
- *
- * @return 集合形式
- */
- public List<ErrorMessage> getAllErrors() {
- return errors;
- }
-
- /**
- * 获取所有验证信息
- *
- * @return 字符串形式
- */
- public String getErrors() {
- StringBuilder sb = new StringBuilder();
- for (ErrorMessage error : errors) {
- sb.append(error.getPropertyPath()).append(":").append(error.getMessage()).append(" ");
- }
- return sb.toString();
- }
-
- public void addError(String propertyName, String message) {
- this.errors.add(new ErrorMessage(propertyName, message));
- }
-
- /**
- * 获取去重之后的非法属性值,以逗号分隔
- * @return
- */
- public String getProperties() {
- return errors.stream().map(error -> error.getPropertyPath()).collect(Collectors.toSet()).stream().collect(Collectors.joining(", "));
- }
- }
-
- @Data
- public class ErrorMessage {
-
- private String propertyPath;
-
- private String message;
-
- public ErrorMessage() {
- }
-
- public ErrorMessage(String propertyPath, String message) {
- this.propertyPath = propertyPath;
- this.message = message;
- }
- }
- }
自定义校验器
- @Target({FIELD})
- @Retention(RUNTIME)
- @Documented
- @Constraint(validatedBy = {DateValidator.DateValidatorInner.class})
- public @interface DateValidator {
-
- /**
- * 必须的属性
- * 显示 校验信息
- * 利用 {} 获取 属性值,参考了官方的message编写方式
- *
- * @see org.hibernate.validator 静态资源包里面 message 编写方式
- */
- String message() default "日期格式不匹配{dateFormat}";
-
- /**
- * 必须的属性
- * 用于分组校验
- */
- Class<?>[] groups() default {};
-
- Class<? extends Payload>[] payload() default {};
-
- /**
- * 非必须
- */
- String dateFormat() default "yyyy-MM-dd HH:mm:ss";
-
- /**
- * 必须实现 ConstraintValidator接口
- */
- class DateValidatorInner implements ConstraintValidator<DateValidator, String> {
- private String dateFormat;
-
- @Override
- public void initialize(DateValidator constraintAnnotation) {
- this.dateFormat = constraintAnnotation.dateFormat();
-
- }
-
- /**
- * 校验逻辑的实现
- *
- * @param value 需要校验的 值
- * @return 布尔值结果
- */
- @Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
- if (value == null) {
- return true;
- }
- if ("".equals(value)) {
- return true;
- }
- try {
- Date date = DateUtils.parseDate(value, dateFormat);
- return date != null;
- } catch (ParseException e) {
- return false;
- }
- }
- }
- }
定义分组
- public interface AccountGroup {
- }
使用自定义校验器和自定义分组:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class MyAccount {
- private String id;
-
- @NotNull
- @Length(max = 20)
- private String userName;
-
- @NotNull
- @Pattern(regexp = "[A-Z][a-z][0-9]")
- private String passWord;
-
- @DateTimeFormat(pattern = "yyy-MM-dd")
- private Date createTime;
-
- // @Pattern(regexp = "[A-Z][a-z][0-9]")
- @Min(2)
- private String alias;
-
- @Max(10)
- @Min(1)
- private Integer level;
-
- private Integer vip;
-
- @DateValidator(dateFormat = "yyyy-MM-dd", groups = {AccountGroup.class})
- private String birthday;
- }
- @AssertFalse @AssertTrue 检验boolean类型的值
-
- @DecimalMax @DecimalMin 限定被标注的属性的值的大小
-
- @Digits(intege=,fraction=) 限定被标注的属性的整数位数和小数位数
-
- @Future检验给定的日期是否比现在晚
-
- @Past 校验给定的日期是否比现在早
-
- @Max检查被标注的属性的值是否小于等于给定的值
-
- @Min检查被标注的属性的值是否大于等于给定的值
-
- @NotNull检验被标注的值不为空
-
- @Null 检验被标注的值为空
-
- @Pattern(regex=,flag=) 检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配
-
- @Size(min=,max=) 检查被标注元素的长度
-
- @Valid递归的对关联的对象进行校验
如果是比较短小的参数直接加@NotNull (int) @NotBlank等就可以了
public int getUser(String username) {
Assert.hasText(username,"用户名不能为空");//用用户名查询用户信息的时候
}
其他断言的用法可以直接看Assert里面的方法,一共没几个,可以校验list等!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。