Struts2 メモ

Struts2はStrutsというよりはWebWork2の動作を多く継承している印象。

設定

とりあえず、インスコとかEclipseとかの設定は割愛(気が向いたらメモるけど)。 Struts2を利用するというとき、Struts経験者は、まずその過去の経験を一度忘れる。WebWork?経験者は結構そのままの知識で移行可能。

Struts2の設定の基本は次のファイル。

  1. struts.properties
  2. web.xml
  3. struts.xml
  4. struts-default.xml
  5. struts-plugin.xml

開発時に頻繁に書き換えるのは3になるでしょう。

struts.xml

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 
 
-
!
 
 
 
 
 
 
 
 
 
 
 
 
 
<?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="true" />
 
    <include file="category1.xml"/>
    <include file="category2.xml"/>
    <include file="category3.xml"/>
 
    <!-- Add packages here -->
 
</struts>

アクションやインターセプタなどの定義はこのファイルに書くことになるが、規模が大きくなるに連れてこのファイルに書く設定の量が肥大化してくる。そこで、あるカテゴリごと、機能ごとなどにxmlを分割して作成し、それをここにincludeすることができる。

例えば上記ではcategory1.xml、category2.xml、category3.xmlの3つの外部ファイルをincludeしている。

category1.xml の例

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 
-
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<?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>
 
    <package name="category1" namespace="/category1" extends="struts-default">
 
        <action name="HelloWorld" class="category1.HelloWorld">
            <result>/category1/HelloWorld.vm</result>
        </action>
 
        <action name="login" class="category1.LoginAction">
            <result name="input">/category1/login.vm</result>
            <result name="success">/category1/top.vm</result>
        </action>
        
        <!-- Add actions here -->
 
    </package>
</struts>

ワイルドカードマッピング

アクションが呼び出されるときの挙動例。

次のように書いたら、

<action name="login" method="login" class="category1.LoginAction">
    <result name="input">/category1/login.vm</result>
    <result name="success">/category1/top.vm</result>
</action>
  1. LoginAction?クラスのloginというメソッドが呼び出される。
  2. メソッドが失敗するとinputという文字列が返り、その場合はLogin.vmで示されるページが表示される。
  3. メソッドが成功するとsuccessという文字列が返り、Top.vmで示されるページが表示される。

Struts2ではexecute()というメソッドを必ず用意しなければならない、ということはない。好きな名前のメソッド名をつくって使える。

ちなみに、vmというのはvelocityというテンプレートエンジンが使用するファイルの拡張子。jspのようなもの。

上記は、nameで指定されているアクション(エイリアス)名とメソッド名が同じなので、次のようにも記述できる。

<action name="*" method="login" class="category1.LoginAction">
    <result name="input">/category1/login.vm</result>
    <result name="success">/category1/top.vm</result>
</action>

これでlogin.doなどで呼び出されたら、LoginAction?クラスのloginメソッドが呼び出されることになる。

<action name="*Menu" method="{1}" class="category1.MenuAction">
    <result name="input">/category1/init.vm</result>
    <result name="success">/category1/menu.vm</result>
</action>

この場合、呼び出されるメソッド名は自動的にMenuAction?クラスが実装しているメソッドから検索される。例えば、initMenu.doなどと呼び出せば、methodには"init"が挿入され、MenuAction?のinitメソッドが呼び出されることになる。

さらに上記はresultで指定されているinit.vmというファイル名がメソッド名と同じなので、

<action name="*Menu" method="{1}" class="category1.MenuAction">
    <result name="input">/category1/{1}.vm</result>
    <result name="success">/category1/menu.vm</result>
</action>

と書けば、戻り値がinputのときにinit.vmというページが表示されることになる。

アクションの拡張子

Struts2では、標準で"action"という拡張子が設定されている(Strutsの"do"に相当する拡張子)。これが気に入らないという場合、これも自由に変更可能。

struts.properties ファイルの中に

  1
  2
### Used by the DefaultActionMapper
### You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do
struts.action.extension=action

という行があるので、ここを好きな拡張子に書き換えるか追記する。

例えば、従来のStrutsのようにdoじゃないとダメだという人は、

struts.action.extension=do

と書いてしまえば良い。

ここは何でも良い。極端な話、"html"とか"aspx"などを指定することもできるので、静的ページや.NETで動いているページに偽装することもできるヨ?(そんな意味ないけど)。

基本的なアクション

Strutsのexecute()メソッドではActionMapping?ActionForm?HttpServletRequest?HttpServletResponse?の4つの引数が渡されてきていた。しかし、Struts2のアクションクラスで呼び出されるメソッドには引数がない。Strutsから移行してきた人の多くは、まずこれに戸惑うはず?

