かんがるーさんの日記

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

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その19 )( 検索対象図書館登録画面の作成 )

概要

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その18 )( 図書館一覧取得 WebAPI の作成2 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。2~3回に分けて書きます。
    • 検索対象図書館登録画面 ( 管理者のみ ) の作成

参照したサイト・書籍

  1. HTML Table width in percentage, table rows separated equaly
    http://stackoverflow.com/questions/7700534/html-table-width-in-percentage-table-rows-separated-equaly

    • テーブルレイアウトで <colgroup>...</colgroup> を使用してカラムの幅を調整する方法を参照しました。
  2. CSSでのフォント指定について考える(2014年)
    http://www.dtp-transit.jp/misc/web/post_1881.html

    • CSS で指定する日本語フォントを参考にしました。
  3. Bootstrapのレスポンシブなテーブルの列の幅を動的に変える
    http://qiita.com/tkm_kj/items/2c60a49d9c8e9d8fbd85

    • Bootstrap で table タグを使用してテーブル表示した時に、ブラウザの画面の幅を狭めてもカラムの幅が固定のままになった原因を調査した時に参照しました。
  4. Twitter Bootstrapで端末サイズ毎にHTML要素の表示・非表示を切り替え
    http://easyramble.com/twitter-bootstrap-responsive-utilities.html

    • Bootstrap で画面の幅を狭めた時にテーブルの一部のカラムを非表示にする方法を調べた時に参照しました。
  5. twitter bootstrap text in navbar
    http://stackoverflow.com/questions/9844861/twitter-bootstrap-text-in-navbar

    • Bootstrap の navbar 内にテキストを表示する方法を参照しました。
  6. 意外と要注意 HTML5データ属性とjQuery Data APIの関係まとめ
    http://tokkono.cute.coocan.jp/blog/slow/index.php/xhtmlcss/html5-data-attributes-vs-jquery-data-api/

    • jQueryHTML5 のデータ属性を取り扱う方法を調べた時に参照しました。
  7. jQueryのカスタムデータ属性(data-*)の設定/取得の挙動が思ったのと違った件
    http://qiita.com/Kta-M/items/2eda39750abd10df9801

    • jQueryHTML5 のデータ属性を取り扱う方法を調べた時に参照しました。
  8. jQuery入門道場 - 2章 セレクタ
    http://jquery-master.net/selectors/

    • jQuery で name 属性の値を指定して要素を取得する方法を調べた時に参照しました。
  9. jQuery.ajax で form データを送信
    http://surferonwww.info/BlogEngine/post/2012/07/14/posting-form-data-using-jquery-ajax.aspx

    • jQuery で WebAPI を呼び出す時に日本語をエンコードする方法を参考にしました。
  10. jQuery+jQuery UI+jQuery Mobile逆引きハンドブック

    jQuery+jQuery UI+jQuery Mobile逆引きハンドブック

    jQuery+jQuery UI+jQuery Mobile逆引きハンドブック

    • jQuery 関連で分からないところを調べる時に参照しました。
  11. Change field name in JSON using Jackson
    http://stackoverflow.com/questions/7263282/change-field-name-in-json-using-jackson

    • RestController クラスから JSON を返す時に変数名をクラスのフィールド名から変更する方法を参考にしました。

目次

  1. はじめに
  2. 1.0.x-make-admin-library ブランチの作成
  3. 検索対象図書館登録画面の HTML ファイルの作成
  4. Thymeleaf テンプレートファイルの作成
  5. AdminLibraryController クラスの作成
  6. 動作確認
  7. 都道府県名を入力して検索ボタンを押したら図書館一覧を表示する

手順

はじめに

管理権限 ( ROLE_ADMIN ) を持つユーザのみが使用できる検索対象図書館登録画面を作成します。

  • Javascript で図書館一覧取得 WebAPI ( /webapi/library/getLibraryList ) を呼び出して取得した JSON データを画面上に表示します。
  • 図書館選択時はサーバへリクエストを送信してデータを登録します。
  • 管理権限 ( ROLE_ADMIN ) を持つユーザがログインした場合には、最初に検索対象図書館登録画面へ遷移するようにします。
  • メニューの項目は管理権限 ( ROLE_ADMIN ) を持つユーザにのみ表示されるようにします。

1.0.x-make-admin-library ブランチの作成

  1. IntelliJ IDEA で 1.0.x-make-admin-library ブランチを作成します。

検索対象図書館登録画面の HTML ファイルの作成

  1. src/main/resources/static/html の下の template.html をコピーして adminlibrary.html を作成します。作成後、リンク先の内容 に変更します。

    以下のような画面になります。

    f:id:ksby:20150904044141p:plain

    f:id:ksby:20150905141448p:plain

    • 上の Extra small devices の時 ( col-xs 適用時 ) には以下のようにしています。
      • 都道府県名入力フィールドと「検索」ボタンの幅が変わるようにしました。
      • 一覧表の systemname 欄が表示されないようにしました。

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

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

  2. src/main/resources/templates/admin/library の下に src/main/resources/static/html/adminlibrary.html をコピーして、ファイル名を library.html に変更します。

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

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

  5. src/main/resources/templates/common の下に bottom-js.html を作成します。作成後、リンク先の内容 に変更します。

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

  7. src/main/resources/templates/admin/library の下の library.html を リンク先のその1の内容 に変更します。

AdminLibraryController クラスの作成

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

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

動作確認

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

  2. ブラウザを起動し http://localhost:8080/admin/library へアクセスします。最初はログイン画面が表示されますので ID に "tanaka.taro@sample.com"、Password に "taro" を入力して、「次回から自動的にログインする」をチェックせずに「ログイン」ボタンをクリックします。

    以下の画面が表示されることを確認します。

    f:id:ksby:20150905054057p:plain

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

  4. 一旦 commit します。

都道府県名を入力して検索ボタンを押したら図書館一覧を表示する

  1. 最初に図書館一覧取得 WebAPI で返る JSON で formal が formalName になっていることに気づいたので修正します。src/main/java/ksbysample/webapp/lending/service.calilapi の下の Library.javaリンク先の内容 に変更します。

  2. src/main/resources/templates/admin/library の下の library.html を リンク先のその2の内容 に変更します。

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

  4. ブラウザを起動し http://localhost:8080/admin/library へアクセスします ( ログイン画面が表示されたら tanaka.taro@sample.com / taro でログインします )。最初に以下の画面が表示されます。

    f:id:ksby:20150905161510p:plain

  5. "東京都" と入力して「検索」ボタンを押すとカーリル図書館APIで検索してヒットした図書館一覧が表示されます。

    f:id:ksby:20150905161753p:plain

  6. "神奈川県" で検索すると今度は神奈川県の検索結果が表示されます。

    f:id:ksby:20150905162020p:plain

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

  8. 一旦 commit します。

ソースコード

adminlibrary.html

<!DOCTYPE html>
<html>
<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"/>
    <!-- Bootstrap 3.3.4 -->
    <link href="/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    <!-- Font Awesome Icons -->
    <link href="/css/font-awesome.min.css" rel="stylesheet" type="text/css"/>
    <!-- Ionicons -->
    <link href="/css/ionicons.min.css" rel="stylesheet" type="text/css"/>
    <!-- Theme style -->
    <link href="/css/AdminLTE.min.css" rel="stylesheet" type="text/css"/>
    <!-- AdminLTE Skins. Choose a skin from the css/skins
         folder instead of downloading all of them to reduce the load. -->
    <link href="/css/skins/_all-skins.min.css" rel="stylesheet" type="text/css"/>

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="/js/html5shiv.min.js"></script>
        <script src="/js/respond.min.js"></script>
    <![endif]-->

    <style>
        .jp-gothic {
            font-family: Verdana, "游ゴシック", YuGothic, "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
        }
        .noselected-library {
            color: #ff8679 !important;
            font-size: 100%;
            font-weight: 700;
        }
        .selected-library {
            color: #ffffff !important;
            font-size: 100%;
            font-weight: 700;
        }
        .content-wrapper {
            background-color: #fffafa;
        }
        .table>tbody>tr>td
        , .table>tbody>tr>th
        , .table>tfoot>tr>td
        , .table>tfoot>tr>th
        , .table>thead>tr>td
        , .table>thead>tr>th {
            padding: 5px;
            font-size: 90%;
        }
    </style>
</head>

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

    <header class="main-header">
        <nav class="navbar navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <a href="#" class="navbar-brand"><b>ksbysample-lending</b></a>
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
                        <i class="fa fa-bars"></i>
                    </button>
                </div>

                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">メニュー <span class="caret"></span></a>
                            <ul class="dropdown-menu" role="menu">
                                <li><a href="/booklist">貸出希望書籍登録</a></li>
                                <li><a href="/lendingapp">貸出申請</a></li>
                                <li><a href="/confirmresult">貸出申請結果確認</a></li>
                                <li class="divider"></li>
                                <li><a href="/lendingapproval">貸出承認</a></li>
                                <li class="divider"></li>
                                <li><a href="/admin/library">検索対象図書館登録</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
                <!-- /.navbar-collapse -->
                
                <!-- Navbar Right Menu -->
                <div class="navbar-custom-menu">
                    <p class="navbar-text noselected-library">※図書館が選択されていません</p>
                    <ul class="nav navbar-nav">
                        <li><a href="/logout">ログアウト</a></li>
                    </ul>
                </div>
                <!-- /.navbar-custom-menu -->
            </div>
            <!-- /.container-fluid -->
        </nav>
    </header>

    <!-- 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">
                        <div class="box">
                            <div class="box-head">
                                <form>
                                    <table class="table">
                                        <tbody>
                                            <tr>
                                                <th class="col-xs-8 col-sm-4">
                                                    <input type="text" name="pref" id="pref" class="form-control input-sm" value="" placeholder="都道府県名を入力してください"/>
                                                </th>
                                                <th class="col-xs-2 col-sm-2">
                                                    <button class="btn btn-sm bg-orange js-search-library"><i class="fa fa-search"></i> 検索</button>
                                                </th>
                                                <th></th>
                                            </tr>
                                        </tbody>
                                    </table>
                                </form>
                            </div>
                            <div class="box-body no-padding">
                                <table class="table table-hover">
                                    <colgroup>
                                        <col width="5%"/>
                                        <col width="20%"/>
                                        <col width="30%"/>
                                        <col width="45%"/>
                                    </colgroup>
                                    <thead class="bg-purple">
                                        <tr>
                                            <th></th>
                                            <th class="hidden-xs">systemname</th>
                                            <th>formal</th>
                                            <th>address</th>
                                        </tr>
                                    </thead>
                                    <tbody class="jp-gothic">
                                    <tr>
                                        <th><button class="btn btn-sm bg-blue">選択</button></th>
                                        <th class="hidden-xs">アジア・アフリカ図書館</th>
                                        <th>アジア・アフリカ図書館</th>
                                        <th>東京都三鷹市新川5-14-16</th>
                                    </tr>
                                    <tr>
                                        <th><button class="btn btn-sm bg-blue">選択</button></th>
                                        <th class="hidden-xs">米国大使館レファレンス資料室</th>
                                        <th>アメリカンセンターJapan</th>
                                        <th>東京都港区赤坂1-1-14 NOF溜池ビル8階</th>
                                    </tr>
                                    <tr>
                                        <th><button class="btn btn-sm bg-blue">選択</button></th>
                                        <th class="hidden-xs">農林水産関係試験研究機関総合目録</th>
                                        <th>農林水産省図書館農林水産政策研究所分館</th>
                                        <th>東京都千代田区霞が関3-1-1 中央合同庁舎第4号館9F</th>
                                    </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

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

<!-- jQuery 2.1.4 -->
<script src="/js/jQuery-2.1.4.min.js" type="text/javascript"></script>
<!-- Bootstrap 3.3.2 JS -->
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<!-- AdminLTE App -->
<script src="/js/app.min.js" type="text/javascript"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function() {
        $('#pref').focus();
    });
    -->
