顯示具有 struts 標籤的文章。 顯示所有文章
顯示具有 struts 標籤的文章。 顯示所有文章

2009年1月5日 星期一

[Struts] Struts 1.x V.S. Struts 2.x

最近很意外的找到 RoseIndia 這個網站,裡面擁有很多的 tutorials,這篇網誌裡我將會討論在 RoseIndia 中的一篇文章:Struts 1.x Vs Struts 2.x

這篇文章中指出 10 點在 Struts 1.x 中的缺點,在 Struts 2.x 中解決的辦法。

1. Servlet Dependency

在 Struts 1.x 中,programmer 開發一個 Action 時,必須 override execute method,然而 execute method 的 parameter 卻與 HttpServletResponse, HttpServletRequest 物件有相依性,這樣造成 Action 的 execute method 就變得不單純!

反觀 Struts 2.x 中的 Action,我們只要有一個沒有任何 parameter 的 execute method 就可以成為一個 Action,也就是我們只要是一個 POJO(Plain Old Java Object)。這樣的 Action 相對於 Struts 1.x 的 Action 來說,的確是輕量(light-weight)了許多。當然,這樣當 Struts 2.x 的 Action 要使用一些 JSP 中的 Implicit Object (如:request, session 等) 就會比較不方便,其實不方便也倒是還好,為了降低物件之間的 coupling,這樣的不方便就值得了! 順帶一提,Struts 2.x 是採用 IoC 的方式解決這樣的問題。

2. Action classes

承上述中所提到的,Struts 1.x 中的 Action 必須 override execute method,因為 Struts 1.x 中的 Action 都必須 extends Action 這個 abstract class,這樣就造成了 programmer 無法寫出一個很單純的 Action,一旦物件有繼承的關係,這就造成此物件無形中的肥大!

Struts 2.x 中的 Action 是一個 POJO,也就是 programmer 不必去繼承或實作任何的 class 或 interfaces 就可以寫出一個 Action,這樣就讓 Action 物件相對的單純許多! 當然,如果你希望讓 Struts 2 提供更多服務給你所開發的 Action 物件,你可能就必須要實作一些必要的 interfaces,不過比起寄程來說,實作 interface 還是來的單純太多~

3. Validation

Struts 1.x 與 Struts 2.x 都有提供 validate method。不過,Struts 1.x 必須實作在 ActionForm 之上。

而 Struts 2.x 則是在 Action 中 implements Validatable interface 就可以,這當然比 Struts 1.x 的 ActionForm 來得輕量,畢竟繼承所造成的複雜度遠遠超過實作。

4. Threading Model

在 Struts 1.x 中,Action 一定是 thread-safe 或是 synchronized。也就是說 Action 一定是一個 Singleton。

Struts 2.x 則並非如此,每次有一個 request 進來,Struts 2.x 就會為每一個 request 所需求的 Action 初始化一個 instance。

5. Testability

在 Struts 1.x 中測試 Action 是很複雜的,因為 Action 的 execute() method 是帶有 parameter,而這些 parameters 都是 Container 物件~所以測試這樣的 Action 是比較困難的,不過還是有 StrutsTestCase for JUnit 這樣的測試 framework 提供 mock 物件。

由於 Struts 2.x 的 Action 的 execute() method 不帶任何的 parameters,所以在測試 business logic 是很簡單的,使用最原始的 JUnit 就能夠完成測試。

6. Harvesting Input

Struts 1.x 中採用 ActionForm 物件才取得使用者輸入的資料,這樣的 ActionForm 物件必須繼承 ActionForm class,而且不能使用 JavaBean 來代替,也就是 programmer 不可以使用 domain javabean 來取代,所以 programmer 必須重新撰寫一個一模一樣的物件來取得使用者的輸入資料。

在 Struts 2.x 中則不具有這樣的問題,因為 Action 物件本身就會負責取得使用者的輸入資料,而且 Action 物件屬於一個 POJO,使得 Action 物件單純許多,而且,我們還可以重複使用 domain javabean。

7. Expression Language

Struts 1.x 中只有整合 JSP 中提供的 JSTL 與 EL,然而,JSTL 與 EL 只有基本的 object navigator 功能,對於 collection-basec 與 index-based 的物件支援卻很少。