どこからパラメータを取れば良いのか?の回答は、どこでも取れる、ということになる。 例えば、ログイン画面から入力されたユーザ名とパスワードをアクションが取得して認証する、という処理を書きたい場合、

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 
-
|
|
|
-
|
!
-
|
-
-
|
!
|
!
|
-
|
!
|
|
-
|
!
-
|
!
|
-
|
!
|
|
-
|
!
-
|
!
!
import com.opensymphony.xwork2.ActionSupport;
 
public class LoginAction extends ActionSupport {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * ログイン処理を実行する。
     */    
    public String login() throws Exception {
        
        // NOTICE authentication() はどこかに作成しておく。
        if (authentication(userName,password)) {
            return "success";
        }
        return "input";
    }
 
    /**
     * ユーザ名
     */
    private String userName;
 
    /**
     * ユーザ名を設定する。
     */
    public void setUserName(String userName){
        this.userName = userName;
    }
 
    /**
     * パスワード
     */
    private String password;
 
    /**
     * パスワードを設定する。
     */
    public void setPassword(String password){
        this.password = password;
    }
}

と書けば良い。

ActionSupport?を継承したクラスをアクションクラスとし、パラメータ名を設定するsetterメソッド(publicスコープで)を用意しておくだけ。

これで、アクションが起動されたときに、その名前のパラメータが渡されてきたら、自動的にそのsetterが呼び出され、メンバ変数に設定されることになる。なんと便利。

モデルドリブン

アクションの中にすべての変数を用意してそこにsetterを書いても良いが、パラメータは別オブジェクトに分離して持たせることができる。そのオブジェクトのことを「モデル」と呼ぶ。

モデルとなるクラスにはパラメータとなる変数を持たせておいて、そのsetter、getterを用意しておくだけ。これで、アクションクラスに持つパラメータはモデルのみとなり、処理に専念するクラスにすることができる。

モデルドリブンを使用するには、struts.xmlにModelDrivenInterceptor?を設定し(多分デフォルトで設定されている?)、アクションクラスではModelDriven?をimplements、getModel()メソッドを実装しておく。

アクション側

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 
 
 
 
-
|
|
|
-
|
!
-
|
-
-
|
!
|
!
|
-
|
!
|
|
-
|
!
-
|
!
!
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
 
import category1.LoginModel;
 
public class LoginAction extends ActionSupport implements ModelDriven {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * ログイン処理を実行する。
     */    
    public String login() throws Exception {
        
        // NOTICE authentication() はどこかに作成しておく。
        if (authentication(loginModel.getUserName(),loginModel.getPassword())) {
            return "success";
        }
        return "input";
    }
 
    /**
     * パラメータを保持するモデル
     */
    private LoginModel loginModel = new LoginModel();
 
    /**
     * モデルを取得する。
     */
    public Object getModel() {
        return loginModel;
    }
}

モデル側

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
-
|
|
|
-
|
!
-
|
!
|
|
|
-
|
!
-
|
!
!
public class LoginModel {
 
    private String userName;
 
    public void setUserName(String userName){
        this.userName = userName;
    }
    public String getUserName(){
        return userName;
    }
 
    private String password;
 
    public void setPassword(String password){
        this.password = password;
    }
    public String getPassword(){
        return password;
    }
}

Strutsのアクションの引数を取得したい

それでもやっぱりStruts時代に取得できていたHttpServletRequest?などの情報もほしいよ?という場合もある。それらの情報は消えているわけじゃなく、ちゃんとどこかに保持されているので、それを取り出せるようなsetter、getterを実装すれば良い。

例えばHttpServletRequest?を取得する場合、ServletRequestAware?インタフェースをimplementsしてsetServletRequest?()を実装する。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 
 
 
 
 
-
|
|
|
-
|
!
|
!
 
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts2.interceptor.ServletRequestAware;
 
public class ExampleAction extends ActionSupport
    implements ModelDriven, ServletRequestAware {
 
    private HttpServletRequest request;
 
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
 
}

インターセプタ

Job から ServletContext? を参照する

Action 以外から ServletContext? を参照するとか。

jobContext.xml

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 
 
 
 
 
 
 
 
 
 
 
<bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>
 
<bean name="myDataUpdater" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="MyDataUpdater"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="servletContext"><ref bean="servletContext"/></entry>
        </map>
    </property>
</bean>

こうすればマップからとれる。

jobSample.java

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
-
|
|
!
 
public void executeInternal(JobExecutionContext cntxt) throws JobExecutionException {
         ServletContext servletContext=(ServletContext)cntxt.getJobDetail().getJobDataMap().get("servletContext");
 
}

または、setter で。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
 
 
-
|
!
 
    private ServletContext servletContext;
 
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

リソースパス

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 
 
-
-
!
|
|
|
!
 
 
    String path = context.getRealPath("");
 
    if (path == null) {
        // resources are in a .war (JBoss, WebLogic)
        java.net.URL url = context.getResource("");
 
        System.out.println("found url; " + url);
        path = url.getPath();
    }
 
    p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);

参考サイト

公式


MLEXP. Wiki


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS