• JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对 Bean进行验证.
Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:
@Email(被注解的元素必须是电子邮箱)
@Length(被注释的字符串的大小必须在指定的范围内)
@NotEmpty(被注释的字符串必须非空)
@Range(被注释的元素必须在合法 的范围内)
Spring 4.0 拥有自己独立的数据校验框架,同时支持 JSR303 标准的校验框架。 • Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验。 • Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在 Spring 容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。 • Spring 本身并没有提供 JSR303 的实现,所以必须将JSR303 的实现者的 jar 包放到类路径下。
<mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作 • 在已经标注了 JSR303 注解的表单/命令对象前标注一个@Valid,Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验 • Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或Errors 类型,这两个类都位于org.springframework.validation 包中。
需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参 • Errors 接口提供了获取错误信息的方法,如 getErrorCount() 或getFieldErrors(String field) • BindingResult 扩展了 Errors 接口
• 在表单/命令对象类的属性中标注校验注解,在处理方法对应的入参前添加 @Valid,Spring MVC 就会实施校验并将校验结果保存在被校验入参对象之后的 BindingResult 或 Errors 入参中。 • 常用方法: FieldError getFieldError(String field) List<FieldError> getFieldErrors() Object getFieldValue(String field) Int getErrorCount()
如果把错误的结果显示到页面上应该怎么做呢?
• Spring MVC 除了会将表单/命令对象的校验结果保存到对应的 BindingResult 或 Errors 对象中外,还会将所有校验结果保存到 “隐含模型”。 • 即使处理方法的签名中没有对应于表单/命令对象的结果入参,校验结果也会保存在 “隐含对象” 中。 • 隐含模型中的所有数据最终将通过 HttpServletRequest 的属性列表暴露给 JSP 视图对象,因此在 JSP 中可以获取错误信息。 • 在 JSP 页面上可通过 <form:errors path=“userName”>显示错误消息。
ex:
首先在项目添加maven的依赖:
<!--添加hibernate validator 5依赖--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.0.2.Final</version> </dependency>创建如下的bean: public class Employee { private Integer id; @NotEmpty private String lastName; @Email private String email; //1 male, 0 female private Integer gender; private Department department; @Past @DateTimeFormat(pattern="yyyy-MM-dd") private Date birth; @NumberFormat(pattern="#,###,###.#") private Float salary; } 在Handler中添加@Valid注解: @RequestMapping(value ="/emp",method = RequestMethod.POST) public String save(@Valid Employee employee, BindingResult result,Map<String,Object> map){ if(result.getErrorCount()>0){ System.out.println("出错了!"); for(FieldError error:result.getFieldErrors()){ System.out.println(error.getField()+":"+error.getDefaultMessage()); } //如果验证出错,那么转向出错的页面 map.put("departments",departmentDao.getDepartments()); return "input"; } employeeDao.save(employee); return "redirect:/emps"; } 页面上的错误显示: <body> <%--如果修改的时候会发生错误,实际上开发的时候都推荐使用绝对路径--%> <form:form action="${pageContext.request.contextPath}/emp" method="POST" modelAttribute="employee"> <c:if test="${employee.id==null}"> LastName:<form:input path="lastName"/><%--input表示文本框--%> <form:errors path="lastName"></form:errors> </c:if> <c:if test="${employee.id!=null}"> <form:hidden path="id"/> <input type="hidden" name="_method" value="PUT"><%--表示这个方法是一个PUT请求--%> <%--对于method不能使用form:hidden标签,因为modelAttrbiute对应的bean中没有_method这个属性--%> <%--<form:hidden path="_method" value="PUT"/>--%> </c:if> <br> Email:<form:input path="email"/> <form:errors path="email"></form:errors> <br> <% Map<String,String> genders=new HashMap<>(); genders.put("1","Male"); genders.put("0","Female"); request.setAttribute("genders",genders);//需要放在域对象中 %> <%--radio Button--%> Gender:<form:radiobuttons path="gender" items="${genders }"/> <br> <%--下拉框--%> Department:<form:select path="department.id" items="${departments}" itemLabel="departmentName" itemValue="id"> </form:select> <br> Birth:<form:input path="birth"/> <form:errors path="birth"></form:errors> <br> Salary:<form:input path="salary"/> <br> <input type="submit" value="Submit"> </form:form> <form action="testConversionServiceConverter" method="POST"> Employee:<input type="text" name="employee"> <input type="submit" value="Submit"> </form> </body> path属性对应html表单标签的name属性即可。