然而,Struts 2.x 中採用了 OGNL 來執行 object navigator,OGNL 對於 collection-based 與 index-based 物件支援很高,並且提供強大的 convertor將 String-based 的 HTTP 資料轉換成 Java type object。

8. Binding values into views

在 Struts 1.x 中採用標準的 JSP 資料儲存機制(也就是 page,request, session, application)。

在 Struts 2.x 中則進一步將這些 JSP 資料儲存機制放置於更高層的 ActionContext,並且提供 ValueStack 來存放 view 中所需要的資料。

9. Type Conversion

Struts 1.x 中的 ActionForm 物件的變數,通常都是以 String 為主,這是因為 HTTP 的資料都是以 String 為主要型態,programmer 必須自行使用 Commons 的 BeanUtils 來進行型態的轉換。

由於 Struts 2.x 中引進了 OGNL 的技術,使得資料型態的轉換皆由 OGNL 來處理,並且支援複雜物件的資料型態轉換。

10. Control of Action Execution

Struts 1.x 中針對每一個 module 的 Action 提供不同的 Request Processor。但是在同一個 module 中的所有 Actions 則是使用同一個 Request Processor。

而 Struts 2.x 中可以針對每一個 Action 提供不同的 interceptor stack,如此可以讓同一個 Action 在不同情況下使用圖一樣的 interceptor stack,進行使得 Action 有不一樣的 life cycle。

2008年7月29日 星期二

[Struts] StrutsTestCase for JUnit

Introduction

對於寫過test case 的 programmer 來說,JUnit 應該是不陌生,JUnit 是被大家公認用來執行java測試最好的framework,但是對於像Struts這種以MVC為宗旨的framework,我們又該如何去執行測試呢?StrutsTestCase for JUnit[1] 就是一個用來達成我們目的的solution。從字面上就可以了解,StrutsTestCase其實就是將JUnit延伸到Struts framework可以使用的library。所以,大致上對於測試的方式是大同小異的,不過對於StrutsTestCase[1]來說,還是有一些不一樣之處。

下圖一是官方網站的簡介,此網站對於StrutsTestCase[1]有很詳細的說明。

clip_image003

圖一 官方網站的說明

圖一中的紅圈處就可以下載該library。點選後就會進入SourceForge.net的網站,如下圖二。

clip_image005

圖二 SourceForge.net的下載點

接個點選Download字樣,進入如下圖三的畫面。

clip_image007

圖三 SourceForge.net的下載點(2)

畫面中請下載您所需要的版本,通常是選擇下載最新版本為主,圖中最後一個載點是在檔名後方加上 -src代表是原始碼的版本,若您有需要訂做自己適用的StrutsTestCase,您也可以下載原始碼版本。

下載完的壓縮檔案解開後的資料夾中會包含一個strutstest-x.jar(其中x會依照您所下載的版本不同而有所改變)。若是一般的 Java Application 要使用,請設定 classpath 位置;若是需要在 Web Server 上面的 Web Application 使用,請放置該 Web Application 的 WEB-INF / lib 之下。

Example

首先假設您有一個action如下:

public class LoginAction extends Action {

    public ActionForward excute(...) {

        String username = ((LoginForm)form).getUsername();

        String password = ((LoginForm)form).getPassword();

        String role = “user”;

        if (username.equals(“adm”) && password.equals(“test”)) {

            role = “adm”;

        }

        request.getSession().setAttribute(“role”,role);

        request.getSession().setAttribute(“username”,username);

    }

}

上述程式碼中,我們假設您已經有一個LoginForm class。上述的action您在struts-config.xml中設定如下:

<action path=”/login” type=”LoginAction” />

接下來您就可以根據您的action來開發strutstestcases測試,開發strutstestcase步驟如下:

(1) 您必須建立新的class,我們命名為LoginActionTest並且extends MockStrutsTestCase:

public class LoginActionTest extends MockStrutsTestCase {

}

(2) 如果您是在 eclipse 環境下執行測試,請您務必加入以下的程式碼:

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”)); //註一

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

}

註一:其中WebContent要根據您在eclipse中建立的資料夾而定,依照我所設定的資料夾如下圖四,所以我們採用WebContent:

clip_image013

圖四 Eclipse專案的目錄結構