</script>
</body>
</html>

head-cssjs.html

    <!-- Bootstrap 3.3.4 -->
    <link href="/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    <!-- Font Awesome Icons -->
    <link href="/css/font-awesome.min.css" rel="stylesheet" type="text/css"/>
    <!-- Ionicons -->
    <link href="/css/ionicons.min.css" rel="stylesheet" type="text/css"/>
    <!-- Theme style -->
    <link href="/css/AdminLTE.min.css" rel="stylesheet" type="text/css"/>
    <!-- AdminLTE Skins. Choose a skin from the css/skins
         folder instead of downloading all of them to reduce the load. -->
    <link href="/css/skins/_all-skins.min.css" rel="stylesheet" type="text/css"/>
    
    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="/js/html5shiv.min.js"></script>
        <script src="/js/respond.min.js"></script>
    <![endif]-->

bottom-js.html

<!-- jQuery 2.1.4 -->
<script src="/js/jQuery-2.1.4.min.js" type="text/javascript"></script>
<!-- Bootstrap 3.3.2 JS -->
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<!-- AdminLTE App -->
<script src="/js/app.min.js" type="text/javascript"></script>

mainparts.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"/>
    <!-- Bootstrap 3.3.4 -->
    <link href="/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    <!-- Font Awesome Icons -->
    <link href="/css/font-awesome.min.css" rel="stylesheet" type="text/css"/>
    <!-- Ionicons -->
    <link href="/css/ionicons.min.css" rel="stylesheet" type="text/css"/>
    <!-- Theme style -->
    <link href="/css/AdminLTE.min.css" rel="stylesheet" type="text/css"/>
    <!-- AdminLTE Skins. Choose a skin from the css/skins
         folder instead of downloading all of them to reduce the load. -->
    <link href="/css/skins/_all-skins.min.css" rel="stylesheet" type="text/css"/>

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="/js/html5shiv.min.js"></script>
        <script src="/js/respond.min.js"></script>
    <![endif]-->

    <style>
        .noselected-library {
            color: #ff8679 !important;
            font-size: 100%;
            font-weight: 700;
        }
        .selected-library {
            color: #ffffff !important;
            font-size: 100%;
            font-weight: 700;
        }
        .content-wrapper {
            background-color: #fffafa;
        }
    </style>
