一、JSR-303的定义
JSR-303 是JAVA EE 6 中的一项子规范,叫做BeanValidation,现在一共有两个规范:BeanValidation1.0(即JSR303)和BeanValidation1.1(即JSR349),主要用于对数据进行校验,确保输入进来的数据从语义上来讲是正确的。
特点:1.JSR 303 用于对Java Bean 中的字段的值进行验证,使得验证逻辑从业务代码中脱离出来。
2.是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
应用场景:一般用于表单提交页面(如用户名必填、只能由数字字母组成等等)
二、如何使用
注意:此操作还是必须annotation-driven
首先添加依赖:
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.12.Final</version>
</dependency>
然后注解简介:
序号 |
注解 | 验证字段 | 注解说明 | 属性说明 |
---|---|---|---|---|
1 | @NotNull/@Null | 引用数据类型 | 注解元素必须是非空或空 | |
2 | @Digit | byte、short、int、long及各自的包装类型以及BigDecimal、BigInteger、String | 验证数字构成是否合法 | integer:指定整数部分数字位数,fraction:指定小数部分数字位数 |
3 | @Future/@Past | java.util.Date,java.util.Calendar | 验证是否在当前系统时间之后/之前 | |
4 | @Max/@Min | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger | 验证值是否小于等于最大指定整数值或大于等于最小指定整数值 | |
5 | @Pattern | String | 验证字符串是否匹配指定的正则表达式 | regexp:匹配的正则表达式,flags:指定Pattern.Flag的数值,表示正则表达式的选项 |
6 | @Size | String、Collection、Map和数组 | 验证元素大小是否在指定范围内 | max:最大长度,min:最小长度,message:提示信息,默认:{constraint.size} |
7 | @DecimalMax/@DecimalMin | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger、String | 验证值是否小于等于最大指定小数值或大于等于最小指定小数值 | |
8 | @Valid | 验证值是否需要递归调用 |
Hibernate Validator 附加的 constraint(与Hibernate orm没有关系):
9 | 被注释的元素必须是电子邮箱地址 | |||
10 | @Length | 被注释的字符串的大小必须在指定的范围内 | ||
11 | @NotEmpty | 被注释的字符串的必须非空 | ||
12 | @Range | 被注释的元素必须在合适的范围内 |
检验的错误同样是放在BindingResult中!
三、代码实例
在bean中我们修改代码至:
private int id;
@NotNull(message = "姓名不能为空")
@Size(min = 1, max = 10, message = "姓名长度在0到10之间")
private String name;
private boolean gender;
@Min(value = 1, message = "年龄必须大于0")
private int age;
private School school;
@NotNull(message = "生日必须不为空")
@Past(message = "生日必须是在过去")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
在添加操作的目标方法中相应的加上@Valid注解:
/* add one student information*/
@RequestMapping(value = "/stu", method = RequestMethod.POST)
public String saveStu(@Valid @ModelAttribute Student student, BindingResult result) {
/*if something goes wrong during the project running*/
if (result.hasErrors()) {
System.out.println("there is some thing wrong!");
for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField() + " has problem:" + error.getDefaultMessage());
}
}
/* it is the solution of the question that input.jsp only give student'school id value but no name value */
School school = schoolDao.getSchoolById(student.getSchool().getId());
student.setSchool(school);
studentDao.saveStudent(student);
return "redirect:/stus";
}
然后运行(不按规矩填入表单,点击添加按钮):
点击后
或者
都还是能成功添加:
但控制台打印报错误信息
四、在页面中显示错误消息
只要在input.jsp页面加上<form:error path=""/>即可!
修改目标方法为出现错误回到本页面:
/* add one student information*/
@RequestMapping(value = "/stu", method = RequestMethod.POST)
public String saveStu(@Valid @ModelAttribute Student student, BindingResult result) {
/*if something goes wrong during the project running*/
if (result.hasErrors()) {
System.out.println("there is some thing wrong!");
for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField() + " has problem:" + error.getDefaultMessage());
}
return "input";
}
/* it is the solution of the question that input.jsp only give student'school id value but no name value */
School school = schoolDao.getSchoolById(student.getSchool().getId());
student.setSchool(school);
studentDao.saveStudent(student);
return "redirect:/stus";
}
然后可以直接在input.jsp文件中添加代码:
<form:errors path="*"> </form:errors>
<br>
path设置为*代表显示所有错误信息:
点击添加信息
或者在表单每项input后面添加error:
name:<form:input path="name"/><form:errors path="name"/><br>
age:<form:input path="age"/><form:errors path="age"/><br>
birth(format=yyyy-mm-dd):<form:input path="birth"/><form:errors path="birth"/><br>
然后再运行
五、错误信息国际化
首先就是要新建国际化的资源文件(Resource Bundle 'i18n'这个文件夹是自己生成的,不算一个文件夹):
键值对的写法就是 jar303的注解名 + 属性所在类名第一个字母小写 + 属性名 比如:
i18n_zh_CN:
Size.student.name = ^.^\u59D3\u540D\u957F\u5EA6\u5FC5\u987B\u57281-10\u4E4B\u95F4
Min.student.age = ^.^\u5E74\u9F84\u5FC5\u987B\u5927\u4E8E0\u5C81
NotNull.student.birth = ^.^\u751F\u65E5\u5FC5\u987B\u4E0D\u4E3A\u7A7A
Past.student.birth = ^.^\u751F\u65E5\u5FC5\u987B\u662F\u5728\u8FC7\u53BB
i18n_en_US:
Size.student.name = ^.^Length of name must range from 1 to 10
Min.student.age = ^.^Age must be greater than 0
NotNull.student.birth = ^.^Birth can not be empty
Past.student.birth = ^.^Birth must be past time
在Intellij IDEA中点击ResouceBundle 会显示对应关系:
然后再配置资源
最后在springmvc.xml中配置资源文件:
<!--config internationalize resource files-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="../main/sources/properties/i18n"> </property>
</bean>
然后我们在IE浏览器(可以切换语言!)中运行:
中文:
切换语言:点击右上角设置,internet选项,选择语言
将英文(美国)上移,然后刷新界面:
成功!