[Java][JHipster]バリデーションチェックを行う

java

はじめに

前回はJHipsterを使いScaffoldでデータをCRUDする機能を実装しました。今回はこれに、サーバ側でバリデーションを行う機能を追加する方法について書きたいと思います。

実装する機能について

前回作成したArticleのEntityを登録する際に、同じタイトルが既に登録されていたらエラーとするバリデーションを実装します。画面上では以下の様な感じとなります。 hipster-validation-check-1

バリデーションの実装

上記のバリデーションを実現するには以下を実装する必要があります。

  • (入力した)タイトルに一致するArticleを検索する機能
  • バリデーションの判定を行い、エラー時にはエラーを返却する機能
  • 画面にエラーメッセージを表示する機能

以下、それぞれの実装について見ていきたいと思います。

タイトルに一致するArticleを検索する機能

この機能はデータの検索機能となるため、Repository層に実装します。「src/main/java/org/jhipster/repository/ArticleRepository.java」に「findByCurrentUserAndTitle」という名前で作成します。

src/main/java/org/jhipster/repository/ArticleRepository.java
package org.jhipster.repository;
(中略)
/**
 * Spring Data JPA repository for the Article entity.
 */
@SuppressWarnings("unused")
public interface ArticleRepository extends JpaRepository<Article,Long> {
    (中略)
    @Query("select article from Article article where article.user.login = ?#{principal.username} and article.title = :title")
    List<Article> findByCurrentUserAndTitle(@Param("title")String title);
}

Articleはユーザ毎に作成されるため、検索条件にユーザ名とタイトルを指定してArticleを検索しています(同一ユーザ名のユーザが複数いる場合については・・・、今回は無視します)。「@Query」でSQL文を記述しているため直感的に分かるかと思います。

バリデーション判定

バリデーションの判定については、画面で入力したデータのPostリクエストを受け取るコントローラに実装しました。

/src/main/java/org/jhipster/web/rest/ArticleResource.java
    @PostMapping("/articles")
    @Timed
    public ResponseEntity<Article> createArticle(@Valid @RequestBody Article article) throws URISyntaxException {
        log.debug("REST request to save Article : {}", article);
        if (article.getId() != null) {
            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new article cannot already have an ID")).body(null);
        }
        List<Article> articles = articleRepository.findByCurrentUserAndTitle(article.getTitle());
        if(!articles.isEmpty()){
            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "article.titleexists", "Title already exist!")).body(null);
        }
        Article result = articleRepository.save(article);
        return ResponseEntity.created(new URI("/api/articles/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

8〜11行目が今回追加したソースです。8行目で先に実装した「findByCurrentUserAndTitle」を呼び出して、タイトルが一致するデータを取得しています。9〜11行目ではデータが存在するかを判定し、存在する場合にはエラーメッセージのキー(「article.titleexists」)を指定して返却しています。6行目のreturn文とほぼ同じなのに注目してください。これはエラーメッセージ以外はScaffoldで作成された仕組みを踏襲しているためです。

画面に表示するエラーメッセージ

JHipsterではメッセージの定義にi18nを使用しています。今回は使用言語がデフォルト(英語)の場合のみメッセージを定義しました。「/src/main/webapp/i18n/en/global.json」の「error」項目にメッセージを追加しました。

/src/main/webapp/i18n/en/global.json
    (中略)
    "error": {
        (中略)
        "emailexists": "E-mail is already in use!",
        "idexists": "A new {{ entityName }} cannot already have an ID",
        "article": {
            "titleexists": "Title already exist!"
        }
    (中略)

「error」の中に「article」を作成し、その中に「titleexists」というキー名でメッセージを定義しています。このキーは先のコントローラ内で「article.titleexists」として指定したキーとなります。

まとめ

バリデーションチェックでよくある、サーバ側でのデータ検索 → バリデーション判定 → エラーメッセージの表示、というパターンを実装してみました。Scaffoldで用意されたソースを元に、少ない変更で実装できることが分かりました。