新規のエンタープライズJava開発において現在有力視される3つのフレームの違いについて解説する連載。今回から複数回に分けて、MVCのViewとControllerにフォーカスして各要素を紹介していきます。今回はJSFについて。サンプルコードを通じてJSFの機能を紹介し、JSFの特徴を3つ挙げた上で、JSFのメリット・デメリットを検討します。
新規のエンタープライズJava開発において現在有力視される3つのフレームワーク、Java EE、Spring Framework、Play Framework。本連載では、3つの違いについて、アーキテクチャ、UI開発/画面の作り方、画面遷移、セッション管理、トランザクション、DBアクセス、開発生産性(ツール/デプロイ/CI/テスト)、外部システムとの連携などの観点から見ていきます。
前回の「Strutsを使い続けることの問題点&現在有力なJava EE、Spring、Play Frameworkの基礎知識とアーキテクチャ」では、本連載で取り上げる3つのフレームワークの概要について解説し、全体的なアーキテクチャを俯瞰しました。今回から複数回に分けて、MVCのViewとControllerにフォーカスして各要素を紹介していきます。ViewとControllerは互いの要素が密接に連携していますので、2つを合わせて解説していきます。
今回はJava EEのJSF(Java Server Faces)を取り上げます。
まずは、サンプルコードを通じてJSFの機能を紹介し、Struts 1との違いを説明します。その後、JSFの特徴を3つ挙げた上で、JSFのメリット・デメリットを検討します。
JSFはJava EE標準のWebアプリケーション仕様です。Java EE 7ではJSFのバージョンは2.2です。
結論から先に言うと、JSFによるアプリケーションは基本的に、「Facelets」によるXHTMLと、「バッキングBean」の作成だけで実際に動くアプリケーションができてしまいます。
今回紹介するサンプルアプリケーションは、IDとパスワードによる認証を行うものです。入力したID・パスワードのバリデーションを行い、不備があれば不備の内容を表示し、不備がなければ別のViewを表示するもので、画面への入出力・検証・画面遷移といったWebアプリケーションの基本的な機能を使用しています。
フレームワークによっては認証機能そのものが提供されている場合がありますが、今回はView・Controllerの機能を紹介するため、あえて自作しています。ソースコードは本稿の最後でダウンロードできます。
まずは、ログイン画面に当たる「login.xhtml」(抜粋)です。
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <!-- 割愛 --> <h1>ログイン</h1> <h:form class="form" id="form"> <div> <h:messages id="message"/> </div> <h:inputText id="id" value="#{loginAction.id}" p:placeholder="user1を入力" /> <h:inputSecret id="password" value="#{loginAction.password}" /> <h:commandButton action="#{loginAction.login}" value="ログイン"/> </h:form> <!-- 割愛 --> </html>
JSFではXHTMLでViewを記述します。「h:form」「h:inputText」などはJSFが提供するXMLタグで、「Facelets」と呼ばれるViewを構築するコンポーネントです。これらのコンポーネントはJSFの中核となる部品で、JSFではViewはコンポーネントの集合として表現します。これらのコンポーネントは、HTMLの表示、サーバサイドJavaプログラムへの入力値の伝達、ボタンを押したときに実行するJavaメソッドの指定などさまざまな働きをします。
例えば、9行目の「h:inputText」はブラウザにinput要素を表示してその入力値を「LoginAction」というクラスのidフィールドに設定します。12行目の「h:commandButton」はボタン要素を表示してボタンがクリックされたら、LoginActionのloginメソッドを実行します。
続いて「バッキングBean」のLoginActionクラスのソースコードを紹介します。バッキングBeanはサーバサイドのJavaプログラムで、JSFのコンポーネントからの入力値の保持や、サーバサイドロジックの実行などを行います。
/** * ログインバッキングBean */ @RequestScoped // 【1】 @Named public class LoginAction { // 【2】View入力値:id @NotNull // 【3】 バリデーション @Size(min = 1) private String id; // View入力値: password @NotNull @Size(min = 1) private String password; // 【4】 commandButton の action属性で指定されたメソッド public String login() { // メソッドが呼ばれる時点でバリデーションが成功し、フィールドにview入力値が設定済み // フィールドid, passwordを使用して認証処理を実施。 boolean success = service.login(id,password); if (success) { // 【5】画面遷移は 次のViewを戻り値にすることで行う。 return "/views/welcome.xhtml?faces-redirect=true"; } else { // 認証失敗による任意のメッセージ設定 FacesContext.getCurrentInstance().addMessage("error", new FacesMessage("Invalid id or password.")); // 自画面再表示は null をリターンすればよい return null; } } // アクセッサ、他のメソッドは割愛 }
ポイントをかいつまんで話します。
【1】の@RequestScopedおよび次行の@NamedはこのクラスをバッキングBeanとして扱うことを意味しています。
@RequestScopedは「CDI」の「スコープアノテーション」と呼ばれるもので、バッキングBeanのスコープを指定しています(「CDI」「スコープアノテーション」の詳細は後述します)。
@NamedはバッキングBeanをViewで照会可能にすることを示します。リスト1のvalue="#{loginAction.id}" のような記述がこれに該当します。
【2】では、Viewの入力値を格納するバッキングBeanのフィールドを宣言しています。
【3】では、制約アノテーションを記述することでバリデーションの種類を指定しています。
JSFでは、入力値の必須チェックや長さのチェックといったバリデーションは、フィールドに制約アノテーションを付与することで行います。
ここでは、@NotNullによってnull値を不正とし、次行の「@Size(min=1)」によって未入力を不正とすることを指定しています。こうすることでloginメソッド呼び出し前にバリデーション処理が呼び出され、チェックが通らない場合は自動的にメッセージを設定して、自画面を再表示します。
制約アノテーションによるバリデーションは「Bean Validation」という仕様としてJava EEで定義されているものです。独自チェックの追加や任意のメッセージの設定ができるなど柔軟な仕組みを持ち、「Spring MVC」でも使われています。
【4】のloginメソッドは、viewのcommandButtonに指定したメソッドでViewのボタンを押すと呼ばれる処理です。ボタンを押すと【3】の検証が行われ、成功した場合に【2】で指定したフィールドに入力値が格納され、メソッドが呼び出されます。
【5】では、画面遷移のために次に表示するView名を戻り値に指定しています。このとき、自画面を再表示させたいならnullを戻り値にします。
では、この仕組みをStruts 1と比較してみましょう。Struts 1で先のサンプルと同等のアプリケーションを作る場合、以下の作業が必要になります。
それぞれについて、もう少し詳しく説明します。
【1】で述べたように、Struts 1のActionおよびActionFormクラスはいずれもStruts 1の特定のクラスを継承して作る必要があります。一方、JSFではActionに該当するバッキングBeanは何も継承する必要がない普通のJavaクラスです。また、ActionFormに該当する画面入力値はバッキングBeanのフィールドになっています。
普通のJavaクラスであることにより、サーブレット関連のAPIの呼び出しがなく単体テストが実行しやすくなっています。また、Struts 1のActionクラスはHTTPリクエストごとに1クラス作る必要がありますが、JSFでは関連のあるメソッドを1つのバッキングBeanにまとめられるため、コードの見通しが良くなります。
【2】の設定ファイル「struts-config.xml」の記述はコードの記述量に大きく影響する部分です。
Struts 1ではViewを追加するたびに設定ファイルを変更する必要があります。しかし、JSFでは設定ファイルの内容はバッキングBeanに付与するアノテーションで行うため、Struts 1のように、設定ファイルを頻繁に編集する必要がありません。
【3】の「Bean Validation」によるバリデーションもコードの記述量の削減に大きく貢献します。Struts 1のvalidation.xmlによるチェック定義の設定は記述量が多くなりがちです。一方、JSFの「制約アノテーション」による設定は簡単で、またソースコードに直接定義を設定できるため複数のファイルを同時に扱う必要がありません。
このようにJSFでは、Struts 1と比較してViewとJavaプログラムとを設定ファイルを用いず直接結び付けることができるようになっており、開発がしやすいフレームワークだと言えます。
Copyright © ITmedia, Inc. All Rights Reserved.