かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その58 )( セッションに値をセットする・取り出す処理を実装する )

概要

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その57 )( 気になった点を修正2 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • セッションに値をセットする・取り出す処理を実装する。
  • 既存の画面に実装する案が思い浮かばなかったので、サンプルの画面を作成することにします。

参照したサイト・書籍

  1. indexnext |previous |TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.1.0.RELEASE documentation - 5.8. セッション管理
    http://terasolunaorg.github.io/guideline/5.1.0.RELEASE/ja/ArchitectureInDetail/SessionManagement.html

    • Web でいろいろ調べましたが、一番分かりやすいのはこのドキュメントだと思います。

目次

  1. 実装仕様
  2. feature/106-issue ブランチの作成
  3. Form クラスの作成
  4. Thymeleaf テンプレートファイルの作成
  5. Controller クラスの作成
  6. 動作確認
  7. commit、GitHub へ Push、feature/106-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/106-issue ブランチを削除
  8. 感想&次回は。。。

手順

実装仕様

以下の仕様で実装します。

  • 入力画面1(「名前」「年齢」を入力できる画面)、入力画面2(「住所」「メールアドレス」を入力できる画面)、確認画面の3画面を用意します。
  • 入力画面1、入力画面2で入力されたデータはセッションに保存します。
  • セッションに保存する方法には @SessionAttributes アノテーションを使用します。
  • 確認画面にはセッションをクリアするボタンを設けます。

画面デザインは以下のものを使用します。

f:id:ksby:20160326015220p:plain

f:id:ksby:20160326015346p:plain

f:id:ksby:20160326015536p:plain

feature/106-issue ブランチの作成

  1. feature/106-issue ブランチを作成します。

Form クラスの作成

  1. src/main/java/ksbysample/webapp/lending/web の下に sessionsample パッケージを作成します。

  2. src/main/java/ksbysample/webapp/lending/web/sessionsample の下に SessionSampleForm.java を作成します。作成後、リンク先の内容 に変更します。

Thymeleaf テンプレートファイルの作成

  1. src/main/resources/templates の下に sessionsample ディレクトリを作成します。

  2. src/main/resources/templates/sessionsample の下に first.html を作成します。作成後、リンク先の内容 に変更します。

  3. src/main/resources/templates/sessionsample の下に next.html を作成します。作成後、リンク先の内容 に変更します。

  4. src/main/resources/templates/sessionsample の下に confirm.html を作成します。作成後、リンク先の内容 に変更します。

Controller クラスの作成

  1. src/main/java/ksbysample/webapp/lending/web/sessionsample の下に SessionSampleController.java を作成します。作成後、リンク先の内容 に変更します。

  2. /sessionsample 以下の URL はログイン有無の対象外にします。src/main/java/ksbysample/webapp/lending/config の下の WebSecurityConfig.javaリンク先の内容 に変更します。

動作確認

  1. 動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。

  2. ブラウザを起動して http://localhost:8080/sessionsample にアクセスします。

    f:id:ksby:20160327101308p:plain

  3. 名前、年齢を入力して「入力その2へ」ボタンをクリックします。

    f:id:ksby:20160327101441p:plain

    f:id:ksby:20160327101536p:plain

  4. 「入力その1へ戻る」ボタンをクリックして入力画面1へ戻ると、入力したデータが表示されることが確認できます。

    f:id:ksby:20160327101736p:plain

    「入力その2へ」ボタンをクリックして入力画面2へ戻ります。

  5. 住所、メールアドレスを入力して「確認画面へ」ボタンをクリックします。

    f:id:ksby:20160327101911p:plain

    確認画面に遷移すると入力画面1、入力画面2で入力したデータが表示されることが確認できます。

    f:id:ksby:20160327102003p:plain

  6. 「セッションをクリアする」ボタンをクリックすると入力画面1に戻ります。

    f:id:ksby:20160327102354p:plain

    「確認画面へ」ボタンをクリックして確認画面へ遷移すると、表示されているデータが消えていることが確認できます。

    f:id:ksby:20160327102436p:plain

  7. 「入力その2へ戻る」ボタンをクリックして、今度は入力画面2→入力画面1→確認画面の順で入力してみます。

    f:id:ksby:20160327102707p:plain

    f:id:ksby:20160327102803p:plain

    入力画面の順番を変えても、確認画面上に入力したデータが表示されることが確認できます。

    f:id:ksby:20160327102849p:plain

  8. Ctrl+F2 を押して Tomcat を停止します。

commit、GitHub へ Push、feature/106-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/106-issue ブランチを削除

  1. commit、GitHub へ Push、feature/106-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/106-issue ブランチを削除、をします。

感想&次回は。。。

  • 最初は仕組みを理解できていなくて試行錯誤したのですが、分かってしまうとすごく簡単にセッションにデータを入れられて驚きでした。
  • 次回は JDK の 8u77 が出ているのでバージョンアップした後、Windows で本番稼働させるためのディレクトリ作成、jar ファイル配置、bat ファイル作成、サービス登録、動作確認へと進む予定です。

ソースコード

SessionSampleForm.java

package ksbysample.webapp.lending.web.sessionsample;

import lombok.Data;

import java.io.Serializable;

@Data
public class SessionSampleForm implements Serializable {

    private static final long serialVersionUID = 1183516008630394266L;

    private String name;

    private String age;

    private String address;

    private String email;

}
  • セッションに保存するので Serializable インターフェースを実装します。

first.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>セッションサンプル</title>
    <!-- Tell the browser to be responsive to screen width -->
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
    <link th:replace="common/head-cssjs"/>

    <style type="text/css">
        <!--
        .table {
            background-color: #ffccff;
            margin-bottom: 10px;
        }
        .has-error .form-control {
            background-color: #fff5ee;
        }
        .form-group {
            margin-bottom: 0px;
        }
        -->
    </style>
</head>

<!-- ADD THE CLASS layout-top-nav TO REMOVE THE SIDEBAR. -->
<body class="skin-blue layout-top-nav">
<div class="wrapper">

    <!-- Main Header -->
    <div th:replace="common/mainparts :: main-header"></div>

    <!-- Full Width Column -->
    <div class="content-wrapper">
        <div class="container">
            <!-- Content Header (Page header) -->
            <section class="content-header">
                <h1>セッションサンプル(入力その1)</h1>
            </section>

            <!-- Main content -->
            <section class="content">
                <div class="row">
                    <div class="col-xs-12">
                        <!-- @thymesVar id="sessionSampleForm" type="ksbysample.webapp.lending.web.sessionsample.SessionSampleForm" -->
                        <form id="sessionSampleForm" method="post" action="/sessionsample/confirm" th:action="@{/sessionsample/confirm}"
                              th:object="${sessionSampleForm}">
                            <table class="table table-bordered">
                                <colgroup>
                                    <col width="20%"/>
                                    <col width="80%"/>
                                </colgroup>
                                <tbody>
                                    <tr>
                                        <th>名前</th>
                                        <td>
                                            <div class="col-xs-12">
                                                <div class="form-group">
                                                    <div class="row"><div class="col-xs-8">
                                                        <input type="text" name="name" id="name" class="form-control input-sm" value=""
                                                               placeholder="氏名を入力してください" th:field="*{name}"/>
                                                    </div></div>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                    <tr>
                                        <th>年齢</th>
                                        <td>
                                            <div class="col-xs-12">
                                                <div class="form-group">
                                                    <div class="row"><div class="col-xs-3">
                                                        <input type="text" name="age" id="age" class="form-control input-sm" value=""
                                                               placeholder="年齢を入力してください" th:field="*{age}"/>
                                                    </div></div>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                            <div class="text-center">
                                <button class="btn bg-blue js-btn-next"><i class="fa fa-hand-o-right"></i> 入力その2へ</button>
                                <button class="btn bg-blue js-btn-confirm"><i class="fa fa-eye"></i> 確認画面へ</button>
                           </div>
                        </form>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

</div>
<!-- ./wrapper -->

<script th:replace="common/bottom-js"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function() {
        $('.js-btn-next').bind('click', function(){
            $("#sessionSampleForm").attr("action", "/sessionsample/next");
            $('#sessionSampleForm').submit();
            return false;
        });

        $('.js-btn-confirm').bind('click', function(){
            $('#sessionSampleForm').submit();
            return false;
        });
    });
    -->