</head>

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

    <!-- Main Header -->
    <header class="main-header" th:fragment="main-header">
        <nav class="navbar navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <a href="#" class="navbar-brand"><b>ksbysample-lending</b></a>
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
                        <i class="fa fa-bars"></i>
                    </button>
                </div>

                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">メニュー <span class="caret"></span></a>
                            <ul class="dropdown-menu" role="menu">
                                <li><a href="/booklist">貸出希望書籍登録</a></li>
                                <li><a href="/lendingapp">貸出申請</a></li>
                                <li><a href="/confirmresult">貸出申請結果確認</a></li>
                                <li class="divider"></li>
                                <li><a href="/lendingapproval">貸出承認</a></li>
                                <li class="divider"></li>
                                <li><a href="/admin/library">検索対象図書館登録</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
                <!-- /.navbar-collapse -->

                <!-- Navbar Right Menu -->
                <div class="navbar-custom-menu">
                    <p class="navbar-text noselected-library">※図書館が選択されていません</p>
                    <ul class="nav navbar-nav">
                        <li><a href="/logout">ログアウト</a></li>
                    </ul>
                </div>
                <!-- /.navbar-custom-menu -->
            </div>
            <!-- /.container-fluid -->
        </nav>
    </header>

    <!-- 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">
                ここに画面本体を入れる
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

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

