出るみたいです。

原書買わずに待てば良かった。。。

Programming in Scalaで勉強

配列に値を設定してfor文で出力

var greetings = new Array[String](3)
greetings(0) = "Hello"
greetings(1) = "Good Morning"
greetings(2) = "Good Evening"
greetings(3) = "Good Afternoon"

for(i <- 0 to 3){
prnitln(greeting(i)
}


こんな書き方もできる。
var greetings = Array("Hello","Good Morning","Good Afternoon","Good Afternoon")
for(i <- 0 to 3){
prnitln(greeting(i))
}

Programming in Scalaで勉強

引数を2つ渡し、大きい方の値を返却するメソッドmaxを定義する。

public int max(int a, int b){
if(a > b){
return a;
} else {
return b;
}
}

上記のjavaで書いたメソッドをそのままscalaで書き換えると
def max(a:Int, b:Int):Int = {
if(a > b){
return a;
} else {
return b;
}
}
になる。

scalaではメソッドはdefで始まる。
javaでは戻り値、メソッド名、引数の順番だが、scalaではメソッド名、引数、戻り値の順番になる。
また、javaの引数は型、仮引数の順番だが、scalaでは仮引数、型の順番になる。


scalaではセミコロンを省略できるので
def max(a:Int, b:Int):Int = {
if(a > b){
return a
} else {
return b
}
}
と書いてもよい。

また、returnも省略できるので
def max(a:Int, b:Int):Int = {
if(a > b){
a
} else {
b
}
}
と書ける。

ついでにカッコも省略して
def max(a:Int, b:Int):Int = {
if(a > b)
a
else
b
}
}

Programming in Scalaで勉強

Scalaには2種類の変数(valとvar)がある。
valはjavaのfinal変数と同じ。
varはjavaのfinalでない変数と同じ。

var greeting = "Hello"
greeting = "bey"
はOKだが

val greeting = "Hello"
greeting = "Bey"
はエラーとなる。

PrepareInterceptorはActionで実際に呼び出されるメソッドの前処理用のメソッドを呼び出す。使用するためにはActionクラスでPreparableを継承する。

前処理用のメソッドとして以下のメソッドが順番に呼び出される(1,2はメソッドが存在する場合のみ、また2は1のメソッドが存在したら呼び出されない。)

  1. prepare{メソッド名}()
  2. prepareDo(メソッド名}()
  3. prepare()

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;

public class ProperSample extends ActionSupport implements Preparable{

public void prepareHoge() throws Exception {
System.out.println("prepareHoge()")
}

public void prepareDoHoge() throws Exception {
System.out.println("prepareHoge()")
}

public void prepare() throws Exception {
System.out.println("prepare")
}

public String hoge() throws Exception{

return SUCCESS;
}
}

例えば、上記のようなクラスが存在しhoge()メソッドが呼び出されるURLが叩かれたとすると、
まずprepareHoge()がよばれ、次にprepare()がよばれる。(prepareHoge()が存在するのでprepareDoHoge()は呼び出されない。)その後に、他に積まれているインターセプターがあればそれを実行し、その後hoge()メソッドが呼ばれる。

デフォルトではprepare()は必ず呼び出される。これを止めたい(要するにprepare{メソッド名}()またはprepareDo{メソッド名}()だけを呼び出したい)場合はalwaysInvokePrepareフィールドを"false"にする。で、これを行うためには以下のような記述をする。

<interceptor-ref name="prepare">
<param name="alwaysInvokePrepare">false</param>
</interceptor-ref>

PrepareInterceptorはstruts-default.xmlで宣言されているinterceptor-stackにはすべて組み込まれている。よって、struts-default.xmlで宣言されているいずれかを使用する場合はstruts.xmlにPrepareInterceptorを使用するための定義を書く必要はない。

ServletConfigInterceptorはActionクラスにHttpServletRequest、HttpServletResponse、ServletContextなどの情報を設定してくれる。ただし、設定される為にはサポートされてるインターフェースをActionで継承しなければならない。サポートされるのは以下のインターフェース。

  • ServletContextAware
  • ServletRequestAware
  • ServletResponseAware
  • ParameterAware
  • RequestAware -
  • SessionAware
  • ApplicationAware
  • PrincipalAware


仮にサポートされるすべてのインターフェースを継承したクラスを作成すると以下のようになる。各setterメソッドに対してServletConfigInterceptorが値を設定してくれる。


