1. 概述
在本教程中,我們將探討如何創建一個自定義驗證註解,該註解使用從數據庫檢索的正則表達式與字段值進行匹配。
我們將使用 Hibernate Validator 作為基礎實現。
2. Maven 依賴
為了開發,我們需要以下依賴項:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.1.5</version>
</dependency>最新版本的 spring-boot-starter-thymeleaf 和 spring-boot-starter-data-jpa 可從 Maven Central 下載。
3. 自定義驗證標註
為了我們的示例,我們將創建一個名為 @ContactInfo 的自定義標註,它將驗證值與從數據庫檢索的正則表達式進行匹配。我們將在此對 contactInfo 字段(字段)應用於名為 Customer 的 POJO 類上進行驗證。
要從數據庫檢索正則表達式,我們將這些建模為 ContactInfoExpression 實體類。
3.1. 數據模型與存儲庫
讓我們創建一個 客户 類,包含 id 和 聯繫信息 字段:
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String contactInfo;
// standard constructor, getters, setters
}接下來,讓我們來查看一下 ContactInfoExpression 類——它將包含正則表達式值在一個名為 pattern 的屬性中:
@Entity
public class ContactInfoExpression {
@Id
@Column(name="expression_type")
private String type;
private String pattern;
//standard constructor, getters, setters
}接下來,我們添加一個基於 Spring Data 的倉庫接口,用於操作 ContactInfoExpression 實體:
public interface ContactInfoExpressionRepository
extends Repository<ContactInfoExpression, String> {
Optional<ContactInfoExpression> findById(String id);
}3.2. 數據庫設置
為了存儲正則表達式,我們將使用一個駐留在內存中的 H2 數據庫,並採用以下持久化配置:
@EnableJpaRepositories("com.baeldung.dynamicvalidation.dao")
@EntityScan("com.baeldung.dynamicvalidation.model")
@Configuration
public class PersistenceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2)
.addScript("schema-expressions.sql")
.addScript("data-expressions.sql")
.build();
return db;
}
}以下是翻譯後的內容:
這兩個腳本用於創建模式以及將數據插入到 contact_info_expression 表中:
CREATE TABLE contact_info_expression(
expression_type varchar(50) not null,
pattern varchar(500) not null,
PRIMARY KEY ( expression_type )
);data-expressions.sql 腳本將添加三條記錄,分別代表 email、phone 和 website 類型。這些類型對應於正則表達式,用於驗證值是否為有效的電子郵件地址、有效的美國電話號碼或有效的 URL。
insert into contact_info_expression values ('email',
'[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')
insert into contact_info_expression values ('phone',
'^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$')
insert into contact_info_expression values ('website',
'^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$')3.3. 創建自定義驗證器
讓我們創建一個名為 ContactInfoValidator 的類,其中包含實際的驗證邏輯。遵循 Java Validation 規範,該類 實現了 ConstraintValidator 接口,並覆蓋了 isValid() 方法。
該類將獲取當前使用的聯繫信息類型——電子郵件、電話號碼或網站,該類型設置為一個名為 contactInfoType 的屬性,然後使用它從數據庫中檢索正則表達式的值:
public class ContactInfoValidator implements ConstraintValidator<ContactInfo, String> {
private static final Logger LOG = Logger.getLogger(ContactInfoValidator.class);
@Value("${contactInfoType}")
private String expressionType;
private String pattern;
@Autowired
private ContactInfoExpressionRepository expressionRepository;
@Override
public void initialize(ContactInfo contactInfo) {
if (StringUtils.isEmptyOrWhitespace(expressionType)) {
LOG.error("Contact info type missing!");
} else {
pattern = expressionRepository.findById(expressionType)
.map(ContactInfoExpression::getPattern).get();
}
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (!StringUtils.isEmptyOrWhitespace(pattern)) {
return Pattern.matches(pattern, value);
}
LOG.error("Contact info pattern missing!");
return false;
}
}<em>contactInfoType</em> 屬性可以在 <em>application.properties</em> 文件中設置為以下值之一:<em>email</em>、<em>phone</em> 或 <em>website</em>。
contactInfoType=email3.4. 創建自定義約束標註接口
現在,讓我們創建自定義約束的標註接口:
@Constraint(validatedBy = { ContactInfoValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ContactInfo {
String message() default "Invalid value";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}3.5. 應用自定義約束
最後,讓我們為 contactInfo 字段(即 Customer 類中的字段)添加驗證註解:
public class Customer {
// ...
@ContactInfo
@NotNull
private String contactInfo;
// ...
}4. Spring 控制器和 HTML 表單
為了測試我們的驗證註解,我們將創建一個 Spring MVC 請求映射,它使用 @Valid 註解來觸發對 Customer 對象進行驗證:
@PostMapping("/customer")
public String validateCustomer(@Valid Customer customer, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("message", "The information is invalid!");
} else {
model.addAttribute("message", "The information is valid!");
}
return "customer";
}客户對象是從 HTML 表單中發送到控制器的。
<form action="customer" method="POST">
Contact Info: <input type="text" name="contactInfo" /> <br />
<input type="submit" value="Submit" />
</form>
<span th:text="${message}"></span>為了總結,我們可以將我們的應用程序作為 Spring Boot 應用程序運行:
@SpringBootApplication
public class DynamicValidationApp {
public static void main(String[] args) {
SpringApplication.run(DynamicValidationApp.class, args);
}
}5. 結論
在本示例中,我們演示瞭如何創建自定義驗證註解,該註解可以動態從數據庫中檢索正則表達式並使用它來驗證註解的字段。