您好,登錄后才能下訂單哦!
這篇“Spring Boot之Validation自定義實現的方法”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Spring Boot之Validation自定義實現的方法”文章吧。
雖然在Spring Boot中已經提供了非常多的預置注解,用以解決在日常開發工作中的各類內容,但是在特定情況仍然存在某些場景,無法滿足需求,需要自行定義相關的validator。
自定義的注解
這里的場景設置為進行IP地址的驗證,通過注解的方式,讓用戶使用驗證規則。注解定義如下:
@Target({ElementType.FIELD}) @Retention(RUNTIME) @Documented @Constraint(validatedBy = IPAddressValidator.class) public @interface IPAddress { String message() default "{ipaddress.invalid}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
這個注解是作用在Field字段上,運行時生效,觸發的是IPAddressValidator這個驗證類。
message
定制化的提示信息,主要是從ValidationMessages.properties里提取,也可以依據實際情況進行定制
groups
這里主要進行將validator進行分類,不同的類group中會執行不同的validator操作
payload
主要是針對bean的,使用不多。
然后自定義Validator,這個是真正進行驗證的邏輯代碼:
public class IPAddressValidator implements ConstraintValidator<IPAddress, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { Pattern pattern = compile("^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"); Matcher matcher = pattern.matcher(value); try { if (!matcher.matches()) { return false; } else { for (int i = 1; i <= 4; i++) { int octet = Integer.valueOf(matcher.group(i)); if (octet > 255) { return false; } } return true; } } catch (Exception e) { return false; } } }
關于IP地址的驗證規則是通用的,具體邏輯不用太在意,主要是需要這里Validator這個接口,以及其中的兩個泛型參數,第一個為注解名稱,第二個為實際字段的數據類型。
定義了實體類CustomFieldBean.java
@Data public class CustomFieldBean { @IPAddress private String ipAddr; }
使用方法非常簡約,基于注解,無侵入邏輯。
單元測試用例
測試代碼:
@RunWith(SpringRunner.class) @SpringBootTest public class CustomFieldValidatorTest { @Autowired private ProductService productService; @Test(expected = ConstraintViolationException.class) public void testInvalid() { CustomFieldBean customFieldBean = new CustomFieldBean(); customFieldBean.setIpAddr("1.2.33"); this.productService.doCustomField(customFieldBean); } @Test public void testValid() { CustomFieldBean customFieldBean = new CustomFieldBean(); customFieldBean.setIpAddr("1.2.33.123"); this.productService.doCustomField(customFieldBean); } }
如果不希望由系統自行觸發Validator的驗證邏輯,則可以由開發者自行進行驗證。在Spring Boot已經內置了Validator實例,直接將其加載進來即可。
使用示例如下:
@Autowired private Validator validator;
自定義執行的單元測試
測試代碼如下:
@RunWith(SpringRunner.class) @SpringBootTest public class CodeValidationTest { @Autowired private Validator validator; @Test(expected = ConstraintViolationException.class) public void testValidator() { CustomFieldBean input = new CustomFieldBean(); input.setIpAddr("123.3.1"); Set<ConstraintViolation<CustomFieldBean>> violations = validator.validate(input); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } } }
最近新開了一個項目,雖然hibernate-validator很好用,但是有時不能滿足稍微復雜一些的業務校驗。為了不在業務代碼中寫校驗邏輯,以及讓代碼更優雅,故而采用了自定義校驗注解的方式。
本例注解應用場景: 填寫表單時,某一項數據存在時,對應的一類數據都應存在,一同提交。
1.類注解
主注解用于標記要在校驗的實體類
@Target( { TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = RelateOtherValidator.class) @Documented public @interface RelateOther { String message() default ""; /** * 校驗數量 */ int num() default 2; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2.輔助注解
輔助注解用于標注于要校驗的字段,isMaster區分為主注解和從注解。
主注解是關鍵字段,存在才進行校驗從注解對應字段的有效性;主注解的value()屬性可以設置默認值,當字段對應值對應value()時才開啟校驗。
從注解為等待校驗的值,默認為從注解。
@Target( { FIELD }) @Retention(RUNTIME) @Documented public @interface RelateOtherItem { /** * 是否為主字段,主字段存在才進行校驗 */ boolean isMaster() default false; /** * 用于開啟對指定值校驗判斷,master字段有效 * 當前為master且value與標注字段值相等才進行校驗, */ String value() default ""; }
3.校驗類
校驗類為實際執行校驗邏輯的類,在類注解的@Constraint的validatedBy屬性上設置。
要設置為校驗類,首先要實現ConstraintValidator類的isValid方法。
@Slf4j // @Slf4j是lombok的注解 public class RelateOtherValidator implements ConstraintValidator<RelateOther, Object> { // 要校驗的個數 private int validateNum; @Override public void initialize(RelateOther constraintAnnotation) { validateNum = constraintAnnotation.num(); } @Override public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) { if (o == null) { return true; } Field[] declaredFields = o.getClass().getDeclaredFields(); boolean mater = false; int emptyNum = 0; try { // 總共需要校驗的字段數 int totalValidateNum = validateNum; for (Field field : declaredFields) { // 校驗是否進行過標注 if (!field.isAnnotationPresent(RelateOtherItem.class)) { continue; } if (validateNum > 0 && totalValidateNum-- < 0) { return false; } field.setAccessible(true); Object property = field.get(o); RelateOtherItem relateOtherItem = field.getAnnotation(RelateOtherItem.class); // 主字段不存在,則校驗通過 if (relateOtherItem.isMaster()) { if (property==null) { return true; } // 與指定值不一致,校驗通過 if (!StringUtils.isEmpty(relateOtherItem.value()) && !relateOtherItem.value().equals(property)) { return true; } mater = true; continue; } if (null == property) { emptyNum++; } } // 主字段不存在,則校驗通過 if (!mater) { log.info("RelateOther注解主字段不存在"); return true; } return emptyNum==0; } catch (Exception e) { log.info("RelateOther注解,解析異常 {}", e.getMessage()); return false; } } }
4.校驗失敗
注解校驗不同時會拋出一個MethodArgumentNotValidException異常。這里可以采用全局異常處理的方法,進行捕獲處理。捕獲之后的異常可以獲取BindingResult 對象,后面就跟hibernate-validator處理方式一致了。
BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
5.使用demo
注解的使用類似下面,首先在請求實體類上標注類注解,再在對應的字段上標注輔助注解。
@RelateOther(message = "xx必須存在!",num=2) public class MarkReq { @RelateOtherItem (isMaster= true,value="1") private Integer girl; @RelateOtherItem private Integer sunscreen; private String remarks; }
以上就是關于“Spring Boot之Validation自定義實現的方法”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。