2011年2月21日月曜日

Struts 2 Viewレイヤーの仕組み

Result処理

 Struts 2Viewは、URIリクエストから実行されたActionクラスの処理結果や状態を出力するレイヤーです。デフォルトでは、JSPファイルをテンプレートとして、HTMLが生成されます。またHTMLだけでなく、プレーンなテキストであったり、画像データなどのバイナリデータを指定することもできます。

リクエストからレスポンスまでの処理フロー

リクエストからレスポンスまでの処理フロー

Result Type

 ちょっとこれまでのサンプルコードをふりかえってみましょう。URIリクエストから実行されるActionクラスのメソッドでは、処理結果を"success"などの文字列で返すようにしていました。この結果の文字列を受けて、どのような処理をさせるかは、struts.xml <result>タグで設定しています。例えば次のように指定すると、結果が"success"のときにindex.jspを用いた出力となります。

<result name="success">/index.jsp</result>

 実はこれは既定値を利用した書き方で、タグを省略しないで書くと、次のようになります。

<result name="success" type="dispatcher">
    <param name="location">/index.jsp</param>
</result>

 type属性で処理のタイプを指定し、<param>タグでその処理のパラメータを指定します。このtype属性で指定している"dispatcher"の実体は、struts-default.xmlにて設定されているorg.apache.struts2.dispatcher.ServletDispatcherResultクラスです。JSPファイルを解釈して、 HTMLを生成する処理を行います。

 <result>タグのtype属性(Result Type)を変更することで、処理を切り替えることができます。Struts 2で用意されているResult Typeは次の表の通りです。これは、本連載の第3回目でも少しふれていますが、さらに詳しく見ていくことにしましょう。

Result Type一覧

Result Type

概要

種別

chain

別のActionクラスを呼び出す

遷移

redirect

指定したURLにリダイレクトする

redirectAction

指定したActionにリダイレクトする

dispatcher

JSPファイルをテンプレートとしてHTML を生成する(デフォルト

データ生成

freemarker

汎用テンプレートエンジンのFreeMarkerを使用してHTMLを生成する

velocity

汎用テンプレートエンジンのVelocityを使用してHTMLを生成する

xslt

XSLTを使用してHTMLXML)を生成する

httpheader

HTTPのステータスヘッダだけを生成する

stream

バイナリデータをそのままクライアントに返す。ファイルのダウンロード等に利用する

plainText

プレーンテキストとして、そのままクライアントに返す

tiles

Tilesフレームワークを利用してHTMLを生成する

jasper

オープンソースの帳票ライブラリJasperReport利用したレスポンスを生成する

chainとリダイレクトとの違い

 Result Typeは大別すると、HTMLなどデータを生成するタイプと、他のActionを呼び出したりリダイレクトを行ったりする遷移タイプに分かれます。HTMLを生成するタイプは後述することにして、まずは、遷移するタイプを説明しましょう。

 Result Typeの「redirect」と「redirectAction」は、いわゆるHTTPリダイレクトを行うものです。つまり、<param>タグのlocationで指定したURIに、クライアントからあらたにリクエストが発生する形になります。

 例えば、次のように記述すると、"success"の場合、sample.jspへリダイレクトします。

<result name="success" type="redirect">
  <param name="location">sample.jsp</param>
</result>

 ここで気をつけたいのは、この処理は、デフォルトの処理であるjspファイルを利用したHTMLを生成する動作とは異なるということです。この例では、単にsample.jspへ遷移するだけであり、sample.jspでは、遷移元のリクエストで生成されたActionクラスのオブジェクトを参照することはできません。別のリクエストになっているため、元のオブジェクトは破棄され、あらたなActionクラスのオブジェクトが生成されているのです。遷移先でもデータが必要であれば、パラメータとして値を設定する必要があります。

redirect」の処理フロー

「redirect」の処理フロー

 「redirectAction」の動作も同じで、別のActionへの遷移は、それぞれ別のリクエストにより実現されることになります。

redirectAction」の処理フロー

「redirectAction」の処理フロー

 これらのリダイレクトを行うResult Typeと似て非なるのが、「chain」というResult Typeです。「chain」は、リダイレクトではなく、同じリクエスト内の処理として別のActionを呼び出します。このとき、Actionクラスのプロパティを、遷移先のActionクラスに自動でコピーする仕組みがあり、リクエストのパラメータなどが引き継がれることになります(同じ名前のアクセッサメソッドが呼び出されます)。

chain」の処理フロー