import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.PrincipalAware;
import org.apache.struts2.interceptor.PrincipalProxy;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;


public class HogeAction extends ActionSupport implements ServletContextAware,
ServletRequestAware,
ServletResponseAware,
ParameterAware,
RequestAware,
SessionAware,
ApplicationAware,
PrincipalAware{

private ServletContext servletContext;
private HttpServletRequest request;
private HttpServletResponse response;
private Map parameterMap;
private Map requestMap;
private Map sessionMap;
private Map applicationMap;
private PrincipalProxy principalProxy;

public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public void setParameters(Map parameterMap) {
this.parameterMap = parameterMap;
}
public void setRequest(Map requestMap) {
this.requestMap = requestMap;
}
public void setSession(Map sessionMap) {
this.sessionMap = sessionMap;
}
public void setApplication(Map applicationMap) {
this.applicationMap = applicationMap;
}
public void setPrincipalProxy(PrincipalProxy principalProxy) {
this.principalProxy = principalProxy;
}
}

ServletContextAware、ServletRequestAware、ServletResponseAwareを継承してしまうとservletApiに依存したクラスになってしまうので注意が必要。(テストがしにくくなるとか、フレームワークがせっかく隠してくれてたのに〜 っているのが理由)リクエストの値がとりたい場合はRequestAware、セッションの値がとりたい場合はSessionAwareを継承しとけば値がとれる(かつservletApiにも依存しなくて済む)のでそれらの値がとりたいだけであれば、上記インターフェースの継承は不要。

また、SessionAware,RequestAware、ParameterAware、を継承してServletConfigInterceptorに値を設定してもらわなくても、Action内で直接以下のように書けば同じように値を取得できる(ServletConfigInterceptorがやっていることと一緒だけど。。)
ActionContext.getContext().getSession().get("foo");
ActionContext.getCongext().get("request").get("bar");
ActionContext.getParameters().get("hoge");


Actionに対して使用するインターセプターをstruts-default.xmlで宣言しているinterceptor-stackを使用する場合はstruts.xmlに対して何も記述の必要はない。(struts-default.xmlで宣言されているすべてのinterceptor-stackにServletConfigInterceptorが入っているため)もし、自分でinterceptor-stackをstruts.xmlに宣言して、その中にServletConfigInterceptorを追加したい場合は以下の記述を追加する。
<interceptor-ref name="servletConfig"/>

2009/07/29

Hello, Scala!


Scalaが最近,将来のJava 後継者の有力候補として注目を集めている。Java の創作者である James Gosling 氏やJRuby の主要開発者である Charles Nutter氏に続いて,Groovy の創作者であるJames Strachan氏もScalaへの賛意を表明している。

Javaの将来的な後継者としての Scala


この記事でScalaに興味が湧き、いろいろといじり始めている。英語ダメダメなのに洋書のProgramming in Scalaも買ってしまった。

まずはお決まりのやつ

object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala!")
}
}

ExceptionMappingInterceptorは例外処理のハンドリングをやってくれる。
具体的には、例外を補足して遷移先画面の振り分けを行う。


<package name="example" extends="struts-default">
<global-results>
<result name="error">error.jsp</result>
</global-results>

<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>

<action name="Foo" class="example.FooAction" >
<interceptor-ref name="defaultStack"/>
<exception-mapping exception="example.HogeException" result="hoge_error"/>
<result >/example/Foo.jsp</result>
<result name="hoge_error">/example/hoge_error.jsp</result>
</action>
</package>

上記struts.xmlだと、exampleという名前でグループ化したURLでjava.lang.Exceptionが発生した場合、error.jspに飛ばされる。また、example.FooAction呼び出しの際にexample.HogeExceptionが発生した場合、example/hoge_error.jspに飛ばされる。

ExceptionMappingInterceptorを使用する際に気をつけることは、複数のインターセプターを呼ぶ場合は1番最初に呼び出すようにする。つまり<interceptor-ref name="exception"/>を1番最初に書くようにする。
理由は、ExceptionMappingInterceptorよりも前に別のインターセプターを呼び出し、そのインターセプターで例外が発生しても補足ができないため。

上記struts.xmlでは<interceptor-ref name="exception"/>はどこにも書いてない。理由はstruts-defaultパッケージを継承しており、そこに含まれているdefaultStackを使用しているため。defaultStackには<interceptor-ref name="exception"/>が含まれている。
フレームワークが用意しているinterceptor-stackはすべて<interceptor-ref name="exception"/>が含まれており、大抵のものが先頭に書いてある。

