struts2でjqueryとbootstrapを使う

これまでサーバサイドのJavaについてはいろいろ設定をしてきたので、いったん置いておいてクライアント側の環境も整えていきたいと思います。
準備まとめの準備編(Java)を前提にしています。
「struts2でアプリ作成」は必須。「struts2とseasar2を使ってアプリ作成」は不要です。


今回使うのはjQueryjQuery UI。それからBootstrap。
jQueryおそらく今は一番使われているjavascriptフレームワーク本家
jQuery UIはjQueryを使って各種のウィジェットやエフェクトを提供してくれるライブラリ。本家
Bootstrapは簡単にオシャレな画面を作ることができるフロントエンドフレームワーク(主にCSS+一部のjavascript)
Bootstrap本家

jQueryjQuery UIの追加

もちろん、直接本家からダウンロードしてきてそれを呼び出すようにしてもいいんですが、struts2にはjQuery-pluginが用意されているのでコレをつかってみます。
https://code.google.com/p/struts2-jquery/

まずはpomにライブラリを追加します。

pom.xml
  	<dependency>
  		<groupId>com.jgeppert.struts2.jquery</groupId>
  		<artifactId>struts2-jquery-plugin</artifactId>
  		<version>3.5.1</version>
  	</dependency>

で、新しくアクションクラスとjspファイルを用意します。

src/main/java/kamegu/action/fwtest/JspTopAction.java
package kamegu.action.fwtest;

import com.opensymphony.xwork2.Action;

public class JspTopAction implements Action {
	public String execute() {
		return SUCCESS;
	}
}
src/main/webapp/WEB-INF/content/fwtest/jsp-top.jsp
<%@page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ taglib prefix="sj" uri="/struts-jquery-tags"%>
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="UTF-8">
  <sj:head/>
</head>
<body>
JSPトップ画面です
<br>
  <div id="div1">Div 1</div>
  <p>
    <sj:a id="link1" href="./top-ajax" targets="div1">Update Content</sj:a>
  </p>
  <p>
    <sj:datepicker name="date" id="date"/>
  </p>
</body>
</html>

2,3行目はそれぞれstrutsタグ、struts-jqueryタグを使用するための宣言です。
4,7行目の宣言はHTML5にあわせるように、TopActionから書き換えています。
8行目はjQueryjQuery UIのjsファイルやcssファイルを読み込むための宣言です。
jquery-pluginのバージョンは3.5.1ですが、このときのjQueryjQuery UIのバージョンはそれぞれ1.8.3と1.9.2です。
最新ではないので、最新のほうがよければsjタグを使わず、直接指定してください。その場合は他のsjタグも使用できません。
この画面は、「Update Content」というリンクをクリックするとid="div1"の要素にAjaxを使ってコンテンツを読み込む機能と、jQuery UIのdatepickerを含んでいます。

次にdiv1に読み込むコンテンツを作成します。呼び出されるたびにカウントアップして、その回数を表示する画面です。

src/main/java/kamegu/action/fwtest/TopAjaxAction.java
package kamegu.action.fwtest;

import com.opensymphony.xwork2.Action;

public class TopAjaxAction implements Action {

	private static int counter = 0;

	@Override
	public String execute() throws Exception {
		counter++;
		return SUCCESS;
	}

	public Integer getCounter() {
		return counter;
	}
}
src/main/webapp/WEB-INF/content/fwtest/top-ajax.ftl (この画面はFreemarkerを使っています。)
<!DOCTYPE HTML>
この画面は${counter}回呼び出されました。

以上の設定で、/myapp/fwtest/jsp-topにアクセスして、「Update Content」をクリックするたびに
「この画面はxx回呼び出されました。」のxxがカウントアップされていけばOKです。
また、テキストフィールドもしくはその横のカレンダーアイコンをクリックするとカレンダー形式のウィジェットが表示されて日付を選べれる用になっていることも確認できると思います。

ただ、よく見てみるとカレンダーは英語になっており、日付の表示も「月/日/年」となっています。

DatePickerの日本語化、および日付のフォーマット変更

8行目と18行目にそれぞれattributeを追加して次のように書き換えてください。

~
  <sj:head locale="ja" loadAtOnce="true"/><sj:datepicker name="date" id="date" displayFormat="yy/mm/dd"/>

sj:headタグのloadAtOnce="true"はこのセクションの内容とは関係ありませんが、今後のことも考えて設定します。
ちなみに、この設定をしないとjquery.ui.core.jsしか読み込まれず、それ以外は必要に応じて読み込む必要があります。

これで画面をリロードすると、カレンダーが日本語化されて表示も「年/月/日」となっているはずです。

Bootrsrapの追加

