2009年1月4日 星期日

[Struts2] 初啼試聲 HelloStruts2

上次我們完成了如何在 Eclipse 中開發 Struts2 project。這次我們就小試身手一下~按照各書的慣例,我們也來個 HelloStruts2 project。

1. 我們將之前我們所包裝成 WAR 檔匯入到 Eclipse 中。由 [File] -> [Import] 來進行匯入的動作~接著我們就選擇 Web 底下的 [WAR file],如下圖一。

image
圖一 Import WAR file

2. 在圖一中的 WAR file 選擇上次所包裝的 WAR 檔。並且在 Web Project 中打入您想要的 project 名稱,既然是 HelloStruts2,那我們就輸入 HelloStruts2 囉~

3. 匯入後的 web project,我們可以看到檔案的結構如圖二,src 的部份就讓我們撰寫 source code 之處,而 WebContent 會在我們完成 project 後匯出成 WAR 檔的實際結構。

image
圖二 HelloStruts2 檔案結構

4. 說了這麼多,直接來試試吧~首先我們先在 src 中建立一個新的 class,名稱取為 HelloUser(我會順便輸入 package:silver8250.hellow)。內容就輸入如下:

/**
*
* HelloUser.java class
* at silver8250.hello package
* in HelloStruts2 project
* 2009/1/4 建立
* @author Silver8250
*/
package silver8250.hello;
public class HelloUser
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String execute()
{
this.setName("Hello~"+this.getName());
return "success";
}
}

程式中的 execute() method 是身為一個 Action 的必要元素,從 HelloUser class 中可以發現,Struts2 的 Action 不必繼承任何的 super class,只要將提供給外界存取的資料,以符合 JavaBean 的規範來使用就可以!簡單來說,JavaBean 的規範有三點:

1) 一定要有 public default constructo(也就是不帶任何 parameters 的 constructor),如果不撰寫任何的 constructors,compiler 會幫我們完成 default constructor。

2) 欲提供給外界存取的 fields,必須提供適當得 accessor methods 與 mutator methods,也就是由 get/set 為首的 methods(其實沒有那麼簡單)。

3) 一定要是一個可以 Serializable 的 class,也就是至少要 implements java.io.Serializable 這個 interface。

不過對於我們的 Action 來說,只要符合上述的兩點就可以,至於第三點就可有可無囉~其實,這樣的 Action 就是一種 POJO(Plain Old Java Object)

另外,execute() method 要回傳一個 String,這個 String 是要告知 Struts2 在執行完 Action 之後,所要導向的頁面,而 String 的內容會對應到接下來說到的 <result>。

5. 有了 Action,我們就要開始來讓 Struts 2 幫我們讓網頁可以連結到~所以我們要編輯 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.devMode" value="true" />
<package name="hello" extends="struts-default">
<action name="Hello" class="silver8250.hello.HelloUser">
<result name="success">/WEB-INF/pages/hello_user.jsp</result>
</action>
</package>
</struts>

首先,我們會看到 struts.xml 中一定要以 <struts> 作為 root node。接著我們就加入一個 <constant>,這是告知 struts2 目前我們是開發測試階段,這些 constant 是用來複寫 Struts2 中的 intelligent defaults (智慧型預設值,提供事前的預設設定,讓開發者可以無須再設定任何的設定就可以直接開發系統),這些 intelligent defaults 可以在 lib/struts2-core-(version).jar 中的 org.apache.struts2 底下的 default.properties 找到。

在 default.properties 中我們可以找到 struts.devMode 這個設定檔,並請獲得進一步的使用說明。

再來我們就是加入了 <package> 來告知 Struts2 我們在這設定檔中有一些 actions 要可以提供給外界呼叫。package tag 中的 name 是設定 package 的名稱。而 package 的使用可以就像 object 一樣可以有繼承跟抽象化,正如同我們使用 extends 的 attribute 一樣,告知 Struts2 我們的 package 要繼承 struts-default,struts-default 一樣可以在 lib/struts2-core-(version).jar 中找到,初學使用建議還是繼承 struts-default,因為在 struts-default.xml 中設定了很多開發者需要的預設設定,就像是 intelligent defaults 一般。

package 之中我們加入了 <action> 來告知 Struts2 我們有一個 Action 要讓外界存取,name 是用來設定讓外界呼叫的名稱,而 class 則是告訴 Struts2 我們的 Action 是哪個 class,class 的值一定要是完整的名稱(也就是 package 路徑加上 class 名稱)。

在 action 之下,我們又加入了 <result> 的 tag,這個 tag 是呼應到 Action 中的 String 回傳值,就如我們在 Action 的 execute() method 中回傳一個 "success" 的字串,Struts2 會到 action tag 之下的 result 中找尋是否有符合的 result tag 可以對應。所以我們加入的 result tag 中設定 name 為 success,這樣 Action 在執行完後,就會呼叫 <result name="success"> tag 中的設定頁面囉~

6. 針對 Action 與設定完成後,目前來說我們算是完成了 Server 端的設定囉~接下來就是 Client 端的設定,也就是 MVC 中 View 的部份了~