(3) 接著我們就要開始來正式的撰寫我們的test case,所有的test case method都必須以test開頭,例如:testLogin。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {}

}

(4) 有了test case method,我們就要開始撰寫內容了。首先,我們要先告知strutstestcase我們要測試的路徑,也就是瀏覽器如何存取該action的方法,不過,我們只需要設定在struts-config.xml中的路徑即可,無須增加IP位址,因為MockStrutsTestCase是屬於Mock Test測試(也就是非in-container測試,所謂的container就是由tomcat這類的server來啟動,所以in-container就是會啟動tomcat server來進行測試,Mock Test就是另一種不用啟動tomcat server的離線測試),先前我們已經將LoginAction class在struts-config.xml中設定的路徑為/login,所以我們可以透過MockStrutsTestCase所提供的setRequestPathInfo() method來設定action的存取位置。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

    }

}

NOTE: 呼叫superclass的methods時,可以使用super關鍵字,本人建議所有呼叫superclass的methods時,都加上super關鍵字,以方便未來觀看程式碼時就可以一目了然,另外,若是呼叫同一個method時,請您也加上this來方便日後的維護。這並沒有硬性的規定,所以的關鍵字都不加上去,程式碼依舊可以執行,這只是習慣性的問題而已。

(5) 再來就是告知該action我們要傳入的資料,此資料就是模擬使用者會傳入哪些資料給action。切記,雖然我們的action是接收一個ActionForm物件,不過在MockStrutsTestCase中是用類似URL GET method(../login.do?username=adm&…)的方式給予。我們並不能給予ActionForm物件。所以我們要呼叫MockStrutsTestCase的addRequestParameter() method,並將我們要給予的參數名稱與參數值。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

    }

}

(6) 設定好路徑與參數後,我們就要告知MockStrutsTestCase,該測試可以啟動了,所以我們就呼叫他的actionPerform() method來正式的執行該action。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

        super.actionPerform();

    }

}

(7) Action執行完後,我們就可以針對action執行後的結果作測試,因為我們的action是將結果儲存在session中,所以我們就要從session中取出結果,並且呼叫JUnit的測試method來檢驗結果。

public class LoginActionTest extends MockStrutsTestCase {

    public void setUp() {

        super.setUp();

        setContextDirectory(new File(“WebContent”));

        this.setConfigFile(“/WEB-INF/struts-config.xml”);

    }

    public void testLogin() {

        super.setRequestPathInfo(“/login”);

        super.addRequestParameter(“username”,”adm”);

        super.addRequestParameter(“password”,”test”);

        super.actionPerform();

        String role = super.getSession().getAttribute(“role”);

        super.assertEquals(role,”adm”);

    }

}

NOTE:若action是將結果儲存在request中,您就要改呼叫super.getRequest() method來進行測試。

References

[1] StrutsTestCase官方網站 http://strutstestcase.sourceforge.net/

2008年5月7日 星期三

[Struts] 分享我的開發流程

對於 Web Programmer 來說,使用 framework 是一件既方便也是必須作的事

因為 framework 幫助我們減少開發上枯燥乏味的 details

增加我們開發 Application(Web or Alone) 的速度!!

Struts 是一個在 JAVA 環境下的 Web framework

它的主要精神就是在於 MVC (Model-View-Controller) 的結構

以往使用 JSP 開發的 programmer,為了要達到 MVC 的 pattern

往往採用 MVC Model1 - JSP + JavaBean 的使用,

或是採用 Model2 - Servlet + JSP + JavaBean

但是無論是 Model1 or Model2 最困難的問題就是 effort 太高

MVC 之間的元件需要自行管理,Request Processes 需要自行管理等...

這些繁雜瑣碎的事物,我們透過使用 framework 就可以輕鬆的幫我們解決

Struts 對於 MVC 的支援相當的完整,使用者透過向 controller 發出 request

Controller 會決定是否需要到 Model 中取得資料給 View ,或是直接顯示 View來回應使用者

MVC 的 pattern 讓 programmer 之間可以達到 separate of concern,好處有太多,大家可以慢慢的體會~~

不過一種 framework 有再多的好處,如果無法掌握其開發的 process,對於 programmer 來說,那還不如就不要用!!

接下來我就提供我歷經兩個專案後所得到的開發經驗:

