一、dwr配置篇之web.xml
1、最小配置
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
2、
當(dāng)我們想看DWR自動(dòng)生成的測(cè)試頁(yè)(Using debug/test mode)時(shí),可在servlet配置中加上
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
這個(gè)參數(shù)DWR默認(rèn)是false。如果選擇true,我們可以通過http://localhost:port/app/dwr看到你部署的每個(gè)DWR class。并且可以測(cè)試java代碼的每個(gè)方法是否運(yùn)行正常。為了安全考慮,在正式環(huán)境下你一定把這個(gè)參數(shù)設(shè)為false。
3、多個(gè)dwr.xml文件的配置
可能有幾種情況,我們一一列舉。一個(gè)servlet,多個(gè)dwr.xml配置文件;多個(gè)servlet,每個(gè)servlet對(duì)應(yīng)一個(gè)或多個(gè)dwr.xml配置文件。
3.1、一個(gè)servlet,多個(gè)dwr.xml配置文件
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>config-1</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<init-param>
<param-name>config-2</param-name>
<param-value>WEB-INF/dwr2.xml</param-value>
</init-param>
</servlet>
在這種配置下,param-name的值必須以config開頭。param-name可以有>=0個(gè)。如果沒有param-name,那么將會(huì)讀取 WEB-INF/dwr.xml。如果有大于零個(gè)param-name,那么WEB-INF/dwr.xml文件將不會(huì)被讀取。
3.2、多個(gè)servlet,每個(gè)servlet對(duì)應(yīng)一個(gè)或多個(gè)dwr.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>dwr-invoker1</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>config-admin</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dwr-invoker1</servlet-name>
<url-pattern>/dwr1/*</url-pattern>
</servlet-mapping>
在這種情況下,我們可以根據(jù)J2EE security來(lái)控制權(quán)限,針對(duì)不同url,加不同的角色。
AB:調(diào)用沒有返回值和參數(shù)的JAVA方法
AC:調(diào)用有簡(jiǎn)單返回值的java方法
AD:調(diào)用有簡(jiǎn)單參數(shù)的java方法
AE:調(diào)用返回JavaBean的java方法
AF:調(diào)用有JavaBean參數(shù)的java方法
AG:調(diào)用返回List、Set或者M(jìn)ap的java方法
AH:調(diào)用有List、Set或者M(jìn)ap參數(shù)的java方法
二、dwr使用篇
AB
1、調(diào)用沒有返回值和參數(shù)的JAVA方法
1.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod1"/>
</create>
</allow>
</dwr>
<allow>標(biāo)簽中包括可以暴露給javascript訪問的東西。
<create>標(biāo)簽中指定javascript中可以訪問的java類,并定義DWR應(yīng)當(dāng)如何獲得要進(jìn)行遠(yuǎn)程的類的實(shí)例。creator="new"屬性指定java類實(shí)例的生成方式,new意味著DWR應(yīng)當(dāng)調(diào)用類的默認(rèn)構(gòu)造函數(shù)來(lái)獲得實(shí)例,其他的還有spring方式,通過與IOC容器Spring進(jìn)行集成來(lái)獲得實(shí)例等等。javascript=" testClass "屬性指定javascript代碼訪問對(duì)象時(shí)使用的名稱。
<param>標(biāo)簽指定要公開給javascript的java類名。
<include>標(biāo)簽指定要公開給javascript的方法。不指定的話就公開所有方法。
<exclude>標(biāo)簽指定要防止被訪問的方法。
1.2、javascript中調(diào)用
首先,引入javascript腳本
<script src='dwr/interface/ testClass.js'></script>
<script src='dwr/engine.js'></script>
<script src='dwr/util.js'></script>
其中TestClass.js是dwr根據(jù)配置文件自動(dòng)生成的,engine.js和util.js是dwr自帶的腳本文件。
其次,編寫調(diào)用java方法的javascript函數(shù)
Function callTestMethod1(){
testClass.testMethod1();
}
?
AC
2、調(diào)用有簡(jiǎn)單返回值的java方法
2.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod2"/>
</create>
</allow>
</dwr>
2.2、javascript中調(diào)用
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)和接收返回值的回調(diào)函數(shù)
Function callTestMethod2(){
testClass.testMethod2(callBackFortestMethod2);
}
Function callBackFortestMethod2(data){
//其中date接收方法的返回值
//可以在這里對(duì)返回值進(jìn)行處理和顯示等等
alert("the return value is " + data);
}
其中callBackFortestMethod2是接收返回值的回調(diào)函數(shù)
?
AD
3、調(diào)用有簡(jiǎn)單參數(shù)的java方法
3.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod3"/>
</create>
</allow>
</dwr>
3.2、javascript中調(diào)用
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)
Function callTestMethod3(){
//定義要傳到j(luò)ava方法中的參數(shù)
var data;
//構(gòu)造參數(shù)
data = “test String”;
testClass.testMethod3(data);
}
?
AE
4、調(diào)用返回JavaBean的java方法
4.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod4"/>
</create>
<convert converter="bean" match=""com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
<creator>標(biāo)簽負(fù)責(zé)公開用于Web遠(yuǎn)程的類和類的方法,<convert>標(biāo)簽則負(fù)責(zé)這些方法的參數(shù)和返回類型。convert元素的作用是告訴DWR在服務(wù)器端Java 對(duì)象表示和序列化的JavaScript之間如何轉(zhuǎn)換數(shù)據(jù)類型。DWR自動(dòng)地在Java和JavaScript表示之間調(diào)整簡(jiǎn)單數(shù)據(jù)類型。這些類型包括Java原生類型和它們各自的封裝類表示,還有String、Date、數(shù)組和集合類型。DWR也能把JavaBean轉(zhuǎn)換成JavaScript 表示,但是出于安全性的原因,要求顯式的配置,<convert>標(biāo)簽就是完成此功能的。converter="bean"屬性指定轉(zhuǎn)換的方式采用JavaBean命名規(guī)范,match=""com.dwr.TestBean"屬性指定要轉(zhuǎn)換的javabean名稱,<param>標(biāo)簽指定要轉(zhuǎn)換的JavaBean屬性。
4.2、javascript中調(diào)用
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)和接收返回值的回調(diào)函數(shù)
Function callTestMethod4(){
testClass.testMethod4(callBackFortestMethod4);
}
Function callBackFortestMethod4(data){
//其中date接收方法的返回值
//對(duì)于JavaBean返回值,有兩種方式處理
//不知道屬性名稱時(shí),使用如下方法
for(var property in data){
alert("property(屬性名):"+property);
alert(property(對(duì)應(yīng)的屬性值)+":"+data[property]);
}
//知道屬性名稱時(shí),使用如下方法
alert(data.username);
alert(data.password);
}
其中callBackFortestMethod4是接收返回值的回調(diào)函數(shù)
?
AF
5、調(diào)用有JavaBean參數(shù)的java方法
5.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod5"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
5.2、javascript中調(diào)用
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)
Function callTestMethod5(){
//定義要傳到j(luò)ava方法中的參數(shù)
var data;
//構(gòu)造參數(shù),date實(shí)際上是一個(gè)object
data = { username:"user", password:"password" }
testClass.testMethod5(data);
}
?
AG
6、調(diào)用返回List、Set或者M(jìn)ap的java方法
6.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod6"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
注意:如果List、Set或者M(jìn)ap中的元素均為簡(jiǎn)單類型(包括其封裝類Double,F(xiàn)loat等)或String、Date、數(shù)組和集合類型,則不需要<convert>標(biāo)簽。
6.2、javascript中調(diào)用(以返回List為例,List的元素為TestBean)
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)和接收返回值的回調(diào)函數(shù)
Function callTestMethod6(){
testClass.testMethod6(callBackFortestMethod6);
}
Function callBackFortestMethod6(data){
//其中date接收方法的返回值
//對(duì)于JavaBean返回值,有兩種方式處理
//不知道屬性名稱時(shí),使用如下方法
for(var i=0;i<data.length;i++){
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
}
//知道屬性名稱時(shí),使用如下方法
for(var i=0;i<data.length;i++){
alert(data.username);
alert(data.password);
}
}
----------------------------------------------------------------------
如果java方法的返回值為Map,則在接收該返回值的javascript回調(diào)函數(shù)中如下處理:
function callBackFortestMethod(data){
//其中date接收方法的返回值
for(var property in data){
var bean = data[property];
alert(bean.username);
alert(bean.password);
}
AH
7、調(diào)用有List、Set或者M(jìn)ap參數(shù)的java方法
7.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod7"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(List<TestBean>);
]]>
</signatures>
</dwr>
<signatures>標(biāo)簽是用來(lái)聲明java方法中List、Set或者M(jìn)ap參數(shù)所包含的確切類,以便java代碼作出判斷。
7.2、javascript中調(diào)用(以返回List為例,List的元素為TestBean)
首先,引入javascript腳本
其次,編寫調(diào)用java方法的javascript函數(shù)
Function callTestMethod7(){
//定義要傳到j(luò)ava方法中的參數(shù)
var data;
//構(gòu)造參數(shù),date實(shí)際上是一個(gè)object數(shù)組,即數(shù)組的每個(gè)元素均為object
data = [
{
username:"user1",
password:"password2"
},
{
username:"user2",
password:" password2"
}
];
testClass.testMethod7(data);
}
------------------------------------------------------------------
如果java的方法的參數(shù)為Map(假設(shè)其key為String,value為TestBean),則在調(diào)用該方法的javascript函數(shù)中用如下方法構(gòu)造要傳遞的參數(shù):
function callTestMethod (){
//定義要傳到j(luò)ava方法中的參數(shù)
var data;
//構(gòu)造參數(shù),date實(shí)際上是一個(gè)object,其屬性名為Map的key,屬性值為Map的value
data = {
"key1":{
username:"user1",
password:"password2"
},
"key2":{
username:"user2",
password:" password2"
}
};
testClass.testMethod(data);
}
并且在dwr.xml中增加如下的配置段
<signatures>
<![CDATA[
import java.util.Map;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(Map<String,TestBean>);
]]>
</signatures>
說明:
對(duì)于java方法的返回值為L(zhǎng)ist(Set)的情況,DWR將其轉(zhuǎn)化為Object數(shù)組,傳遞給javascript;對(duì)于java方法的返回值為Map的情況,DWR將其轉(zhuǎn)化為一個(gè)Object,其中Object的屬性為原Map的key值,屬性值為原Map相應(yīng)的value值。
???
?
這幾天做項(xiàng)目,需要一個(gè)消息提醒功能,決定用
dwr
實(shí)現(xiàn),在
dwr
官網(wǎng)和網(wǎng)上找了很多資料,也沒實(shí)現(xiàn)精準(zhǔn)推送,大多數(shù)的例子具體步驟寫的不清楚,不怎么了解
dwr
的人看了也未必能看懂,反正我是沒看懂,那時(shí)就決定,若自己實(shí)現(xiàn)了,一定將具體步驟寫下來(lái),希望能給那些和我一樣的人一些幫助,若有不明白的,可以給小弟留言。我只寫步驟,不寫原理,下面開始。
????
?
第一、在項(xiàng)目中引入
dwr.jar
,然后在
web.xml
中進(jìn)行配置,配置如下:
???? <servlet>
??????? <servlet-name>dwr-invoker</servlet-name>
??????? <servlet-class>
??????????? org.directwebremoting.servlet.DwrServlet
??????? </servlet-class>
??????? <init-param>
??????????? <param-name>crossDomainSessionSecurity</param-name>
?????? ??????? <param-value>false</param-value>
???? ???????</init-param>
??????? <init-param>
?????? ?? <param-name>allowScriptTagRemoting</param-name>
?????? ?? <param-value>true</param-value>
??????? </init-param>
??????? <init-param>
?????? ?? <param-name>classes</param-name>
?????? ?? <param-value>java.lang.Object</param-value>
??????? </init-param>
??????? <init-param>
??????????? <param-name>activeReverseAjaxEnabled</param-name>
??????????? <param-value>true</param-value>
??????? </init-param>
??????? <init-param>
?????? ??? <param-name>initApplicationScopeCreatorsAtStartup</param-name>
?????? ??? <param-value>true</param-value>
??????? </init-param>
??????? <init-param>
??????????? <param-name>maxWaitAfterWrite</param-name>
??????????? <param-value>3000</param-value>
??????? </init-param>
??????? <init-param>
??????????? <param-name>debug</param-name>
??????????? <param-value>true</param-value>
??????? </init-param>
??????? <init-param>
??????????? <param-name>logLevel</param-name>
??????????? <param-value>WARN</param-value>
??????? </init-param>
??? </servlet>
???
?
第二:在
web.xml
的同級(jí)目錄下新建
dwr.xml
文件,內(nèi)容如下
???? <!DOCTYPE dwr PUBLIC
????????? "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
????????? "http://getahead.org/dwr/dwr30.dtd">
???? <dwr>
????????? <alow>
?????????????? <create creator="new" javascript="MessagePush">
????????????? ?? <param name="class" value="com.huatech.messageremind.service.MessagePush"/>
????????????? </create>
????????? </alow>
???? </dwr>
???
?
這個(gè)是
dwr
的基本配置,
MessagePush
在頁(yè)面的
javascript
中使用,
com.huatech.messageremind.service.MessagePush
實(shí)現(xiàn)了想要調(diào)用的方法,
MessagePush
我覺得就相當(dāng)于
java
類中的一個(gè)映射,在
javascript
中使用
MessagePush.java
類中實(shí)現(xiàn)的方法,即可在
dwr
中調(diào)用。
???
?
第三,要想使用
dwr
,還要在你想要推送的頁(yè)面中引入
script
,
????????? <script type="text/javascript" src="<%=basepath%>dwr/engine.js"></script>
?????? ?<script type="text/javascript" src="<%=basepath%>dwr/util.js"></script>
?????? ?<script type="text/javascript" src="<%=basepath%>dwr/interface/MessagePush.js"></script>
?????????
?
可以看見,也引入了
dwr.xml
中配置的
javascript
,
engine.js
和
util.js
是必須引入的。
?以上三點(diǎn)都是基本配置,沒什么好說的,想使用
dwr
,就得這么做。
??
?
第四,實(shí)現(xiàn)消息的精準(zhǔn)推送
???????
?
消息推送簡(jiǎn)單,但是想實(shí)現(xiàn)精準(zhǔn)推送就需要做一些別的操作了
??????? 1
?
在任何一個(gè)用戶登錄的時(shí)候,都需要將其
userId
或者其他唯一性標(biāo)識(shí)放入
session
中,我放的是
userId
,
?????????
?
這里就以
?
userId
為唯一性標(biāo)識(shí)。
??????? 2
?
在載入想推送的頁(yè)面時(shí),需要
onload
一個(gè)我在
MessagePush
類中實(shí)現(xiàn)的方法,當(dāng)然了,需要使用
dwr
調(diào)用
????????? js
的調(diào)用方法如下:
?????????? function onPageLoad(){
?????? ????? var userId = '${userinfo.humanid}';
?????? ????? MessagePush.onPageLoad(userId);
?????? ?? }
??????????? <body onload="dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);onPageLoad();>
?
在
onload
中的三個(gè)函數(shù)都是必須的,其中
dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);
是
dwr
中的函數(shù)。
?????????? MessagePush
類中實(shí)現(xiàn)的方法如下:
?????????? public void onPageLoad(String userId) {
????????????? ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
????????????? scriptSession.setAttribute(userId, userId);
????????????? DwrScriptSessionManagerUtil dwrScriptSessionManagerUtil = new DwrScriptSessionManagerUtil();
????????????? try {
???????????????????? dwrScriptSessionManagerUtil.init();
????????????? } catch (ServletException e) {
???????????????????? e.printStackTrace();
????????????? }
?????? }
????????
?
大家注意到,
onPageLoad
方法中還有一個(gè)名為
DwrScriptSessionManagerUtil
的類,該類如下實(shí)現(xiàn):
???????? public class DwrScriptSessionManagerUtil extends DwrServlet{
?????? private static final long serialVersionUID = -7504612622407420071L;
?
?????? public void init()
?????? throws ServletException {
?
?
????????????? Container container = ServerContextFactory.get().getContainer();
?
????????????? ScriptSessionManager manager = container
??????????????????????????? .getBean(ScriptSessionManager.class);
?
????????????? ScriptSessionListener listener = new ScriptSessionListener() {
?
???????????????????? public void sessionCreated(ScriptSessionEvent ev) {
?
??????????????????????????? HttpSession session = WebContextFactory.get().getSession();
?
??????????????????????????? String userId =((User) session.getAttribute("userinfo")).getHumanid()+"";
??????????????????????????? System.out.println("a ScriptSession is created!");
??????????????????????????? ev.getSession().setAttribute("userId", userId);
?
???????????????????? }
?
???????????????????? public void sessionDestroyed(ScriptSessionEvent ev) {
??????????????????????????? System.out.println("a ScriptSession is distroyed");
???????????????????? }
?
????????????? };
?
????????????? manager.addScriptSessionListener(listener);
?
?????? }
?
}
第四步是最最重要的,為了第四步我研究了兩天多,下面開始消息推送。
?????
?
第五、消息推送
???????????
?
在你想要推送消息的時(shí)候,調(diào)用如下方法:
?????????? ? public void sendMessageAuto(String userid,String message) {
????????????? final String userId = userid ;
????????????? final String autoMessage = message;
????????????? Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
???????????????????? public boolean match(ScriptSession session) {
??????????????????????????? if (session.getAttribute("userId") == null)
?????????????????????????????????? return false;
??????????????????????????? else
?????????????????????????????????? return (session.getAttribute("userId")).equals(userId);
???????????????????? }
????????????? }, new Runnable(){
???????????????????? private ScriptBuffer script = new ScriptBuffer();
???????????????????? public void run() {
??????????????????????????? script.appendCall("showMessage", autoMessage);
??????????????????????????? Collection<ScriptSession> sessions = Browser
??????????????????????????? .getTargetSessions();
??????????????????????????? for (ScriptSession scriptSession : sessions) {
?????????????????????????????????? scriptSession.addScript(script);
??????????????????????????? }
???????????????????? }
????????????????????
????????????? });
?????? }
???????? userid
即為你想推給消息的人,
message
為你想推送的消息,大家注意到這里
script.appendCall("showMessage", autoMessage);
????????
?
其中
showMessage
為在想推送的頁(yè)面中的
javascript
方法,
autoMessage
是這個(gè)方法的參數(shù),這樣那個(gè)頁(yè)面就能得到推送的內(nèi)容了,至于如何展現(xiàn),就看你的需要了。
?
???????
?
至此,一個(gè)
dwr
消息精準(zhǔn)推送的步驟就寫完了,其實(shí)很多東西都不難,只是我們不知道該怎么用而已。