</script>
</body>
</html>

next.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>セッションサンプル</title>
    <!-- Tell the browser to be responsive to screen width -->
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
    <link th:replace="common/head-cssjs"/>

    <style type="text/css">
        <!--
        .table {
            background-color: #ffccff;
            margin-bottom: 10px;
        }
        .has-error .form-control {
            background-color: #fff5ee;
        }
        .form-group {
            margin-bottom: 0px;
        }
        -->
    </style>
</head>

<!-- ADD THE CLASS layout-top-nav TO REMOVE THE SIDEBAR. -->
<body class="skin-blue layout-top-nav">
<div class="wrapper">

    <!-- Main Header -->
    <div th:replace="common/mainparts :: main-header"></div>

    <!-- Full Width Column -->
    <div class="content-wrapper">
        <div class="container">
            <!-- Content Header (Page header) -->
            <section class="content-header">
                <h1>セッションサンプル(入力その2)</h1>
            </section>

            <!-- Main content -->
            <section class="content">
                <div class="row">
                    <div class="col-xs-12">
                        <!-- @thymesVar id="sessionSampleForm" type="ksbysample.webapp.lending.web.sessionsample.SessionSampleForm" -->
                        <form id="sessionSampleForm" method="post" action="/sessionsample/confirm" th:action="@{/sessionsample/confirm}"
                              th:object="${sessionSampleForm}">
                            <table class="table table-bordered">
                                <colgroup>
                                    <col width="20%"/>
                                    <col width="80%"/>
                                </colgroup>
                                <tbody>
                                    <tr>
                                        <th>住所</th>
                                        <td>
                                            <div class="col-xs-12">
                                                <div class="form-group">
                                                    <div class="row"><div class="col-xs-12">
                                                        <input type="text" name="address" id="address" class="form-control input-sm" value=""
                                                               placeholder="住所を入力してください" th:field="*{address}"/>
                                                    </div></div>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                    <tr>
                                        <th>メールアドレス</th>
                                        <td>
                                            <div class="col-xs-12">
                                                <div class="form-group">
                                                    <div class="row"><div class="col-xs-8">
                                                        <input type="text" name="email" id="email" class="form-control input-sm" value=""
                                                               placeholder="メールアドレスを入力してください" th:field="*{email}"/>
                                                    </div></div>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                            <div class="text-center">
                                <button class="btn bg-blue js-btn-first"><i class="fa fa-hand-o-left"></i> 入力その1へ戻る</button>
                                <button class="btn bg-blue js-btn-confirm"><i class="fa fa-eye"></i> 確認画面へ</button>
                           </div>
                        </form>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