MVC 的核心在於 Controller,Controller 是整個 MVC 的開端,但是 Controller 端又需要 Model 端做為 Data Supplier

所以,以我的經驗事先從 MVC 的 M 開始著手

接下來就直接開發 Model components 囉!!

等等,先別急~~

Model components 對於 programmer 來說大多是跟 Database 存取有關

所以市面上有許多 ORM 的 solutions,比如目前最有名的 Hibernate (小弟尚在研究中~~)

這些 ORM 主要就是幫助我們解決 object and relative 的 mapping

畢竟,Database 的世界與 Program 的世界還是相距甚遠~~

今天不談 ORM,所以我們就將 Model components 用 JDBC 來設計

熟悉 JDBC 的人都知道,最中取出來的資料是一個 ResultSet 物件

如果我們就直接將 ResultSet 物件丟給 Controller 去處理,這樣就需要由 Controller 負責將 Model 產生的結果作收尾的動作

因為 ResultSet 是一個持續跟 Database 有連線關係的物件,照理說應該是由 Model 端元件來負責 ResultSet 的資料清裡

所以我們就需要在 Controller and Model 之間改以 JavaBean 做為溝通的橋樑

所以我們的開發第一步就是:開發一個與 Database Table 一樣內容的 JavaBean,也就是開發一個 Entity Bean

有了 Entity Bean,第二步就是:開發我們的 Model 元件

透過撰寫 SQL 語法對 JDBC 作存取的動作,並且在查詢結果 return 之前,Model 元件需要負責關閉 JDBC 物件與 Database 之間的連線,以確保資源的釋放

有了這兩樣的元件後,直觀的來說,就是對 Controller 開始動手囉!!

不過,回到 Struts 的運作,因為使用者可能由 View 端 submit requests,所以 View and Controller 之間的溝通是透過 ActionForm 物件

ActionForm 其實算是一種 JavaBean,不過他提供更多一點的功能

所以我們的第三步就是:開發 ActionForm

開發 ActionForm 物件最主要就是需要釐清使用者會將哪些資料 submit 給 Controller

有了這三樣元件後,我們就是真的要開始開發 Struts 中最核心的 Controller

第四步:開發 Controller

完成了 Controller 的內容,我們就可以知道哪些資訊是需要給使用者觀看的,所以我們就可以開發 View 端

第五步:開發 View

View 端透過一些 tags 來完成顯示的內容

以上是我開發的習慣流程,如果您是正需要使用 Struts 來開發您的 Web Application,您可以參考這樣的開發流程,來減低您 survey 的時間

2008年5月3日 星期六

[Struts] 建立一個可以讓使用者下載檔案的 Action

Struts 的 Action 扮演 MVC(Model-View-Controller) 中的 Controller 角色

所有 Struts 的 request 都會先經過 Controller 在進行後端的 Model 計算並產生前端的 View

相信對於使用 Struts 的 programmer 來說,一般的 Action 都是不陌生的!!

但是,要如何可以讓使用者透過瀏覽器來下載檔案呢??

當然這檔案不是一個 static file,要對使用者的 request 產生一個 dynamic file

static file要做到就是直接將路徑指到 browser 的 URL 就OK

那 dynamic file呢?

Struts 提供一種 Action - DownloadAction,就如同一般的 Action 使用一樣

但是不同點在於需要 implement 一個 getStreamInfo method

所以我的 Controller 就會長成這樣:

public class MyController extends DownloadAction {
    public StreamInfo getStreamInfo(...) {
    }
}

基本的 class 架構就如上面的樣子,那 getStreamInfo method 呢?? 我要怎樣去完成??

我們先討論為何會有 getStreamInfo method 的存在

這個 method 是讓我們可以撰寫要讓使用者下載檔案的內容

觀察 Struts 的 DownloadAction source code 就可以發現,DownloadAction 是如何執行的:

1.首先呼叫我們撰寫的 getStreamInfo() method 來建立一個 StreamInfo object

2.接著就是由 StreamInfo object 中獲得 content type and inputStream

3.再來就是設定 browser 的 content type,告知 browser 要如何處理該檔案,如果是可以由外部存取的檔案,就會試著呼叫相關的 application 來支援

4.最後就是將 inputStream 的內容 copy 到 response 的 outputStream

使用者就可以透過 browser 取得檔案或是呼叫相關的 application 來處理檔案

