Spring Boot + npm + Geb で入力フォームを作ってテストする ( その8 )( 各画面の HTML を作成する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その7 )( webpack + browser-sync をインストールする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- 各画面の HTML を作成します。
- 今回は入力画面1だけです。2~3回に分ける予定です。
参照したサイト・書籍
Bootstrap3でFormを簡単に作る方法
http://tetra-themes.com/bootstrap3-form-197/Bootstrap3日本語リファレンス - CSS - フォーム - サポートしているフォーム部品
http://bootstrap3.cyberlab.info/css/forms-supportedControls.htmlForm inline inside a form horizontal in twitter bootstrap?
https://stackoverflow.com/questions/12201835/form-inline-inside-a-form-horizontal-in-twitter-bootstrapリキッド・レイアウトでチェックボックスを綺麗に並べる
http://webos-goodies.jp/archives/51275332.htmlnpm-scripts で作るフロントエンド環境の構築
http://ceblog.mediba.jp/post/154522336717/npm-scripts
目次
- 画面の仕様を決める
- starter.html からテンプレートに使用する template.html を作成する
- src/main/assets/css の下で更新された css ファイルを自動で src/main/resources/static/css の下に反映する仕組みを作成する
- 画面共通で使用する css ファイルを作成する
- 入力画面1の HTML を作成する
手順
画面の仕様を決める
「Spring Boot + npm + Geb で入力フォームを作ってテストする」は Geb でのテストのサンプルを作成することが目的なので、いろいろ要素を盛り込みます。
- 入力項目には以下の要素を入れます。
- 画面の入力チェックは Javascript で行います。入力チェックエラー時にはラベルと入力フィールドを赤く表示し、入力項目の下にエラーメッセージが表示されるようにします。
- Ajax でデータを送受信する仕組みも入れます。「郵便番号」を入力したら「住所」に都道府県・市区町村・町丁目名がセットされるようにします。郵便番号検索API を利用する想定です。
starter.html からテンプレートに使用する template.html を作成する
作業開始前にコマンドプロンプトで npm run server
コマンドを実行して browser-sync を起動しておきます。
node_modules/admin-lte/starter.html を static の下にコピーし、ファイル名を template.html に変更した後、以下の点を変更します。
- header タグ内の以下の部分を変更します。
<title>AdminLTE 2 | Starter</title>
→<title>入力フォーム</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
→<link rel="stylesheet" href="/vendor/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
→<link rel="stylesheet" href="/vendor/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">
→<link rel="stylesheet" href="/vendor/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="dist/css/AdminLTE.min.css">
→<link rel="stylesheet" href="/vendor/admin-lte/css/AdminLTE.min.css">
<link rel="stylesheet" href="dist/css/skins/skin-blue.min.css">
→<link rel="stylesheet" href="/vendor/admin-lte/css/skins/skin-blue.min.css">
- 以下の2行は削除します。
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<body class="skin-blue layout-top-nav">
→<body class="skin-blue layout-top-nav">
に変更します。- body タグ内の以下の部分は削除します。
<!-- Main Header -->
と<header class="main-header"> ... </header>
の部分<!-- Left side column. contains the logo and sidebar -->
と<aside class="main-sidebar"> ... </aside>
の部分<!-- Main Footer -->
と<footer class="main-footer"> ... </footer>
の部分<!-- Control Sidebar -->
と<aside class="control-sidebar control-sidebar-dark"> ... </aside>
の部分<!-- Add the sidebar's background. This div must be placed immediately after the control sidebar -->
と<div class="control-sidebar-bg"></div>
の部分- js ファイルを読み込んでいる以下の3行。
<script src="plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
<script src="dist/js/app.min.js"></script>
<section class="content-header"> ... </section>
内の以下の部分を削除します。<small>Optional description</small>
<ol class="breadcrumb"> ... </ol>
の部分
- あとはコメントで残す必要がないものも全て削除します。
ここまでの変更で template.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.6 --> <link rel="stylesheet" href="/vendor/bootstrap/css/bootstrap.min.css"> <!-- Font Awesome --> <link rel="stylesheet" href="/vendor/font-awesome/css/font-awesome.min.css"> <!-- Ionicons --> <link rel="stylesheet" href="/vendor/ionicons/css/ionicons.min.css"> <!-- Theme style --> <link rel="stylesheet" href="/vendor/admin-lte/css/AdminLTE.min.css"> <link rel="stylesheet" href="/vendor/admin-lte/css/skins/skin-blue.min.css"> </head> <body class="hold-transition skin-blue sidebar-mini"> <div class="wrapper"> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Page Header </h1> </section> <!-- Main content --> <section class="content"> <!-- Your Page Content Here --> </section> <!-- /.content --> </div> <!-- /.content-wrapper --> </div> <!-- ./wrapper --> <!-- REQUIRED JS SCRIPTS --> </body> </html>
http://localhost:9080/template.html にアクセスして画面を表示すると以下の画像のようになります。
Ctrl+C を押して npm run server
コマンドを一旦停止します。
src/main/assets/css の下で更新された css ファイルを自動で src/main/resources/static/css の下に反映する仕組みを作成する
src/main/assets/css の下に common.css を新規作成し、変更されたら自動で src/main/resources/static/css の下にコピーする仕組みを作成します。変更の検知は cpx の watch 機能を利用します。
src/main/assets の下に css ディレクトリを新規作成し、その下に common.css を新規作成します。この時点では common.css の中身は空です。
package.json の scripts を以下のように変更します。
"scripts": { .........., "copy:css:watch": "cpx src/main/assets/css/**/* src/main/resources/static/css -w", "server": "run-p copy:css:watch webpack:watch browser-sync:start" },
"copy:css:watch": "cpx src/main/assets/css/**/* src/main/resources/static/css -w"
を追加します。"server"
にcopy:css:watch
を追加します。
static/template.html を以下のように変更します。
<head> .......... <!-- 画面共通で使用する css --> <link rel="stylesheet" href="/css/common.css"> </head>
<link rel="stylesheet" href="/css/common.css">
を追加し、src/main/resources/static/css/common.css を読み込むようにします。
以上で準備は完了です。common.css を変更したら自動でブラウザに反映されるか確認します。
npm run server
コマンドを実行します。
src/main/resources/static の下に css/common.css がコピーされます。
http://localhost:9080/template.html にアクセスすると以下の画面が表示されます。
src/main/assets/css/common.css に背景色を変更する以下の記述を追加します。
/* body 内の背景色を白より少し色がついた色にする */ .content-wrapper { background-color: ivory; }
browser-sync が common.css の変更を検知したことを示すログを出力し、
ブラウザに表示している画面の背景色も手動リロードすることなく変わりました。
画面共通で使用する css ファイルを作成する
src/main/assets/css/common.css に以下の内容を記述します。
- Bootstrap テーマ Honoka と adminLTE で画面を作ってみる から今回必要そうなものを持ってきました。
- 今回は form-horizontal で作成することにします。form-horizontal で作成する際に追加で必要になりそうな定義を追加しました。
/* body 内の背景色を白より少し色がついた色にする */ .content-wrapper { background-color: ivory; } /* フォーカス時の入力フィールドの色合いが adminLTE より Bootstrap のものが好みなので、そちらに定義し直す */ .form-control:focus { border-color: #66afe9; outline: 0; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6); } /* form-control-static の文字列を入力項目のすぐ下に隙間をほとんど空けずに表示されるようにする */ .form-control-static { padding-top: 0px; padding-bottom: 0px; margin-bottom: -15px; } /* 入力チェックエラーの入力項目の背景色を薄い赤色にする */ .has-error .form-control { background-color: #fff5ee; } /* form-horizontal 内で form-control, form-control-static-inline の入力フィールドを横並びで表示する */ .form-control-inline { float:left; margin-right: 10px; } .form-control-static-inline { float: left; padding-top: 7px; margin-right: 10px; } /* checkbox の文字列の右側に少し隙間を空ける */ .checkbox label { margin-right: 10px; } /* 必須ラベル */ /* 767px 以下の場合には必須ラベルを右側に移動する */ @media (min-width: 768px) { .label-required { background-color: red; margin-right: 5px; } .form-group .float-label { float: right; } } @media (max-width: 767px) { .label-required { background-color: red; margin-left: 5px; } } /* 画面下のボタンを大きく表示させる */ .btn { width: 150px; }
入力画面1の HTML を作成する
static の下に inquiry ディレクトリを作成した後、static/template.html をコピーして static/inquiry/input01.html を作成します。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>入力フォーム - 入力画面1</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.6 --> <link rel="stylesheet" href="/vendor/bootstrap/css/bootstrap.min.css"> <!-- Font Awesome --> <link rel="stylesheet" href="/vendor/font-awesome/css/font-awesome.min.css"> <!-- Ionicons --> <link rel="stylesheet" href="/vendor/ionicons/css/ionicons.min.css"> <!-- Theme style --> <link rel="stylesheet" href="/vendor/admin-lte/css/AdminLTE.min.css"> <link rel="stylesheet" href="/vendor/admin-lte/css/skins/skin-blue.min.css"> <!-- 画面共通で使用する css --> <link rel="stylesheet" href="/css/common.css"> </head> <body class="skin-blue layout-top-nav"> <div class="wrapper"> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- 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"> <form id="input01Form" class="form-horizontal" method="post" action=""> <!-- お名前(漢字) --> <div class="form-group" id="form-group-name"> <div class="control-label col-sm-2"> <label class="float-label">お名前(漢字)</label> <div class="label label-required">必須</div> </div> <div class="col-sm-10"> <div class="row"><div class="col-sm-10"> <input type="text" name="lastname" id="lastname" class="form-control form-control-inline" style="width: 150px;" value="" placeholder="例)田中"/> <input type="text" name="firstname" id="firstname" class="form-control form-control-inline" style="width: 150px;" value="" placeholder="例)太郎"/> </div></div> <div class="row hidden js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <!-- お名前(かな) --> <div class="form-group" id="form-group-kana"> <div class="control-label col-sm-2"> <label class="float-label">お名前(かな)</label> <div class="label label-required">必須</div> </div> <div class="col-sm-10"> <div class="row"><div class="col-sm-10"> <input type="text" name="lastkana" id="lastkana" class="form-control form-control-inline" style="width: 150px;" value="" placeholder="例)たなか"/> <input type="text" name="firstkana" id="firstkana" class="form-control form-control-inline" style="width: 150px;" value="" placeholder="例)たろう"/> </div></div> <div class="row hidden js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <!-- 性別 --> <div class="form-group" id="form-group-sex"> <div class="control-label col-sm-2"> <label class="float-label">性別</label> <div class="label label-required">必須</div> </div> <div class="col-sm-10"> <div class="row"><div class="col-sm-10"> <div class="radio-inline"><label><input type="radio" name="sex" value="1">男性</label></div> <div class="radio-inline"><label><input type="radio" name="sex" value="2">女性</label></div> </div></div> <div class="row hidden js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <!-- 年齢 --> <div class="form-group" id="form-group-age"> <div class="control-label col-sm-2"> <label class="float-label">年齢</label> <div class="label label-required">必須</div> </div> <div class="col-sm-10"> <div class="row"><div class="col-sm-10"> <input type="text" name="age" id="age" class="form-control form-control-inline" style="width: 150px;" value="" placeholder="例)30"/> <p class="form-control-static-inline">歳</p> </div></div> <div class="row hidden js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <!-- 職業 --> <div class="form-group" id="form-group-job"> <div class="control-label col-sm-2"> <label class="float-label">職業</label> </div> <div class="col-sm-10"> <div class="row"><div class="col-sm-10"> <select name="job" id="job" class="form-control" style="width: 250px;"> <option value="">選択してください</option> <option value="1">会社員</option> <option value="2">学生</option> <option value="3">その他</option> </select> </div></div> <div class="row hidden js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div> <div class="text-center"> <button class="btn bg-green js-btn-next" disabled><i class="fa fa-arrow-right"></i> 次へ</button> </div> </form> </div> </div> </section> <!-- /.content --> </div> <!-- /.content-wrapper --> </div> <!-- ./wrapper --> <!-- REQUIRED JS SCRIPTS --> <script src="/js/inquiry/input01.js"></script> </body> </html>
画面の初期表示は以下のようになります。
画面上の入力項目を全て入力し、入力チェックでエラーが出なかった場合は以下のようになります。
<!-- 職業 --> <div class="form-group has-success" id="form-group-job"> .......... </div> <div class="text-center"> <button class="btn bg-green js-btn-next"><i class="fa fa-arrow-right"></i> 次へ</button> </div>
- form-group に has-success を追加して
<div class="form-group" ...>
→<div class="form-group has-success" ...>
にします。 - disabled を削除して
<button class="btn bg-green js-btn-next" disabled>
→<button class="btn bg-green js-btn-next">
にします。
入力チェックがエラーだった場合は以下のようになります。
<!-- 職業 --> <div class="form-group has-error" id="form-group-job"> .......... <div class="col-sm-10"> .......... <div class="row js-errmsg"><div class="col-sm-10"><p class="form-control-static text-danger"><small>ここにエラーメッセージを表示します</small></p></div></div> </div> </div>
- form-group に has-error を追加して
<div class="form-group" ...>
→<div class="form-group has-error" ...>
にします。 - エラーメッセージの表示部分から hidden を削除して
<div class="row hidden js-errmsg">
→<div class="row js-errmsg">
にします。
今回 HTML を作成して思いましたが browser-sync が本当に便利です。手動でリロードをしなくてよいのがこんなに便利だとは。もっと早く知りたかった。。。
履歴
2017/07/29
初版発行。