Zero ConfigurationでHello World
まずは、例によって「Hello Worldアプリケーション」を作成していきましょう。次の図のように、ごくシンプルに、リンクをクリックすれば、Action
クラスが処理されて、文字列を表示するというものです。
ファイル構成
バージョンが2.1.6ということもありますので、新たなプロジェクト「ZeroProject」、としました。最初に、バージョン2.1.6のjarファイルをコピーしておきます。「http://www.meisei-u.ac.jp/mirror/apache/dist/struts/binaries/struts-2.1.6-all.zip」を解凍してできたlibディレクトリ以下のファイルが、Struts 2本体とプラグインファイルです。今回は、以下に示した、基本となるjarファイルとConventionプラグインを使用します。
- /WEB-INF/lib/commons-fileupload-1.2.1.jar
- /WEB-INF/lib/commons-io-1.3.2.jar
- /WEB-INF/lib/commons-logging-1.1.jar
- /WEB-INF/lib/freemarker-2.3.13.jar
- /WEB-INF/lib/junit-3.8.1.jar
- /WEB-INF/lib/ognl-2.6.11.jar
- /WEB-INF/lib/spring-test-2.5.6.jar
- /WEB-INF/lib/struts2-core-2.1.6.jar
- /WEB-INF/lib/xwork-2.1.2.jar
- /WEB-INF/lib/struts2-convention-plugin-2.1.6.jar
全体のファイル構成は、次のようになります。順に見ていきましょう。ここでは、「Hello Worldアプリケーション」の構成だけを示しています。ダウンロードできるサンプルには、後述するサンプルも含まれています。
<ContextRoot> ├ /WEB-INF │ ├ /classes │ │ ├ /zero.action │ │ │ └ ZeroAction.class │ │ └ struts.xml │ ├ /content │ │ └ zero.jsp │ ├ /lib │ │ └ 参照ライブラリー │ └ web.xml └ index.jsp
web.xml
web.xmlの記述も新しいバージョンでは、若干変更があります。
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>ZeroProject</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
<filter>
タグで指定するクラスが、org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
クラスとなりました。以前のFilterDispatcher
クラスは、非推奨に変更されています。ただし、このクラスには、前述した文字コードの変換漏れがあるため、リクエスト文字などで文字化けが発生してしまいます。応急的な解決策としては、文字コードの変換処理をAction
クラスに追加するか、以前のFilterDispatcher
クラスを使うかのどちらかです。
それ以外は、2.0系列との違いはありません。
struts.xml
次にstruts.xmlですが、これは以下の記述だけです。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="false" /> </struts>
「Zero Configuration」でなければ、Action
クラスの定義など、いろいろ記述する必要があるところですが、これだけで大丈夫です。画面遷移もまったく記述不要です。
Conventionプラグインの設定も、デフォルトでかまわないのであれば、特に指定する必要はありません(既定値などは後述します)。
Actonクラス
Acton
クラスは、次のように、連載第一回目のものとほぼ同じです。異なるのは、このクラスが、あるルールに従っているところだけです。
package zero.action; public class ZeroAction { private static final long serialVersionUID = 1L; private String replyMsg; public String getReplyMsg() { return replyMsg; } public void setReplyMsg(String message) { this.replyMsg = message; } public String execute() throws Exception { this.setReplyMsg( "これがZero Configuration" ); return "success"; } }
あるルールとは、このクラスをAction
クラスだと認識させるためのもので、struts.xmlでの定義の代わりになるものです。Conventionプラグインによって、デフォルトでは、以下のいずれかのルールに従っているクラスをAction
クラスと認識します。
- com.opensymphony.xwork2.Actionインターフェイスを実装してるクラス
- クラス名が「Action」で終わっているクラス
またConventionプラグインは、この条件に当てはまるAction
クラスを、struts、struts2、action、actionsという名前のパッケージからサーチします。
サンプルのZeroAction.javaでは、パッケージ名がzero.actionで、クラス名がZeroActionとなっていますので、このクラスはAction
クラスとして認識されることになります。
Action
クラスの名前が、デフォルトのAction名の生成に使用され、execute()
メソッドが呼び出されます。ただし、クラス名の最後の「Action」は、Action名から除かれ、さらに大文字と小文字を組みあわせたCamel形式の名前は、小文字をハイフンで区切った名前に変換されます。ZeroAction
クラスなら、「zero.action」になるということです。
また、ここで重要なポイントは、パッケージの階層とクラス名が、ActionのURIと対応(マッピング)していることです。パッケージの階層を上位からサーチして、最初にAction
クラスのパッケージだと認識したところがURIのルートになります。つまり、sample.actionパッケージにあるZeroAction
クラスなら、sample.actionがルートとなり、「/zero.action」ということです。その他、クラス名とActionを示すURIのマッピング例は、次のとおりです。
クラス名 | URI |
zero.action.ZeroAction | /zero.action |
sample.action.test.ZeroAction | /test/zero.action |
sample.struts.company.details.HelloWorldAction | /company/details/hello-world |
なお、URIの.actionは省略可能ですので、「/zero」とするだけで、「/zero.action」と見なされます。
Result処理
Resultに指定するViewテンプレートファイルにもルールがあります。サンプルコードでは、/WEB-INF/content/zero.jspとしていますが、デフォルトでは、/WEB-INF/content/以下からファイルがサーチされます。サーチされるファイル名は、Resultコードと対応しており、「Action名-Resultコード.jsp」となります。つまり、zero.actionから呼ばれるメソッドが"success"を返すなら、「zero-success.jsp」となります。
なお、Resultコードが"success"の場合は省略可能ですので、サンプルコードのように「Action名.jsp」が対応します。また、Action
クラスがサブパッケージにあれば、対応するResultファイルも同じ階層にあるものが対応することになります。
実際のマッピング例は、次のとおりです。
ActionのURI | サーチされるデフォルトのViewファイル |
/zero.action | /zero.jsp |
/test/zero.action | /test/zero-success.jsp |
/company/details/hello-world | /company/details/hello-world.jsp |
なお、デフォルトのResultタイプが「Dispatcher」ですので、まずjspファイルがサーチされ、それがなければ、HTMLファイル(.html)、velocity(.vm)、freemarker(.ftl)の順に探していきます。
従ってサンプルコードでは、「/zero」を指定すると、「/WEB-INF/content/zero.jsp」がViewテンプレートファイルとして用いられることになります。
注意点
Conventionプラグインの動作で、注意が必要なものがあります。それは、Action
クラスが見つからない場合、Action
クラスの処理がスキップされて、Viewテンプレートのみを処理してしまうことです。例えば、/WEB-INF/content/zero2.jspというファイルだけがあり、対応するAction
クラスがない状態でも、「/zero2.action」とすると、そのjspファイルが表示されてしまいます。
使い方によっては便利な機能ですが、危険な機能とも言えます。あやまって、Action
クラスと認識されないAction
クラスを作ってしまうと、そのクラスの実行がスルーされることになってしまうのです。