一、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選項,選擇語言
將英文(美國)上移,然後刷新界面:
成功!