知道流程後,我們就必須要撰寫 getStreamInfo() method 來符合流程囉~~

由上述的流程中,我們需要建立一個 StreamInfo object,裡面包含 content type and inputStream,所以重點就在於 StreamInfo object 的撰寫

觀察 Struts API 就會發現我們竟然找不到 StreamInfo interface 的內容!! 該不會 API 出錯??

身為一個 JAVA Programmer 的直覺,StreamInfo 一定是 DownloadAction 的 inner interface,所以我們要改查 DownloadAction.StreamInfo,果然不出我所料!!

既然是一個 interface 那我們就要接著觀察他有哪些 Known Implementing Classes

在 API 中立即就寫出:
All Known Implementing Classes:
    DownloadAction.FileStreamInfo, DownloadAction.ResourceStreamInfo


所以我們就要觀察哪個 implementing class 是我們所需要的!!

從 DownloadAction.FileStreamInfo 中知道這是用來產生檔案下載的,而 DownloadAction.ResourceStreamInfo 是用來產生網路資源的

所以我們就鎖定 DownloadAction.FileStreamInfo class 來使用

決定好關鍵的 class 之後,就是開始撰寫我們 getStreamInfo() method 囉~~

然而,需要建立一個 DownloadAction.FileStreamInfo 物件就需要設定他的 content type and file object(因為 constructor 的 parameter)

所以我們就要先建立一個 file 物件來讓 DownloadAction 的 inputStream 可以完成第四項流程

我們需要將我們的 dynamic file 備份到 local 的 HD 中,再將我們存放的路徑給予 File object

所以我們的 getStreamInfo() method 會先有這樣的內容:

public StreamInfo getStreamInfo(...) {
    String path = "/a.dat";
    File file = new File(path);
}

再來就是 content type 的部分,content type 就是告知 browser 該如何去處理接著要下載的檔案,例如我們設定 application/pdf,browser 就會預設呼叫 Adobe Acrobat Reader 來讀取

但是這樣還是無法完成正確的下載,所以我們必須在 StreamInfo 物件送交之前,對 response 設定 Header 為 "Content-disposition",value 為 "attachment; filename=a.dat"

這段設定的目的在於,強制 browser 不要在 browser 本身開啟檔案,強制 browser 透過下載檔案的方式來處理,而 filename 的部分卻可以讓我們對於使用者下載的檔名給與預設值

所以最後完成的內容應該會包含這樣的樣子:
public class MyController extends DownloadAction {
    public StreamInfo getStreamInfo(...) {

        String path = "/a.dat";
        File file = new File(path);
        String contentType = "application/unknow";
        //商業邏輯...
        response.setHeader(
            "Content-disposition",
            "attachment; filename=a.dat");
        return new FileStreamInfo(contentType,file);

    }
}

這樣我們就可以完成讓使用者下載檔案的功能了!!

2008年2月9日 星期六

[Struts] Struts 的 TAG 與 javascript 互動

在Struts 中的 TAG 例如: 等,須要跟 javascript互動時,又碰巧變數儲存在 jsp scope 中,那我們該如何去解決勒??

這個問題看似簡單

<html : link action="test" onclick="javascript : return confirm( ' <%= i %>' )" />

你以為這樣就解決嗎??

上面的結果就會出現一個 javascript confirm box 上面顯示 <%= i %>的訊息

剛開始我以為這樣是一定可以成功,結果出來卻不是我要的XD

因為透過 struts tag 裡面的 scriptlets(<%=%>) 是不會被JSP 先解析,所以就想說那就把呼叫confirm 所給的 arguments 的單括號拿掉!!

<html : link action="test" onclick="javascript : return confirm( <%= i %>)" />

結果就是連 confirm box都彈不出來, 透過 firefox 的 javascript console 來觀察錯誤在哪,結果就是跟你說 < 符號不能理解XD

這問題困擾了很多天,有一天透過 google 大神終於找到解答了!!!

這解答果然有撇步~~~

只要將上面的 TAG 改為

<html : link action="test" onclick= ' <%= "return confirm( ' " +i+ " ' )" %>' />

也就是將呼叫 javascript 的 code 在 scriptlets 中當作字串來處理

然後有牽涉到 JSP scope 中變數的部分就利用 string 相加的方式完成整句在client browser 先由 server 解析

