一、前言
在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节。比如参数不能为null,email那么必须符合email的格式,如果手动进行if判断或者写正则表达式判断无意开发效率太慢,在时间、成本、质量的博弈中必然会落后。所以把校验层抽象出来是必然的结果,下面说下几种解决方案。
二、几种解决方案
1、struts2的valid可以通过配置xml,xml中描述规则和返回的信息,这种方式比较麻烦、开发效率低,不推荐
2、validation bean 是基于JSR-303标准开发出来的,使用注解方式实现,及其方便,但是这只是一个接口,没有具体实现.Hibernate Validator是一个hibernate独立的包,可以直接引用,他实现了validation bean同时有做了扩展,比较强大 ,实现图如下:
3、oval 是一个可扩展的Java对象数据验证框架,验证的规则可以通过配置文件、Annotation、POJOs 进行设定。可以使用纯 Java 语言、JavaScript 、Groovy 、BeanShell 等进行规则的编写,本次不过多讲解
三、bean validation 框架验证介绍
bean validation 包放在maven上维护,最新包的坐标如下:
1
2
3
4
5
6
7
8
9
|
< dependency > < artifactId >validation-api</ artifactId > < version >1.1.0.Final</ version > </ dependency > |
下载之后打开这个包,有个package叫constraints,里面放的就是验证的的注解:
下面开始用代码实践一下:
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()方法,输处如下:
- 地址应该在6-30字符之间
- 邮箱的格式不合法
- 生日必须在当前时间之前
- 多吃点饭吧
- 名字不能为空
4、总结
- 像@NotNull、@Size等比较简单也易于理解,不多说
- 因为bean validation只提供了接口并未实现,使用时需要加上一个provider的包,例如hibernate-validator
- @Pattern 因为这个是正则,所以能做的事情比较多,比如中文还是数字、邮箱、长度等等都可以做
- @AssertTRue 这个与其他的校验注解有着本质的区别,这个注解适用于多个字段。例子中isHaveFriend方法依赖friendName字段校验
- 验证的api是经过我加工了一下,这样可以批量返回校验的信息
- 有时我们需要的注解可能没有提供,这时候就需要自定义注解,写实现类,下面说一下自定义注解的使用
四、自定义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()方法,输处如下:
- 地址应该在6-30字符之间
- 邮箱的格式不合法
- 生日必须在当前时间之前
- 多吃点饭吧
- 名字的拼音需要小写
- 名字不能为空
7、说明新增的约束生效了,大功告成
代码下载地址:git@github.com:xiaogangfan/vaidation.git
命令: git clone git@github.com:xiaogangfan/vaidation.git
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/xiaogangfan/p/5987659.html