http://twitter.github.io/bootstrap/getting-started.html#download-bootstrap
ここから、「Download Bootstrap」ボタンをクリックしてダウンロードします。
「Download Bootstrap Source」というのもありますが、今回は無視で。
ダウンロードしたzipファイルを解凍すると、bootstrapフォルダができると思いますのでそれをそのままsrc/main/webappフォルダにコピーしてください。

Bootstrapファイルの読み込み

jsp-top.jsp

下記をheadタグ内(s.j:headの下)に追加します

  <link href="<s:url value="/bootstrap/css/bootstrap.min.css"/>" rel="stylesheet" media="screen">
  <script src="<s:url value="/bootstrap/js/bootstrap.min.js"/>"></script>
  <script>
    var bootstrapBtn = $.fn.button.noConflict();
    $.fn.bootstrapBtn = bootstrapBtn;
  </script>

本日時点のバージョンは2.3.1。
jQuery UIとBootstrapには共通の拡張メソッドが定義されています。(button(), tooltip(),他は不明)
そのまま使用するとconflictが発生して予期せぬ動きをしたりエラーとなったりします。
そこで、conflictを避けるためにBootstrapのnoConflict()を呼び出して、名前を変えてしまいます。それが上記の最後のscriptタグの中身です。
tooltip()についてもconflictが発生していてnoConflict()もあるのですが、なにやらバグがあるようでエラーとなってしまいます。
今回はとりあえず放置しておきます。この状態だと、Bootstrap側のtooltip()が呼び出されます。

動作確認

次の動作確認をします。

  • tooltip (Bootstrap)
  • button (jQuery UI)
  • bootstrapBtn (Bootstrap)

それぞれjsp-top.jspにコードを追加して確認してください。確認後はそのコードは消してください。

tooltip
  <p>
    <s:textfield name="hoge1" title="hoge1" id="hoge1" data-placement="right" placeholder="入力してください"/>
    <sj:textfield name="hoge2" title="hoge2" id="hoge2" data-placement="bottom" placeholder="入力してください"/>
  </p>
  <script>
    $(function(){
      $('#hoge1,#hoge2').tooltip();
    });
  </script>

http://twitter.github.io/bootstrap/javascript.html#tooltips
strutsタグ、struts-jqueryタグのそれぞれについてtooltipが表示されるはずです。カーソルを移動して確認してください。
inputタグである必要もありません。

button
  <form action="jsp-top">
    <p>
      <s:checkbox id="check" name="bool1" label="Toggle" theme="xhtml"/>
    </p>
    <p id="format">
      <s:checkbox id="check2" name="bools" fieldValue="2" value="bools != null && bools.contains(2)"/><label for="check2">B</label>
      <s:checkbox id="check3" name="bools" fieldValue="3" value="bools != null && bools.contains(3)"/><label for="check3">I</label>
      <s:checkbox id="check4" name="bools" label="U" fieldValue="4" value="bools != null && bools.contains(4)" theme="xhtml"/>
    </p>
    <button type="submit" class="btn btn-primary">update</button>
  </form>
  <script>
    $(function(){
      $( "#check" ).button();
      $( "#format" ).buttonset();
    });
  </script>

http://jqueryui.com/button/
checkboxで定義した要素の見た目がボタンになっていることを確認できます。
ここでは見た目が変わっているだけでなくフォームの値としてセットされていることも確認するために、formタグで囲んでいます。
Action側にpublic Boolean bool1;public List bools;を定義して値が渡されていることを確認できます。
ちなみに、id="check"のところでtheme="xhtml"とやっているのはlabelタグを表示するためです。labelを定義せずにjQuery UIのbutton()メソッドを使うとcheckboxが見えなくなってしまいますので気をつけてください。theme="simple"(struts.xmlで設定)のままでもid="check2"のようにラベルを定義すればボタン化できます。

bootstrapBtn
  <p>
    <button type="button" id="button1" >スタイル未設定</button>
    <button type="button" id="button2" class="btn btn-primary" data-loading-text="loading...">bootstrapスタイル</button>
  </p>
  <script>
    $(function(){
      $('#button2').click(function(){
        var $btn = $(this);
        $btn.bootstrapBtn('loading');
        setTimeout(function(){
          $btn.bootstrapBtn('reset');
        }, 1500);
      });
    });
  </script>

http://twitter.github.io/bootstrap/base-css.html#buttons
ボタンのスタイルが適用されていることを確認できます。(未適用との比較)
http://twitter.github.io/bootstrap/javascript.html#buttons
「bootstrapスタイル」のボタンを押すと、一時的に「Loading...」となってしばらくすると元のボタンに戻ることを確認できます。

画面のレイアウト

画面のレイアウトについては省略。
下記リンクを参考にいろいろ試したほうが楽しいと思います。
http://twitter.github.io/bootstrap/getting-started.html#examples