<!-- jQuery 2.1.4 -->
<script src="/js/jQuery-2.1.4.min.js" type="text/javascript"></script>
<!-- Bootstrap 3.3.2 JS -->
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<!-- AdminLTE App -->
<script src="/js/app.min.js" type="text/javascript"></script>
</body>
</html>

library.html

■その1

<!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>
        .jp-gothic {
            font-family: Verdana, "游ゴシック", YuGothic, "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
        }
        .noselected-library {
            color: #ff8679 !important;
            font-size: 100%;
            font-weight: 700;
        }
        .selected-library {
            color: #ffffff !important;
            font-size: 100%;
            font-weight: 700;
        }
        .content-wrapper {
            background-color: #fffafa;
        }
        .table>tbody>tr>td
        , .table>tbody>tr>th
        , .table>tfoot>tr>td
        , .table>tfoot>tr>th
        , .table>thead>tr>td
        , .table>thead>tr>th {
            padding: 5px;
            font-size: 90%;
        }
    </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">
                        <div class="box">
                            <div class="box-head">
                                <form id="searchLibraryForm" method="post" action="#" th:action="@{/}">
                                    <table class="table">
                                        <tbody>
                                            <tr>
                                                <th class="col-xs-8 col-sm-4">
                                                    <input type="text" name="pref" id="pref" class="form-control input-sm" value="" placeholder="都道府県名を入力してください"/>
                                                </th>
                                                <th class="col-xs-2 col-sm-2">
                                                    <button class="btn btn-sm bg-orange js-search-library"><i class="fa fa-search"></i> 検索</button>
                                                </th>
                                                <th></th>
                                            </tr>
                                        </tbody>
                                    </table>
                                </form>
                            </div>
                            <div class="box-body no-padding">
                                <table class="table table-hover">
                                    <colgroup>
                                        <col width="5%"/>
                                        <col width="20%"/>
                                        <col width="30%"/>
                                        <col width="45%"/>
                                    </colgroup>
                                    <thead class="bg-purple">
                                        <tr>
                                            <th></th>
                                            <th class="hidden-xs">systemname</th>
                                            <th>formal</th>
                                            <th>address</th>
                                        </tr>
                                    </thead>
                                    <tbody class="jp-gothic">
                                    <tr>
                                        <th>
                                            <button class="btn btn-sm bg-blue js-select-library"
                                                    data-systemid="Special_Aacf"
                                                    data-formal="アジア・アフリカ図書館">選択</button>
                                        </th>
                                        <th class="hidden-xs">アジア・アフリカ図書館</th>
                                        <th>アジア・アフリカ図書館</th>
                                        <th>東京都三鷹市新川5-14-16</th>
                                    </tr>
                                    <tr>
                                        <th>
                                            <button class="btn btn-sm bg-blue js-select-library"
                                                    data-systemid="Special_Acrs"
                                                    data-formal="アメリカンセンターJapan">選択</button>
                                        </th>
                                        <th class="hidden-xs">米国大使館レファレンス資料室</th>
                                        <th>アメリカンセンターJapan</th>
                                        <th>東京都港区赤坂1-1-14 NOF溜池ビル8階</th>
                                    </tr>
                                    <tr>
                                        <th>
                                            <button class="btn btn-sm bg-blue js-select-library"
                                                    data-systemid="Special_Affrc"
                                                    data-formal="農林水産省図書館農林水産政策研究所分館">選択</button>
                                        </th>
                                        <th class="hidden-xs">農林水産関係試験研究機関総合目録</th>
                                        <th>農林水産省図書館農林水産政策研究所分館</th>
                                        <th>東京都千代田区霞が関3-1-1 中央合同庁舎第4号館9F</th>
                                    </tr>
                                    </tbody>
                                </table>
                                <form id="setSelectedLibraryForm" method="post" action="/admin/library/addSearchLibrary" th:action="@{/admin/library/addSearchLibrary}">
                                    <input type="hidden" name="systemid" value=""/>
                                    <input type="hidden" name="formal" value=""/>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

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

