Struts 2の場合 1
Struts 1について理解したところで、もう1つのdefect-trackerを見てみましょう。今度はStruts 2を使用します。Struts 1とStruts 2の比較のために、設計はあまり変えないようにしたいと思います。
defect-trackerをStruts 2アプリケーションとして実装するには、まず「web.xml」ファイルを変更する必要があります。Struts 1では、ActionServletという名前のJavaサーブレットを使用して、特定のURIパターン(既定では「*.do」)に一致する要求をインターセプトしました。
Struts 2では、代わりにサーブレットフィルタを使用します。Struts 2の既定の拡張子は「*.do」ではなく、「*.action」です。この拡張子をフィルタマッピングで指定する必要はなく、これが前提となります。これは、多くの既定のStrutsプロパティと同様、「struts.properties」ファイルを編集し、classpathに配置することによってオーバーライドできます。Strutsの各バージョンはそれぞれ異なる方法で要求をマップするため、同じアプリケーションでStruts 1とStruts 2の両方を一緒に使用しても問題はありません。
Struts 2の「web.xml」内のフィルタマッピング
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher. FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Struts 1では、Strutsの構成に「struts-config.xml」ファイルを使用しました。たとえば、Actionへのパス名の割り当て、そのActionに伴うActionFormの定義、さまざまな種類のAction結果に対するActionForwardの指定は、「struts-config.xml」で行いました。
Struts 2では、この点が大きく変わっています。まず、Struts 2では「struts-config.xml」が「struts.xml」という名前のファイルに置き換わりました。「struts.xml」ファイルは、classpath内のどこにでも配置できます。「struts.xml」をよく見ると、いくつかの大きな変更に気づきます。何よりもまず、ActionFormが見当たりません。Struts 2では、開発者がページのデータを格納する場所について、制限を設けていません。たとえば、フォームデータをActionクラスから取得することができます(Struts 2ではActionが重要です)。また、Struts 2では、ActionForwardオブジェクトがResultオブジェクトに置き換わりました。Struts 1と同様、Actionは、「struts.xml」内のエントリに一致する文字列結果を返します。
defect-tracker内の2つのActionが、Struts 2ではどのように構成されているかを、以下に示します。要素名もそれぞれ変わっていることに注意してください。ほとんどの場合、この新しい要素名は、それぞれの内容を直感的に表すものとなっています。
<struts> <include file="struts-default.xml"/> <constant name="struts.custom.i18n.resources" value="MessageResources" /> <package name="default" extends="struts-default"> <action name="list" class="web.DefectsList"> <result>/pages/defects.jsp</result> </action> <action name="action_*" method="{1}" class="web.DefectsAction"> <result name="input">/pages/editDefect.jsp</result> <result type="redirect">list.action</result> </action> </package> </struts>
「struts.xml」内では、関連するアクションをパッケージ(package)にグループ化します。ここでは、既定のパッケージをそのまま使用します。もしたとえば「crud」という名前のパッケージを作成し、同様のタイトルをnamespace属性に指定した場合は、そのパッケージ内のActionに対応するURI要求は「/crud/*.action」という形式になります。開発者はここで定数を定義することにより、Struts 2フレームワーク内のいくつかの既定の設定をオーバーライドできます。Action宣言を見るとわかるように、1つの結果を名前なしで指定することができます。
Struts 2では、この既定のエントリが「success」結果とみなされるため、名前を指定する必要がありません。本稿の前半部分で説明したように、Struts 1では、DispatchActionを使用して不具合のCRUDイベントを処理していました。Struts 2では、DispatchActionを拡張する必要はありません(実際、Struts 2にDispatchActionは存在しません)。Struts 2では、特定のActionメソッドに制御を移すのではなく、ワイルドカード/プレースホルダのメカニズムを使用できます。たとえば、Struts 2のDeffectsActionでは、「action_go」というURIによって、対応するActionクラスのgoメソッドが呼び出されます。
「list.action」URI要求は、Struts 2バージョンのDefectsList Actionクラスにマップされます。そのコードを以下に示します。
package web; import business.DefectsManager; import com.opensymphony.xwork2.ActionSupport; import java.util.List; public class DefectsList extends ActionSupport { private List defects; private DefectsManager defectsManager; public List getDefects() { return defects; } public void setDefects(List defects) { this.defects = defects; } public void setDefectsManager(DefectsManager defectsManager) { this.defectsManager = defectsManager; } public String execute() { this.defects = this.defectsManager.getDefects(); return SUCCESS; } }
元のDefectsList Actionクラスと比較してみると、このコードの方がずっとすっきりしていますね。Struts 2 ActionSupportクラスを拡張する必要はありませんが、多くの有用なメソッドや定数にアクセスできます(結果として使用するSUCCESS定数など)。コードがこれだけすっきりしたのは、以前はexecuteメソッドに4つもパラメータがあったのに、今度は1つもなくなったからです。不要になったパラメータの1つはActionForm用であり、ActionFormはもうありません。さらに他のパラメータも、Struts 2が内部でSpringフレームワークを使用することにより、HTTPServletRequestオブジェクトなどの依存オブジェクトが実行時に必要に応じて注入されるようになったため、不要になりました。
Struts 2において依存性の注入と同じくらい重要な概念に、インターセプタの使用があります。インターセプタは、基本的に、Struts 2フレームワークで提供されるJavaクラスです。インターセプタを使用すると、Action実行の前後にロジックを実行できます。多くのStruts 2インターセプタが最初から用意されていますが、独自のインターセプタも作成できます。通常、インターセプタを使用するには、Actionクラスが適切なインターフェイスを実装します。次に、これが、実行するジョブを持つそのインターフェイスに関連付けられているインターセプタを呼び出します。
SpringはStruts 2に組み込まれているため、Spring Beanの注入は、Springマネージドビーンのsetterメソッドを作成するのと同じくらい簡単です。Struts 2は、この依存オブジェクトを実行時に自動的に注入します。Struts ActionクラスをSpring BeanとしてSpringの構成ファイル内で宣言することもできます。詳細については、Struts 2のドキュメントを参照してください。
Struts 2の「list」アクション(defects.jsp)の結果を示します。Struts 2タグライブラリは、Struts 1タグライブラリより使いやすく、ずっと強力です。タグライブラリの注目すべき機能の1つが、テーマの使用です。設定するテーマに応じて、タグは定型化された多くのマークアップを生成し、ページがごちゃごちゃになるのを防ぎます。テーマは全体で設定することも、個々のタグに対してオーバーライドすることもできます。ここでは、生成される出力がStruts 1バージョンのdefect-trackerに似るように、後者の方法を使用しています。リストページ上のStruts 2タグの例を示します。
<!--passes id as parameter to the input method on our Action--> <s:url id="editLink" action="action!input"> <s:param name="id" value="%{id}" /> </s:url> <!--Displays a formatted date as a label--> <s:date name="submittedOn" format="yyyy-MM-dd hh:mm" />
Struts 2のDefectsActionは、含まれるメソッド数を考えると、DefectsListよりすっきりしています。対処するActionFormもなく、長々としたメソッドAPIもありません。また、DefectsListの場合と同様、Springビジネス層に簡単にアクセスできます。完全なコードを以下に示します。
package web; import business.DefectsManager; import business.data.Defect; import com.opensymphony.xwork2.ActionSupport; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.interceptor.ServletRequestAware; import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut; public class DefectsAction extends ActionSupport implements ServletRequestAware { private Defect defect; private DefectsManager defectsManager; private HttpServletRequest request; public Defect getDefect() { return defect; } public void setDefect(Defect defect) { this.defect = defect; } public void setDefectsManager(DefectsManager defectsManager) { this.defectsManager = defectsManager; } public void setServletRequest(HttpServletRequest httpServletRequest) { this.request = httpServletRequest; } public String input() { if (request.getParameter("id") != null) { long id = Long.parseLong(request.getParameter("id")); this.defect = this.defectsManager.getDefect(id); } return INPUT; } public String delete(){ long id = Long.parseLong(request.getParameter("id")); this.defectsManager.removeDefect(id); return SUCCESS; } public String save() { this.defectsManager.saveDefect(this.defect); return SUCCESS; } }
Struts 1と同様、HTTPServletRequestにアクセスして、不具合のIDを取得する必要があります。このIDを取得するために、DefectsActionは、使用する中でおそらく最も一般的なStruts 2インターセプタを利用します。ServletRequestAwareインターフェイスを実装し、要求のsetterメソッドを追加すると、フレームワークによって、必要なときにそれを使用できます。このクラスのinputメソッドは、Struts 1版のアプリケーションのaddメソッドとeditメソッドに代わるものです。IDがあれば、不具合を照会します。それ以外の場合は、そのまま継続して結果を求めます。これが、「editDefect.jsp」になります。
Struts 2では、ページにnullオブジェクトへの参照が渡されると、自動的に新しいオブジェクトが作成されます。新しいDefectオブジェクトを作成するときには、まさにこれが必要です。
