java validation 后台参数验证的使用详解

时间:2022-09-18 12:22:23

一、前言

后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节。比如参数不能为null,email那么必须符合email的格式,如果手动进行if判断或者写正则表达式判断无意开发效率太慢,在时间、成本、质量的博弈中必然会落后。所以把校验层抽象出来是必然的结果,下面说下几种解决方案。

二、几种解决方案

1、struts2的valid可以通过配置xml,xml中描述规则和返回的信息,这种方式比较麻烦、开发效率低,不推荐

2、validation bean 是基于JSR-303标准开发出来的,使用注解方式实现,及其方便,但是这只是一个接口,没有具体实现.Hibernate Validator是一个hibernate独立的包,可以直接引用,他实现了validation bean同时有做了扩展,比较强大 ,实现图如下:

java validation 后台参数验证的使用详解

点此查看中文官方手册

3、oval 是一个可扩展的Java对象数据验证框架,验证的规则可以通过配置文件、Annotation、POJOs 进行设定。可以使用纯 Java 语言、JavaScript 、Groovy 、BeanShell 等进行规则的编写,本次不过多讲解

三、bean validation 框架验证介绍

bean validation 包放在maven上维护,最新包的坐标如下:

?
1
2
3
4
5
6
7
8
9
<dependency>
 
  <groupId>javax.validation</groupId>
 
  <artifactId>validation-api</artifactId>
 
  <version>1.1.0.Final</version>
 
</dependency>

 点击这里查看最新的坐标地址

下载之后打开这个包,有个package叫constraints,里面放的就是验证的的注解:

java validation 后台参数验证的使用详解  

下面开始用代码实践一下:

1、定义一个待验证的bean:Student.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.shishang;
 
import javax.validation.constraints.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
 
public class Student implements Serializable {
 
 
  @NotNull(message = "名字不能为空")
  private String name;
 
  @Size(min = 6,max = 30,message = "地址应该在6-30字符之间")
  private String address;
 
  @DecimalMax(value = "100.00",message = "体重有些超标哦")
  @DecimalMin(value = "60.00",message = "多吃点饭吧")
  private BigDecimal weight;
 
  private String friendName;
  @AssertTrue
  private Boolean isHaveFriend(){
    return friendName != null?true:false;
  }
 
  @Future(message = "生日必须在当前实践之前")
  private Date birthday;
 
  @Pattern(regexp = "^(.+)@(.+)$",message = "邮箱的格式不合法")
  private String email;
 
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public String getAddress() {
    return address;
  }
 
  public void setAddress(String address) {
    this.address = address;
  }
 
  public BigDecimal getWeight() {
    return weight;
  }
 
  public void setWeight(BigDecimal weight) {
    this.weight = weight;
  }
 
  public String getFriendName() {
    return friendName;
  }
 
  public void setFriendName(String friendName) {
    this.friendName = friendName;
  }
 
  public Date getBirthday() {
    return birthday;
  }
 
  public void setBirthday(Date birthday) {
    this.birthday = birthday;
  }
 
  public String getEmail() {
    return email;
  }
 
  public void setEmail(String email) {
    this.email = email;
  }
}

2、测试类:StudentTest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.use;
 
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
 
public class StudentTest implements Serializable {
  public static void main(String[] args) {
    Student xiaoming = getBean();
    List<String> validate = validate(xiaoming);
    validate.forEach(row -> {
      System.out.println(row.toString());
    });
 
  }
 
  private static Student getBean() {
    Student bean = new Student();
    bean.setName(null);
    bean.setAddress("北京");
    bean.setBirthday(new Date());
    bean.setFriendName(null);
    bean.setWeight(new BigDecimal(30));
    bean.setEmail("xiaogangfan163.com");
    return bean;
  }
 
  private static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
 
  public static <T> List<String> validate(T t) {
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
 
    List<String> messageList = new ArrayList<>();
    for (ConstraintViolation<T> constraintViolation : constraintViolations) {
      messageList.add(constraintViolation.getMessage());
    }
    return messageList;
  }
}

3、运行testValidation()方法,输处如下:

  1. 地址应该在6-30字符之间
  2. 邮箱的格式不合法
  3. 生日必须在当前时间之前
  4. 多吃点饭吧
  5. 名字不能为空

4、总结

  1. 像@NotNull、@Size等比较简单也易于理解,不多说
  2. 因为bean validation只提供了接口并未实现,使用时需要加上一个provider的包,例如hibernate-validator
  3. @Pattern 因为这个是正则,所以能做的事情比较多,比如中文还是数字、邮箱、长度等等都可以做
  4. @AssertTRue 这个与其他的校验注解有着本质的区别,这个注解适用于多个字段。例子中isHaveFriend方法依赖friendName字段校验
  5. 验证的api是经过我加工了一下,这样可以批量返回校验的信息
  6. 有时我们需要的注解可能没有提供,这时候就需要自定义注解,写实现类,下面说一下自定义注解的使用

四、自定义bean validation 注解验证

有时框架自带的没法满足我们的需求,这时就需要自己动手丰衣足食了,恩恩 ,这个不难,下面说下。

这个例子验证字符串是大写还是小写约束标注,代码如下:

1、枚举类型CaseMode, 来表示大写或小写模式

?
1
2
3
4
5
6
7
8
9
10
package com.defineconstrain;
 
/**
 * created by xiaogangfan
 * on 16/10/25.
 */
public enum CaseMode {
  UPPER,
  LOWER;
}

2、定义一个CheckCase的约束标注

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.defineconstrain;
 
/**
 * created by xiaogangfan
 * on 16/10/25.
 */
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
 
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
import javax.validation.Constraint;
import javax.validation.Payload;
 
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
 
  String message() default "{com.mycompany.constraints.checkcase}";
 
  Class<?>[] groups() default {};
 
  Class<? extends Payload>[] payload() default {};
 
  CaseMode value();
 
}

3、约束条件CheckCase的验证器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.defineconstrain;
 
/**
 * created by xiaogangfan
 * on 16/10/25.
 */
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
 
  private CaseMode caseMode;
 
  public void initialize(CheckCase constraintAnnotation) {
    this.caseMode = constraintAnnotation.value();
  }
 
  public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
 
    if (object == null)
      return true;
 
    if (caseMode == CaseMode.UPPER)
      return object.equals(object.toUpperCase());
    else
      return object.equals(object.toLowerCase());
  }
 
}

4、在Student.java中增加一个属性

?
1
2
@CheckCase(value = CaseMode.LOWER,message = "名字的拼音需要小写")
private String spellName;

5、在StudentTest.java的getBean()方法中增加一行

?
1
bean.setSpellName("XIAOGANGFAN");

6、运行testValidation()方法,输处如下:

  1. 地址应该在6-30字符之间
  2. 邮箱的格式不合法
  3. 生日必须在当前时间之前
  4. 多吃点饭吧
  5. 名字的拼音需要小写
  6. 名字不能为空

7、说明新增的约束生效了,大功告成

代码下载地址:git@github.com:xiaogangfan/vaidation.git

命令: git clone git@github.com:xiaogangfan/vaidation.git

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/xiaogangfan/p/5987659.html