圖 1 典型Stripes流程
因為我們已經用annotation把index方法標記為@DefaultHandler,Stripes無須event屬性也知道要執行哪一個方法。
用約定、不用配置文件
我們現在有了Java組件,我們該做配置了,把動作映射的一個URL上,並將其連接到我們的兩個view上面去。等一下!我們在用Stripes,我們不需要外部配置文件!
雖然這聽來似乎好得不像是真的,但這的確是Stripes的一項最具生產效率的功能。Stripes使用約定而非配置文件來映射動作到URL上。我們也無須使用一個外部配置文件來把view映射到一個個標記名字上。這意味著程序員不用再為了一個標記名字——比方說SUCCESS——的實際來源,而在配置文件中跳來跳去了。沒有必要在Java和view組件的外部進行配線,因而導致更好地維護性和更高的生產率。
Stripes是如何提供隱式的URL映射而無需在外部配置每一個動作或者而外的annotation呢?這個可以從Stripes在web.XML中的配置以及它是如何通過實用默認法建立URL映射來解釋。首先,我們來看看Servlet過濾器:StripesFilter。其在web.xml中的默認配置如下:
<filter>
<display-name>Stripes Filter</display-name>
<filter-name>StripesFilter</filter-name>
<filter-class> net.sourceforge.stripes.controller.StripesFilter </filter-class>
<init-param>
<param-name>ActionResolver.UrlFilters</param-name>
<param-value>/WEB-INF/classes</param-value>
</init-param>
</filter>
當Servlet容器啟動的時候,StripesFilter對其init-param元素執行初始化。其中最重要的init-param元素就是ActionResolver.UrlFilters參數。這個參數告訴Stripes到哪裡查找跟Stripes有關的類。這個例子裡面,Stripes將查找/WEB-INF/classes目錄下的所有實現ActionBean接口的類。每一個被找到的類和其綁定的URL都將被加入一個Map中。
讓我們來看看Stripes是如何處理我們的HelloWorldAction動作為例子吧。因為HelloWorldAction類位於/WEB-INF/classes目錄下,所以會被認為是一個Stripes servlet。在我們的例子當中,其完整類名是com.myco.web.stripes.action.example.HelloWorldAction。隨後,其完整類名將按照如下法則被翻譯成一個URL綁定。
1. 將含有www、web、stripes、和action的部分及其以前的內容刪掉。在我們的例子有三個上述單詞,所以我們得到了example.HelloWorldAction。
2. 假如類名中包涵帶Action或Bean的尾巴,刪掉。因為我們的類名以Action結尾,我們得到了example.HelloWorld。
3. 將.替換為/,我們得到了example/HelloWorld。
4. 最後,添加上一個尾綴(默認是.action)從而完成了URL綁定。最後的結果是example/HelloWorld.action。
現在Stripes找到了ActionBean類並為其創建了一個URL綁定,然後存放在一個java.util.Map<String, Class<? extends ActionBean>>之中。其中key參數是URL綁定,value參數是實現ActionBean的類名。下面是我們的例子中的Map:
URL綁定:/example/HelloWorld.action
ActionBean類:com.myco.web.stripes.action.example.HelloWorldAction
我們要看的第二個組件是Stripes如何把URL綁定翻譯成你正在做的這個ActionBean類。這是Stripes調度servlet的職責,在web.xml中的配置如下:
<servlet>
<servlet-name>StripesDispatcher</servlet-name>
<servlet-class>
net.sourceforge.stripes.controller.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>StripesDispatcher</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
StripesDispatcher的一個職責就是將URL解析為Stripes的ActionBean類。當用戶激活URL http://host/uri/example/HelloWorld.action的時候,Stripes調度servlet將在URL映射表中查詢並找到com.myco.web.stripes.action.example.HelloWorldAction類,並實例化產生該類的一個實例。最後,index方法被激活,因為在annotation中它被定義為默認局柄而在該URL中並沒有指定一個事件。
假如我們想要直接執行HelloWorldAction中的hello方法怎麼辦?應該象下面這個URL這樣把事件的名字放在request的參數中:
http://host/uri/example/HelloWorld.action?hello=&firstName=Mark&age=13
請注重我們沒有給hello這個request參數名指定任何值。在這個情況下,StripesDispatcher會把hello這個這個request參數名和HelloWorldAction類中個一個帶有public Resolution hello()簽名的函數識別並映射。該方法名城在初始化的時候為了性能而緩存在另一個Map中。
我們已經看到Stripes的基礎以及假如創建簡單的動作和一些該框架是如何運作的細節。通過在web.xml中的初始化,我們能夠避免用多個單獨的XML配置文件來把我們的顯示層組建寫在一起。這很重要,原因如下:首先,假如你需要任何改動,你可以看到一個URL就立即知道你該查看哪一個類。其次,我們不需要任何單獨的工具來在你的配置文件過大而且不可治理的時候幫助你。通過消除掉配置文件,我們不再需要給框架一大堆的metadata。最後,我們不再需要為一個獨立的用來描述我們的組件是假如相互關聯的文件來一刻不停維護了。
Ajax
要不要更高級的功能?那我們就來看看Stripes是怎麼處理Ajax的。我們將把先前的Hello World例程改成使用Ajax調用Stripes動作。本例子的源代碼可以在本文資源中找到。首先,我們對Hello.jsp作改動使其引用Prototype javascript函數庫。我們還要為Ajax調用增加一個JavaScript函數,並更改提交按鈕為其添加一個onclick事件:
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %>
......
<script src="${pageContext.request.contextPath}/js/prototype.js" type="text/javascript">
</script>
<script type="text/javascript">
function sayHelloAjax(){
var myAjax = new Ajax.Updater('hello', "<stripes:url beanclass="com. myco. web. stripes. action. example. HelloWorldAction" event="sayHelloAjax"/>", { method: 'get', parameters: Form.serialize('helloForm') });
}
</script>
......
<stripes:errors/>
<stripes:form beanclass="com. myco. web. stripes. action. example. HelloWorldAction" id="helloForm">
Say hello to:
<br> First name:
<stripes:text name="person.firstName"/><br>
Age:<stripes:text name="person.age"/><br>
<stripes:button name="helloAjax" value="Say Hello" onclick="sayHelloAjax()"/>
<div id="hello"></div>
</stripes:form> ......
stripes:button有一個onclick事件將會調用HelloWorldAction類中的sayHelloAjax方法並將其結果返回在一個叫hello的div tag中。下面是我們要在HelloWorldAction中介紹的一個新方法:
public Resolution sayHelloAjax()
{
return new ForwardResolution("SayHelloAjax.jsp");
}
這個方法沒有多少工作,因為Stripes已經承擔了姓名內容的綁定。因此,本方法唯一的責任就是轉發到一個叫SayHelloAjax.jsp的頁面片斷上去。該葉面片段的內容如下:
<h2>Hello ${actionBean.person.firstName} your age is ${actionBean.person.age}!</h2>
Spring整合
Stripes還內置了對Spring支持。你可以自動地將Spring bean諸如到你的動作中。按照Stripes的風格,除了Spring上下文配置文件以外不需要任何外部配置文件。假如我們Spring的配置文件如下:
<bean id="personService" parent="abstractTxDefinition">
<property name="target">
<bean class="com.myco.service.impl.PersonServiceImpl"/>
</property>
</bean>
要把person服務注入到一個Stripes動作中,得增加一個跟Spring bean的名字一致的屬性和setter。Stripes提供了@SpringBean annotation來查詢正確的Spring bean以注入到動作之中。下面是我們要在動作類中包含的例子:
private PersonService personService;
@SpringBeanpublic void setBlogService(BlogService blogService)
{
this.blogService = blogService;
}
本文無法囊括Stripes的所有高級功能。但是,Stripes有非常完整的文檔。Stripes還包含了一個與Tiles類似但無需外部配置文件的layout治理器。另外,攔截器還可以用於生命周期事件的各處、文件上載等等等等。
結論
Stripes是一個既強大又簡單的Java web框架。Stripes利用了Java 5的annotation和泛型功能,從而使得Java程序員避免維護外部配置文件並增加工作效率。Stripes可以簡化困難的web開發工作,並使得簡單的工作更加簡單!