欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Boot之Validation自定義實現(xiàn)方式的總結(jié)

 更新時間:2022年07月04日 11:19:46   作者:bladestone  
這篇文章主要介紹了Spring?Boot之Validation自定義實現(xiàn)方式的總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Validation自定義實現(xiàn)方式

Spring Boot Validation定制

雖然在Spring Boot中已經(jīng)提供了非常多的預(yù)置注解,用以解決在日常開發(fā)工作中的各類內(nèi)容,但是在特定情況仍然存在某些場景,無法滿足需求,需要自行定義相關(guān)的validator。本節(jié)將針對自定義的validator進(jìn)行介紹。

自定義的注解

這里的場景設(shè)置為進(jìn)行IP地址的驗證,通過注解的方式,讓用戶使用驗證規(guī)則。注解定義如下:

@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字段上,運(yùn)行時生效,觸發(fā)的是IPAddressValidator這個驗證類。

  • message
  • 定制化的提示信息,主要是從ValidationMessages.properties里提取,也可以依據(jù)實際情況進(jìn)行定制
  • groups
  • 這里主要進(jìn)行將validator進(jìn)行分類,不同的類group中會執(zhí)行不同的validator操作
  • payload
  • 主要是針對bean的,使用不多。

然后自定義Validator,這個是真正進(jìn)行驗證的邏輯代碼:

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;
? ? ? ? }
? ? }
}

關(guān)于IP地址的驗證規(guī)則是通用的,具體邏輯不用太在意,主要是需要這里Validator這個接口,以及其中的兩個泛型參數(shù),第一個為注解名稱,第二個為實際字段的數(shù)據(jù)類型。

使用自定義的注解

定義了實體類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);
? ? }
}

自定義執(zhí)行Validator

如果不希望由系統(tǒng)自行觸發(fā)Validator的驗證邏輯,則可以由開發(fā)者自行進(jìn)行驗證。在Spring Boot已經(jīng)內(nèi)置了Validator實例,直接將其加載進(jìn)來即可。

使用示例如下:

@Autowired
private Validator validator;

自定義執(zhí)行的單元測試

測試代碼如下:

@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);
? ? ? ? }
? ? }
}

自定義Validation注解

最近新開了一個項目,雖然hibernate-validator很好用,但是有時不能滿足稍微復(fù)雜一些的業(yè)務(wù)校驗。為了不在業(yè)務(wù)代碼中寫校驗邏輯,以及讓代碼更優(yōu)雅,故而采用了自定義校驗注解的方式。

場景說明

本例注解應(yīng)用場景: 填寫表單時,某一項數(shù)據(jù)存在時,對應(yīng)的一類數(shù)據(jù)都應(yīng)存在,一同提交。

源碼

1.類注解

主注解用于標(biāo)記要在校驗的實體類

