概念:java中的Bean Validation是一个数据验证的规范。

说明:Hibernate Validator是Bean Validation的一个具体实现。

举例:在springMVC中使用Hibernate Validator

	1)maven依赖:
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.1.2.Final</version>
		</dependency>

	2)JavaBean:

		import javax.validation.constraints.NotNull;
		import org.hibernate.validator.constraints.NotBlank;

		/**
		 * 在需要进行校验的属性上添加相应的注解:
		 * 
		 * 1)Bean Validation 提供的 constraint:       
		 * 		@Null   	被注释的元素必须为 null       
		 *		@NotNull    被注释的元素必须不为 null       
		 *		@AssertTrue     被注释的元素必须为 true       
		 *		@AssertFalse    被注释的元素必须为 false       
		 *		@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值,可修饰Integer。       
		 *		@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值,可修饰Integer。       
		 *		@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值       
		 *		@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值       
		 *		@Size(max=, min=)   被注释的元素的大小必须在指定的范围内,修饰字符串长度。不可修饰Integer。       
		 *		@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内       
		 *		@Past		 被注释的元素必须是一个过去的日期       
		 *		@Future		 被注释的元素必须是一个将来的日期       
		 *		@Pattern(regexp=,message=)  被注释的元素必须符合指定的正则表达式  
		 *			举例:@Pattern(regexp="^[\\u4e00-\\u9fa5_a-zA-Z0-9]+$", message="只能由中文、英文、数字、下划线组成")
		 *			说明:中文:[\u4e00-\u9fa5] 	英文:[a-zA-Z] 	数字:[0-9]
		 *		     
		 * 2)Hibernate Validator 特有的 constraint:
		 *		@NotBlank(message =)	验证字符串非null,且长度必须大于0 
		 *		@NotEmpty				被注释的字符串或集合的必须非空       
		 *		@Email  				被注释的元素必须符合email的格式       
		 *		@Length(min=,max=)		被注释的字符串的大小必须在指定的范围内             
		 *		@Range(min=,max=,message=)	被注释的元素必须在合适的范围内 
		 *		
		 */	
		public class User {
			 
			@NotBlank(message = "name is null!")
			private String name;

			@NotNull(message = "age is null!")
			private Integer age;

			private String email;

			private String address;

			// getter and setter ..
			
		}
		
	3)控制器:
		方式一:
			import javax.validation.Valid;
			import org.springframework.validation.BindingResult;
			import org.springframework.validation.ObjectError;
			import org.springframework.web.bind.annotation.RequestMapping;
			import org.springframework.web.bind.annotation.RequestBody;
			import org.springframework.web.bind.annotation.RequestMethod;

			@RestController
			@RequestMapping("/sys")
			public class UserController {

				/**
				 * 1.给需要校验的参数添加 @Valid注解 
				 * 2.给方法添加一个类型为 BindingResult的参数,用来封装 校验的结果
				 */
				@RequestMapping(value = "/user/add", method = RequestMethod.POST)
				public String addUser(@Valid @RequestBody User req, BindingResult bindingResult) {
					
					if (bindingResult.hasErrors()) {
						List<ObjectError> allErrors = bindingResult.getAllErrors();
						List<String> msgs = new ArrayList<String>();
						for (ObjectError objectError : allErrors) {
							String msg = objectError.getDefaultMessage();
							msgs.add(msg);
						}
						String paramErrorMsg = StringUtils.join(msgs, " & ");
						return paramErrorMsg;
					} else {
						System.out.println("do add user.");
						return "success!";
					}
				}
			}


		方式二:使用@ControllerAdvice + @ExceptionHandler
		
			@RestController
			@RequestMapping("/sys")
			public class UserController {
				@RequestMapping(value = "/user/add", method = RequestMethod.POST)
				public String addUser(@Valid @RequestBody User req) {
					System.out.println("do add user.");
					return "success!";
				}
			}

			@ControllerAdvice
			public class GlobalExceptionHandler {

			    @ExceptionHandler(ValidationException.class)
			    @ResponseStatus(HttpStatus.BAD_REQUEST)
			    @ResponseBody
			    public String handleValidationException(HttpServletRequest request, ConstraintViolationException e) {

			        LOGGER.error("request uri [{}] error, method: [{}]", request.getRequestURI(), request.getMethod(), e);
			        
			        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();

			        List<String> msgList = new ArrayList();
			        for (ConstraintViolation constraintViolation : constraintViolations) {
			        	String field = constraintViolation.getPropertyPath();
			        	String errorMsg = constraintViolation.getMessage();
			        	msgList.add(field + "-" + errorMsg);
			        }
			        String paramErrorMsg = StringUtils.join(msgList, " & ");
			        return paramErrorMsg;
			    }
			}

	4)接口测试:

		地址:http://localhost:8081/jxn-web/api/sys/user/add
		
		请求类型:Content-Type: application/json

		参数:
			{"name":"","age":null}		==> 响应内容:age is null! & name is null!
			{"name":"","age":""}		==> 响应内容:age is null! & name is null!
			{"name":"jack","age":"17"}	==> 响应内容:success!


常见错误:

	报错:javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.lang.Integer.
	
	分析:是由于@NotBlank修饰了Integer、Long等引用类型的属性
	eg:
		@NotBlank
		private Integer age;
		
	修正:应该使用@NotNull来修饰引用类型的属性。
		@NotNull
		private Integer age;