2009年3月3日星期二

Ajax(DWR) + Struts 實例開發

Ajax是近年最火爆的網頁開發技術,以gmail為先驅的Ajax應用已經逐漸深入人心了。也許這就是所謂的輪回吧,電腦介面的設計從最初瘦到胖再 到瘦,如今又要開始胖了。不過,在web介面的胖與之前的胖還是有很多區別的,web介面的胖主要依賴於DHML和Javascript來實現。這也是本 文的來由了,相信很多OO的開發人員都不願與頁面層的效果打交道,尤其是Javascript的這樣的開發語言,我也是其中之一了,非常不喜歡 Javascript,語法鬆散,結構複雜。反正是不喜歡了,但是在web時代,既然流行胖子,想不用Javascript是不可能的了,那麼怎麼樣來簡 化Ajax的開發呢?DWR由此延生了,他封裝了XMLHttpRequest,直接調用服務端的方法,省了好多Javascript啊^_^

Struts雖然已經開始開下陡路,但底子厚,將DWR與Struts結合依然會是大多數開發者的選擇。
本文分兩部分:框架介紹和實例開發。先來:


第一部分 框架介紹


一、Ajax介紹

Ajax--Asynchronous JavaScript and XML,非同步JavaScript和XML。名字中已經包含Ajax的組成部分:非同步處理XMLHttpRequest,JavaScript,XML。
其中:


1、XMLHttpRequest是Ajax的關鍵部分,正是由於他的存在,才使得胖子越來越吃香了。


2、JavaScript是Ajax的必備部分,沒有他還玩個屁


3、XML是Ajax資料格式的推薦方式,但也可以不用
當然還少不了CSS,有了CSS使得在Ajax中更容易修改用戶的介面
Ajax的細節和樣例使用就不多說了,N多的資源,自己找吧。


 


二、DWR介紹
DWR-Direct Web Remote,翻譯過來應該是直接遠端網頁訪問。(這個Web一直找不到好的詞語來表達,這裏就用網頁吧)
如名字所述,DWR的主要特點就是可以在Ajax中直接調用伺服器上的方法,很奇妙吧。就是說,不需要通過URL來告訴服務來處理,而是直接在Javascript中調用類的方法,並返回資料。

DWR簡化了Ajax的開發:


1、封裝了Ajax中的使用,不再需要直接使用XMLHttpRequest了,這可是非常重要的,減少了好多Javascript呀


2、通過回調函數的方式,簡化了錯誤處理及返回資料的處理。


3、直接調用伺服器類的方法,不再需要通過URL方式,也省了不少的事。

DWR的主要部件有:dwr.xml/engine.js/util.js,前者是DWR的Servlet使用的配置檔,後兩者DWR替我們封裝的Ajax的代碼,當然也提供了其他有用的功能。


 


三、Struts介紹
Struts還用介紹嗎?沒聽說過?那就不用往下看,休息休息吧^_^
這裏就說一下在DWR如何調用Struts中Action的方法吧,說白了,是不可能的。這不是白說嗎? 實際上是這樣的,雖然DWR支持方法的調用,但ActionForward/ActionForm/ActionMap這些東西如何在DWR調用方法前生成 呢?我也不知道,所以DWR對Struts的支持實際上就是要重構Action中的方法,去掉上面的東西,然後就可以了(這是DWR說的,可不是我說的 ^_^)。


看了上面的一小通介紹,不知道大家有沒有什麼感覺,我也覺得寫得太少了,可能看了跟沒看差不多。不過這裏主要是想大家對這些概念有個瞭解。接下來的第二部分,將會以實例開發的方式來寫,這樣就更容易依樣畫葫蘆了(我也比較喜歡這樣的方式)。


摘要:先講一下應用的結構頁面端:
demo.jsp用來展示介面服務端: DemoAction是Struts中的Action子類負責控制轉換, DemoFacade是業務類負責業務處理。 Goods是一個業務實體類Struts部分的配置就
先講一下應用的結構
頁面端:
demo.jsp用來展示介面
服務端:
DemoAction是Struts中的Action子類負責控制轉換,
DemoFacade是業務類負責業務處理。
Goods是一個業務實體類

