LoginSignup
3
3

More than 5 years have passed since last update.

[初心者向け] Spring MVC + JSP + Bootstrap 3 の使い方(Form編)

Last updated at Posted at 2018-10-28

前回は、Spring MVC(TERASOLUNA 5)にBootstrap 3を適用する方法を解説しましたが、今回は入力フォームの実装方法を解説してみたいと思います。

アプリのベースとしては、TERASOLUNA 5のブランクプロジェクトを使用しますが、基本的にSpring MVCアプリには適用できます。

今回使用するライブラリ

  • TERASOLUNA GFW 5.4.1.RELEASE
    • Spring MVC 4.3.14.RELEASE
  • Bootstrap 3.3.7
  • Bootstrap DatePicker 1.8.0
  • JQuery Bootstrap 3.3.1

執筆時点で、Bootstrapの最新verは4.1.3です。HTMLに適用するクラス名に違いはありますが、基本的に同じノリで適用できるはずですが、マイグレーションが難しそうなら別に記事を書くかもしれません。

(前置き)Bootstrapのパネルを適用する

入力フォームとは直接関係ありませんが、画面にパネルを適用することで、画面の表示項目を整理することができます。

    <div id="wrapper" class="container-fluid">

        <div class="panel panel-default">
            <div class="panel-heading"><!-- 入力フォームのタイトル --></div>
            <div class="panel-body">
                <!-- ここに入力フォームを実装する -->
            </div>
        </div>
    </div>

divタグにpanelクラスを付与すると、パネルが生成される。
divタグにpanel-headingクラスを付与すると、パネルのタイトルになる。
divタグにpanel-bodyクラスを付与すると、パネルのコンテンツになる。

panel-defaultはパネルの色を指定するクラスで、以下の色が指定できます。
* -primary(青)
* -success(緑)
* -info(水色)
* -warning(黄色)
* -danger(赤)