<script th:replace="common/bottom-js"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function() {
        $('#pref').focus();

        $('.js-search-library').click(function(){
            return false;
        });
        
        $('.js-select-library').each(function(){
            $(this).click(function(){
                $("#setSelectedLibraryForm input[name='systemid']").val($(this).attr('data-systemid'));
                $("#setSelectedLibraryForm input[name='formal']").val($(this).attr('data-formal'));
                $('#setSelectedLibraryForm').submit();
            });
        });
    });
    -->
</script>
</body>
</html>
  • 一番上の <html> タグを Thymeleaf テンプレートファイル用のものに変更します。
  • 共通部分の HTML を common/head-cssjs, commono/mainparts.html, common/bottom-js へ切り出し、th:replace で置換するようにします。
  • form タグに id, action 等を追記します。
  • Javascript の処理を割り当てたいボタンに js- で始まるセレクタを追加します。
  • 図書館一覧の「選択」ボタンの button タグに data-systemid, data-formal データ属性を追加します。
  • 「選択」ボタンが押された時の処理に使用するフォーム <form id="setSelectedLibraryForm" ...> ... </form> を追加します。
  • 「検索」ボタン、「選択」ボタンが押された時の Javascript の処理を追加します。

■その2

<!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>
        .jp-gothic {
            font-family: Verdana, "游ゴシック", YuGothic, "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
        }
        .noselected-library {
            color: #ff8679 !important;
            font-size: 100%;
            font-weight: 700;
        }
        .selected-library {
            color: #ffffff !important;
            font-size: 100%;
            font-weight: 700;
        }
        .content-wrapper {
            background-color: #fffafa;
        }
        .table>tbody>tr>td
        , .table>tbody>tr>th
        , .table>tfoot>tr>td
        , .table>tfoot>tr>th
        , .table>thead>tr>td
        , .table>thead>tr>th {
            padding: 5px;
            font-size: 90%;
        }
    </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">
                        <div class="box">
                            <div class="box-head">
                                <form id="searchLibraryForm" method="post" action="#" th:action="@{/}">
                                    <table class="table">
                                        <tbody>
                                            <tr>
                                                <th class="col-xs-8 col-sm-4">
                                                    <input type="text" name="pref" id="pref" class="form-control input-sm" value="" placeholder="都道府県名を入力してください"/>
                                                </th>
                                                <th class="col-xs-2 col-sm-2">
                                                    <button class="btn btn-sm bg-orange js-search-library"><i class="fa fa-search"></i> 検索</button>
                                                </th>
                                                <th></th>
                                            </tr>
                                        </tbody>
                                    </table>
                                </form>
                            </div>
                            <div class="box-body no-padding">
                                <table id="library-list" class="table table-hover">
                                    <colgroup>
                                        <col width="5%"/>
                                        <col width="20%"/>
                                        <col width="30%"/>
                                        <col width="45%"/>
                                    </colgroup>
                                    <thead class="bg-purple">
                                        <tr>
                                            <th></th>
                                            <th>systemname</th>
                                            <th class="hidden-xs">formal</th>
                                            <th>address</th>
                                        </tr>
                                    </thead>
                                    <tbody id="library-list-body" class="jp-gothic">
                                        <!-- ここにカーリル図書館APIで取得した図書館データを表示する -->
                                    </tbody>
                                </table>
                                <form id="setSelectedLibraryForm" method="post" action="/admin/library/addSearchLibrary" th:action="@{/admin/library/addSearchLibrary}">
                                    <input type="hidden" name="systemid" value=""/>
                                    <input type="hidden" name="formal" value=""/>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
            <!-- /.content -->
        </div>
        <!-- /.container -->
    </div>

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

