深吸一口氣,悶了這杯水,我來記錄一下六個月來與DWR的恩恩怨怨!
2018.3 來到一個新公司(缺人),當時給我一個消息發送的模塊讓我做(我還處在剛剛看完java基礎),讓我用DWR做消息發送
2018.5 在這兩個月期間,斷斷續續的在看網上的各種博客,論壇。這裏吐槽一下自己查資料的水平(已經對各種轉發的技術博客無感,再也不會一股腦兒的上去就看它怎麼寫了。真的是既浪費時間又什麼幫助都沒有)
2018.6 這個月趕上大學畢業,已經再無心思研究消息怎麼發送(不會DWR,其實在逃避)
2018.7 領導讓我繼續做消息發送,沒人能替我寫
-----------------------------------------------------------------------------我是正文-----------------------------------------------------------------------------
簡單的DWR案例網上一搜一大片,我就不多廢話的;我要講的是 把DWR3.0和Spring4.0進行整合。
首先在我是maven項目,在pom.xml中導入 dwr,網上說還要導入commons-logging,親測沒有沒影響,有log4j就行
<dependency>
<groupId>org.directwebremoting</groupId>
<artifactId>dwr</artifactId>
<version>3.0.2-RELEASE</version>
</dependency><dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
官網上將,dwr整合spring有兩種,一是在直接在spring.xml文件中加入namespace,第二種是建一個新的dwrservlet
只能怪我看不懂英文,用不會第一種方式,所以我用的是第二種,在WEB-INFO文件夾下建立一個dwr.xml文件與web.xml在同一個目錄下。
那麼好了,我們現在先來配置web.xml文件。
首先說一下,我們在web.xml文件裏到底配置的是什麼呢?(就因爲我對框架的原理不熟,導致我無腦的粘貼網上的配置文件,都不知道自己錯哪了)
web.xml 中有關dwr的配置
<servlet>
<!--將靜態資源交由 dwr-invoker 下面的class類處理 -->
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param><!--debug 就是用來讓你調試的,如果你的dwr配置好了,運行項目後你就能看到在localhost:8080/projectNaem/dwr下會有你在dwr.xml中暴露的類,沒有就說明你的配置有問題-->
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param><!--我在啓動tomcat的時候總會報錯,錯誤是Missing config file: 'WEB-INF/dwr-*.xml' 這個問題肯定是你配置有問題,我的WEB-INFO下肯定有dwr.xml文件,但是它就是給你報錯,那你就先加上這句,它的意思就是加載配置文件,路徑是/WEB-INF/dwr.xml,如果你不寫這個的話系統默認也會去找你在WEB-INFO下的dwr.xml文件,除非你改名或者有多個dwr.xml文件,那它就真找不到了-->
<param-name>config</param-name>
<param-value>/WEB-INF/dwr.xml</param-value>
</init-param>
<init-param><!--這句話我一開始沒寫,沒寫的後果是什麼呢,就是你的前臺頁面執行不了反向ajax,也就是我走到最後給特定的session發送scriptSession.addScript(script)時,構造的jsp代碼無法傳遞給前臺,這個坑實在是太大了,必須標紅啊-->
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<!--下面這句話的意思,就是說我要攔截靜態文件,那這個靜態文件的攔截是什麼規則呢,就是dwr開頭,後面的所有url都攔截,它攔截了幹嘛用?攔截了給上面的servlet-class,很明顯servlet-class是dwr.jar包裏的東西,是用來生成engine.js和util.js用的。哦,當然還有interface/你想暴露的.js。所以要是攔截不到,那麼你的頁面上肯定就會報404,找不到這幾個.js文件。我相信很多人在用spring整合dwr時候都會遇到這個問題,原因主要還是你頁面的src路徑寫的不對,打個正確的比方 http://localhost:8080/ProjectName/dwr/engine.js,網上有人說是什麼springmvc的攔截器給誤攔截了,因爲springmvc配置的時候配的規則是 <url-pattern>/</url-pattern>,那就要看你暴露的類怎麼寫了,要是你寫在controller裏,那也出問題了,其他沒影響,不過保險起見,你可以把dwr的配置信息全部放在springmvc的前面。--><servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
dwr.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
"http://getahead.org/dwr/dwr30.dtd">
<dwr>
<allow>
<create javascript="Message" creator="new" scope="application"><!-- application -->
<param name="class" value="com.dwr.Message"></param>
</create>
</allow>
</dwr>
有關dwr.xml出錯,網上的答案也是夠五花八門的,我一個個試過來,一個個錯過去。
錯誤答案1:有說在application.xml中配置要暴露的bean,然後再在dwre.xml中修改配置。
<create javascript="Message" creator="spring" ><!-- application -->
<param name="beanName" value="Message"></param> 那種方式我覺得太麻煩,最討厭的就是在配置文件里加東西了,直接拿出來寫,或者加註解多方便。錯誤答案2::還有說<!DOCTYPE dwr PUBLI "-//GetAhead LimiteRemo3.0//EN""http://getahead.org/dwr/dwr30.dtd"> 這個有問題的,要改成 10.dtd,這個答案我一直沒看懂,覺得就是在渾水。很煩
接下來,把消息發送的java類寫一下
package com.dwr;
import java.util.Collection;
import javax.servlet.http.HttpSession;
import org.directwebremoting.Browser;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ScriptSessionFilter;
import org.directwebremoting.WebContextFactory;public class Message {
public void addMessage(String ids , String message) {
final String userId = ids;
final String autoMessage = message;
System.out.println("To:" + userId + ",Msg:" + autoMessage);
//執行推送
//注意這裏調用了有filter功能的方法
//如果我們不想要給所有的客戶端 推送消息,只想給特定的客戶端推送,那麼我們可以使用 ScriptSessionFilter來實現。
//在filter中去判定session中的Attribute值是不是我們給定的。
// Browser. withAllSessionsFiltered(filter, run); //注意這裏調用了有filter功能的方法
// 下面的函數相當於上面的擴展
Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
public boolean match(ScriptSession session) {
if (session.getAttribute("name") == null)
return false;
else {
String attribute = (String) session.getAttribute("name");
return (userId.contains(attribute));
}
}
}, new Runnable() {
private ScriptBuffer script = new ScriptBuffer();
/*
script.appendCall("receiveMessages", autoMessage);
其中receiveMessages爲在想推送的頁面中的javascript方法,autoMessage是這個方法的參數,
這樣那個頁面就能得到推送的內容了,至於如何展現,就看你的需要了。
*/
public void run() {
script.appendCall("show", autoMessage);
Collection<ScriptSession> sessions = Browser.getTargetSessions(); //取得所有的頁面訪問者
for (ScriptSession scriptSession : sessions) { //遍歷取得對應用戶的 scriptsession
scriptSession.addScript(script);
System.out.println("userid---"+userId);
}
}
});
}
public void onPageLoad(String name) {
HttpSession session = WebContextFactory.get()
.getSession();
session.setAttribute("name", name);
WebContextFactory.get().getScriptSession().setAttribute("name", name);
System.out.println(name +"---" + session);}
}
我寫代碼有個毛病,是個英文就要翻譯一下寫在旁邊,希望大家能看懂。網上大多關於這部分的內容也沒問題。
下面把消息發送的前端代碼寫一下
<!-- dwr -->.
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<script src="${ctx}/static/jquery-2.1.1.js"></script>
<script type="text/javascript" src="${ctx}/dwr/engine.js"></script>
<script type="text/javascript" src="${ctx}/dwr/util.js"></script>
<script type="text/javascript" src="${ctx}/dwr/interface/Message.js"></script>
<script type="text/javascript">
function init(){
dwr.engine.setActiveReverseAjax(true);
dwr.engine.setNotifyServerOnPageUnload(true);
onPageLoad();
}
window.onload = init;
function onPageLoad(){
var userId = ${User.id};//獲取當前用戶的id
Message.onPageLoad(userId);//把當前用戶的id作爲唯一標識傳遞給後臺生成一個Scriptsession
}function send(){
Message.addMessage(userId,message);//這裏是省略寫了,userId和message都是你要傳遞到後臺的參數,可以用jquery或者document.getelementbyid()的方法獲取具體值。
}
//這個是你在暴露的java類中寫的scriptbuffer
function show(message){
alert("新消息提醒");
}
</script>
<body><button onclick=send()>點擊發送</button>
</body>
好了,關於dwr的所有東西我都寫完了。記得在我想放棄的時候,有位大哥曾經跟我說:就差那一下蹭一下就上去了。看似阻擋在你面前的是一座山,很高很險,當你翻過去了之後,它就成了一張紙,一張薄的不能再薄的紙。
展示一下我做出來的效果: 在左邊窗口點擊發送消息給用戶123和用戶1234,會同時在兩個窗口的消息圖標上加1,而且是在不大叔刷頁面的情況下。
2018.8.1 消息發送做完,加班寫個博客,記錄下我的小心機