@Target( { TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = RelateOtherValidator.class)
@Documented
public @interface RelateOther {
? ? String message() default "";
? ? /**
? ? ?* 校驗數(shù)量
? ? ?*/
? ? int num() default 2;
? ? Class<?>[] groups() default {};
? ? Class<? extends Payload>[] payload() default {};
}

2.輔助注解

輔助注解用于標(biāo)注于要校驗的字段,isMaster區(qū)分為主注解和從注解。

主注解是關(guān)鍵字段,存在才進(jìn)行校驗從注解對應(yīng)字段的有效性;主注解的value()屬性可以設(shè)置默認(rèn)值,當(dāng)字段對應(yīng)值對應(yīng)value()時才開啟校驗。

從注解為等待校驗的值,默認(rèn)為從注解。

@Target( { FIELD })
@Retention(RUNTIME)
@Documented
public @interface RelateOtherItem {
? ? /**
? ? ?* 是否為主字段,主字段存在才進(jìn)行校驗
? ? ?*/
? ? boolean isMaster() default false;
? ? /**
? ? ?* 用于開啟對指定值校驗判斷,master字段有效
? ? ?* 當(dāng)前為master且value與標(biāo)注字段值相等才進(jìn)行校驗,
? ? ?*/
? ? String value() default "";
}

3.校驗類

校驗類為實際執(zhí)行校驗邏輯的類,在類注解的@Constraint的validatedBy屬性上設(shè)置。

要設(shè)置為校驗類,首先要實現(xiàn)ConstraintValidator類的isValid方法。

@Slf4j ?// @Slf4j是lombok的注解
public class RelateOtherValidator implements ConstraintValidator<RelateOther, Object> {
?? ?// 要校驗的個數(shù)
? ? 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 {
? ? ? ? ? ? // 總共需要校驗的字段數(shù)
? ? ? ? ? ? int totalValidateNum = validateNum;
? ? ? ? ? ? for (Field field : declaredFields) {
? ? ? ? ? ? ? ? // 校驗是否進(jìn)行過標(biāo)注
? ? ? ? ? ? ? ? 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異常。這里可以采用全局異常處理的方法,進(jìn)行捕獲處理。捕獲之后的異??梢垣@取BindingResult 對象,后面就跟hibernate-validator處理方式一致了。

BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();

5.使用demo

注解的使用類似下面,首先在請求實體類上標(biāo)注類注解,再在對應(yīng)的字段上標(biāo)注輔助注解。

@RelateOther(message = "xx必須存在!",num=2)
public class MarkReq ?{
?? ?@RelateOtherItem (isMaster= true,value="1")
?? ?private Integer ?girl;
?? ?@RelateOtherItem?
?? ?private Integer sunscreen;
?? ?private String remarks;
}

總結(jié)

自定義注解在開發(fā)中還是很好用的,本文主要起到拋磚引玉的作用。對于首次使用的朋友應(yīng)該還是有些用處的。

這些僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中字符串常見的一些拼接方式總結(jié)

    Java中字符串常見的一些拼接方式總結(jié)

    字符串拼接是我們在Java代碼中比較經(jīng)常要做的事情,就是把多個字符串拼接到一起,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java中字符串常見的一些拼接方式,需要的朋友可以參考下
    2023-04-04
  • 使用RestTemplate調(diào)用https接口跳過證書驗證

    使用RestTemplate調(diào)用https接口跳過證書驗證

    這篇文章主要介紹了使用RestTemplate調(diào)用https接口跳過證書驗證,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 關(guān)于Java中String類字符串的解析

    關(guān)于Java中String類字符串的解析

    這篇文章主要介紹有關(guān)Java中String類字符串的解析,在java中,和C語言一樣,也有關(guān)于字符串的定義,并且有他自己特有的功能,下面就進(jìn)入主題一起學(xué)習(xí)下面文章內(nèi)容吧
    2021-10-10
  • Mybatis逆向工程實現(xiàn)連接MySQL數(shù)據(jù)庫

    Mybatis逆向工程實現(xiàn)連接MySQL數(shù)據(jù)庫

    本文主要介紹了Mybatis逆向工程實現(xiàn)連接MySQL數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Spring入門基礎(chǔ)之依賴注入

    Spring入門基礎(chǔ)之依賴注入

    Idea中使用@Autowire注解會出現(xiàn)提示黃線,強(qiáng)迫癥患者看著很難受,使用構(gòu)造器注入或者setter方法注入后可解決,下面我們一起來看看
    2022-07-07
  • Java實現(xiàn)順序表的增刪查改功能

    Java實現(xiàn)順序表的增刪查改功能

    這篇文章主要介紹了Java實現(xiàn)順序表的增刪查改功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 使用eclipse創(chuàng)建java項目的方法

    使用eclipse創(chuàng)建java項目的方法

    這篇文章主要為大家詳細(xì)介紹了使用eclipse創(chuàng)建java項目的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • IntelliJ IDEA窗口組件具體操作方法

    IntelliJ IDEA窗口組件具體操作方法

    IDEA剛接觸不久,各種常用工具窗口找不到,不小心關(guān)掉不知道從哪里打開,今天小編給大家分享這個問題的解決方法,感興趣的朋友一起看看吧
    2021-09-09
  • springboot?serviceImpl初始化注入對象實現(xiàn)方式

    springboot?serviceImpl初始化注入對象實現(xiàn)方式

    這篇文章主要介紹了springboot?serviceImpl初始化注入對象實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • SpringBoot整合kaptcha實現(xiàn)圖片驗證碼功能

    SpringBoot整合kaptcha實現(xiàn)圖片驗證碼功能

    這篇文章主要介紹了SpringBoot整合kaptcha實現(xiàn)圖片驗證碼功能,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07

最新評論