struts2 tutorial
TRANSCRIPT
対象者 / 必要なものeclipse で Javaのコードを書いたことがある人向け
必要なもの
eclipse の Tomcat プラグイン(http://www.eclipsetotale.com/tomcatPlugin.html)
Tomcat (http://struts.apache.org/2.x/)
struts2 をダウンロードしておいてください(http://struts.apache.org/2.x/)
2
公開してます
http://www.agusa.i.is.nagoya-u.ac.jp/person/sydney/20080725/
このスライド (struts2-tutorial.pdf)
サンプルコード (grape_sample.zip)
3
Struts2(*) とは
Java J2EE上のWebアプリフレームワーク Strutsの後継
ただし原型は殆どない
OpenSymphony WebWork2 の拡張版
(*) http://struts.apache.org/2.x/4
アーキテクチャ
J2EE Webサーバ(サーブレットコンテナ)
サーブレット / JSP
Struts2
ビジネスロジックを実現する機能
入力値の整理,バリデーション,JSPのための便利なタグなど
基本的な機能MVC (ServletとJSPの連携),セッション,認証などの実現
HTTPリクエスト・レスポンスをWebブラウザとServlet/JSP間でやりとりデータソース(DBとのTCP接続)の管理
6
Apache Tomcat(*) : サーブレットコンテナ
バージョンは?
5.x 系で良いと思う
インストールは?
適当なフォルダに zipを展開。これだけ。
(*) http://tomcat.apache.org/
J2EE Webサーバ(サーブレットコンテナ)
サーブレット / JSP
Struts2
8
Tomcatプラグイン
eclipseに Tomcatプラグイン(*)をインストール
Tomcatプラグインの設定
Tomcatの起動、webアプリのテスト用配備など
(*) http://www.eclipsetotale.com/tomcatPlugin.html9
J2EE サーブレット/JSP
JavaでWebアプリケーションを書くための基本的技術
Webコンテナ (Apache Tomcat 等)上で動作する
J2EE Webサーバ(サーブレットコンテナ)
サーブレット / JSP
Struts2
12
Java サーブレット拡張Referenced Libraries で Tomcatのjarを参照しているのに注目これが Servletのjarファイルです配備時はTomcatのクラスローダが事前にロード
14
サーブレットを書こう: srcとclaessesTomcatプロジェクトの作成直後の状態では…eclipse で WEB-INF/src 以下にソースを置くとWEB-INF/classes に .classファイルが配置されます以後、src と classes フォルダを同一視します
package explorerではclassesフォルダは不可視です
eclipseにより自動コンパイル後WEB-INF/classesに配置 される
15
サーブレットを書いてみよう文字列 Hello, World ! を出力する コード
package controller;
<import...>
public class MyServlet1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().println("Hello, World !"); }
}
WEB-INF/src/controller/MyServlet1.java
16
サーブレットのきまりHttpServlet クラスを extend して、doGetメソッドをオーバーライドする引数 HttpServletRequest, HttpServletResponsereq は HTTPのリクエストパラメータを得る為に,res は HTTPのレスポンスを返す為に使う
public class MyServlet1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().println("Hello, World !"); }}
WEB-INF/src/controller/MyServlet1.java
17
web.xml
<web-app> <servlet> <servlet-name>my_servlet1</servlet-name> <servlet-class>controller.MyServlet1</servlet-class> </servlet> <servlet-mapping> <servlet-name>my_servlet1</servlet-name> <url-pattern>/myServlet1</url-pattern> </servlet-mapping></web-app>
最低限の設定URL /myServlet1 を クラス controller.MyServlet1 にマッピング
WEB-INF/web.xml
19
さあ実行しよう :Webアプリの配備
プロジェクトを右クリック -> Tomcat project -> Update context definition<CATALINA_HOME>/conf/Catalina/localhost/ に、 eclipseのプロジェクトフォルダをコンテキストルートとして配備する設定が書き込まれる。
20
アクセスしてみようweb.xml に書いた <url-pattern> に対応するURLにアクセスしてみよう
http://localhost:8080/grape_sample/myServlet1
:: <servlet-mapping> <servlet-name>my_servlet1</servlet-name> <url-pattern>/myServlet1</url-pattern> </servlet-mapping>:
web.xml (再掲)
ブラウザ
22
そのほか<cxt-root> 以下に置いたファイルは静的コンテンツとして扱えます (URLから直接参照できる)
例外:WEB-INF 以下は不可視 (セキュリティ上)
.jsp という拡張子をもつファイルは JSP (Java Server Pages) で、スクリプトレットが記述できる
JSPはstruts2でも使います。後述。
23
JSP (Java Server Pages)HTMLの文の中に、Javaのコードを埋め込めるスクリプトレット という機能
<% someStatement; %>, <%= “文字列” %>
<% while(...) { %> <tr>...</tr> <% } %> みたいな
タグ拡張
jspタグ e.g. <jsp:include page=””/>
タグは追加できる。タグライブラリも豊富にある(strutsのタグライブラリ、JSTLなど)
24
Struts2 と サーブレットの関係
サーブレット … 何でもできるが、使い勝手がわるい
入力値の扱いが面倒 e.g. Integer.parseInt(req.getParameter(“param1”))
バリデーション機能がない
サーブレットの上に新しいフレームワークを作った
一部、サーブレットの機能を使う
JSPのタグライブラリを含むJ2EE Webサーバ
(サーブレットコンテナ)
サーブレット / JSP
Struts2
26
Struts2 : 準備
WEB-INF/lib/*.jar
struts-blank から
struts2-codebehind
設定
WEB-INF/web.xml
WEB-INF/classes/struts.xml
この状態にしよう
27
jarstruts-blankのWEB-INF/lib のものをコピー
あと struts2-codebehind-plugin-*.jar も
コピーしただけでは参照できないぞ!eclipseの設定でクラスパスに追加するのを忘れずに
commons-logging-1.0.4.jar struts2-core-2.0.11.2.jar freemarker-2.3.8.jar xwork-2.0.5.jar ognl-2.6.11.jar struts2-codebehind-plugin-2.0.11.2.jar
WEB-INF/lib
28
web.xml の設定Servlet/JSPフレームワークの <フィルタ> として設定全リクエストはまず struts2に処理される (url-pattern が /* )
<web-app> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> <init-param> <param-name>actionPackages</param-name> <param-value>actions</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping></web-app>
WEB-INF/web.xml
Zero Configuration固有の設定。
後でこの actionsというパッケージを作ります
29
struts.xml の設定クラスパスのルート、すなわち WEB-INF/classes に配置 ( → WEB-INF/srcに置けばよい)
Zero Configuration のおかげで ほぼ空っぽ
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /></struts>
WEB-INF/classes/struts.xml
30
(*) Zero Configuration+codebehindで省力化
struts2 の Zero Configuration + codebehindプラグインで、徹底的に省力化しよう!
Zero Configuration が無い場合=> struts.xml に <action> タグが必要
codebehind が無い場合1. <action>タグを書くか、2. アクションクラスに @Result を加える
31
MVCアーキテクチャModel (データやビジネスロジック), View (表示系), Controller (その間) をきちんと分けて書きましょうねという考え方
Struts では、アクションが Controller Model, JSP が View にあたる (インタセプタ等がController)
Ian Roughleyの本を参照のこと
コンポーネント間の依存関係をスッキリさせる
実のところ私はよくわかってないかも wikipediaより33
??データ
PDFデータ
struts2 Webアプリのフロー
GETやPOSTでアクションが呼ばれる。アクションはビジネスロジックを実行する。
アクションはリザルトの名前を返す。リザルトの名前に従ってJSP等が返される。
JSP Action
JSP
GET または POST
フォーム
データ
TestAction(test.action)
test-input.jsp
test-success.jsp
“fail”
...
success
fail
...
リザルト...
...
34
??データ
PDFデータ
struts2 と MVC
アクションはMVCにおけるコントローラ(C) モデル(M) 。
JSPはMVCにおけるビュー(V)。
JSP Action
JSP
GET または POST
フォーム
データ
TestAction(test.action)
test-input.jsp
test-success.jsp
“fail”
...
success
fail
...
リザルト...
...
35
Model : アクションの作成
struts2 の init-param で指定したパッケージ ”actions” にアクションを配置~~ Action という名前にする。Zero Configurationの規約。TestAction という名前にしてみた
: <init-param> <param-name>actionPackages</param-name> <param-value>actions</param-value> </init-param> :
WEB-INF/web.xml (抜粋)パッケージ
36
アクションクラスの書き方何もextends/implementsしなくていい (ActionSupportクラスをextendsすると便利...?)public な executeメソッドだけ準備する戻り値”success”は リザルトの名前.転送先ページを指定する(後述)
package actions;
public class TestAction { public String execute() { /* ビジネスロジックをココに書く */ return "success"; }}
TestAction.java
超スッキリ!37
View : JSP の作成
<アクション名>-<リザルトの名前>.jsp というファイル名で、JSPを配置する. codebehindの規約。
ここでは test-success.jsp という名前になる
public class TestAction { public String execute() { return "success"; }}
Hello, this is JSP!!
TestAction.java
test-success.jsp
38
MVC Webアプリのフロー
制御の流れはそのままデータの流れでもある
フォームに入力したデータが、GETでActionに渡され、 Actionの結果は転送先のJSPで表示される
JSP
Action
JSP
GET または POST
フォーム データ
TestAction(test.action)
input.jsp test-success.jsp
return “success”;
41
MVC Webアプリのフロー
この部分の流れを考えてみよう
JSP
Action
JSP
GET または POST
フォーム データ
TestAction(test.action)
input.jsp test-success.jsp
return “success”;
42
Actionからデータを受け取るJSP カスタムタグ
Struts用カスタムタグを使いましょう
JSPの頭にカスタムタグの宣言を置こう
タグの接頭辞には s: が付きますよという意味
タグ定義はstruts2のjarに入ってる /struts-tags
<%@ taglib prefix="s" uri="/struts-tags" %>
43
s:propertyタグ
<s:property name=”foobar” />
Actionの getFoobar() メソッドの戻り値が出力される
<s:property value=”foobar” />
44
s:propertyタグ を使う
public class GetTodayAction { public String execute() { return "success"; } public String getToday() { // 今日は何日? return new SimpleDateFormat("yyyy/MM/dd") .format(new Date()); }}
<%@ taglib prefix="s" uri="/struts-tags" %>今日は <s:property value=”today” /> です。
GetTodayAction.java
getToday-success.jsp
45
実行してみると
<%@ taglib prefix="s" uri="/struts-tags" %>今日は <s:property value=”today” /> です。
getToday-success.jsp
46
Struts2のタグライブラリ(*)
Genericタグ
制御構造タグ if-else(elseif), iterator他
Dataタグ
property タグ他
色々使ってみてください。
(*) http://struts.apache.org/2.x/docs/tag-developers-guide.html47
MVC Webアプリのフロー
この部分の流れを考えてみよう
フォームでPOST / リクエストパラメータでGET
まずは リクエストパラメータを受け取ってみる
JSP
Action
JSP
GET または POST
フォーム データ
TestAction(test.action)
input.jsp test-success.jsp
return “success”;
49
getterも必要
setter でリクエストパラメータを受け取る
public class Test3Action { // 計算機 int x, y, sum, diff, mult, div; public String execute() { sum = x+y; diff = x-y; mult = x*y; div = x/y; return "success"; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; }
public int getX() { return x; } public int getY() { return y; } :
リクエストパラメータを受け取るsetter
CalcAction.java
http://.../calc.action?x=100&y=33
50
あとはさっきと同じ<s:property .../>
<%@ taglib prefix="s" uri="/struts-tags" %>x + y = <s:property value="sum"/><br/>x - y = <s:property value="diff"/><br/>x * y = <s:property value="mult"/><br/>x / y = <s:property value="div"/><br/>
calc-success.jsp
public class CalcAction { // 計算機 : public int getSum() { return sum; } public int getDiff() { return diff; } public int getMult() { return mult; } public int getDiv() { return div; }}
CalcAction.java
51
実行結果
<%@ taglib prefix="s" uri="/struts-tags" %>x + y = <s:property value="sum"/><br/>x - y = <s:property value="diff"/><br/>x * y = <s:property value="mult"/><br/>x / y = <s:property value="div"/><br/>
calc-success.jsp
52
Struts2 UI タグとバリデーション
フォーム入力のバリデーション(妥当性検査)次第で入力ページに転送されることもある
この時、以前に入力した値が消えていたら困る…
Struts2の UI タグを使おう(*) http://struts.apache.org/2.x/docs/ui-tags.html
Action
GET または POST
JSPフォーム
TestAction(test.action)test-input.jsp
バリデーション失敗(リザルト “input”)
“success”
54
Struts2 UI タグ : フォームの作成
<%@ taglib prefix="s" uri="/struts-tags" %><s:form action='calc'> <s:textfield label="x is" name="x"/> <s:textfield label="y is" name="y"/> <s:submit/></s:form>
calc-input.jsp
ブラウザで http://localhost:8080/grape_sample_struts2/test3-input.jsp にアクセス
55
アノテーションでバリデーション
public class CalcAction extends ActionSupport { : @FieldExpressionValidator( expression="y!=0", message="y should not be zero.") public int getY() { return y; } :}
CalcAction.java
FieldExpressionValidator で getter か setter にアノテーション を加える (FieldExpressionValidatorなど)
ValidationAware を implement する
普通、ActionSupport を extends すればよい
ブラウザ
57
UI タグとテーマcalc-input.jsp
<form action="calc.action" method="post"><table> <tr><td><label>x is:</label></td> <td><input type="text" name="x"/></td></tr> <tr><td><label>y is:</label></td> <td><input type="text" name="y"/></td> </tr> <tr><td colspan="2"> <div align="right"> <input type="submit" value="Submit" /></div></td> </tr></table></form>
<%@ taglib prefix="s" uri="/struts-tags" %><s:form action='calc'> <s:textfield label="x is" name="x"/> <s:textfield label="y is" name="y"/> <s:submit/></s:form>
このようにレンダリングされる:
デフォルトの‘xhtml’ テーマを使っている
58
テーマの切り替え勝手に<table> や <label> を入れられたくない…
‘simple’テーマを使おう
calc-input.jsp
<form action="calc.action" method="post"> <input type="text" name="x"/> <input type="text" name="y"/> <input type="submit" value="Submit"/></form>
<%@ taglib prefix="s" uri="/struts-tags" %><s:form action='calc' theme="simple" > <s:textfield label="x is" name="x"/> <s:textfield label="y is" name="y"/> <s:submit/></s:form>
このようにレンダリングされる:
<s:form action='calc' theme="simple" >
59
Struts2 の制御フロー
設定編でみたように、struts2はサーブレットAPI の Filter Dispatcherから駆動される。
様々なインターセプタが、バリデーションの実行、リクエストパラメータの設定などする
アクションがビジネスロジックを実行し、リザルトはブラウザにHTML等をレンダリングし返す。
64
struts1との比較Convention over Configuration
URL、ファイル名やクラス名に関する規約により、 設定ファイルを可能なかぎり廃している。
設定もできるので、カスタマイズ可能性は十分に残されている。
アノテーション
バリデーションの設定を ~~.xml ではなくソースにアノテーションを使って記述。
ActionはPOJO!
より軽量なWeb開発が可能に67
struts1との比較 (私の主観とぐち)struts-config : 設定の嵐、嵐…
Servletのように、ソースコードにファイル名やURLをハードコードするよりはマシだった
「どのactionと、どのクラスを結びつけたのか」「どのActionForwardが、どのJSPに転送されるのか」「どのActionFormがどのActionで使われるのか」等、管理が二重になっていた
そのかわり、再コンパイルなしで様々な設定が変更できた…が、あまり修正の必要がないものばかりだったような。(むしろ識別子の変更がやりにくくて不便)
また、設定ファイルを増やしても信頼性が上がるとはいえない
言うほどActionやJSPのモジュール性は良くない (再利用しない)
よりシンプルなほうが良いじゃん!68
form beanは…
各クラスそのものにgetter/setterを定義
型付き (かつ、Integer.parseIntとかは要らない)
余計なクラスは要らない
<form-beans> <form-bean name="searchForm" type="agusadb.struts.action.person.form.SearchForm"/> <form-bean name="updateStartForm" type="agusadb.struts.action.person.form.UpdateStartForm"/> <form-bean name="person" type="agusadb.struts.action.person.form.PersonForm"/> </form-beans>
各アクション毎にform beanのクラス1つ (DynaActionFormとかもあったけど…)
69
action mapping は…Zero Configuration
設定が要らなくなった!(書いてもよいが)
名前付け規約。
<action>-<result>.jsp
これぞ CoC
<action path="/main" forward="person.main"/><action path="/searchStart" forward="person.search"/><action path="/search" type="agusadb.struts.action.person.SearchPersonAction" name="searchForm" scope="request" input="person.search"> <forward name="notFound" path="person.search"/> <forward name="detailView" path="person.detail"/> <forward name="listView" path="person.list"/></action><action path="/updateStart" type="agusadb.struts.action.person.UpdateStartAction" name="person" scope="request"> <forward name="existPerson" path="person.update.start"/> <forward name="newPerson" path="person.register.start"/></action><action path="/updateConfirm" type="agusadb.struts.action.person.UpdatePersonConfirmAction" name="person" scope="request"> <forward name="retryUpdate" path="person.update.start"/> <forward name="retryRegister" path="person.register.start"/> <forward name="confirmUpdate" path="person.update.confirm"/> <forward name="confirmRegister" path="person.register.confirm"/></action><action path="/updateProceed" type="agusadb.struts.action.person.UpdatePersonProceedAction" name="person" scope="request"> <forward name="retryUpdate" path="person.update.start"/> <forward name="retryRegister" path="person.register.start"/> <forward name="proceededUpdate" path="person.update.proceeded"/> <forward name="proceededRegister" path="person.register.proceeded"/></action>
70
参考文献・サイトServlet/JSP 古典コア・サーブレット&JSP―Javaサーバ技術によるWeb開発 (単行本), Marty Hall著, サンモア・サーブレット
Struts2Apache Struts2 Documentation - Guides
すべてはここに始まり、ここに終わる (かも)
http://struts.apache.org/2.x/docs/guides.htmlStarting Struts 2 (PDF版; free)
http://www.infoq.com/minibooks/starting-struts273