與大家分享之~~

[Struts] Struts 解決中文問題

其實Struts 已經用了一陣子了!!當初自己在開發時,遇到最大的問題就是中文的問題!!

好在 LAB 有學長也是有碰過類似的經驗,大家討論之下終於有了答案... Filter

在每個 Struts 的請求中先透過 Filter 來作編碼的動作:

package filter.encoding;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

public class EncodingServlet extends HttpServlet implements Filter
{
    private FilterConfig filterConfig;

    //Handle the passed-in FilterConfig
    public void init(FilterConfig filterConfig) throws ServletException
    {
        this.filterConfig = filterConfig;
    }

    //Process the request/response pair
    public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain)
    {
        try
        {
            request.setCharacterEncoding("utf-8");
            filterChain.doFilter(request, response);
        }
        catch(ServletException sx)
        {
            filterConfig.getServletContext().log(sx.getMessage());
        }
        catch(IOException iox)
        {
            filterConfig.getServletContext().log(iox.getMessage());
        }
    }

    //Clean up resources
    public void destroy()
    {
    }
}

然後在 web.xml 中加入

<filter>
    <filter-name>EncodingServlet</filter-name>
    <filter-class>filter.encoding.EncodingServlet</filter-class>
</filter>
<filter-mapping>
    <filter-name>EncodingServlet</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>

就是讓所有對 Controller 發出 request 的請求都能夠先經過我們的 filter

網頁之間的編碼問題解決了!!

事情還沒結束勒~~~

因為 Struts 有一種 i18n 的機制,就是讓所有 Message 都包裝在一個 ApplicationResource.properties 之中

這個檔案裡面不能將中文很正確的在 view 中顯示,所以我們需要一個工具來輔助:property editor

下載的網址如下:
http://propedit.sourceforge.jp/index_en.html

因為我是用 Eclipse 來開發的,所以我是用他對於 Eclipse 的 plug-in

安裝方式網頁上有說,不是用下載的方式,而是可以透過 Eclipse 的安裝 feature 工具來 support

當你重新開啟 Eclipse 後,對於 *.properties 檔案按下右鍵選擇 [Open with] -> [PropertiesEditor]

就可以利用這個工具來編輯 *.properties 檔案

當然它看起來就跟一般 Eclipse 內建的工具差不多,只是如果你是輸入非英文字母,它會自動幫你轉成 UTF-8 的編碼方式

另外還有一點要注意,在 view 的編碼也要改成 UTF-8 不然,我也不知道會怎樣XD

最近找到有 support struts 在 eclipse 上的 plug-in ,可是似乎都不太好用~~

但是有一個工具也可以提供給大家:Struts Console

網址如下:
http://www.jamesholmes.com/struts/console/

他也是有支援 eclipse 讓我在開發時對於編輯 struts-config.xml 來說就不是只是看一堆 XML TAG 了

他的工具也支援 Validator and Tiles 的 struts plug-in

不過對大的缺點就是對於 struts 與支援到 1.2的版本,殘念!!

剩下對於支援 Struts 的工具就有限了!!

如果要開新的 struts project ,我個人是建議直接將 struts-blank.war 匯入後在去更改內容

因為這樣是最快的方法了!! 很多東西要重新撰寫很累人!!!

希望對正要開始開發 struts 的 programmer 來說會有一些些的幫助

P.S. 還是要感謝涼鳥學長在Struts 方面給的指導!!

[Struts] Struts的 標籤使用javascript來顯示

找了好久,怕網頁不見,乾脆就先記錄下來囉!!

原網址:http://www.mail-archive.com/struts-user@jakarta.apache.org/msg69201.html


Re: <html:errors> tag in javascript alert

Martin Fekete
Thu, 12 Jun 2003 23:29:54 -0700

try this ...

errors.header =alert(
errors.prefix ="
errors.suffix ="+ "\\n" +
errors.footer ="");\n

...
<script>
function load() {
<html:errors>
}

</script>
...
<body onload="load()">
...

it should work but it won't because of
http://issues.apache.org/bugzilla/show_bug.cgi?id=17418
so you need to hack org.apache.struts.taglib.html.ErrorsTag

Feky

P.S. 感謝涼鳥學長的幫忙!!