一、POM依賴
<!-- dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.1-b06</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.6</version> </dependency>
注:hibernate-validator-6.0.13.Final
本身依賴validation-api
的版本即是2.0.1.Final
,若無沖突,則無需單獨顯式依賴validation-api-2.0.1.Final
二、初始化Validator
2.1 方法一 注冊Bean實現
import org.hibernate.validator.HibernateValidator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; @Configuration public class ValidatorConfig { @Bean public MethodValidationPostProcessor methodValidationPostProcessor(@Qualifier("validator") Validator validator) { MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); processor.setValidator(validator); // 若不定制validator,此處可不用set return processor; } @Bean public Validator validator() { ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) .buildValidatorFactory(); return validatorFactory.getValidator(); } }
2.2 方法二 手動實例化validator
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator();
2.3 補充說明
failFast
默認為false
,即會校驗完全部參數后再返回全部參數的校驗結果信息.failFast(true)
也可用.addProperty("hibernate.validator.fail_fast", "true")
替代,若是用的defaultProvider,即Validation.byDefaultProvider()
,則只能使用后者
三、校驗接口方法入參
3.1 方法一
若是通過上面方法一實例化validator,則不需要手動校驗
3.2 方法二
若是使用的方法二,則可通過下面方法來校驗方法入參
Set<ConstraintViolation<Object>> constraintViolationSet = validator.forExecutables().validateParameters(bean, method, args);
- 入參
bean
是接口實現bean
,非入參bean
- 也可使用
validator.validate(arg)
來遍歷校驗單個參數,但要求arg
不能為null
,有些接口方法是平鋪入參,且部分入參可為null
的則不適應
四、獲取校驗失敗返回信息
可以通過AOP或Filter來處理方法入參校驗
4.1 獲取校驗結果
- 若是通過上面方法一,則直接捕捉
javax.validation.ConstraintViolationException
異常即可,然后e.getConstraintViolations()
即可獲取到Set<ConstraintViolation>
- 若是通過上面方法二,則校驗結果直接返回了
Set<ConstraintViolation>
4.2 拼裝校驗信息
// constraintViolationSet = 上面校驗結果Set if (constraintViolationSet.isEmpty()) { return null; } StringBuilder errorMsg = new StringBuilder(); for (ConstraintViolation violation : constraintViolationSet) { errorMsg.append(";"); errorMsg.append(violation.getMessage()); } return errorMsg.substring(1);
五、使用示例
5.1 入參類
import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; public class User { @NotBlank(message = "名稱不能為空") private String name; @NotNull(message = "年齡不能為空") @Min(value = 1, message = "年齡不能小於{value}") private Integer age; // .... getters and setters }
5.2 接口方法
// 接口 import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; public interface UserService { void register1(@NotNull(message = "請求入參不能為空") @Valid User user); void register2(@NotBlank(message = "名稱不能為空") String name, Integer age); }
// 實現類 import org.springframework.validation.annotation.Validated; @Validated public class UserServiceImpl implements UserService { public void register1(User user) { // .... } public void register2(String name, Integer age) { // .... } }
- 若入參是個大參數,如register1的入參,則必須加
@Valid
注解,否則大參數里的屬性不會校驗 - 實現類上必須加
@Validated
注解
六、FAQ
6.1 若不指定校驗失敗的message,則會返回什么
若不指定message,則會返回默認的message,即注解的message默認值,如@NotNull
注解默認message占位符是{javax.validation.constraints.NotNull.message}
,如下圖
根據占位符可搜索到在hibernate-validator
包下的Resource配置文件中,如下圖
里面有對應的中文版本,如下圖
上圖上有各種語言版本,針對中文版的內容使用ASCII碼,可通過工具轉成native查看具體的message。
6.2 報錯“Caused by: java.lang.NoClassDefFoundError: org/hibernate/validator/internal/engine/DefaultClockProvider”
原因是包沖突,根本原因是引入hibernate-validator依賴包后出現了validation-api的1.1.0.Final版本,應用中依賴的spring-boot中聲明了validation-api-1.1.0.Final
包,所以在引入時出現了沖突。 解決:可以顯示在parent的POM中顯示依賴validation-api-2.0.1.Final
即可。
6.3 報錯“HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead”
原因是沒有依賴el相關包,增加如下包依賴即可
<dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.1-b06</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.6</version> </dependency>
6.4 如何依賴一個包即可包含上面包的所有依賴
可依賴以下包,即包含所有依賴,若有依賴包沖突則同樣需單獨處理
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>2.1.0.RELEASE</version> </dependency>
上面spring-boot-starter-validation
包無其他邏輯,僅單純依賴了hibernate-validator-6.0.13.Final
、tomcat-embed-el-8.5.31
和spring-boot-starter-1.5.13.RELEASE
3個包