「chain」の処理フロー

 このような「chain」の処理は、Action間にまたがる処理のため、他のResult Typeと違って、前回説明したインターセプターとして実装されています。

 なお、実は「chain」は利用を推奨されていません。データをひきつれてActionを遷移すると、いわゆるスパゲッティコードになる恐れがあるためです。処理の流れや構造が把握しにくいアプリケーションにならないよう、「chain」の使用には十分な検討が必要です。

 Struts 2では、Actionクラスはできるだけシンプルに設計することが望ましいとされています。Actionクラスは、あくまでWebページからの窓口とし、主要な処理は別のクラスとして実装する構造(デザインパターンのFacadeパターンにあたる)が、アプリケーションの構造として推奨されています。

 このような構造では、セッション単位のデータをページ間にまたがって保持する方法が気になるところですが、このあたりはまた回をあらためて解説することにします。

データを生成するResult Type

 このタイプのResult Typeは、デフォルトの「dispatcher」をはじめとした、HTMLやバイナリデータを生成するものです。ここでは、いくつか個別にとりあげてみます。

httpheader

 「httpheader」は少し変わっていて、レスポンスにコンテンツがなく、HTMLのヘッダーだけをクライアントに返すResult Typeです。例えば、struts.xmlに次のように記述すると、ページがみつからない場合におなじみの404コードを返すことができます。

<result name="success" type="httpheader">
  <param name="status">404</param>
  <param name="headers.test1">custom header1</param>
  <param name="headers.test2">custom header2</param>
</result>

 <param>タグで、独自のヘッダー文字列を設定することもできます。このサンプルの場合、実際のレスポンスヘッダーは次のようになります。

HTTP/1.x 404 Not Found
Server: Apache-Coyote/1.1
test1: custom header1
test2: custom header2
Content-Type: text/html;charset=utf-8
Content-Length: 977

plaintext

 プレーンなテキストをクライアントに返すResult Typeです。ソースファイルの表示など、テキストをそのまま表示させたい場合に用いるもので、次のように指定します。

<result name="success" type="plaintext">
  <param name="location">/sample.txt</param>
  <param name="charSet">UTF-8</param>
</result>

 パラメータのlocationでファイルパス名、charSetで、文字コードの種別を記述します。

stream

 「stream」は、java.io.InputStreamクラスを用いたバイト列のデータをクライアントに返します。画像ファイルやPDFファイルなどを動的に生成してダウンロードする場合などに便利に使えます。例えば、次のstruts.xmlの設定例では、sample.pngという画像ファイルをダウンロードデータとして指定しています。

<action name="SampleAction" method="download" class="SampleAction">
<result name="success" type="stream">
  <param name="contentType">application/octet-streamg</param>
  <param name="contentDisposition">attachment; filename="sample.png"</param>
</result>
</action>

 <param>タグには、HTTPレスポンスヘッダに応じたパラメータを指定します。このサンプルでは、pngファイルをブラウザに表示させるのではなく、ダウンロードデータとするために、ContentTypeContentDispositionに値を設定しています。このふたつ以外のパラータでは、特にデフォルト値を変えなくても動作します。

 なお、「stream」では、設定ファイルだけでなく、Actionクラスにも前述したInputStreamクラスを使ったコードが必要です。

 まずActionクラスには、InputStreamを返すプロパティを定義します。デフォルトでは、inputStreamという名前でゲッターを参照しますので、getInputStreamメソッドを定義し、フィールドのinputStreamを返すようにします。そして、ダウンロードの処理としては、FileInputStreamクラスを使ってファイルを読む込むようにし、inputStreamに設定します。

public class SampleAction {

    private InputStream inputStream;

    public InputStream getInputStream() {
        return inputStream;
    }

    // ダウンロードActionメソッド
    public String download() throws Exception {
        this.inputStream = new FileInputStream("sample.png");
        return "success";
    }
}

Struts Tag

 最終的にHTMLを表示するViewレイヤーでは、Actionクラスのデータやセッションで保持する情報にアクセスすることが不可欠です。Struts 2では、カスタムタグ(Struts Tag)を用いて、そのようなデータを扱うことになります。

 またStruts Tagには、それ以外にも、フォームなどのユーザーインターフェイスのタグ(UIタグ)や、条件判定を行うタグ、さらにはJavaScriptが組み込まれたAjax機能のタグもあります。