もしフレームワークが用意しているinterceptor-stackを使用せず、インターセプターの定義をすべて自分で書くのであれば<interceptor-ref name="exception"/>を書くことと、書く順番に注意する。

ExceptionMappingInterceptorで補足した例外の内容(Throwable.getMessage)をログに出力したい場合は以下のような書き方をする。

<interceptor-ref name="exception">
<param name="logEnabled">true</param>
<param name="logCategory">jp.co.hogehoge</param>
<param name="logLevel">WARN</param>
</interceptor-ref>

<param name="logEnabled">true</param>は必須で <param name="logLevel">は記載がないとdebugレベルになる。(trace, debug, info, warn, error, fatal以外の値を書くとIllegalArgumentExceptionが発生)

ExceptionMappingInterceptorの処理はexception-mappingのresult要素に関連付けられた画面に飛ばすだけだが、他に何か処理をしたい場合は
publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder)
という拡張ポイントが用意されているのでExceptionMappingInterceptorを継承したクラスを作成し、上記メソッドに処理を書くとよいかもしれない。

2009/07/25

netbeansよさげ

最近Scalaを覚え始め、eclipseにscalaのプラグインを入れてコーディングし始めたけど、プラグインが全然使い物にならない。(mainメソッドがあるのにmainメソッドがないので実行できないと怒られたり、undoが効かなくなったりする。)

で、netbeansにもscalaプラグインがあるみたいなのでnetbeansでコーディングしてみると全然問題なし。scalaプラグインの件を別にしてもnetbeansは昔に比べるとすごく使いやすくなってる気がする。なので、これを機にメインをIDEをnetbeansに変えちゃおうと思う。

AliasInterceptorはパラメータにエイリアスをつける。


<package name="example" namespace="/hogehoge" extends="struts-default">
<action name="hoge" class="example.HogeAction" method="browse">
<param name="aliases">#{ 'foo' : 'bar' }</param> - (1)
<interceptor-ref name="alias"/> - (2)
<result name="success">/date.jsp</result>
</action>
</package>

class HogeAction{
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}

上記のようなstruts.xmlとActionクラスがあるとする。
通常、http://struts2/hogehoge/hoge.action?foo=aaaとリクエストが来たらHogeActionクラスのfooに対して"aaa"が設定されるが、(1)と(2)があることによりHogeActionクラスのbarに対して"aaa"が設定される。複数のパラメータに対してエイリアスをつけたい場合は#{ 'foo' : 'bar', 'foo2' : 'bar2'}のようにカンマで区切れば良い。また、デフォルトのエイリアスキー"aliases"を変更したい場合は、以下のようにすればよい。(以下は"booboo"に変更)


<package name="example" namespace="/hogehoge" extends="struts-default">
<action name="hoge" class="example.HogeAction" method="browse">
<param name="booboo">#{ 'foo' : 'bar' }</param>
<interceptor-ref name="alias">
<param name="aliasesKey">booboo</param>
</interceptor-ref>
<result name="success">/date.jsp</result>
</action>
</package>

