本文部分內(nèi)容來自互聯(lián)網(wǎng)。
在進(jìn)行REST接口開發(fā)的時(shí)候,需要對(duì)POST/PUT等接口傳入的參數(shù)進(jìn)行一些校驗(yàn)的時(shí)候,可以通過Hibernate Validator提供的注解進(jìn)行校驗(yàn)。這些注解放在參數(shù)實(shí)體定義的屬性或者類上面,能夠進(jìn)行默認(rèn)的校驗(yàn)。
配合@Valid注解和BindingResult功能一起使用,則可以在Controller的具體實(shí)現(xiàn)邏輯中進(jìn)行校驗(yàn)后的處理。
1. 常用的校驗(yàn)注解
| 注解 | 功能 |
|---|---|
@NotNull |
值不為空 |
@Null |
值只能為空 |
@Pattern(regex=) |
字符串必須匹配括號(hào)內(nèi)的正則表達(dá)式 |
@Size(max=,min=) |
集合的元素?cái)?shù)量必須max和min之間的值 |
@CreditCardNumber(ignoreNonDigitCharacters=) |
字符串必須是美國(guó)標(biāo)準(zhǔn)的信用卡卡號(hào) |
@Email |
字符串必須是email地址 |
@Length(min=,max=) |
檢查字符串的長(zhǎng)度 |
@NotBlank |
字符串必須有字符 |
@NotEmpty |
字符串不為null,集合有元素 |
@Range(min=,max=) |
數(shù)字必須大于min,小于max |
@SafeHtml |
字符串是安全的html代碼 |
@URL |
字符串是合法的url |
@AssertFalse |
值必須是false |
@AssertTrue |
值必須是true |
@DecimalMax(value=,inclusive=) |
值必須小于等于(inclusive=true)/值必須小于(inclusive=false):可以注解在字符串類型上 |
@DecimalMin(value=,inclusive=) |
值必須大于等于(inclusive=true)/值必須大于(inclusive=false):可以注解在字符串類型上 |
@Max(value=) |
值必須小于等于value指定的值,不能注解在字符串類型上 |
@Min(value=) |
值必須大于等于value執(zhí)行的值,不能注解在字符串類型上 |
@Digits(integer=,fraction=) |
數(shù)字格式檢查,integer指定整數(shù)部分的長(zhǎng)度,fraction指定小數(shù)部分的長(zhǎng)度 |
@Futrue |
值必須是未來的注解 |
@Past |
值只能是過去的時(shí)間 |
2. 在服務(wù)中使用校驗(yàn)
例如,通過請(qǐng)求添加一個(gè)用戶信息,
- 那么首先需要在這個(gè)用戶的定義時(shí)確定好要滿足哪些信息。比如,用戶名不能為空,密碼不能為空等。
public class UserInfo {
private int id;
@NotBlank
private String name;
@NotNull
private String passwd;
@Range(min=10, message = "年齡不能小于10")
private int age;
private String mail;
private String phoneNumber;
private String address;
}
- 通過REST的post接口添加用戶,則用戶信息的body體必須滿足這些條件,否則的話controller的服務(wù)中,就要校驗(yàn),并捕獲這些異常。
/**
* 添加一個(gè)新的用戶
*/
@PostMapping(value = "/user")
public UserInfo addOneSpecifiedUser(@Valid UserInfo userInfo, BindingResult errors) {
if(errors.hasErrors()){
errors.getAllErrors().stream().forEach(
error -> logger.error(error.toString())
);
}
logger.info("進(jìn)入到用戶添加的頁面");
return userInfo;
}
@Valid注解的功能是檢查REST請(qǐng)求推送來的請(qǐng)求體是否滿足預(yù)定義的格式,如果不滿足,那么這些請(qǐng)求中的錯(cuò)誤信息將會(huì)被BindingResult綁定的變量errors所接收,并帶著這些異常進(jìn)入請(qǐng)求響應(yīng)代碼,由請(qǐng)求響應(yīng)部分去處理這些異常。
- 使用REST工具發(fā)送這樣的請(qǐng)求后,產(chǎn)生的效果如下:
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController : Field error in object 'userInfo' on field 'age': rejected value [1]; codes [Range.userInfo.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.age,age]; arguments []; default message [age],9223372036854775807,10]; default message [年齡不能小于10]
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController : Field error in object 'userInfo' on field 'passwd': rejected value [null]; codes [NotNull.userInfo.passwd,NotNull.passwd,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.passwd,passwd]; arguments []; default message [passwd]]; default message [不能為null]
3. 自定義校驗(yàn)
要實(shí)現(xiàn)類似于本文中提供那些常用校驗(yàn)方式同樣的便利,需要自定義我們自己的校驗(yàn)規(guī)則注解。
自定義注解進(jìn)行校驗(yàn)的步驟:
- 寫一個(gè)校驗(yàn)注解,在注解中指定校驗(yàn)器類,校驗(yàn)注解與校驗(yàn)器一般一一對(duì)應(yīng)。
- 寫一個(gè)校驗(yàn)器類并在校驗(yàn)器類中寫校驗(yàn)邏輯,校驗(yàn)器必須實(shí)現(xiàn)ConstraintValidator<?, ?>接口,第一個(gè)參數(shù)是對(duì)應(yīng)的注解,第二個(gè)參數(shù)是要校驗(yàn)的屬性的類型。
代碼實(shí)例
S1: 自定義校驗(yàn)注解
package com.kunlun.validation.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import com.kunlun.validation.validator.KlPatternValidator;
/**
* 自定義的校驗(yàn)注解
* 規(guī)則:
* 1.如果字符串為空串或者為null,則不進(jìn)行正則校驗(yàn)
* 2.如果字符串不為空串,則必須進(jìn)行正則校驗(yàn)
* @author xc
* @date 2018年1月19日上午11:38:02
*/
@Documented
// 指定該注解可以使用的地方
@Target(value= {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
// 指定實(shí)際進(jìn)行校驗(yàn)的校驗(yàn)器,該校驗(yàn)器是自己寫的且必須實(shí)現(xiàn)ConstraintValidator接口
@Constraint(validatedBy=KlPatternValidator.class)
public @interface KlPattern {
/*
* 用于驗(yàn)證的注解下列這三個(gè)方法必須要,這是Hibernate Validation框架要求的,否則程序再在調(diào)用的時(shí)候會(huì)報(bào)錯(cuò)
* default用于對(duì)屬性給定默認(rèn)值
* 如果不給定默認(rèn)值,則在使用注解的時(shí)候必須給屬性指定屬性值,否則報(bào)錯(cuò)
* 給定默認(rèn)值時(shí),在使用注解的時(shí)候可以不用指定屬性值
*/
String message() default "不符合正則!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 沒加default給定默認(rèn)值,使用注解的時(shí)候該屬性必須賦值,否則報(bào)錯(cuò)
String regex();
// value屬性,加上了default "mercy" 使得該屬性在使用注解的時(shí)候可以不用輸入也不會(huì)報(bào)錯(cuò)
String value() default "mercy";
}
S2: 與上面校驗(yàn)注解對(duì)應(yīng)的校驗(yàn)器類
package com.kunlun.validation.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.kunlun.validation.annotation.KlPattern;
/**
* KlPatternValidator是KlPattern注解實(shí)際調(diào)用的驗(yàn)證器
* 在KlPatternValidator中完成校驗(yàn)邏輯
*
* @author xc
* @date 2018年1月19日上午11:44:38
*/
public class KlPatternValidator implements ConstraintValidator<KlPattern, String> {
private String regex;
/**
* 通過initialize()可以獲取注解里的屬性值
*/
@Override
public void initialize(KlPattern constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
regex = constraintAnnotation.regex();
}
/**
* 實(shí)際驗(yàn)證邏輯
* 返回值為true表示驗(yàn)證通過,
* 返回值為false表示驗(yàn)證未通過
*/
@Override
public boolean isValid(String s, ConstraintValidatorContext ctx) {
// 當(dāng)前前端傳過來的請(qǐng)求參數(shù)是空串,或者沒傳的時(shí)候,不進(jìn)行后續(xù)正則校驗(yàn)
if ("".equals(s) || s == null) {
return true;
}
// 進(jìn)行正則校驗(yàn)
if(s.matches(regex)) {
return true;
}
return false;
}
}