データベースから取得した動的DTO検証構成
1. 概要
このチュートリアルでは、create a custom validation annotation that uses a regular expression retrieved from a database to match against the field valueを実行する方法を見ていきます。
Hibernate Validatorを基本実装として使用します。
2. Mavenの依存関係
開発には、次の依存関係が必要です。
org.springframework.boot
spring-boot-starter-thymeleaf
2.0.1.RELEASE
org.springframework.boot
spring-boot-starter-data-jpa
2.0.1.RELEASE
spring-boot-starter-thymeleaf、spring-boot-starter-data-jpaの最新バージョンは、MavenCentralからダウンロードできます。
3. カスタム検証アノテーション
この例では、データベースから取得した正規表現に対して値を検証する@ContactInfoというカスタムアノテーションを作成します。 次に、この検証をCustomerというPOJOクラスのcontactInfoフィールドに適用します。
データベースから正規表現を取得するために、これらをContactInfoExpressionエンティティクラスとしてモデル化します。
3.1. データモデルとリポジトリ
idフィールドとcontactInfoフィールドを使用してCustomerクラスを作成しましょう。
@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 {
Optional findById(String id);
}
3.2. データベースのセットアップ
正規表現を格納するために、次の永続性構成を持つH2インメモリデータベースを使用します。
@EnableJpaRepositories("com.example.dynamicvalidation.dao")
@EntityScan("com.example.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;
}
}
上記の2つのスクリプトは、スキーマを作成し、データを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を表す3つのレコードを追加します。 これらは、値が有効な電子メールアドレス、有効な米国の電話番号、または有効な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検証仕様のガイドラインに従い、クラスimplements the ConstraintValidator interfaceは、isValid()メソッドをオーバーライドします。
このクラスは、現在使用されている連絡先情報のタイプ(email、phone,、またはwebsite)の値を取得します。これは、contactInfoTypeというプロパティで設定され、次の目的で使用されます。データベースから正規表現の値を取得します。
public class ContactInfoValidator implements ConstraintValidator {
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;
}
}
contactInfoTypeプロパティは、application.propertiesファイルで値email、phone、またはwebsiteのいずれかに設定できます。
contactInfoType=email
3.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. カスタム制約の適用
最後に、CustomerクラスのcontactInfoフィールドに検証アノテーションを追加しましょう。
public class Customer {
// ...
@ContactInfo
@NotNull
private String contactInfo;
// ...
}
4. SpringControllerとHTMLフォーム
検証アノテーションをテストするために、@Validアノテーションを使用してCustomerオブジェクトの検証をトリガーするSpringMVCリクエストマッピングを作成します。
@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";
}
Customerオブジェクトは、HTMLフォームからコントローラーに送信されます。
すべてをまとめるために、アプリケーションをSpring Bootアプリケーションとして実行できます。
@SpringBootApplication
public class DynamicValidationApp {
public static void main(String[] args) {
SpringApplication.run(DynamicValidationApp.class, args);
}
}
5. 結論
この例では、データベースから動的に正規表現を取得し、それを使用して注釈付きフィールドを検証するカスタム検証注釈を作成する方法を示しました。
例の完全なソースコードはover on GitHubにあります。