package me.test; import java.util.Set; import javax.validation.Configuration; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import junit.framework.TestCase; import org.hibernate.validator.constraints.ScriptAssert; import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; /** * 什么是JSR303-Bean Validation? * 是一套类似于Apache Commons Validator,但是可以通过注解进行配置, * 也可以通过XML文件进行配置。 * http://jcp.org/en/jsr/detail?id=303 * * 参考实现: * Hibernate Validator * http://www.hibernate.org/subprojects/validator.html * * 注意: * Hibernate Validator 4.2.0.Beta2版本的压缩包中包含中文的文档,在线看时总#¥@的被连接重置。 * 但这个工程里我使用的是 4.1.0.Final 版 * * 小结: * 1. 缺少一些感觉比较常用的Validate, * 比如,对字符串类型的日期格式验证。 * 假如一个字段是"yyyyMMdd"格式的年月日字符串, * 可以通过@Pattern用正则表达式限定为全部为字符串, * 可是用户仍能发送"20011299" 或 "20010231"这样不存在的日期。 * JSR303中只提供了@Past,@Future以对java.util.Date和java.util.Calendar * 验证其是否是过去/将来的时间。 * * 比如,如果要保证某个字符串的长队必须为某个固定的值,这时可以使用@Size, * 但是@Size是用来保证长度在一个区域内的,有个min和max, * 若把min和max设为某个固定值,则消息不太合适。 * * 2. 该规范以及RI实现中只能够对单个字段进行Validate,没有类似Struts中使用的 validateWhen. * 若是能够提供一个使用EL表达式的类似实现就好了。 * 也许这种验证应该拿到业务里进行验证吧?使用Spring的Validator? * * RI实现中又扩展了4个注解:@Email,@Length,@NotEmpty,@Range * 其中@Length与规范中定义的@Size类似,但仅仅适用于string类型,而@Size则不限于String,还可以用于Collection,Map,Array * * 工程目录树: * / * |- src * | | ValidationMessages.properties * | |- me * | |- test * | Person.java * | PersonTest.java * |- lib: * hibernate-validator-4.0.1.GA.jar * jpa-api-2.0.Beta-20090815.jar * log4j-1.2.14.jar * slf4j-api-1.5.6.jar * slf4j-log4j12-1.5.6.jar * validation-api-1.0.0.GA.jar * junit-4.6.jar * * @author btpka3@163.com * */ public class PersonTest { private Validator validator = null; @Before public void setUp() { if (validator == null) { // Configuration<?> config = Validation.byDefaultProvider().configure(); // config.messageInterpolator(new ResourceBundleMessageInterpolator(ResourceBundle.getBundle("me.test.ValidationMessages") )); // validator = config.buildValidatorFactory().getValidator(); ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); validator = validatorFactory.getValidator(); } } /** * 正常 - 全部检验通过 */ @SuppressWarnings("unchecked") @Test public void test001() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(25); p.setAddress("abcdefg"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(0, arr.length); // ■ 验证环境 } /** * 异常 - id格式不正确 */ @SuppressWarnings("unchecked") @Test public void test002() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U00X"); p.setName("zhang3"); p.setAge(25); p.setAddress("abcdefg"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("id", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("必须匹配正则表达式 \"^U\\d{3}$\"", message); // ■ 验证环境 } /** * 异常 - name == null */ @SuppressWarnings("unchecked") @Test public void test003() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName(null); p.setAge(25); p.setAddress("abcdefg"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("name", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("用户名不能为null", message); // ■ 验证环境 } /** * 异常 - age值的范围不正确(0) */ @SuppressWarnings("unchecked") @Test public void test004() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(0); p.setAddress("abcdefg"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("age", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("必须大于等于1", message); // ■ 验证环境 } /** * 异常 - age值的范围不正确(200) */ @SuppressWarnings("unchecked") @Test public void test005() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(200); p.setAddress("abcdefg"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("age", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("must be less than or equal to 150", message); // ■ 验证环境 } /** * 异常 - address长度不正确(3) */ @SuppressWarnings("unchecked") @Test public void test006() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(25); p.setAddress("abc"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("address", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("地址长度不能为>=5 && <=10", message); // ■ 验证环境 } /** * spring message source */ @SuppressWarnings("unchecked") @Test public void test007() { // ■ 准备环境 ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("test007.xml"); LocalValidatorFactoryBean vf = (LocalValidatorFactoryBean) appContext.getBean("vf"); Validator validator = vf.getValidator(); // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(25); p.setAddress("abc"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("address", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("地址长度不能为>=5 && <=10", message); // ■ 验证环境 } /** * test ScriptAssert */ @SuppressWarnings("unchecked") @Test public void test008() { // ■ 准备环境 // ■ 准备参数 Person p = new Person(); p.setId("U001"); p.setName("zhang3"); p.setAge(25); p.setAddress("abcde"); p.setPwd1("123"); p.setPwd1("456"); // ■ 执行 Set<ConstraintViolation<Person>> violations = validator.validate(p); // ■ 验证结果 ConstraintViolation<Person>[] arr = violations.toArray(new ConstraintViolation[0]); TestCase.assertEquals(1, arr.length); ConstraintViolation<Person> violation = arr[0]; String propertyPath = violation.getPropertyPath().toString(); TestCase.assertEquals("", propertyPath); String message = violation.getMessage(); TestCase.assertEquals("两次密码不一致", message); // ■ 验证环境 } }