以降は、パネルのコンテンツに入力フォームを実装していきます。`

ベーシックな入力フォームを実装する

まずは、ベーシックな入力フォームを実装してみます。

  • 期待するHTML
<form method="post" action="/sample">

    <!-- (1) -->
    <div class="form-group">
        <label for="input" class="control-label">Input</label>
        <input id="input" name="input" class="form-control" placeholder="Input" />
        <span id="input.errors" class="help-block">Error Message</span>
    </div>

    <!-- (2) -->
    <button type="submit" class="btn btn-primary">Submit</button>
    <button type="reset" class="btn btn-default">Reset</button>

</form>

(1)
入力項目のラベル・入力フィールド・エラーメッセージをdivタグで囲み、form-groupクラスを付与する。
ラベルにcontrol-labelクラスを付与する。
入力フィールドにform-controlクラスを付与する。
エラーメッセージにhelp-blockクラスを付与する。

これを1セットとして、すべての入力項目に適用すると、Bootstrapにより入力項目がきれいに並べられます。

入力フィールドのplaceholderで、入力例や入力条件を示しておくと、ユーザビリティがアップします。

(2)
ボタンにbtnクラスを付与する。

これにより、ボタンやリンクをBootstrapのボタンデザインに統一することができます。

ボタンの色と位置のルールを統一すると、アプリのアクセシビリティがアップします。
* ポジティブなアクションのボタンは青系、ネガティブなアクションのボタンは赤系とか
* ポジティブなアクションのボタンは右側、ネガティブなアクションのボタンは左側とか

  • JSPの実装
<!-- (1) -->
<form:form method="post" action="${pageContext.request.contextPath}/sample"
    modelAttribute="inputForm">

    <!-- (2) -->
    <div class="form-group">
        <form:label path="input" cssClass="control-label">Input</form:label>
        <form:input path="input" cssClass="form-control" placeholder="Input" />
        <form:errors path="input" cssClass="help-block" />
    </div>

    <!-- (3) -->
    <form:button class="btn btn-primary">Submit</form:button>
    <form:button class="btn btn-default" type="reset">Reset</form:button>

</form:form>

(1)
form:formタグを利用して、モデルとバインドする。

(2)
form:labelタグのcssClasscontrol-labelクラスを付与する。
form:inputタグのcssClassform-controlクラスを付与する。
form:errorsタグのcssClasshelp-blockクラスを付与する。

idnamepathから自動的に付与されます。

(3)
form:buttonタグではclassbtnクラスを付与する。

form:buttonタグにはcssClassがないので、注意しましょう。
type="submit"は自動的に付与されるので、それ以外にしたいときだけtypeを付与します。

Inlineな入力フォームを実装する

すべての入力項目を一行で表現する入力フォームを実装します。

  • 期待するHTML
<form method="post" action="/sample" class="form-inline">
  ...
</form>

formタグにform-inlineクラスを付与する。

これだけです。

  • JSPの実装
<form:form method="post" action="${pageContext.request.contextPath}/sample"
    modelAttribute="inputForm" class="form-inline">
  ...
</form:form>

JSPも同じように実装できます。

Horizontalな入力フォームを実装する

ひとつの入力項目を一行で表現する入力フォームを実装します。

  • 期待するHTML
<!-- (1) -->
<form method="post" action="/sample" class="form-horizontal">

    <!-- (2) -->
    <div class="form-group">
        <label for="input" class="control-label col-sm-2">Input</label>
        <div class="col-sm-10">
            <input id="input" name="input" class="form-control" placeholder="Input" />
            <span id="input.errors" class="help-block">Error Message</span>
        </div>
    </div>

    <!-- (3) -->
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-primary">Submit</button>
            <button type="reset" class="btn btn-default">Reset</button>
        </div>
    </div>

</form>

(1)
formタグにform-horizontalクラスを付与する。

(2)
col-sm-2クラスを付与して、ラベルと入力フィールドの表示位置を調整する。

Bootstrapでは1行を12分割して表示位置を調整することができ、col-sm-の合計が12になるよう数字を調整するだけでOKです。
入力フィールドはdivで囲んでcol-sm-を付与する必要があることに注意しましょう。

(3)
ボタンをform-groupdivで囲み、さらにcol-sm-divで表示位置を調整する。

col-sm-offset-は見たままですが、オフセットを指定してボタンを入力フィールドと並べます。

  • JSPの実装
<form:form method="post" action="${pageContext.request.contextPath}/sample"
    modelAttribute="inputForm"  class="form-horizontal">

    <div class="form-group">
        <form:label path="input" cssClass="control-label col-sm-2">Input</form:label>
        <div class="col-sm-10">
            <form:input path="input" cssClass="form-control" placeholder="Input" />
            <form:errors path="input" cssClass="help-block" />
        </div>
    </div>

    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <form:button class="btn btn-primary">Submit</form:button>
            <form:button class="btn btn-default" type="reset">Reset</form:button>
        </div>
    </div>

</form:form>

JSPも同じように実装できます。

入力チェックエラー時にスタイルを変更する

入力チェックエラーになった入力項目(ラベル・入力フィールド・エラーメッセージ)を赤く表示してみます。

  • 期待するHTML
<form method="post" action="/sample">

    <!-- (1) -->
    <div class="form-group has-error">
        <label for="input" class="control-label">Input</label>
        <input id="input" name="input" class="form-control" placeholder="Input" />
        <span id="input.errors" class="help-block">Error Message</span>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
    <button type="reset" class="btn btn-default">Reset</button>

</form>

(1)
入力項目を囲むdivタグにhas-errorクラスを付与する。

これだけで、ラベル・入力フィールドの枠・エラーメッセージが赤く表示されます。
control-labelform-controlhelp-blockクラスがついていないと色が変わらないので注意。

  • JSPの実装
<form:form method="post" action="${pageContext.request.contextPath}/sample"
    modelAttribute="inputForm">

    <!-- (1) -->
    <spring:hasBindErrors name="inputForm">
        <c:set var="errors" value="${errors}" />
    </spring:hasBindErrors>

    <!-- (2) -->
    <div class="form-group ${errors.hasFieldErrors('input') ? 'has-error' : ''}">
        <form:label path="input" cssClass="control-label">Input</form:label>
        <form:input path="input" cssClass="form-control" placeholder="Input" />
        <form:errors path="input" cssClass="help-block" />
    </div>

    <form:button class="btn btn-primary">Submit</form:button>
    <form:button class="btn btn-default" type="reset">Reset</form:button>

</form:form>

(1)
spring:hasBindErrorsタグでエラー情報を取得して、c:setタグでページ変数に登録する。

入力チェックエラーかどうかを判定する必要がありますが、エラー情報を参照するためには一工夫必要です。

spring:hasBindErrorsタグは、エラーがあるときだけ有効になり、そのタグ内でだけエラー情報を参照可能にするタグです。
spring:hasBindErrorsタグをまっとうに利用して正常時とエラー時の画面を実装するのはかなり面倒なので、エラー情報だけいただいてフレキシブルなエラー判定を可能にします。

これはControllerでmodel.addAttribute("errors", bindingResult)してるのと同じです。

(2)
入力項目を囲むdivタグでEL式を利用して、エラーのときだけhas-errorクラスを付与する。

errorsはController引数で扱うのと同じBindingResultオブジェクトです。
BindingResult#hasFieldErrors(フィールド名)で、入力チェックエラーかどうかを判定することができます。

入力チェックエラーメッセージをツールチップに表示する

エラーメッセージをツールチップに表示してみます。

通常、ツールチップを表示するには、入力フィールドにdata-toggle="tooltip"title="メッセージ"を付与しますが、Spring MVCではエラーメッセージを入力フィールドとは別に出力するので、自前でツールチップに表示してあげる必要があります。

  • JSPの実装
<form:form method="post" action="${pageContext.request.contextPath}/sample"
    modelAttribute="inputForm">

    <div class="form-group">
        <form:label path="input" cssClass="control-label">Input</form:label>
        <form:input path="input" cssClass="form-control" placeholder="Input" />
        <!-- (1) -->
        <form:errors path="input" cssClass="hidden" />
    </div>

    <form:button class="btn btn-primary">Submit</form:button>
    <form:button class="btn btn-default" type="reset">Reset</form:button>

</form:form>

...

<!-- (2) -->
<script type="text/javascript">
    $('.form-control').tooltip({
        html : true,
        title : function() {
            return $('#' + $(this).attr('id') + '\\.errors').html();
        }
    });
</script>


(1)
form:errorsタグにhiddenクラスを付与し、エラーメッセージを非表示にする。

(2)
画面の最下部で、入力フィールドのツールチップを有効にします。

form-controlクラスが付与された入力フィールドにツールチップに、form:errorsタグで出力したエラーメッセージをセットしています。
form:errorsタグは、[フィールド名].errorsというidでエラーメッセージを出力するので、idでフックしています。

入力部品

入力部品:select

select項目を実装します。

Bootstrap的には通常の入力フィールドと変わらないので、期待するHTMLは省略します。

  • JSPの実装
    <div class="form-group">
        <form:label path="select" cssClass="control-label">Select</form:label>
        <form:select path="select" cssClass="form-control">
            <form:option value="">Please Select...</form:option>
            <form:options items="${selectList}" />
        </form:select>
        <form:errors path="select" cssClass="help-block" />
    </div>

入力部品:チェックボックス

チェックボックス項目を実装します。

Spring MVCのform:checkboxesタグでは実現できないので、少々実装が面倒です。

  • 期待するHTML
    <div class="form-group">
        <!-- (1) -->
        <label class="control-label">CheckBox</label>
        <!-- (2) -->
        <label for="checkboxes1" class="checkbox-inline">
            <input type="checkbox" id="checkboxes1" name="checkboxes1" value="1">[1]
        </label>
        <label for="checkboxes2" class="checkbox-inline">
            <input type="checkbox" id="checkboxes2" name="checkboxes2" value="2">[2]
        </label>
        <label for="checkboxes3" class="checkbox-inline">
            <input type="checkbox" id="checkboxes3" name="checkboxes3" value="3">[3]
        </label>
        <span id="checkboxes.errors" class="help-block">Error Message</span>
    </div>

(1)
チェックボックス項目全体のラベルは、入力フィールドに紐づけない。

(2)
入力フィールドをラベルで囲んで、checkbox-inlineクラスを付与する。

labelタグのforinputタグのidがひとつずつリンクしているのがポイントです。

  • JSPの実装
    <div class="form-group">
        <!-- (1) -->
        <label class="control-label">CheckBox</label>
        <!-- (2) -->
        <c:forEach items="${selectList}" var="item" varStatus="status">
            <label for="checkboxes${status.count}" class="checkbox-inline">
                <form:checkbox path="checkboxes" value="${item.key}" />${item.value}
            </label>
        </c:forEach>
        <form:errors path="checkboxes" cssClass="help-block" />
    </div>

(1)
チェックボックス項目全体のラベルは、form:labelでなくlabelタグを使う。

(2)
form:checkboxesタグは使用せず、自前で繰り返してラベルと入力フィールドを出力する。

form:checkboxesタグだとlabelタグにクラスを付与できないので、自前で出力する必要があります。
その際、form:labelタグではforにインデックスがつかないので、labelタグを使う必要があります。

入力部品:ラジオボタン

ラジオボタン項目を実装します。

checkbox項目と同様に、Spring MVCのform:radiobuttonsタグでは実現できないので、少々実装が面倒です。

  • 期待するHTML
    <div class="form-group">
        <!-- (1) -->
        <label class="control-label">Radio</label>
        <!-- (2) -->
        <label for="radio1" class="radio-inline">
            <input type="radio" id="radio1" name="radio" value="1">[1]
        </label>
        <label for="radio2" class="radio-inline">
            <input type="radio" id="radio2" name="radio" value="2">[2]
        </label>
        <label for="radio3" class="radio-inline">
            <input type="radio" id="radio3" name="radio" value="3">[3]
        </label>
        <span id="radio.errors" class="help-block">Error Message</span>
    </div>

(1)
ラジオボタン項目全体のラベルは、入力フィールドに紐づけない。

(2)
入力フィールドをラベルで囲んで、radio-inlineクラスを付与する。

labelタグのforinputタグのidがひとつずつリンクしているのがポイントです。

  • JSPの実装
    <div class="form-group">
        <!-- (1) -->
        <label class="control-label">Radio</label>
        <!-- (2) -->
        <c:forEach items="${selectList}" var="item" varStatus="status">
            <label for="radio${status.count}" class="radio-inline">
                <form:radiobutton path="radio" value="${item.key}" />${item.value}
            </label>
        </c:forEach>
        <form:errors path="radio" cssClass="help-block" />
    </div>

(1)
ラジオボタン項目全体のラベルは、form:labelでなくlabelタグを使う。

(2)
form:radiobuttonsタグは使用せず、自前で繰り返してラベルと入力フィールドを出力する。

form:radiobuttonsタグだとlabelタグにクラスを付与できないので、自前で出力する必要があります。
その際、form:labelタグではforにインデックスがつかないので、labelタグを使う必要があります。

入力部品:日付

日付項目を実装します。

BootstrapのアシストライブラリBootstrap DatePickerを利用すると、日付選択ダイアログを表示することができます。

Bootstrap DatePickerは、CDNまたはダウンロードして参照します。WebJarsとしては提供されていないようです。

  • JSPの実装
<html>
<head>
<!-- BootstrapやJQueryの参照は省略します -->
<!-- (1) -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/app/css/bootstrap-datepicker3.min.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/app/js/bootstrap-datepicker.min.js"></script>
</head>
<body>

    ...

    <div class="form-group">
        <form:label path="date" cssClass="control-label">Date</form:label>
        <!-- (3) -->
        <form:input path="date" cssClass="form-control date" placeholder="Date" />
        <form:errors path="date" cssClass="help-block" />
    </div>

    ...

    <!-- (2) -->
    <script type="text/javascript">
        $('.date').datepicker({
            format : 'yyyy-mm-dd'
        });
    </script>

</body>
</html>

(1)
Bootstrap DatePickerへの参照を追加します。

ここでは、事前にダウンロードしたCSS・JSファイルを参照しています。

(2)
画面の最下部で、Bootstrap DatePickerを有効にします。

ここでは、dateクラスが付与された項目に対してBootstrap DatePickerを有効にしています。

HTMLの特定の要素に紐づけるため、scriptタグはbodyタグの終わりに書く必要があります。
オプションで日付フォーマットを指定できるので、入力項目をバインドするフィールドの@DateTimeFormatと一致させましょう。

他に、選択する日付を制限できたり、様々な言語に対応していたりします。

(3)
入力フィールドを、Bootstrap DatePickerを有効にする条件と合致させます。

(2)に従い、dateクラスを付与しています。

まとめ

今回は、Spring MVC(TERASOLUNA 5)アプリでBootstrap 3を利用した入力フォームを実装する方法をまとめてみました。

BootstrapのようなCSSフレームワークを使うと、手軽に画面デザインを洗練することができて良いのですが、Spring MVC+JSPのように一部のHTMLを自動的に構築してくれるフレームワークとはかみ合わない場合が多々あります。

このような問題を解決するポイントは、CSSフレームワークとAPフレームワーク双方が意図するHTMLの構造を把握することにあります。これを踏まえて、CSSフレームワークを使用するかどうかを検討すると良いですね。

次回は、Bootstrap 3を利用したテーブル表示の実装方法についてまとめます。

参考資料

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3