3つのテンプレートエンジン

 Struts 2では、JSPに加え、「freemarker」や「velocity」といった3つのテンプレートエンジンに対応しており、Struts Tag3つのテンプレートで使用することができます。Struts Tagは、基本的にViewの実装とは切り離されており、テンプレートの文法によって若干書式が異なるだけで、同じように使えます。

 なお、JSPの標準的なカスタムタグであるJSTLもサポートしていますが、EL式には対応していません。そのため、EL式固有の表記を使用することはできませんので、OGNL式で記述する必要があります。

 以下、Struts Tagsを表にまとめています。タグの個別の詳細については、Struts 2のドキュメントを参照してください。

UIタグ

 UIタグは、その名の通りユーザーがデータを操作するタグで、checkboxselectといった通常のHTMLタグを拡張したものが中心です。UIタグの特徴的な機能の一つに「テーマ」機能があります。FreeMarkerのテンプレート機能を組み合わせて、コントロールを「テーマ」に従ってレンダリングすることができる機能です。

UIタグ一覧(ファームタグ)

タグ名

説明

checkbox

<input type="checkbox">と同じ

combobox

コンボボックス(テキストボックス+プルダウンメニュー)

form

HTMLタグと同じ

hidden

<input type="hidden">と同じ

password

<input type="password"> と同じ

select

HTMLタグと同じ

textarea

HTMLタグと同じ

radio

<input type="radio">と同じ

reset

<input type="reset">と同じ

submit

<input type="submit">と同じ

textfield

<input type="text">と同じ

head

HEADタグ内でthemeの指定などを行う時に使用

optiontransferselect

2つのセレクトボックスで連携処理を行う

optgroup

セレクトボックスのグループ分け表示

token

Submitのダブルクリック防止用

updownselect

セレクトボックスの要素を上下移動させる

doubleselect

連携動作する2つのセレクトボックス

file

ファイルアップロード用

checkboxlist

複数のチェックボックスを作成

label

文字列表示

UIタグ一覧(Form以外のUIタグ)

タグ名

説明

actionerror

エラー表示用のメッセージ

actionmessage

Actionオブジェクトのメッセージ表示

component

テンプレート定義用

div

HTMLのタグと同じ

fielderror

入力エラーを表示

UIタグ一覧(Ajaxタグ)

タグ名

説明

a

XMLHttpRequestを呼び出す

autocompleter

入力補完機能

bind

イベント待ち処理

datetimepicker

カレンダーを表示した日付選択

div

XMLHttpRequestを呼び出す

tree

ツリー構造の表示

treenode

tabbedpanel

タブ形式のページ表示

 ただ、標準のxhtmlテーマは、コントロールをTableタグで配備したりするので、昨今のWebレイアウトには合わない部分も少なくないでしょう。テンプレートを自作したりして、テーマをカスタマイズすることはできますが、テンプレートの変更は面倒な場合が多くて不便です。もう一つの方法として、Tilesプラグインの利用を検討した方がよいかもしれません。「Tiles」とは、複数のJSPファイルを1枚のWebページに合成する機能です。Webページのヘッダーやフッターなど、共通して使う部分を独立して定義することができます。

 その他UIタグには、Ajaxタグなど便利そうなものもありますが、かゆいところに手が届かないものも多く、状況に応じて利用することが肝要です。

汎用タグ

 汎用タグは、Struts 2のドキュメントの分類では、制御タグとデータタグに分かれています。

汎用タグ一覧(制御タグ)

タグ名

説明

if

条件判定を行う

elseIf

else

append

複数の要素リストを連結する

generator

iteratorタグで処理できる要素を生成する

iterator

要素リストから、ひとつずつ要素を取り出す

merge

複数の要素リストを合成する

sort

要素をソートする

subset

要素リストの一部分を切り出す

汎用タグ一覧(データタグ)

タグ名

説明

a

HTMLのタグと同じ

action

Actionを呼び出す

bean

JavaBeansの生成

date

日付表示

debug

Value Stack(内部データ)の表示

i18n

メッセージリソースの変換

include

JSPファイルなどの呼び出し

param

struts.xml<param>タグを読み出す

property

オブジェクトのプロパティを参照する

push

Value Stack(内部データ)にデータを格納

set

変数に値をセットする

text

国際化に対応した文字列表示

url

URLの生成

 制御タグは、結果として返すHTMLにはまったく現れないタグです。条件判定を行ったり、内部のデータを操作するものです。

 データタグには、変数の表示など何らかの結果をレスポンスのHTMLで利用するもの、Actionを呼び出したりするものがあります。

 

0 件のコメント:

コメントを投稿