見出し画像

【SpringBoot+Docker】Web MVC ベース その⑥ ~検索条件はセッションとヘルパーで管理する~

前回は一覧に検索条件を追加し、条件に応じて JPQL を動的に作成する JPQL ビルダーを紹介しました。
Ruby on Rails の ActiveRecord の API を参考に比較的読みやすい仕組みになっています。
サブセット版ですが活用して下さい。

今回は検索条件を残す方法です。
一覧を検索できるようにすると別の画面から一覧に戻るときに検索した条件を残しておきたくなります。
例えば、一覧で検索したあと参照画面を開き、参照画面から戻ると、検索条件が消えて全件表示されているのは少し不便です。
検索条件を保存し、クエリー付きのパスを生成する仕組みが必要です。

検索条件の保存にはセッションを使います。
クエリー付きのパスの生成はパスを管理しているヘルパーコンポーネントに任せます。
こうすることで簡単に管理できるようになります。

ついでなのでセッション情報を redis サーバーに保存するようにしたいと思います。

今回もソースコードを添付します。
実際に動かしてみながら読んで下さい。

この記事は Java、Docker、Visual Studio Code(以下、vscode)、シェルなどのプログラミングに関する基本的な技術を知っている、または、調べれば分かる程度の知識がある前提で書いています。
分かりづらいところがあったらコメントでお知らせ下さい。

今日のノウハウ

検索条件をセッションに保存し、クエリー付きパスを生成する方法

redis でセッション管理する方法

ヘルパーコンポーネントは Spring Boot が管理するコンポーネントなので HttpSession オブジェクトを注入することができます。
検索条件をセッション経由で受け渡せば、ヘルパーでクエリー付きのパスを生成するのは簡単です。

ついでに Docker に redis を追加し、redis でセッション管理ができるようにします。

セッションに検索条件を保存する

セッションに検索条件を保存できるようにします。
UsersSearchForm に Serializable インタフェースを実装させて下さい。

@Data
@NoArgsConstructor
public class UsersSearchForm implements Serializable {  // ユーザー検索条件フォーム

これがないと redis を導入したときにエラーになります。

次にコントローラーでセッションに検索条件を保存します。
HttpSession を必須コンストラクタで注入し、index ページのリクエスト時に検索条件をセッションに保存します。

@Controller                                                         // コントローラーとして扱う
@RequiredArgsConstructor                                            // 必須フィールドのコンストラクターを生成
public class UsersController {

  ※省略

  private final HttpSession httpSession;                            // HttpSession を注入

  ※省略

  @GetMapping("#{usersHelper.indexPageMappingPath()}")                      // /users にマッピング
  public String indexPage(UsersSearchForm usersSearchForm, Model model) {   // usersSearchForm はクエリを受け取る役、クエリがなければ初期値。
                                                                            // model はビューへオブジェクト受け渡す役
    httpSession.setAttribute("usersSearchForm", usersSearchForm);           // usersSearchForm をセッションに保存する。

  ※省略

ヘルパーでクエリー付きパスを生成する

ヘルパーは Spring Boot が管理するコンポーネントなので HttpSession を注入できます。

@Component                                // コンポーネントとして扱う
@RequiredArgsConstructor                  // 必須フィールドのコンストラクターを生成
public class UsersHelper {

  private final HttpSession httpSession;  //  HttpSession を注入

そして、次のようにクエリー付きのパスを生成するメソッドとクエリーなしのパスを生成するメソッドを用意します。

@Component                                                            // コンポーネントとして扱う
@RequiredArgsConstructor                                              // 必須フィールドのコンストラクターを生成
public class UsersHelper {

  ※省略

  public String indexPagePath() {                                     // クエリー付き index ページのパス
    Object obj = httpSession.getAttribute("usersSearchForm");         // usersSearchForm をセッションから取得する
    if (obj == null || !(obj instanceof UsersSearchForm)) {           // 存在しない・UsersSearchForm じゃないとき
      return indexPagePathNoQuery();                                  // クエリーなしパスを返す
    }

    UriBuilder uriBuilder = UriComponentsBuilder.newInstance();       // UriBuilder を準備する。
    uriBuilder.path(indexPagePathNoQuery());                          // パスを設定

    UsersSearchForm usersSearchForm = (UsersSearchForm) obj;
    uriBuilder.queryParam("query", usersSearchForm.getQuery());       // クエリーを設定
    uriBuilder.queryParam("enabled", usersSearchForm.isEnabled());

    return uriBuilder.build().toString();                             // クエリー付きパスを返す。
  }

  public String indexPagePathNoQuery() {                              // クエリーなし index ページのパス
    return indexPageMappingPath();
  }

  ※省略

クエリー付きパスを生成することのほうが多いので、indexPagePath() をクエリー付きパスを生成するメソッドにしています。
メニューや form の action 属性に指定するパスなどクエリーなしのパスが必要なときは indexPagePathNoQuery() を使って下さい。

クエリー付きのパスを生成するのに Spring Boot に含まれている UriComponentsBuilder を使用しています。
これは、何を使っても構いません。
何をしているかは見てもらえれば分かると思うので説明は省略します。

これで完了です。

indexPagePath() メソッドでクエリー付きパスを生成するようにしたので、何も修正しなくても index ページに遷移するリンクはクエリー付きになっています。
更新したときも検索条件を保存したまま index ページに戻って来ます。

ただし、一覧の検索条件の action にもクエリーが付いてしまうので次のように修正して下さい。

  <form th:action="${#usersHelper.indexPagePathNoQuery()}" method="get" th:object="${usersSearchForm}">

docker に redis を導入する

セッションは redis で管理しておくとアプリケーションを再起動してもセッションを残すことができます。
スケールすることにも対応できるのでセッションを使うときは redis を導入しておきましょう。

docker-compose.yml に次の設定を追加します。

  ※省略

  redis:
    image: redis
    restart: always

  ※省略

次に pom.xml にライブラリを追加します。

※省略

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>

※省略

最後に application.properties に redis ホストの設定を追加します。

## Redis
spring.data.redis.host=redis

それぞれ追加したら Docker を再起動して下さい。
redis が有効になり、redis でセッションの管理が行えるようになります。

まとめ

検索条件をセッションに保存し、ヘルパーコンポーネントでセッションの検索条件を使ってクエリー付きパスを生成しました。
また、redis でセッションを管理するように Docker などの設定を変更しました。
パスの生成をヘルパーコンポーネントに一元管理することでパス関連のプログラミングが楽になります。

JPQL ビルダーやヘルパーなど Spring Boot が提供していないちょっとした機能を開発して、業務システムが楽に作れるようになると開発も楽しくなります。

次回はパスワード認証を実装します。

この記事が気に入ったらサポートをしてみませんか?