InterceptorはActionの実行前や実行後に処理を差し込むことができる。
Actionに対してinterceptorを追加、変更、削除したい場合はstruts.xmlを修正するだけで済む。
com.opensymphony.xwork2.interceptor.Interceptorやcom.opensymphony.xwork2.interceptor.AbstractInterceptorを継承して自分でInterceptorを作ることもできるが、大抵のものはFrameworkで用意されているのでそれを使用するとよい。(struts-default.xmlのinterceptor要素でFrameworkで用意されているinterceptorが定義されている。

サンプル1


<package name="example" namespace="/hogehoge" extends="struts-default">

<action name="Foo" class="example.Foo" method="insert">
   <interceptor-ref name="defaultStack"/>
<result>/example/Foo.jsp</result>
</action>

<action name="Bar" class="example.Bar" method="update">
   <interceptor-ref name="defaultStack"/>
<result>/example/Foo.jsp</result>
</action>
<package/>

example.Foo.insert(),example.Bar.update()が実行される前にdefaultStackというinterceptorが実行される。interceptor-refのname属性は1つのinterceptorにつけられた名前、または複数のinterceptorをひとまとめにしたものに名前をつけたもになている。struts-default.xmlで確認するとわかるが、上記のdefaultStackというinterceptorは複数のinterceptorを1まとめにして名前をつけたものになっている。
また、上記のようにpackage要素内それぞれのactionで同じinterceptorを使うのであれば下記のようにdefault-interceptor-refを使った書き方もできる。


サンプル2

<package name="example" namespace="/hogehoge" extends="struts-default">
<default-interceptor-ref name="defaultStack"/>

<action name="Foo" class="example.Foo" method="insert">
<result>/example/Foo.jsp</result>
</action>

<action name="Bar" class="example.Bar" method="update">
<result>/example/Foo.jsp</result>
</action>
<package/>



自分で作成したinterceptorやstruts-default.xmlに記載してある方法以外でひとまとめにしたものを使用したい場合は下記のように定義をすればよい

サンプル3

<package name="example" namespace="/hogehoge" extends="struts-default">
<interceptors> - (1)
<interceptor name="hogehoge" class="example.HogeHogeInterceptor"> - (2)

<interceptor-stack name="defaultStackHogeHoge"> - (3)
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="hogehoge"/>
</interceptor-stack>
<interceptors>

<action name="Foo" class="example.Foo" method="insert">
<interceptor-ref name="hogeHoge"/>
<result>/example/Foo.jsp</result>
</action>

<action name="Bar" class="example.Bar" method="update">
<interceptor-ref name="defaultStackHogeHoge"/>
<result>/example/Foo.jsp</result>
</action>
<package/>

定義の仕方は(1)のようにinterceptors要素を定義し、子要素として、新たなinterceptorの定義は(2)のように、新たなinterceptorをまとめたものの定義は(3)のように記載する。

result要素の属性には、以下の値が設定できる
name: マッピング名。省略した場合は"success"になる
type: Actionクラスの処理終了後に呼ばれるタイプ。省略した場合は"dispatcher"になる

tpyeに設定できる値としてデフォルトでは以下のものが設定できる

Type説明
chain他のActionクラスを呼び出す
dispatcherviewにjspを使う
freemarkerviewにfreemarkerを使う
httpheaderHTMLのヘッダーのみ返す
redirect他のURLへリダイレクトする
redirectAction他のActionクラスへリダイレクトする
streamファイルのダウンロードで使用
velocityviewにvelocityを使う
xsltviewにxsltを使う
plainTextviewにplainTextを使う


上記の値はstruts-default.xml内のresult-typeに定義されている

サンプルを使って説明

<package name="example" namespace="/hogehoge" extends="struts-default">
<action name="Foo" class="example.Foo">
<result>/example/Foo1.jsp</result>
<result name="input">/example/Foo2.jsp</result>
</action>
<package/>
  • example.Fooクラスが"success"を返すと/example/Foo1.jspが呼ばれる。
  • example.Fooクラスが"input"を返すと/example/Foo2.jspが呼ばれる。


struts-default.xml内に定義してあるもので要件を満たせなければ、com.opensymphony.xwork2.Resultインターフェース、もしくはそれらの子クラスを継承する形で自分で作れば良い。作ったものはstruts-default.xmlで記載してあるように<result-types>タグでくくって宣言すれば使えるようになる


<package name="example" namespace="/hogehoge" extends="struts-default">
<result-types>
<result-type name="freemarker2" class="example.FreemarkerResult2" />
</result-types>

<action name="Foo" class="example.Foo">
<result type="freemarker2">/example/Foo.ftl</result>
</action>
<package/>

action要素の属性には、以下の値が設定できる
name: マッピング名
class: 呼び出されるクラス。省略するとcom.opensymphony.xwork2.ActionSupportクラスが呼ばれる。
method: 呼び出されるメソッド。省略するとexecute()メソッドが呼ばれる。
converter: ???

サンプル(基本パターン)

<package name="example" namespace="/hoge" extends="struts-default">
<action name="aaa"> - (1)
<result>showcase.jsp</result>
</action>
<action name="bbb" class="example.FooAction"> - (2)
<result>/example/Foo.jsp</result>
</action>
<action name="ccc" class="example.BarAction" method="insert"> - (3)
<result>/example/Foo.jsp</result>
</action>
<action name="ddd" class="example.BarAction" method="update"> - (4)
<result>/example/Foo.jsp</result>
</action>
<package/>


コンテキスト名はstruts2,マッピングされる拡張子をactionとすると、
  • http://struts2/hoge/aaa.actionで(1)にマッピングされる。class、methodが省略されているのでcom.opensymphony.xwork2.ActionSupport.execute()が呼ばれる。
  • http://struts2/hoge/bbb.actionで(2)にマッピングされる。example.FooAction.execute()が呼ばれる
  • http://struts2/hoge/ccc.actionで(3)にマッピングされる。example.BarAction.insert()が呼ばれる
  • http://struts2/hoge/ccc.actionで(4)にマッピングされる。example.BarAction.update()が呼ばれる


ワイルドカードを使ったマッピングを行うこともできる。

サンプル(ワイルドカード使用パターン)
<package name="example" namespace="/hoge" extends="struts-default">
<action name="hoo_*" class="example.BarAction" method="{1}"> - (1)
<result>/example/Foo.jsp</result>
</action>
<action name="*_bar" class="example.Hoge{1}Action""> - (2)
<result>showcase.jsp</result>
</action>
<package/>
  • http://struts2/hoge/hoo_insert.actionで(1)にマッピングされる。example.BarAction.insert()が呼び出される。
  • http://struts2/hoge/hoo_bar.actionで(1)にマッピングされる。example.BarAction.update()が呼び出される。
  • http://struts2/hoge/hoge_insert.actionで(2)にマッピングされる。example.HogeinsertAction.execute()が呼び出される。
  • http://struts2/hoge/hoge_update.actionで()にマッピングされる。example.HogeupdaterAction.execute()が呼び出される。
(1)は基本パターンの(3)と(4)を1つにまとめて書く例になっている。


Springと一緒に使用して、Actionをspringに管理させる場合は以下のようになる。
サンプル(ActionクラスをSpringで管理パターン)
<package name="example" namespace="/hoge" extends="struts-default">
<action name="hoge" class="hogehoge">
<result>/example/Foo.jsp</result>
</action>

これはspringで使用するapplicationContext.xmlの一部

<bean id="hogehoge" class="example.HogeAction" scope="request" ></bean>

classで指定しているhogehogeがhogehoge.javaではなく、springで管理しいるbeanのidとマッピングされる。springで管理する際にはscope要素に気をつける。springはデフォルトスコープがsingletonだが、struts2のActionクラスはステートフルなクラスなのでスコープがsingletonということはほぼない。大抵はrequestでよいと思われる。Actionクラスをセッションで管理したければsessionにすればよい。

package要素の属性には、以下の値が設定できる
name :複数のアクションをグループ可する際の名前。別のpakage名とダブらないようにする(必須)
extends :別のpackageを継承する。継承することによりそのパッケージの要素にアクセスできるようになる(任意)
namespace:urlの一部になる(任意)
abstract :trueを設定すると、子要素のactionが必須項目でなくなる(任意)

サンプルを使って説明


<package name="example" namespace="/hogehoge" extends="struts-default">
<action name="Foo" class="example.Foo">
<result>/example/Foo.jsp</result>
</action>

<action name="Bar" class="example.Bar">
<result>/example/Bar.jsp</result>
</action>
<package/>

上の例だと、
・exampleという名前でグループ化
・アプリケーションのコンテキストがstruts2とすると、このグループのURLはhttp(s)://struts2/hogehoge/xxx になる
・struts-defaultの要素にアクセスできる
・abstract要素がないので子要素にはactionが必ず必要
ということになる。

ちなみにstruts-defaultのパッケージ要素はstruts2がデフォルトで持っているもので、
src/main/resources/struts-default.xml内に記載してある。以下がその内容。

<package name="struts-default" abstract="true">
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
</result-types>

<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />

<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
</interceptor-stack>

<!-- Sample validation and workflow stack -->
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>

<!-- Sample JSON validation stack -->
<interceptor-stack name="jsonValidationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="jsonValidation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>

<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample model-driven stack -->
<interceptor-stack name="modelDrivenStack">
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample action chaining stack -->
<interceptor-stack name="chainStack">
<interceptor-ref name="chain"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample i18n stack -->
<interceptor-stack name="i18nStack">
<interceptor-ref name="i18n"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- An example of the paramsPrepareParams trick. This stack
is exactly the same as the defaultStack, except that it
includes one extra interceptor before the prepare interceptor:
the params interceptor.
This is useful for when you wish to apply parameters directly
to an object that you wish to load externally (such as a DAO
or database or service layer), but can't load that object
until at least the ID parameter has been loaded. By loading
the parameters twice, you can retrieve the object in the
prepare() method, allowing the second params interceptor to
apply the values on the object. -->
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
<!-- A complete stack with all the common interceptors in place.
Generally, this stack should be the one you use, though it
may do more than you need. Also, the ordering can be
switched around (ex: if you wish to have your servlet-related
objects applied before prepare() is called, you'd need to move
servletConfig interceptor up.
This stack also excludes from the normal validation and workflow
the method names input, back, and cancel. These typically are
associated with requests that should not be validated.
-->
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="profiling"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<!-- The completeStack is here for backwards compatibility for
applications that still refer to the defaultStack by the
old name -->
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<!-- Sample execute and wait stack.
Note: execAndWait should always be the *last* interceptor. -->
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>

<default-interceptor-ref name="defaultStack"/>
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
</package>

でましたね。
http://www.eclipse.org/

スプラッシュ画面は3.4とほとんど同じだけど、Welcome画面が大分変わってた。



かっちょいい。

struts.xmlを分割して管理したい場合に使用。


(例)


<struts>
 ...

<include file="struts-chat.xml" />
<include file="struts-interactive.xml" />
<include file="struts-hangman.xml" />
<include file="struts-tags.xml"/>
<include file="struts-validation.xml" />
<include file="struts-actionchaining.xml" />
<include file="struts-ajax.xml" />
<include file="struts-fileupload.xml" />
<include file="struts-person.xml" />
<include file="struts-wait.xml" />
<include file="struts-jsf.xml" />
<include file="struts-token.xml" />
<include file="struts-model-driven.xml" />
<include file="struts-integration.xml" />
<include file="struts-filedownload.xml" />
<include file="struts-conversion.xml" />
<include file="struts-freemarker.xml" />
<include file="struts-tiles.xml" />
<include file="struts-xslt.xml" />

 ...

<struts/>

struts.xmlで使用できる属性、要素はここのdtdファイルでわかる。

まずはconstant要素

これはsturts2のデフォルトの設定を上書く際に使用する。
デフォルトの設定はstruts2-core-2.1.xxx.jarのorg/apache/struts2/default.propertiesに書かれている。
デフォルトでは以下の値が定義されている


struts.i18n.encoding=UTF-8
struts.objectFactory.spring.autoWire = name
struts.objectFactory.spring.useClassCache = true
struts.objectFactory.spring.autoWire.alwaysRespect = false
struts.multipart.parser=jakarta
struts.multipart.saveDir=
struts.multipart.maxSize=2097152
struts.action.extension=action,,
struts.serve.static=true
struts.serve.static.browserCache=true
struts.enable.DynamicMethodInvocation = true
struts.enable.SlashesInActionNames = false
struts.tag.altSyntax=true
struts.devMode = false
struts.i18n.reload=false
struts.ui.theme=xhtml
struts.ui.templateDir=template
struts.ui.templateSuffix=ftl
struts.configuration.xml.reload=false
struts.velocity.configfile = velocity.properties
struts.velocity.contexts =
struts.velocity.toolboxlocation=
struts.url.http.port = 80
struts.url.https.port = 443
struts.url.includeParams = none
struts.dispatcher.parametersWorkaround = false
struts.freemarker.templatesCache=false
struts.freemarker.beanwrapperCache=false
struts.freemarker.wrapper.altMap=true
struts.freemarker.mru.max.strong.size=100
struts.xslt.nocache=false
struts.mapper.alwaysSelectFullNamespace=false
struts.ognl.allowStaticMethodAccess=false

開発中のみ、値を変更する(false→ture)可能性が大きいパラメーター
  • struts.configuration.xml.reload:リクエストの度にxmlファイルを読み直す
  • struts.i18n.reload:リクエストの度にリソースファイルを読み直す(※と書いてあるけどファイルの内容を変更しても読み直してくれなかった。なぜ??)
  • struts.devMode:上記2つを1度に設定し、ログも詳細に吐き出される。
    また、jsp上に<s:debug></s:debug>タグを記載すると[debug]というリンクが出現し、クリックするとValueStackに積まれている内容を見ることができる。これは自分が想定していた値がjsp上でとれなかった場合に原因を探る際にすごく便利
開発以降、変更する可能性が大きいパラーメーター
struts.action.extension:デフォルトはstruts.action.extension=action,,となっている(カンマ区切りで空文字もあることに注意)これは、例えばstruts.xml内で<action name="hoge" class="HogeHoge">と定義があった場合、
xxx/hoge.actionまたは、xxx/hogeというURLでHogeHogeクラスが呼び出されることを意味する。なので、デフォルトのactionという拡張子や拡張子なしが嫌な場合は、この値を変更すればよい。

constantタグ以外でのパラメーターの変更方法
struts.xml内でconstantタグを使用して変更する以外に、変更したい値をstruts.propertiesに書き、classpathが通っているフォルダの直下に置くことでも変更することができる。もし、struts.xmlとstruts.properties両方で同じパラメータに対し違う値を設定していたら、struts.propertiesで設定した値が有効になる。

例)struts.xmlでは<constant name="struts.action.extension" value="do,," />、struts.propertiesではstruts.action.extension=cgiと設定した場合、<action name="hoge">のhogeにマッピングされてるクラスに対してはxxx/hoge.cgiでのみアクセスでき、xxx/hoge.doやxxx/hogeではアクセスできない。

このやり方よりもMavenを使ったほうが楽だったので変更する。

前提

  • ここの前提の状態が終了していること
  • Mavenがインストール、環境設定への設定済みで、eclipseにM2_REPOが設定してあること。(m2eclipseなどのeclipseからMavenを利用する為のプラグインは入れる必要はなし。)

手順
  1. [Java Project]を新規に作成(プロジェクト名はstruts2-showcaseとして以後説明)
  2. 作成したプロジェクトを右クリック→[import]→[General]→[File System]を選択
  3. [File Directory:]にここでダウンロード、展開したフォルダ内のsrc/apps/showcaseまでを入力し[shoucase]にチェックをいれ[Finish]ボタンをクリック。(pom.xmlにもチェックが入っていること。また、この時点ではコンパイルエラーが出てるが気にしない。)
  4. コンソールにて1.で作成したプロジェクト名まで移動し mvn eclipse:eclipse とコマンドを打つ。「BUILD SUCCESSFUL」 が出力されれば成功。
  5. eclipse上から作成したプロジェクト上でF5を押し、コンパイルエラーがなくなっていることを確認する。
  6. Project Explorer上から作成したプロジェクト上で、右クリック→[Properties]→[Tomcat]→[全般]タブを選択し、以下の処理を行う
    ・[Tomcatプロジェクト]にチェックを入れる
    ・コンテキスト名を入力(ここでは「struts2-showcase」とする。)
    ・Webアプリケーション・ルートとするサブディレクトリーに「/src/main/webapp」を入力。
  7. [開発用クラスローダーのクラスパス]タブで以下の処理を行う
    ・開発用クラスローダーを有効にする」にチェックを入れる。
    ・M2_REPO/javax/servlet/servlet-api/servlet-api-2.4.jar以外のチェックボックスにチェックを入れる
  8. Project Explorerのプロジェクト上で、右クリック→[Tomcat プロジェクト]→[コンテキストの定義を更新]
  9. eclipse上のtomcatアイコンをクリックしてtomcatを起動。
  10. http://localhost:8080/struts2にアクセス(struts2-showcaseは6.の「コンテキスト名」で入力した名前)
xworkのソースを別途ダウンロードしなくても、mvnコマンドを打ったときにダウンロードとjarファイルにアタッチしてくれるので楽

ここを参考に導入。

java


public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

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" />
<include file="example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">HelloWorld</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
<!-- Add packages here -->
</struts>


おー、いい感じ。

struts2のサンプルをデバックしながら動かす際に、struts2自体のソースもデバックで追えるようにする。

※Mavenが使用できるのであればここの手順のほうがよい

事前準備

 xworksのソースここからダウンロードしておく。(struts2.1.6で使用している2.1.2のソースの直リンク
 ※xworksはstruts2が継承しているフレームワーク。
 

手順

  1. ここで作ったプロジェクトを右クリック→[Properties]
  2. [Java Build Path]→[Libraries]
  3. [Web App Librarie]内の[struts2-core-2.1.6.jar]→[Source attachment]をダブルクリック
  4. [Extarnal Folder]をクリックし、以前ダウンロードし展開したフォルダ内のsrc/core/src/main/javaまでを選択し、OKをクリック
  5. [Web App Librarie]内の[xwork-2.1.2.jar]→[Source attachment]をダブルクリック
  6. [Extarnal Folder]をクリックし、事前準備でダウンロードし展開したフォルダ内の/src/javaまでを選択入力し、OKをクリック

上記手順終了後、Project Explorerで該当プロジェクトの[Java Resources: src]→[libraries]→[Web App Libraries]内のstruts2-core-2.1.6.jarとxwork-2.1.2.jar内の適当なクラスファイルをクリックすれば、ソースが見れるようになり、デバックポイントも張れるようになる。

※Mavenが使用できるのであればここの手順のほうがよい

前提

  • eclipseインストール済み(バージョン3.4)
  • tomcatプラグインインストール済み(まず、eclipseのdropinsフォルダに展開したフォルダをごと配備し、次にtomcatのlibフォルダにDevLoader.zipのみを配備する)


手順
  1. eclipseのProject Explorer上で右クリック→[import > ]→[WAR file]
  2. ダイアログが出るので、「WAR file:」にstruts2-showcase-2.1.6.warが置いてある場所を入力して[Finish]
  3. Project Explorer上にstruts2-showcase-2.1.6ができるので、右クリック→[Properties]で、[Java Compailer]を選択し、JDKのバージョンが1.5以上であることを確認。
  4. [Java Build Path]→[Libraries]→[Add External Jars]でtomcatのlibフォルダにあるservlet-api.jarを追加。
    (JVMAction.javaと言うクラスがコンパイルできないため)
  5. [Tomcat]→[全般]で以下の処理を行う
    ・[Tomcatプロジェクト]にチェックを入れる。
    ・コンテキスト名を入力(ここでは「struts2」とする。)
    ・Webアプリケーション・ルートとするサブディレクトリーに「/WebContent」を入力。 
  6. [Tomcat]→[開発用クラスローダーのクラスパス]で以下の処理を行う
    ・開発用クラスローダーを有効にする」にチェックを入れる。
    ・4.で追加したservlet-api.jar以外のチェックボックスにチェックを入れる
  7. Project Explorerのプロジェクト上で、右クリック→[Tomcat プロジェクト]→[コンテキストの定義を更新]
  8. eclipse上のtomcatアイコンをクリックしてtomcatを起動。
  9. http://localhost:8080/struts2にアクセス(struts2は5.の「コンテキスト名」で入力した名前)
これで、eclipse上からブレークポイントを張ってデバックしながら動作を確認できる。

2009/06/09

struts2

復習もかねて、つらつらと書いていく。

前提

  • javaインストール済み(バージョン6)
  • tomcatインストール済み(バージョン6)

まずは、サンプルを動かしてみる。
ここから全部入りのstruts-2.1.x-all.zipファイルをダウンロード、展開する。
(今の最新バージョンはstruts-2.1.6-all.zip。以後、このバージョンで話をすすめる。)

appsフォルダにあるのがサンプルアプリ。
その中のstruts2-showcase-2.1.6.warをtomcatのwebappsフォルダにコピー。

tomcatを起動し、http://localhost:8080/struts2-showcase-2.1.6 にアクセス。




validationチェック、tokenチェック、ファイルアップロードなど、いろいろなサンプルがある。画面下のView Sourcesをクリックすれば、そのサンプルがどのようなソースコードで作られてるか確認できる。

AmazonからGrails徹底入門が届いたのでGrailsを触ってみる。

以下、Grailsではないが、ちょっとはまったこと。

P.34 手順3 Grailsを使えるように設定するで
export JAVA_HOME=xxxx (未設定の場合)
export GRAILS_HOME=xxxx

とあるが、以下の設定もしないと次の手順4 Grailsを使ってみるで
$ grails xxxx とコマンドとコマンドを打っても
bash: grails: command not found
となってしまうので注意!!!

export PATH=$PATH:$JAVA_HOME/bin (未設定の場合)
export PATH=$PATH:$GRAILS_HOME/bin

javaが使用できるようになったので、とりあえず登録だけした。

構文
nkf [オプション] [ファイル名] [>出力ファイル名]

オプション
-g : 文字コードの確認
-j : JISに変換
-s : Shift_JISに変換
-e : EUC-JPに変換
-w : UTF-8に変換
-Lu : unix形式の改行に変換
-Lw : windows形式の改行に変換

--overwrite : 上書き


nkf -e Lu foo.txt > bar.txt
 →EUC-JP、unix形式の改行に変換した内容をbar.txtに出力

nkf -w --overwrite *.txt
 →ディレクトリ内の拡張子がtxtのファイルを、すべてUTF-8に変換

まずはインストール
$ sudo apt-get install lha

そんで、解凍
$ lha e xxxxx.lzh