Struts部分的配置就忽略不說了,實際上這個應用並沒有包含Struts的配置
主要講一下dwr的配置,首先需要在web.xml增加下面的servelt映射:


 


<servlet>

   
<description>Direct Web Remoter Servlet</description>

   
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>

 
</servlet>

 
<servlet-mapping>

   
<servlet-name>dwr-invoker</servlet-name>

   
<url-pattern>/dwr/*</url-pattern>

 
</servlet-mapping>


如上uk.ltd.getahead.dwr.DWRServlet是dwr的核心,用來處理javascript的對遠端方法的調用,還有其他參數請參考相關文檔。
然後,需要在dwr.xml配置相應的遠端方法(與具體需要在用戶端調用的方法相關),如下為演示應用的配置:


<dwr>

   
<allow>

       
<convert converter="bean" match="dwr.demo.Goods"/>

       
<create creator="new" javascript="DemoAction" class="dwr.demo.DemoAction">

           
<include method="query4dwr"/>

           
<include method="copy4dwr"/>

           
<include method="paste4dwr"/>

       
</create>

       
<create creator="new" javascript="DemoFacade" class="dwr.demo.DemoFacade">

           
<include method="queryList"/>

           
<include method="restore"/>

           
<include method="del"/>

       
</create>

      
</allow>

</dwr>


 


















如 上有一個轉換器(converter)是用來映射dwr.demo.Goods為bean類型,其他轉換器類型請參考相關文檔;還有兩個創建器分別創建 javascript中的DemoAction類和DemoFacade類,分別對應dwr.demo.DemoAction類和 dwr.demo.DemoFacade,其中定義的方法就可以從javascript中直接調用了。


最後,我們需要在頁面中包含相應的javascript:





 


<script src='dwr/interface/DemoAction.js'></script>

 
<script src='dwr/interface/DemoFacade.js'></script>

 
<script src='dwr/engine.js'></script>

 
<script src='dwr/util.js'></script>


 


如上,dwr/interface/DemoAction.js和dwr/interface/DemoFacade.js是dwr自动生成的 javascript文件,包含相应的类及方法,dwr/engine.js是dwr的核心引擎脚本处理客户端调用的转换,dwr/util.js包含了 工具函数简化页面处理。



下面以查询为例,看一下dwr的具体使用:

DemoAction:

   
public List query4dwr(int type, boolean needClear, HttpServletRequest request) {

       
if (needClear) request.getSession().removeAttribute("dwr.demo.goodsId");

       
return demoFacade.queryList(type);

   
}

demo.jsp:

 
function updateResults() {

   
DWRUtil.removeAllRows("goodsbody");

   
var type = document.getElementById("type").value;

   
DemoAction.query4dwr(type, true, fillTable);

 
}

 
function fillTable(goods) {

   
document.forms[0].select.checked = false;

   
document.getElementById("totalRecords").innerHTML = goods.length;

   
DWRUtil.addRows("goodsbody", goods, [ addCheckbox, getName, getPrice, getCount]);

 
}

如 上,DemoAction.query4dwr(type, true, fillTable)就可以直接调用DemoAction的方法了,这里fillTable是函数,dwr通过回调函数的方式来进行后续处理。比较一下 javascript和action中的方法参数,HttpServletRequest是可以不传的,dwr会自动加上,另一个就是回调参数放在最后, 这是比较好的方式,其他方式请参考文档。



最后看一下,dwr如何与Struts集成,如下代码:

   
public ActionForward query(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

       
String type = request.getParameter("type");

       
//或者从form中取值

        


       
List goodsList = query4dwr(Integer.parseInt(type), true, request);

       
request.setAttribute("goodsList", goodsList);

        


       
return mapping.findForward("success");

   
}



   
public List query4dwr(int type, boolean needClear, HttpServletRequest request) {

       
if (needClear) request.getSession().removeAttribute("dwr.demo.goodsId");

       
return demoFacade.queryList(type);

   
}

前一个方法是Struts的方式,但dwr不支持,因此要重构一下在下面的方法才可以被dwr调用。

实际上,只有在方法中需要使用到HttpServletRequest是才需要重构方法,如果不使用HttpServletRequest,我们就可以直接调用业务层的类的方法,这样即简单又方便,如下:

demo.jsp:

 
function restore() {

   
DemoFacade.restore(updateResults);

 
}



DemoAction:

   
public synchronized void restore() {

       
goodsList.clear();    

       
initGoods();

   
}



小结



 
dwr封装了ajax中与服务端交互的模块,通过直接调用服务端类的方法简化了客户端与服务端的交互。虽然说还缺省类似tag这样的组件,但已经很大程度简化了ajax的开发。

DWR - Easy Ajax for Java

DWR is a Java library that enables Java on the server and JavaScript in a browser to interact and call each other as simply as possible.


DWR介紹
What is DWR?:
在伺服器上運行的Servlet來處理請求並把結果返回流覽器。

運行在流覽器上的Javascript,可以發送請求,並動態 改變頁面。DWR會根據你的Java類動態的生成Javascript代碼。這些代碼魔力是讓你感覺整個Ajax調用都是在流覽器上發生的,但事實上是伺服器執行了這些代碼,DWR負責資料的傳遞和轉換。

這種Java和Javascript之間的遠端調用會讓DWR用
戶感覺像是曾經習慣使用的RMI或SOAP的RPC機制。而且這一過程還不需要額外的流覽器插件。
Java是同步的,而Ajax是非同步的。所以當你調用一個遠端方法時,你要給DWR一個回調函數,當資料從網路上回來時,DWR會調用這個函數。

DWR的作用
:
有效地從應用程式碼中把 Ajax 的全部請求-回應迴圈消除掉。
用戶端代碼再也不需要直接處理XMLHttpRequest 物件或者伺服器的回應。
不再需要編寫物件的序列化代碼或者使用第三方工具才能把物件變成 XML。
不再需要編寫 servlet 代碼把 Ajax 請求調整成對 Java 域物件的調用


DWR原理

DWR是作為Web應用的一個Servlet進行部 署的,是一個黑盒子中的servlet。

對於公共有的每個類,DWR 動態地生成包含在 Web 頁面中的 JavaScript。生成的JavaScript 包含存根函數,代表 Java 類上的 對應方法並在幕後執行XMLHttpRequest。這些請求被發送給DWR。

把請求翻譯成伺服器端 Java 物件上的方法調用並把方法的返回值放在servlet 回應中發送回用戶端,編碼成 JavaScript。


編寫伺服器端Java類

不要出現Javascript保留關鍵字;和保留關鍵字同名的函數指定被排除。
多數Javascript的關鍵字和Java是相同的。所以你不可能有一個方法叫做”try()”。但是該死”delete()”對與Javascript有著特殊意義,而對Java則不是。

Javascript方法重載是不支援的,所以儘量不要再Java中使用。


1.
2. package test;
3.
4. public class HelloWorld {
5. public String sayHello(String name) {
6. return "Hi, " + name;
7. }
8. }



在dwr.xml檔註冊Java物件


在jsp頁面中添加DWR AJAX庫以及相應的js

注: 可以在啟動項目後,IE位址欄輸入 http://hostName:port/dwr/
查看動態javascript 路徑.以及所有可以運行的方法.




1、$(”username”) = document.getElementById(”username”);
2、setValue(id, value):這個函數能操作大多數HTML元素
3、getValue(id):getValue(id)是 setValue()對應的”讀版本”。
4、setValues():批量設置值
5、getValues():批量獲取值
6、getText(id):為select列表設計的。你可能需要取得顯示的文字,而不是當前選項的值。
7、selectRange:選擇一個輸入框中的一定範圍的文字。

2009年2月28日星期六

Portal (Portlet) or AJAX ?

I am going to develop a web application but not sure what development framework is better.
Nowadays, there are many frameworks for developing web application. For examples: JSF, JSP/Servlet, Java Portal (Portlet) framework, Springframework, Struts, Webworks, and also AJAX, etc. Too many taht I can't list or really know about them.

My first choice is Portal(portlet) + Ajax. For using Java as the development language, which portal is better? I prefer JBoss Portal, the framework is more structure and easy to use. The Liferay Portal has many well developped portlets for use.

Anyway, both of them I give up but customized the Apache Pluto-2.0. It is in the development statge. I want to get more suggestions on a Java Portal Server. Let's say, functions, arcvhitectures, etc.

2009年2月26日星期四

Facebook application

Recently, facebook games are very popular arround us. Almost all of my friends play and use facebbok. They like to share their friend and games.

I am also using facebbok and try to develop a simple application (game) in facebook.

The game is talking about how to be the most rich people in the town. If you have interest, just go to have a look.

AirCoon (娛樂大亨 - 金光大道傳奇)
http://apps.facebook.com/aircoon/

2009年2月25日星期三

What can we do with Google Maps in Macau?

  1. Find the nearest restaurant
  2. Locate the buildings (very useful in real estate agents)
  3. plan a trip
  4. etc.

2008年10月31日星期五

利用 mod_jk 或 mod_proxy 實現 Apache-2.2 + Tomcat-6 負載平衡(Load Balance) 和 集群技術 (Cluster)

Tomcat 是一個廣為人知的 JSP/Servlet 伺服器, 人們通常將它與 Apache 網頁服務器一同使用, 從而增加傳輸速度。

在這篇文章中, 我會示範如何利用 mod_jk 或 mod_proxy 設定 Apache-2.2 + Tomcat-6 平衡負載(Load Balance) 和 集群技術 (Cluster)。


請準備以下的軟件:
  1. Apache web server 2.2.x
  2. Tomcat-6.x
  3. mod_jk


※ 下載位址 :

- Apache web server
http://httpd.apache.org/

- Tomcat
http://tomcat.apache.org

- mod_jk 1.2
http://tomcat.apache.org/download-connectors.cgi



以下是各伺服器的 IP 設定:

Server (IP)
=========================
Apache-2.2.x (192.168.0.1)
Tomcat-6.x(1) (192.168.0.10)
Tomcat-6.x(2) (192.168.0.20)



首先介紹如何用 MOD_JK 1.2 實現平衡負載(Load Balance) 和 集群技術 (Cluster)

- 在 httpd.conf 下加入以下腳本

# -------- START HERE -----------
# Load mod_jk module
# Specify the filename of the mod_jk lib
LoadModule jk_module modules/mod_jk-apache-2.2.3.so

# Where to find workers.properties
JkWorkersFile conf/workers.properties

# Where to put jk logs
JkLogFile logs/mod_jk.log

# Set the jk log level [debug/error/info]
JkLogLevel info

# Select the log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

# JkOptions indicates to send SSK KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories

# JkRequestLogFormat
JkRequestLogFormat "%w %V %T"

JkMount /* loadbalancer

# ------------ END HERE -----------------




接著介紹如何用 MOD_JK 1.2 實現平衡負載(Load Balance) 和 集群技術 (Cluster)

- 在 httpd.conf 下加入以下腳本


# ---------------- START HERE -----------------------

<Location /balancer-manager&rt;
SetHandler balancer-manager
</Location&rt;

<Proxy balancer://cluster&rt;
BalancerMember ajp://192.168.0.10:8009
BalancerMember ajp://192.168.0.20:8009
</Proxy&rt;

<Location /&rt;
ProxyPass balancer://cluster/ stickysession=JSESSIONID
</Location&rt;


# ---------------- END HERE ------------------



安裝完 Tomcat-6.x 後,在 $TOMCAT_HOME/conf 下開啟 server.xml 並 解除 Cluster 註釋



所有設定已完成, 請先啟動 Tomcat 後再啟動 Apache.