Spring 校驗(validator,JSR-303)簡單實現方式
Spring 校驗(validator,JSR-303)實現
什麼是JSR-303規范
JSR 303是Java EE 6中的一項子規范,叫做Bean Validation,官方參考實現是hibernate Validator,此實現與Hibernate ORM沒有任何關系。JSR 303用於對Java Bean中的字段的值進行驗證。
與Spring MVC結合
Spring-mvc.xml配置:
<!--JSR-303--> <mvc:annotation-driven validator="validator"/> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <property name="validationMessageSource" ref="messageSource"/> </bean> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="validatemessage"/> <property name="useCodeAsDefaultMessage" value="false"/> <property name="defaultEncoding" value="UTF-8"/> <property name="cacheSeconds" value="60"/> </bean> <bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"> <property name="conversionService"> <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean> </property> <property name="validator" ref="validator"/> </bean>
實體類添加驗證註解
這裡貼出部分代碼,知道如何加註解即可:
import com.lemontree.common.utils.AjaxResult; import com.lemontree.common.utils.StringUtil; import com.lemontree.common.utils.email.EmailUtils; import org.hibernate.validator.constraints.NotEmpty; import java.util.Date; public class User { /** * This field was generated by MyBatis Generator. * This field corresponds to the database column user.id * * @mbg.generated Thu Mar 16 13:27:38 CST 2017 */ private Integer id; /** * This field was generated by MyBatis Generator. * This field corresponds to the database column user.user_name * * @mbg.generated Thu Mar 16 13:27:38 CST 2017 */ @NotEmpty(message = "用戶名不能為空") private String userName; /** * This field was generated by MyBatis Generator. * This field corresponds to the database column user.password * * @mbg.generated Thu Mar 16 13:27:38 CST 2017 */ @NotEmpty(message = "密碼不能為空") private String password; }
控制器驗證註解添加
將@Validated 註解跟在實體類前面,BindingResult緊跟其後:
@RequestMapping(value = "/login.htm", method = RequestMethod.POST) public @ResponseBody AjaxResult login(@Validated User user, BindingResult bindingResult, HttpServletRequest request, HttpServletResponse response) { if (bindingResult.hasErrors()){ List<FieldError> errorses = bindingResult.getFieldErrors(); if (CollectionUtils.isNotEmpty(errorses)){ errorses.forEach(item->{ System.out.println(item.getDefaultMessage()); }); } } }
Java Hibernate Validator JSR-303驗證
JSR-303是JAVA EE 6中的一項子規范,叫做 Bean Validation,Hibernate Validator是Bean Validation 的參考實現。
實際使用就是通過註解來給字段添加約束,然後校驗字段是否符合規范,如果不符合就會拋出異常,以此來減少校驗數據的代碼,並保證拿到的數據都是符合規范的,也可以和Spring框架配合使用
集成
官方文檔
https://mvnrepository.com/artifact/org.hibernate/hibernate-validator
https://mvnrepository.com/artifact/javax.validation/validation-api
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.10.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b09</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
使用
校驗對象
public class JsrTest { @NotNull(message = "id不能為空!") @Min(value = 1, message = "Id隻能大於等於1") Integer id; @NotNull(message = "姓名不能為空!") String name; public void validateParams() { Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//獲取一個驗證器 Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(this);//驗證數據,獲取到錯誤集合 Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator(); if (iterator.hasNext()) { String errorMessage = iterator.next().getMessage();//獲取到錯誤信息 throw new ValidationException(errorMessage); } } public static void main(String args[]) { JsrTest req = new JsrTest(); req.id = 1; req.validateParams(); } }
像上面那樣將在屬性上添加註解即可聲明約束
校驗屬性
上面是校驗整個對象,也可以單獨校驗某個字段:
validator.validateProperty(object, "name");
分組校驗
public class JsrTest { @NotNull(message = "id不能為空!", groups = {ValidationGroup.class}) @Min(value = 1, message = "Id隻能大於等於1") Integer id; @NotNull(message = "姓名不能為空!", groups = {ValidationGroup.class}) String name; @DecimalMin(value = "1.1") double price; int date; public static void validateParams(JsrTest jsrTest) { Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(jsrTest, ValidationGroup.class); Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator(); if (iterator.hasNext()) { String errorMessage = iterator.next().getMessage(); throw new ValidationException(errorMessage); } } public static void main(String args[]) { JsrTest req = new JsrTest(); validateParams(req); } public interface ValidationGroup { } }
分組校驗所指定的calss必須是一個接口,可以指定多個
自定義約束
通常情況下,框架提供的註解已經可以滿足正常的驗證需求,但是我們也可以自定義註解來滿足我們的需求
我們這裡的例子是所註釋的字符串中不能包含指定字符
@Target(FIELD) //元註解,定義該註解使用在字段上 @Retention(RUNTIME) //定義註解的生命周期 @Constraint(validatedBy = CustomValidator.class)//指明該註解的校驗器 @Documented //表示該註解會被添加到JavaDoc中 public @interface CustomConstraints { String message() default "默認異常message"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; //這個屬性可以用來標註錯誤的嚴重等級,但是並不被API自身所使用 String value() default " "; }
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * 需要實現ConstraintValidator接口 * 泛型的第一個參數是自定義的註解,第二個參數註解所註釋的字段的類型 */ public class CustomValidator implements ConstraintValidator<CustomConstraints, String> { private String value; /** * 初始化調用,拿到註解所指定的value * * @param constraintAnnotation */ @Override public void initialize(CustomConstraints constraintAnnotation) { value = constraintAnnotation.value(); } /** * @param value 註釋的字段的值 * @param context * @return true 通過驗證,false 未通過驗證 */ @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value != null && value.contains(this.value)) { context.disableDefaultConstraintViolation();//禁用默認的消息 context.buildConstraintViolationWithTemplate("新添加的錯誤消息").addConstraintViolation(); return false; } return true; } }
然後就可以和其他註解一樣使用它瞭
封裝
或者是將驗證參數的代碼提取去出來,單獨寫一個方法
public static void validateParams(Object object) { Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//獲取一個驗證器 Set<ConstraintViolation<Object>> violationSet = validator.validate(object);//驗證數據,獲取到錯誤集合 Iterator<ConstraintViolation<Object>> iterator = violationSet.iterator(); if (iterator.hasNext()) { String errorMessage = iterator.next().getMessage();//獲取到錯誤信息 throw new ValidationException(errorMessage); } }
當然這裡也可以不拋出異常,而返回一個boolean值,如何封裝看實際需求
配合Spring使用
@GetMapping("/test") public Integer lookCanBuyGoods(@Valid JsrTest req, BindingResult result) throws Exception { if (result.hasErrors()) { throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage()); } //do something... return 1; }
@Valid添加這個註解之後就會對參數進行驗證,如果在其後沒有跟BindingResult,驗證不通過就會直接拋出異常,如果添加瞭BindingResult參數,就不會直接拋出異常,而會把異常信息存儲在BindingResult中,供開發者自行處理
如果想要使用分組可以這樣
@GetMapping("/test") public Integer test(@Validated (JsrTest.ValidationGroup.class) JsrTest req, BindingResult result) throws Exception { if (result.hasErrors()) { throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage()); } //do something... return 1; }
@Validated如果不使用分組其作用和@Valid一致
註解使用說明
Constraint | 詳細信息 |
---|---|
@Null | 被註釋的元素必須為 null |
@NotNull | 被註釋的元素必須不為 null |
@AssertTrue | 被註釋的元素必須為 true |
@AssertFalse | 被註釋的元素必須為 false |
@Min(value) | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@Max(value) | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@DecimalMin(value) | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@DecimalMax(value) | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@Size(max, min) | 被註釋的元素的大小必須在指定的范圍內 |
@Digits (integer, fraction) | 被註釋的元素必須是一個數字,其值必須在可接受的范圍內 |
@Past | 被註釋的元素必須是一個過去的日期 |
@PastOrPresent | 被註釋的元素必須是過去或現在的日期 |
@Future | 被註釋的元素必須是一個將來的日期 |
@FutureOrPresent | 被註釋的元素必須是將來或現在的日期 |
@Pattern(value) | 被註釋的元素必須符合指定的正則表達式 |
@Digits(integer =, fraction =) | 驗證字符串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度 |
驗證是否是郵件地址,如果為null,不進行驗證,算通過驗證 | |
@NotBlank | 字符串不能是Null還有被Trim的長度要大於0 |
@NotEmpty | 不能為null,且長度大於0 |
@Negative | 被註釋的元素必須是負數 |
@NegativeOrZero | 被註釋的元素必須是負數或0 |
@Positive | 必須是正數 |
@PositiveOrZero | 必須是正數或0 |
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 如何使用Bean Validation 解決業務中參數校驗
- springmvc項目使用@Valid+BindingResult遇到的問題
- @Valid 校驗無效,BindingResult未獲得錯誤的解決
- springboot 參數格式校驗操作
- Spring Boot之Validation自定義實現方式的總結