一、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、
當我們想看DWR自動生成的測試頁(Using debug/test mode)時,可在servlet配置中加上
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
這個參數DWR默認是false。如果選擇true,我們可以通過http://localhost:port/app/dwr看到你部署的每個DWR class。并且可以測試java代碼的每個方法是否運行正常。為了安全考慮,在正式環境下你一定把這個參數設為false。
3、多個dwr.xml文件的配置
可能有幾種情況,我們一一列舉。一個servlet,多個dwr.xml配置文件;多個servlet,每個servlet對應一個或多個dwr.xml配置文件。
3.1、一個servlet,多個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個。如果沒有param-name,那么將會讀取 WEB-INF/dwr.xml。如果有大于零個param-name,那么WEB-INF/dwr.xml文件將不會被讀取。
3.2、多個servlet,每個servlet對應一個或多個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>
在這種情況下,我們可以根據J2EE security來控制權限,針對不同url,加不同的角色。
AB:調用沒有返回值和參數的JAVA方法
AC:調用有簡單返回值的java方法
AD:調用有簡單參數的java方法
AE:調用返回JavaBean的java方法
AF:調用有JavaBean參數的java方法
AG:調用返回List、Set或者Map的java方法
AH:調用有List、Set或者Map參數的java方法
二、dwr使用篇
AB
1、調用沒有返回值和參數的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>標簽中包括可以暴露給javascript訪問的東西。
<create>標簽中指定javascript中可以訪問的java類,并定義DWR應當如何獲得要進行遠程的類的實例。creator="new"屬性指定java類實例的生成方式,new意味著DWR應當調用類的默認構造函數來獲得實例,其他的還有spring方式,通過與IOC容器Spring進行集成來獲得實例等等。javascript=" testClass "屬性指定javascript代碼訪問對象時使用的名稱。
<param>標簽指定要公開給javascript的java類名。
<include>標簽指定要公開給javascript的方法。不指定的話就公開所有方法。
<exclude>標簽指定要防止被訪問的方法。
1.2、javascript中調用
首先,引入javascript腳本
<script src='dwr/interface/ testClass.js'></script>
<script src='dwr/engine.js'></script>
<script src='dwr/util.js'></script>
其中TestClass.js是dwr根據配置文件自動生成的,engine.js和util.js是dwr自帶的腳本文件。
其次,編寫調用java方法的javascript函數
Function callTestMethod1(){
testClass.testMethod1();
}
?
AC
2、調用有簡單返回值的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中調用
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數和接收返回值的回調函數
Function callTestMethod2(){
testClass.testMethod2(callBackFortestMethod2);
}
Function callBackFortestMethod2(data){
//其中date接收方法的返回值
//可以在這里對返回值進行處理和顯示等等
alert("the return value is " + data);
}
其中callBackFortestMethod2是接收返回值的回調函數
?
AD
3、調用有簡單參數的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中調用
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數
Function callTestMethod3(){
//定義要傳到java方法中的參數
var data;
//構造參數
data = “test String”;
testClass.testMethod3(data);
}
?
AE
4、調用返回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>標簽負責公開用于Web遠程的類和類的方法,<convert>標簽則負責這些方法的參數和返回類型。convert元素的作用是告訴DWR在服務器端Java 對象表示和序列化的JavaScript之間如何轉換數據類型。DWR自動地在Java和JavaScript表示之間調整簡單數據類型。這些類型包括Java原生類型和它們各自的封裝類表示,還有String、Date、數組和集合類型。DWR也能把JavaBean轉換成JavaScript 表示,但是出于安全性的原因,要求顯式的配置,<convert>標簽就是完成此功能的。converter="bean"屬性指定轉換的方式采用JavaBean命名規范,match=""com.dwr.TestBean"屬性指定要轉換的javabean名稱,<param>標簽指定要轉換的JavaBean屬性。
4.2、javascript中調用
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數和接收返回值的回調函數
Function callTestMethod4(){
testClass.testMethod4(callBackFortestMethod4);
}
Function callBackFortestMethod4(data){
//其中date接收方法的返回值
//對于JavaBean返回值,有兩種方式處理
//不知道屬性名稱時,使用如下方法
for(var property in data){
alert("property(屬性名):"+property);
alert(property(對應的屬性值)+":"+data[property]);
}
//知道屬性名稱時,使用如下方法
alert(data.username);
alert(data.password);
}
其中callBackFortestMethod4是接收返回值的回調函數
?
AF
5、調用有JavaBean參數的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中調用
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數
Function callTestMethod5(){
//定義要傳到java方法中的參數
var data;
//構造參數,date實際上是一個object
data = { username:"user", password:"password" }
testClass.testMethod5(data);
}
?
AG
6、調用返回List、Set或者Map的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或者Map中的元素均為簡單類型(包括其封裝類Double,Float等)或String、Date、數組和集合類型,則不需要<convert>標簽。
6.2、javascript中調用(以返回List為例,List的元素為TestBean)
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數和接收返回值的回調函數
Function callTestMethod6(){
testClass.testMethod6(callBackFortestMethod6);
}
Function callBackFortestMethod6(data){
//其中date接收方法的返回值
//對于JavaBean返回值,有兩種方式處理
//不知道屬性名稱時,使用如下方法
for(var i=0;i<data.length;i++){
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
}
//知道屬性名稱時,使用如下方法
for(var i=0;i<data.length;i++){
alert(data.username);
alert(data.password);
}
}
----------------------------------------------------------------------
如果java方法的返回值為Map,則在接收該返回值的javascript回調函數中如下處理:
function callBackFortestMethod(data){
//其中date接收方法的返回值
for(var property in data){
var bean = data[property];
alert(bean.username);
alert(bean.password);
}
AH
7、調用有List、Set或者Map參數的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>標簽是用來聲明java方法中List、Set或者Map參數所包含的確切類,以便java代碼作出判斷。
7.2、javascript中調用(以返回List為例,List的元素為TestBean)
首先,引入javascript腳本
其次,編寫調用java方法的javascript函數
Function callTestMethod7(){
//定義要傳到java方法中的參數
var data;
//構造參數,date實際上是一個object數組,即數組的每個元素均為object
data = [
{
username:"user1",
password:"password2"
},
{
username:"user2",
password:" password2"
}
];
testClass.testMethod7(data);
}
------------------------------------------------------------------
如果java的方法的參數為Map(假設其key為String,value為TestBean),則在調用該方法的javascript函數中用如下方法構造要傳遞的參數:
function callTestMethod (){
//定義要傳到java方法中的參數
var data;
//構造參數,date實際上是一個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>
說明:
對于java方法的返回值為List(Set)的情況,DWR將其轉化為Object數組,傳遞給javascript;對于java方法的返回值為Map的情況,DWR將其轉化為一個Object,其中Object的屬性為原Map的key值,屬性值為原Map相應的value值。
???
?
這幾天做項目,需要一個消息提醒功能,決定用
dwr
實現,在
dwr
官網和網上找了很多資料,也沒實現精準推送,大多數的例子具體步驟寫的不清楚,不怎么了解
dwr
的人看了也未必能看懂,反正我是沒看懂,那時就決定,若自己實現了,一定將具體步驟寫下來,希望能給那些和我一樣的人一些幫助,若有不明白的,可以給小弟留言。我只寫步驟,不寫原理,下面開始。
????
?
第一、在項目中引入
dwr.jar
,然后在
web.xml
中進行配置,配置如下:
???? <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
的同級目錄下新建
dwr.xml
文件,內容如下
???? <!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>
???
?
這個是
dwr
的基本配置,
MessagePush
在頁面的
javascript
中使用,
com.huatech.messageremind.service.MessagePush
實現了想要調用的方法,
MessagePush
我覺得就相當于
java
類中的一個映射,在
javascript
中使用
MessagePush.java
類中實現的方法,即可在
dwr
中調用。
???
?
第三,要想使用
dwr
,還要在你想要推送的頁面中引入
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
是必須引入的。
?以上三點都是基本配置,沒什么好說的,想使用
dwr
,就得這么做。
??
?
第四,實現消息的精準推送
???????
?
消息推送簡單,但是想實現精準推送就需要做一些別的操作了
??????? 1
?
在任何一個用戶登錄的時候,都需要將其
userId
或者其他唯一性標識放入
session
中,我放的是
userId
,
?????????
?
這里就以
?
userId
為唯一性標識。
??????? 2
?
在載入想推送的頁面時,需要
onload
一個我在
MessagePush
類中實現的方法,當然了,需要使用
dwr
調用
????????? js
的調用方法如下:
?????????? function onPageLoad(){
?????? ????? var userId = '${userinfo.humanid}';
?????? ????? MessagePush.onPageLoad(userId);
?????? ?? }
??????????? <body onload="dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);onPageLoad();>
?
在
onload
中的三個函數都是必須的,其中
dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);
是
dwr
中的函數。
?????????? MessagePush
類中實現的方法如下:
?????????? 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
方法中還有一個名為
DwrScriptSessionManagerUtil
的類,該類如下實現:
???????? 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);
?
?????? }
?
}
第四步是最最重要的,為了第四步我研究了兩天多,下面開始消息推送。
?????
?
第五、消息推送
???????????
?
在你想要推送消息的時候,調用如下方法:
?????????? ? 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
為在想推送的頁面中的
javascript
方法,
autoMessage
是這個方法的參數,這樣那個頁面就能得到推送的內容了,至于如何展現,就看你的需要了。
?
???????
?
至此,一個
dwr
消息精準推送的步驟就寫完了,其實很多東西都不難,只是我們不知道該怎么用而已。