Goodbye Struts, Hello Java EE #javaee
これは Java EE Advent Calendar 2014 の3日目のブログエントリーです。
昨日は @irof さんの Java EEを説明してみる #javaee - 日々常々 でした。
明日は @kazuhira_r さんです。
はじめに
20年前の今日はプレイステーションの発売日でした。
来年はJavaが誕生してちょうど20年になります。
私が住んでいる神戸もある意味20年の節目の年を迎えます。
この20年の間に色々ありました。
ここ数年はIT技術の進歩がめざましく、とりわけWebの世界においては様々な言語やフレームワークが誕生しては消え(更新が途絶えたり)、Javaにとってはある意味混沌とした時代でもありました。
私はStrutsを10年ぐらいやっていました。それも1系を。
Javaが誕生してから半分の期間も!
Struts 1系は2013年4月にEnd Of Life(開発停止)が宣言されました。そもそも1系の最新である1.3.10がリリースされたのは2008年12月の事なので、事実上もっと前に終わっていた技術だと思います。
それでも企業で使われていたのはStrutsを使える技術者なら容易に集められたり、いわゆる枯れた技術(漠然とした安心感や根拠の無い使い古された技術だと安心)だったからなのではないでしょうか。
Strutsをやっていた10年余りの間にASP.NET(言語は何故かVB系ばかり…)をやっていたり、ベンダーの何とかフレームワークとか、何とかフレームワークとか何とかフレームワークを使っていたりしていました。
これらのフレームワークに一貫して言える事は、MVCモデルのVに当たるjspやaspxにロジックが入り込む事が往々にしてあったという事です。(最近のASP.NETはちょっと勉強不足なので、ここに書いている内容に当てはまらないかも知れません。)
前置きが長くなってしまいました。
今日は、Strutsぐらいしか知らない人がJava EE 7をやってみて良い意味で衝撃を受けたという事を書いてみようと思います。
(悪い意味では、もっと早くJava EE(6以降)に触れておけば良かったという後悔。。)
ViewでJavaScriptを使うという事
一つの例を示したいと思います。
ユーザーの入力によって動的に計算する際にjQueryを使ってテキストボックスの値と隠し項目のhiddenの値を計算したり、一覧に行を追加したりする場合にDOMをjQueryから操作するのが本当に面倒でした。一回作ってしまえば、後は楽と思うかも知れませんが、仕様変更で項目が増減されたときもJavaScriptを修正しないといけない所が面倒でバグの原因にもなっていました。
次のレガシーなjspをご覧下さい。
数ヶ月前までStrutsを触っていたのに、改めて書いてみると結構うろ覚えなので間違っている所もあるかも知れません。
<input type="button" value="行追加" onclick="addrow()"> <table> <thead> <tr> <td>No</td> <td>品名コード</td> <td>品名</td> <td>倉庫コード</td> <td>倉庫名</td> <td>在庫数</td> <td>単価</td> <td>金額</td> </tr> </thead> <tbody> <logic:iterate id="item" property="productList" indexId="idx"> <tr> <td> <bean:write name="idx" /> </td> <td> <bean:write name="item" property="hinmeiCd" /> </td> <td> <bean:write name="item" property="hinmeiNm" /> </td> <td> <bean:write name="item" property="sokoCd" /> </td> <td> <bean:write name="item" property="sokoNm" /> </td> <td> <html:text name="item" property="zaikoSu" size="10" maxlength="3" onblur='calc(<bean:write name="idx" />)' /> </td> <td> <bean:write name="item" property="tanka" /> </td> <td> <html:text name="item" property="kingaku" size="10" readonly /> </td> <input type="hidden" name="zaikoSuMax[<bean:write name='idx' />]"> </tr> </logic:iterate> </tbody> </table>
このテーブルは在庫数を入力すると単価と計算して合計を算出する事が出来、在庫の最大数とのチェックも行えます。
また、行追加ボタンを押すと一番下に新しい行が追加出来ます。
ただし、それらはJavaScriptを使って書いておく必要があります。
EclipseでJavaScriptの入力補完が全く効かず、デバッグもし難いので書いては動かして書いては動かしての繰り返しが辛かった日々を想い出します。。。
もしかしたらNetBeansやIntelliJではその辺りが充実しているのかも知れません。
少し調べてみるとEclipseでもJavaScriptのコード補完が出来るようですが、当時は知りませんでした。
JavaScript 開発環境の用意(Eclipse WTP/JSDT) | hiromasa.another :o)
Viewが完全に切り離せる
Java EE 7 (JSF2.2) を使う場合は、JavaScriptを全く記述する事なく同じ事が出来てしまいます。
(Java EE 6でも基本的に同じだと思います。)
しかもAjaxを全く意識しなくても画面の部分的な更新が簡単に出来ます。
この2点がとても素晴らしいところです。
ロジック部分がJava側に集約されるのでJUnitでしっかりとテストが出来るという点も素晴らしいです。
次のxhtmlをご覧下さい。
(実際に動かしていないので、間違っている部分もあるかも知れません。。。)
hから始まるタグはJSF標準のタグで、pから始まるタグは PrimeFaces というJSFベースのリッチUIコンポーネントです。
見た目が凄く綺麗になりますし、本当にリッチなUIが使えます。
jQueryのプラグインで部分的にリッチにしてしまってアンバランスなUIを構築してしまうという痛恨のミスも最早過去の話です。
<h:form id="form"> <p:growl id="msgs" showDetail="true" /> <p:outputPanel id="panel"> <p:commandButton value="行追加" actionListener="#{zaikoViewModel.addRow}" update=":form:panel, :form:msgs" /> <p:dataTable var="item" value="#{zaikoViewModel.details}" rowIndexVar="rowIndex"> <p:column headerText="No"> <h:outputText value="#{rowIndex+1}" /> </p:column> <p:column headerText="品名コード"> <h:outputText value="#{item.hinmeiCd}" /> </p:column> <p:column headerText="品名"> <h:outputText value="#{item.hinmeiNm}" /> </p:column> <p:column headerText="倉庫コード"> <h:outputText value="#{item.sokoCd}" /> </p:column> <p:column headerText="倉庫名"> <h:outputText value="#{item.sokoNm}" /> </p:column> <p:column headerText="在庫数"> <h:inputText id="zaikoSu" value="#{item.zaikoSu}" > <p:ajax event="blur" listener="#{zaikoViewModel.onBlur}" update=":form:panel, :form:msgs" /> </h:inputText> </p:column> <p:column headerText="単価"> <h:outputText value="#{item.tanka}" /> </p:column> <p:column headerText="金額"> <h:outputText value="#{item.kingaku}" /> </p:column> </p:dataTable> </p:outputPanel> </h:form>
先ほどのjspをJSFに書き換えるとこうなります。
個人的にはテーブルのヘッダー部分とボディー部分を一緒に書ける所が直感的で良いなと思います。
このxhtmlにはhiddenが書かれていません。
代わりにp:ajaxというタグがあり、listenerで指定したzaikoViewModelクラスのonBlurメソッドが呼び出される仕組みがあります。
eventに指定したクライアント側のイベント実行時にformで囲んだ値がサーバー側に送信され、メソッド内での処理が終わるとupdateで指定したコンポーネントが更新されます。
これぞまさしくStruts時代に憧れていたAjaxです。
もう一つ、行追加ボタンについて。
こちらもボタンが押されたときにactionListenerで指定したクラスのメソッドが呼ばれ、updateで指定したコンポーネントが更新されます。
行追加と言っても、Java側でdetails(大体がArrayList)に空のオブジェクトをaddすれば完了です。
たったそれだけで行追加が出来ます。
もうjQueryでDOMをこねくり回す必要はありません。
JavaScriptでやっていた計算やDOMの操作がJSFを使う事によってJava側で出来てしまうのです。
Java EE 6以降をご存知の方には当たり前だと思いますが、知らなかった私はかなり衝撃を受けました。
これって意外と知らない人多いんじゃないかと思います。
(知ってたらJava EEが流行ってる気がするので。)
(技術系の記事によくあるサンプルだと実際の業務システムイメージが付きにくいという事もあるのかも知れませんね。)
業務システムでもUXを
今までjQueryを使って部分的にリッチになっていたり、いまいちパッとしない業務システムの画面もPrimeFacesを使う事でシステム全体が同じデザインで統一されます。デザインを変更するテーマファイルも結構あるので、気に入るものがきっとあると思います。
エンタープライズ系のシステムもエンドユーザー向けのシステムと同じようにとことんUXに拘ってもいいのではないでしょうか。
洗練されたUIはとても使い勝手が良く、おそらくソースも綺麗でしょう。
UXに関してちょうど良いタイミングで記事が出ていましたね。
まとめ
Java EEを使うとAjaxが簡単に使え、PrimeFacesと組み合わせる事でリッチなWebシステムが構築出来ます。
もうJavaScriptで無駄な時間を消費することもありません。
Viewにロジックが入り込まないため、JUnitを使ったテストで充分網羅出来ます。(Excelにエビデンス貼り付けるの止めようよ。)
JUnitとの相性も良いということは仕様変更にビクビクする事もありません。
簡単に再テスト出来るし、何より自分で書いたコードでテストが完了するので安心感もあります。
Java SE 8もあるので、ラムダとStream APIでコーディングが楽しくなるということも言っておきます。
jspベースなフレームワークを使っているという人が居るなら、マイグレーションの際にはJava EE 7を断然オススメします。
使い勝手も悪く工数も掛かるフレームワークはどんどん淘汰されて行くでしょう。
おまけ
先日、関ジャバに初めて参加しました。
Javaエンジニア養成読本にサイン貰いました。
写真大きいままですけど。。。
本の内容はこちらにあります。