<script th:replace="common/bottom-js"></script>
<script type="text/javascript">
    <!--
    $(document).ready(function() {
        $('#pref').focus();

        $('.js-search-library').click(function(){
            if (!$('#pref').val()) {
                alert("都道府県名を入力してください");
                return false;
            }
            
            $.ajax({
                type: "get",
                url: "/webapi/library/getLibraryList",
                data: { pref: $('#pref').val() },
                async: false,
                dataType: "json",
                success: function(json) {
                    if (json.errcode == 0) {
                        $('#library-list-body tr').remove();
                        for (var i = 0; i < json.content.length; i++) {
                            var library = "<tr>"
                                                + "<th>"
                                                    + "<button class=\"btn btn-sm bg-blue js-select-library\""
                                                        + "data-systemid=\"" + json.content[i].systemid + "\""
                                                        + "data-formal=\"" + json.content[i].formal + "\">選択</button>"
                                                + "</th>"
                                                + "<th class=\"hidden-xs\">" + json.content[i].systemname + "</th>"
                                                + "<th>" + json.content[i].formal + "</th>"
                                                + "<th>" + json.content[i].address + "</th>"
                                            + "</tr>";
                            $('#library-list-body').append(library);
                        }
                    }
                    else {
                        alert(json.errmsg);
                    }
                }
            });

            $('#pref').focus().select();
            
            return false;
        });
        
        $('.js-select-library').each(function(){
            $(this).click(function(){
                $("#setSelectedLibraryForm input[name='systemid']").val($(this).attr('data-systemid'));
                $("#setSelectedLibraryForm input[name='formal']").val($(this).attr('data-formal'));
                $('#setSelectedLibraryForm').submit();
            });
        });
    });
    -->
</script>
</body>
</html>
  • <tbody id="library-list-body" class="jp-gothic"> ... </tbody> の中は Javascript で動的に出力するので記述を全て削除します。
  • 「検索」ボタンが押された時の処理を $('.js-search-library').click(function(){ ... }); に記述します。
  • エラー時に WebAPI の HTTPステータスコードを 200 にしたままだったのでエラーハンドラで処理を記述することができないことに気づきましたが、今回はそのままにします。。。

AdminLibraryController.java

package ksbysample.webapp.lending.web.admin.library;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/admin/library")
public class AdminLibraryController {

    @RequestMapping
    public String index() {
        return "admin/library/library";
    }

    @RequestMapping("/addSearchLibrary")
    public String addSearchLibrary() {
        return "admin/library/library";
    }
    
}

Library.java

package ksbysample.webapp.lending.service.calilapi;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

@Data
@Root(name = "Library", strict = false)
public class Library {

    @Element
    private String systemid;

    @Element
    private String systemname;

    @Element(name = "formal")
    @JsonProperty("formal")
    private String formalName;

    @Element
    private String address;

}
  • JSON で返す時に名前を変えるために private String formalName;@JsonProperty("formal") を付加します。

履歴

2015/09/05
初版発行。