</div>
<!-- ./wrapper -->

<script th:replace="common/bottom-js"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function() {
        $('.js-btn-first').bind('click', function(){
            $("#sessionSampleForm").attr("action", "/sessionsample");
            $('#sessionSampleForm').submit();
            return false;
        });

        $('.js-btn-confirm').bind('click', function(){
            $('#sessionSampleForm').submit();
            return false;
        });
    });
    -->
</script>
</body>
</html>

confirm.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>セッションサンプル</title>
    <!-- Tell the browser to be responsive to screen width -->
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
    <link th:replace="common/head-cssjs"/>

    <style type="text/css">
        <!--
        .table {
            background-color: #ffccff;
            margin-bottom: 10px;
        }
        .has-error .form-control {
            background-color: #fff5ee;
        }
        .form-group {
            margin-bottom: 0px;
        }
        -->
    </style>
</head>

<!-- ADD THE CLASS layout-top-nav TO REMOVE THE SIDEBAR. -->
<body class="skin-blue layout-top-nav">
<div class="wrapper">

    <!-- Main Header -->
    <div th:replace="common/mainparts :: main-header"></div>

    <!-- Full Width Column -->
    <div class="content-wrapper">
        <div class="container">
            <!-- Content Header (Page header) -->
            <section class="content-header">
                <h1>セッションサンプル(確認)</h1>
            </section>

            <!-- Main content -->
            <section class="content">
                <div class="row">
                    <div class="col-xs-12">
                        <!-- @thymesVar id="sessionSampleForm" type="ksbysample.webapp.lending.web.sessionsample.SessionSampleForm" -->
                        <form id="sessionSampleForm" method="post" action="/sessionsample/clear" th:action="@{/sessionsample/clear}"
                              th:object="${sessionSampleForm}">
                            <table class="table table-bordered">
                                <colgroup>
                                    <col width="20%"/>
                                    <col width="80%"/>
                                </colgroup>
                                <tbody>
                                    <tr>
                                        <th>名前</th>
                                        <td th:text="*{name}"></td>
                                    </tr>
                                    <tr>
                                        <th>年齢</th>
                                        <td th:text="*{age}"></td>
                                    </tr>
                                    <tr>
                                        <th>住所</th>
                                        <td th:text="*{address}"></td>
                                    </tr>
                                    <tr>
                                        <th>メールアドレス</th>
                                        <td th:text="*{email}"></td>
                                    </tr>
                                </tbody>
                            </table>
                            <div class="text-center">
                                <button class="btn bg-blue js-btn-first"><i class="fa fa-hand-o-left"></i> 入力その1へ戻る</button>
                                <button class="btn bg-blue js-btn-next"><i class="fa fa-hand-o-left"></i> 入力その2へ戻る</button>
                                <button class="btn bg-blue js-btn-clear"><i class="fa fa-eraser"></i> セッションをクリアする</button>
                            </div>
                        </form>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