首先,我們在 WebContent 中加入一個新的 JSP 頁面,名為 index.jsp,內容則輸入如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="Hello">
<s:textfield name="name" label="Your Name"/>
<s:submit />
</s:form>
</body>
</html>

有接觸過 JSP 的人應該都對於第一個 <%@ page %> 的設定很熟悉了~在此就不多作說明了!而接下來的 <%@ taglib %> 就是設定 tag 的宣告,因為要使用 Struts2 的 tags,所以我們要先宣告,這點對於 Struts2 與 Struts1 有不一樣,Struts2 將所有的 tags 都包在一起了~而 Struts1 則是要分別宣告 HTML 專用的、Logic 專用的或是 bean 專用的等等,有點麻煩~(其實也還好)

中間一大串的 HTML 我就不多作解釋了,我直接說明 <s:form>,用 s 開頭事因為剛剛宣告 tags 的 prefix 宣告,這很像 XML 中的 namespace,可以區分不同領域的相同名稱(如,a:thing 跟 b:thing)。撇開 s: 的 prefix 不談,我想有經驗的 programmer 應該可以瞭解這些 tags 的用意與目的,因為由名稱就可以很直觀的說明了~

<s:form> 就跟 HTML 中的 form 用法一樣,不過我們是採用 action attribute,畢竟後端是呼叫 Action 來執行 business logic 的(我都是這樣記的),而 <s:textfield> 就很明顯是讓使用者可以輸入的一個文字欄位,其中 name 是要設定該欄位中使用者輸入的字串要對應到 Action 的哪個變數,回想剛剛的 Action,我們有宣告一個 String name 的變數,就是要儲存前端的使用者所輸入的字串。而 label attribute 就是產生這個 textfield 的顯示標籤,有點難解釋,等等執行你就會瞭解了~最後一個 <s:submit> 我就不多說了~猜猜吧~

7. 第一個頁面完成後,我們好像還差一個頁面沒有寫耶~有嗎?當然有,回想一下 struts.xml 中的設定,當使用者輸入完成後,Action 執行之後的頁面勒?所以我們根據剛剛在 struts.xml 中的 <result> tag 所寫的在 WEB-INF 中新增一個 pages 的資料夾並加入 success.jsp 頁面。而 success.jsp 頁面我們就填入如下的內容:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:property value="name"/>
</body>
</html>

這一頁跟先前的 index.jsp 其實很類似喔~只有倒數第三行的內容不一樣,我們採用 <s:property> tag 來取得 Action 中的值。剛剛我們使用 textfield 將值填入 Action 中的變數,現在我們則使用 property 將值取出來。很直觀吧~

8. 呼~費了好大一番功夫~可不是嗎!我們就要執行看看結果囉~如果你的 HTTP port 為 8080 的話,就輸入:http://localhost:8080/HelloStruts2

看到的頁面應該如圖三。

image
圖三 index.jsp

看到這頁面,在回想一下我們的 index.jsp 中,我們的 textfield 欄位的 label,你應該就可以瞭解 label attribute 的目的了!接著我們就輸入了名字吧~按下 submit 之後就會出現圖四的情形。

image
圖四 success.jsp

還記得我們在 Action 中的 execute() method 是怎樣定義的嗎?我們將使用者輸入的 name 之前加上 "Hello~" 的字串。所以我們在 success.jsp 中取出的結果就會有 Hello~ 的字串在前面囉!

以下就總結一下整個 HelloStruts2 的流程,如下圖五。此流程圖只是簡單的示意圖,實際在運作的過程是很複雜的,往後介紹了 Struts2 的各 components 之後,相信你一定會漸漸的看到全貌!

image

圖五 HelloStruts2 簡單示意圖

1) 使用者在 index.jsp 中輸入 name。

2) Struts2 根據 form 的 action 到 struts.xml 中找到對應的 class,並將 textfield 中的值根據 name 的設定對應到 HelloUser.java 中的 name 變數。

3) Struts2 執行 HelleUser 中的 execute() method 之後,得到 success 的回傳字串,並到 struts.xml 中尋找 action tag 中對應的 result tag。

4) 根據 result tag 中的設定頁面,Struts2 將使用者的 browser 導引到 success.jsp 頁面。

5) success.jsp 頁面中利用 property tag 取得 HelloUser 中的 name 變數,並顯示在頁面上。

這樣簡單的說明了我們整個所作的 HelloStruts2 的流程囉~

簡單得出啼試聲就分享給大家囉~

3 則留言:

Lorenz 提到...

謝謝您詳細的解說, 小弟剛開始學習Struts2, 有個地方一直很困惑, 想請教一下.

如下的博客來書局的加入會員網頁(麻煩點一下同意條款即可看到 )
https://db.books.com.tw/newmember.php

每個欄位後都有說明, 但struts2的html code為ui tag產生, 該怎麼處理? 不太可
能再去修改template吧? 感謝~

Silver Su 提到...

Struts2 對於 UI 的 tag 還可以設定 theme,不過目前我尚未將文章整理完畢,所以還沒開始撰寫!
http://struts.apache.org/2.1.6/docs/themes-and-templates.html
您可以參考這裡的資料!

Lorenz 提到...

謝謝您的回覆. 我再研究一下您提供的建議.

期待您的大作.. ^^