Spring MVCのformタグを簡単にまとめました
Spring MVCの勉強をしていて、Springカスタムタグの日本語情報が少なかったので簡単にまとめまてみました。今回はformタグです。
Springのバージョンは3.1.2を基準にしています。3.1.*系であれば多分動きますが、違う場合には注意が必要です。
記事での説明はあってないようなものなので、動くサンプルを見てもらうのが手っ取り早いと思います。サンプルは、githubに置いてあります。
https://github.com/kuwalab/spring-form-sample
EclipseのWTPの動的Webプロジェクトとして作成しています。
共通の属性
formタグのほとんどで共通している属性があります。
ドキュメントを見るとたくさんあるように見えますが、ほとんどがHTMLに標準的に持っている属性そのままか名称を変えたもの(class→cssClass、style→cssStyle)です。
属性 | 説明 |
---|---|
cssClass | HTML標準のclass属性 |
cssStyle | HTML標準のsytle属性 |
dir | HTML標準のdir属性 |
htmlEscape | 描画する値のHTMLエスケープ |
id | HTML標準のid属性 |
lang | HTML標準のlang属性 |
on〜イベント名 | イベントはJavaScriptで処理するので使わない |
tabindex | HTML標準のtabindex |
title | HTML標準のtitle属性 |
form:formタグ
form関連のタグはこのform:formタグ以下に、他のformタグを配置していきます。formプリフィックスがついているだけで、HTMLのformタグと同じ形になります。
formタグは標準の属性と別に以下の属性を持ちます。ほとんどがHTMLの標準formがそのまま属性になっています。違うのは、commandNameとmodelAttributeの2つなります。
属性 | 説明 |
---|---|
action | HTML標準のaction属性 |
commandName | Controller側で指定した@ModelAttributeの名称。通常これを使わずに、modelAttribute属性を使います。 |
enctype | HTML標準のenctype属性 |
method | HTML標準のmethod属性 |
modelAttribute | SpringのController側で定義し、このformに関連づけるmodelAttribute |
name | HTML標準のname属性 |
target | HTML標準のtarget属性 |
今の理解だと、commandName属性はあまり使わずに、modelAttributeを使います。modelAttributeはControllerでModelにセットする属性値(Model.addAttributeの引数)を指定します。
formの部品共通の属性
checkbox等のformの内部の要素には共通になる部分も以下のように多くあります。ほとんどがHTML標準の属性ですが、一部独自の属性があります。
Springの独自の部分としては、cssErrorClassとlabel、pathになります。
属性 | 説明 |
---|---|
accesskey | HTML標準のaccesskey属性 |
cssErrorClass | このフィールドでエラーがある場合に適用されるclass属性 |
disabled | HTML標準の属性。trueの場合に有効になる。 |
label | HTMLのlabelタグを適切な形で配置する。具体的には以下で確認 |
path | form:formで指定したmodelAttributeの中のフィールドのうち、この要素に割り当てるフィールドの名称 |
value | HTML標準のvalue属性 |
form:checkboxタグ
共通の属性とformの部品共通の属性だけで構成されています。
単純な例
1つのcheckboxを作る例で見てみます。Controllerは以下のように作成します。
CheckboxModelはformのmodelAttributeに渡すためのクラスです。今回は初期値をtrue(checkboxがチェックされた状態)にするために渡しています。
@Controller public class FormController { @RequestMapping(value = "/checkbox", method = RequestMethod.GET) public String product(Model model) { CheckboxModel cm = new CheckboxModel(); cm.setSendMail(true); model.addAttribute("checkboxModel", cm); return "checkbox"; } }
CheckboxModelは以下の通りです。
public class CheckboxModel { private boolean sendMail; public boolean isSendMail() { return sendMail; } public void setSendMail(boolean sendMail) { this.sendMail = sendMail; } }
Controller内でsendMailをtrueにセットし、checkboxにチェックが入った状態にします。checkbox Viewで表示するcheckbox.jspは以下の通りです。
<form:form modelAttribute="checkboxModel"> <form:checkbox path="sendMail" label="今後XX社からのメールを受け取る" /> </form:form>
pathにsendMailを指定しているため、checkboxModel.sendMailを参照して初期値の設定(チェックされた状態)にしています。
上記の例で実際に出力されるHTMLは以下のようになります。(以下すべてそうですが、HTMLの改行やブランクは見やすいように適宜入れています)
labelに関しては、checkboxとは別のタグとして生成され、for属性で関連するidを指定されます。ブラウザの標準的な挙動になりますが、チェックボックスだけでなくラベルの文字列をクリックしてもチェックボックスの状態が変わります。
<form id="checkboxModel" action="/form/checkbox" method="post"> <input id="sendMail1" name="sendMail" type="checkbox" value="true" checked="checked"/><label for="sendMail1">今後XX社からのメールを受け取る</label><input type="hidden" name="_sendMail" value="on"/> </form>
form:checkboxesタグ
実際にcheckboxを生成するのはform:checkboxよりもこちらのform:checkboxesを使うことがほとんどだと思います。
form:checkboxesタグは名前の通りJavaの配列やMapから複数のcheckboxを作ることができます。
checkboxesやoptions等の複数のform要素を扱う場合に、共通で使われる属性は以下の通りです。
属性 | 説明 |
---|---|
delimiter | checkbox間の区切り文字。デフォルトはなし |
element | それぞれのcheckboxを囲む要素。デフォルトはspan |
itemLabel | labelを出力するitemsで指定したクラスのプロパティ名 |
items | checkboxを作るための配列やMap |
itemValue | valueを出力するitemsで指定したクラスのプロパティ名 |
使い方としては、1つのcheckboxに相当するクラスを作成します。クラスには、checkboxのlabelとvalue属性に対応するプロパティを用意します。itemsにはそのクラスのListやMap、配列を指定します。また、そのクラスのどのプロパティをlabelやvalueに割り当てるのかを、itemLabelとitemValueに指定します。
基本的な例
最初にcheckboxで表示するための(itemsで指定する)Bookクラスを作ります。Bookクラスではlabelにあたる書名とvalueにあたるISBNを管理します。
public class Book { private String isbn; private String title; // コンストラクタ/setter/getterは省略 // 以下同様 }
次に画面表示用のModelクラスです。checkboxkは同じパラメータで複数選択されることがあるため配列で受け取ります。
public class CheckboxesModel { private String[] selectedIsbns; }
コントローラは以下のようにします。初期値を設定する場合にはModel用のクラスに初期値の値(今回はISBNが111111111)をセットしておきます。コントローラではcheckboxに表示するためのBookクラスのListを作成しています。この値はformの初期値に使用するModelとは別のクラスとして作成します。
@Controller public class FormController { @RequestMapping(value = "/checkboxes", method = RequestMethod.GET) public String checkboxes(Model model) { List<Book> books = new ArrayList<>(); books.add(new Book("1234567890", "Spring入門")); books.add(new Book("1111111111", "Java入門")); books.add(new Book("9999999999", "Servlet/JSP入門")); CheckboxesModel cm = new CheckboxesModel(); // 初期値の設定 cm.setSelectedIsbns(new String[] { "1111111111" }); model.addAttribute("checkboxesModel", cm); model.addAttribute("books", books); return "checkboxes"; } @RequestMapping(value = "/checkboxesPost", method = RequestMethod.GET) public String checkboxesPost(@ModelAttribute CheckboxesModel checkboxesModel) { for (String s : checkboxesModel.getSelectedIsbns()) { System.out.println(s); } return "forward:/checkboxes"; } }
JSPは以下のように記述します。
<form:form modelAttribute="checkboxesModel" action="checkboxesPost" method="get"> <form:checkboxes path="selectedIsbns" items="${books}" itemLabel="title" itemValue="isbn" /> <input type="submit" value="送信"> </form:form>
items属性にcontrollerでセットした、booksを指定します。checkboxのlabelにBookクラスのtitleプロパティの値を使用するため、itemLabelにtitleを指定します。またitemValueにはisbnを指定します。
実際に出力されるHTMLは以下のようになります。かなり改行を入れています。formの中はほとんど改行は入っていません。
<form id="checkboxesModel" action="checkboxesPost" method="get"> <span> <input id="selectedIsbns1" name="selectedIsbns" type="checkbox" value="1234567890"/> <label for="selectedIsbns1">Spring入門</label> </span> <span> <input id="selectedIsbns2" name="selectedIsbns" type="checkbox" value="1111111111" checked="checked"/> <label for="selectedIsbns2">Java入門</label> </span> <span> <input id="selectedIsbns3" name="selectedIsbns" type="checkbox" value="9999999999"/> <label for="selectedIsbns3">Servlet/JSP入門</label> </span> <input type="hidden" name="_selectedIsbns" value="on"/> <input type="submit" value="送信"> </form>
少し属性を足す
特別な装飾をせずにcheckboxesを使用すると出力されるcheckboxタグの間に空白がないため、非常に見づらいものになります。そのため、checkboxesを含む複数の要素を出力するformカスタムタグにはdelimiter属性があります。
delimiter属性を使うと、出力される要素の間に任意の文字列を出力できます。delimiterの文字列はHTMLエスケープされずにそのまま出力されます。
例えば、以下のようにdelimiter属性を指定することで赤い「|」を区切り文字として出力できます。
<form:checkboxes path="selectedIsbns" items="${books}" itemLabel="title" itemValue="isbn" delimiter=" <span style='color: #f00;'>|</span> " />
出力されるHTMLは以下のようになります。
<form id="checkboxesModel" action="checkboxesPost" method="get"> <span> <input id="selectedIsbns1" name="selectedIsbns" type="checkbox" value="1234567890"/> <label for="selectedIsbns1">Spring入門</label> </span> <span> <span style='color: #f00;'>|</span> <input id="selectedIsbns2" name="selectedIsbns" type="checkbox" value="1111111111" checked="checked"/> <label for="selectedIsbns2">Java入門</label> </span> <span> <span style='color: #f00;'>|</span> <input id="selectedIsbns3" name="selectedIsbns" type="checkbox" value="9999999999"/> <label for="selectedIsbns3">Servlet/JSP入門</label> </span><input type="hidden" name="_selectedIsbns" value="on"/> <input type="submit" value="送信"> </form>
form:radiobuttonタグ
radiobuttonの属性はcheckboxと同様に標準のタグで構成されています。
画面表示用のモデルを作成します。checkboxと違い選択された値を文字列で受け取るためString型で定義します。radiobuttonのvalue値がこの値と等しいものが選択された状態になります。
public class RadiobuttonModel { private String sendMail; }
コントローラは以下のようになります。ここではradiobuttonの初期値を「send」にしています。
@Controller public class FormController { @RequestMapping(value = "/radiobutton", method = RequestMethod.GET) public String Radiobutton(Model model) { RadiobuttonModel rm = new RadiobuttonModel(); rm.setSendMail("send"); model.addAttribute("radiobuttonModel", rm); return "radiobutton"; } }
JSPは以下のようになります。path属性で指定したプロパティの値とvalue属性の値が一致する場合に選択された状態になります。
<form:form modelAttribute="radiobuttonModel"> <form:radiobutton path="sendMail" label="今後XX社からのメールを受け取る" value="send" /> </form:form>
form:radiobuttonsタグ
複数の中から1つ選択する普通のradiobuttonです。属性はcheckboxesと同じです。
サンプル
checkboxesと同様にList
@Controller public class FormController { @RequestMapping(value = "/radiobuttons", method = RequestMethod.GET) public String Radiobuttons(Model model) { List<Book> books = new ArrayList<>(); books.add(new Book("1234567890", "Spring入門")); books.add(new Book("1111111111", "Java入門")); books.add(new Book("9999999999", "Servlet/JSP入門")); RadiobuttonsModel rm = new RadiobuttonsModel(); rm.setSelectedIsbn("9999999999"); model.addAttribute("radiobuttonsModel", rm); model.addAttribute("books", books); return "radiobuttons"; } }
modelは以下です。
public class RadiobuttonsModel { private String selectedIsbn; }
JSPもcheckboxesとほぼ同様になります。
<form:form modelAttribute="radiobuttonsModel"> <form:radiobuttons path="selectedIsbn" items="${books}" itemLabel="title" itemValue="isbn" delimiter=" " /> </form:form>
form:inputタグ
テキストの入力フィールドを作成するタグです。属性は標準的なものに加えて以下のものがあります。基本的にはHTML標準の属性です。
属性 | 説明 |
---|---|
autocomplete | HTML標準のautocomplete属性 |
maxlength | HTML標準のmaxlength属性 |
readonly | HTML標準のreadonly属性 |
size | HTML標準のsize属性 |
サンプル
サンプルでは、Validatorを含めた例で確認します。
まずはコントローラーから確認します。inputメソッドが表示用で、inputSendメソッドが画面からsubmitされたときに呼び出されるメソッドになります。
inputメソッドでは今までのように初期値表示用の設定をしています。入力フォームは文字列ですが、ModelのプロパティをintやIntegerなどの型にすることもできます。しかし、そのままフォームに数値以外の値を入力すると型変換のエラーとなりスタックトレースが出力されてしまいます。そのため、型変換のエラーを適切に処置するため@ModelAttributeをつけたメソッドを作成します。このメソッドを作成することで、エラーをSpringで処置できるようになります。また、メッセージリソースに適切なキーを設定することにより該当のフィールドエラーにすることができます。以下のControllerのInputModelメソッドがある場合とない場合の動作の違いを見ていただくとわかると思います。
@Controller public class FormController { @ModelAttribute("inputModel") public InputModel initInputModel() { return new InputModel(); } @RequestMapping(value = "/input", method = RequestMethod.GET) public String input(Model model) { InputModel im = new InputModel(); im.setName("花中島 太郎"); model.addAttribute("inputModel", im); return "input"; } @RequestMapping(value = "/inputSend", method = RequestMethod.POST) public String inputSend( @Valid @ModelAttribute("inputModel") InputModel inputModel, Errors errors) { if (errors.hasErrors()) { return "input"; } return "forward:/"; } }
ModelはStringとIntegerの2つの項目です。ageにはBean Validatorのアノテーションを設定し、0〜200までの値のみ入力可能としています。
public class InputModel { private String name; @Min(0) @Max(200) private Integer age; }
JSPはValidationのエラー表示用のform:errorタグを追加しています。
<form:form modelAttribute="inputModel" action="inputSend" method="post"> <form:errors path="*" element="div" /> <form:label path="name">名前:</form:label><form:input path="name" size="40" /><br> <form:label path="age">年齢:</form:label><form:input path="age" size="5" cssErrorClass="error" /><br> <input type="submit" value="送信"> </form:form>
form:passwordタグ
password用の入力フィールド。入力した内容がわからないようになります。属性はform:inputと同様ですが、showPassword属性が追加されています。
属性 | 説明 |
---|---|
showPassword | パスワードを表示するかどうか。デフォルトはfalse |
サンプルはform:inputとほぼ同様のため省略します。
form:textareaタグ
複数行のテキスト入力のフィールドです。
属性 | 説明 |
---|---|
cols | 列数 |
rows | 行数 |
サンプルはform:inputとほぼ同様のため省略します。
form:selectタグ
form:selectタグの属性はcheckboxesの属性に追加して以下のものがあります。
属性 | 説明 |
---|---|
multiple | HTML標準のmultiple属性 |
size | HTML標準のsize属性 |
例は今までと同様です。JSPのみmultipleやsizeを使ったものにしています。
@Controller public class FormController { @RequestMapping(value = "/select", method = RequestMethod.GET) public String select(Model model) { List<Book> books = new ArrayList<>(); books.add(new Book("1234567890", "Spring入門")); books.add(new Book("1111111111", "Java入門")); books.add(new Book("9999999999", "Servlet/JSP入門")); SelectModel sm = new SelectModel(); sm.setSelectedIsbn("1111111111"); List<String> selectedIsbns = new ArrayList<String>(); selectedIsbns.add("1234567890"); selectedIsbns.add("9999999999"); sm.setSelectedIsbns(selectedIsbns); model.addAttribute("selectModel", sm); model.addAttribute("books", books); return "select"; } }
public class SelectModel { private String selectedIsbn; private List<String> selectedIsbns; }
<form:form modelAttribute="selectModel"> <form:select path="selectedIsbn" items="${books}" itemLabel="title" itemValue="isbn" /><br> <form:select path="selectedIsbns" items="${books}" itemLabel="title" itemValue="isbn" size="3" multiple="true" /> </form:form>
form:optionsタグ
form:optionsタグはHTMLのoptionタグがそうであるように、単独では使えません。必ずform:selectタグの中に書くようにします。
属性は、checkboxesと同じです。サンプルも同様です。
@Controller public class FormController { @RequestMapping(value = "/options", method = RequestMethod.GET) public String options(Model model) { List<Book> books = new ArrayList<>(); books.add(new Book("1234567890", "Spring入門")); books.add(new Book("1111111111", "Java入門")); books.add(new Book("9999999999", "Servlet/JSP入門")); OptionsModel om = new OptionsModel(); om.setSelectedIsbn("9999999999"); model.addAttribute("optionsModel", om); model.addAttribute("books", books); return "options"; } }
public class OptionsModel { private String selectedIsbn; }
<form:form modelAttribute="optionsModel"> <form:select path="selectedIsbn"> <form:options items="${books}" itemLabel="title" itemValue="isbn" /> </form:select><br> </form:form>
まとめ
Springのカスタムタグは、非常にコンパクトによく考えられて作られているように感じます。タグの使用仕様ではなくSpring MVCの仕様ですが、ModelにString以外のinteger等の数値型を指定することができるのも非常にいいです。
参考
今回の記事は、以下のSpring本がなければできませんでした。ある程度Webアプリを作った人であれば、十分に読め、かつDIの基本からAOP、Spring MVCまでをもれなく記載されている良書です。

Spring3入門 ――Javaフレームワーク・より良い設計とアーキテクチャ
- 作者: 長谷川裕一,大野渉,土岐孝平
- 出版社/メーカー: 技術評論社
- 発売日: 2012/11/02
- メディア: 大型本
- 購入: 8人 クリック: 115回
- この商品を含むブログ (13件) を見る
さらに、偶然発見した以下の資料も非常に参考になりました。
http://d.hatena.ne.jp/tatsu-no-toshigo/20121023