</div>
<!-- ./wrapper -->

<script th:replace="common/bottom-js"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function () {
        $('.js-btn-first').bind('click', function () {
            $("#sessionSampleForm").attr("action", "/sessionsample");
            $('#sessionSampleForm').submit();
            return false;
        });

        $('.js-btn-next').bind('click', function () {
            $("#sessionSampleForm").attr("action", "/sessionsample/next");
            $('#sessionSampleForm').submit();
            return false;
        });

        $('.js-btn-clear').bind('click', function () {
            $('#sessionSampleForm').submit();
            return false;
        });
    });
    -->
</script>
</body>
</html>

SessionSampleController.java

package ksbysample.webapp.lending.web.sessionsample;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

@Controller
@RequestMapping("/sessionsample")
@SessionAttributes("sessionSampleForm")
public class SessionSampleController {

    @RequestMapping
    public String index(SessionSampleForm sessionSampleForm) {
        return "sessionsample/first";
    }

    @RequestMapping("/next")
    public String next(SessionSampleForm sessionSampleForm) {
        return "sessionsample/next";
    }

    @RequestMapping("/confirm")
    public String confirm(SessionSampleForm sessionSampleForm) {
        return "sessionsample/confirm";
    }

    @RequestMapping("/clear")
    public String clear(SessionStatus sessionStatus) {
        sessionStatus.setComplete();
        return "redirect:/sessionsample";
    }

}
  • クラスに @SessionAttributes("sessionSampleForm") アノテーションを付加します。
  • セッションをクリアするための clear メソッドでは引数に SessionStatus sessionStatus を指定し、メソッド内で sessionStatus.setComplete(); を呼び出します。

WebSecurityConfig.java

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                // .antMatchers("/country/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/html/**").permitAll()
                .antMatchers("/encode").permitAll()
                .antMatchers("/urllogin").permitAll()
                .antMatchers("/webapi/**").permitAll()
                .antMatchers("/springMvcMemo/**").permitAll()
                .antMatchers("/sessionsample/**").permitAll()
                .antMatchers("/textareamemo/**").permitAll()
                .anyRequest().authenticated();
  • .antMatchers("/sessionsample/**").permitAll() を追加します。

履歴

2016/03/27
初版発行。