現(xiàn)有項目組用SUN JDK1.5中自帶的示例:jnlp-servlet作為WEBSTART版本管理的SERVLET。它可以很好的實現(xiàn)JNLP相關(guān)資源(JAR,圖片等)的基于版本的管理和增量更新。并有幾個類似 $ $codebase, $ $name的可替換關(guān)鍵字。(原來寫了一個簡單的servlet,可以實現(xiàn)軟編碼,但沒法提供靈活的版本控制)
但現(xiàn)有項目的需求更高一些,即,JNLP中需要傳更多的參數(shù),比如,服務(wù)端IP,端口,上下文,用戶登錄的SESSIONID等,由于jnlp-servlet有源代碼,我們很快修改了JnlpFileHandler和specializeJnlpTemplate方法,并加入了這幾個自定義關(guān)鍵字( $ $host, $ $port, $ $newcontext, $ $sessionid)。JNLP如下所示:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0 " codebase=" $ $codebase" href=” $ $name”>
<information>
<title>My System</title>
<vendor>CFR</vendor>
<icon href="indexbannerleft.jpg" kind="splash" />
<homepage href="index.html"/>
<description>My System</description>
<description kind="short">CFR Inc..</description>
</information>
<security><all-permissions/></security>
<resources>
<j2se version="1.4" initial-heap-size="32m"/>
<jar href="myapp.jar" version="1.1"/>
<nativelib href="swt-lib.jar" version="1.1"/>
</resources>
<resources os="Windows"><jar href="swt.jar" version="1.1"/></resources>
<resources os="Windows"><jar href="jface.jar" version="1.0"/></resources>
<resources os="Windows"><jar href="osgi.jar" version="1.0"/></resources>
<resources os="Windows"><jar href="runtime.jar" version="1.0"/></resources>
<application-desc main-class="com.cfr.app.main">
<argument> $ $session</argument>
<argument> $ $host</argument>
<argument> $ $port</argument>
<argument> $ $newcontext</argument>
<argument>0</argument>
<argument>aa</argument>
</application-desc>
</jnlp>
其中,SESSIONID是用其內(nèi)部的request得到。
一切好象即簡單和明了,工作正常,但很快就發(fā)現(xiàn)了嚴(yán)重的問題。
首先說說該應(yīng)用的使用模式如下:
1、 用戶從網(wǎng)頁登錄系統(tǒng),然后在里面點擊:http://host:port/myapp/swt/index.jnlp鏈接。
2、 啟動應(yīng)用(因為應(yīng)用是跟當(dāng)前登錄SESSION直接相關(guān)的)
按照設(shè)計本意,此時,用戶的應(yīng)用應(yīng)通過JNLP中的參數(shù)得到了該用戶登錄后的SESSIONID才對,但事實并非如此。這種情況只出現(xiàn)在WEBSTART第一次下載的時候,以后當(dāng)用戶重新打開瀏覽器登錄后(此時當(dāng)然是一個新的SESSION),在頁面中啟動WEBSTART后,發(fā)現(xiàn),該SESSIONID還是以前的,并沒有想象中的將新SESSIONID傳了進來。
后來還是看看JnlpFileHandler中的源代碼,發(fā)現(xiàn)主要在getJnlpFile(客戶端是JRE1.5以下時調(diào)用)和getJnlpFileEx(客戶端是JDK1.5以上時用)進行了相關(guān)實現(xiàn)。原來,它每生成一個JNLP,就將其緩存在HASHMAP中,下一次請求,如果請求的URL相關(guān)并且文件的timestamp(就是Web服務(wù)器中的jnlp文件的修改時間,可想而知,除了升級,這個文件一般不會變)一樣,就從緩存中取,這樣一來,我們也可以推測,按照上面的設(shè)計,如果有一個用戶下載了應(yīng)用,其它用戶從其它機器下載到的JNLP還是第一個用戶的JNLP,這是一個更加嚴(yán)重的問題。
由于URL是一樣的,現(xiàn)在考慮更改時間戳,即在getJnlpFile中顯式的將timesstamp改為當(dāng)前的時間:
long lastModified = new java.util.Date().getTime();
這樣,任何一次請求都不會從緩存中獲得,而是重新生成一個,好象這能很好的解決這個問題了吧?
但事實遠沒有想象的那么簡單。這跟WEBSTART與服務(wù)端的交互過程有關(guān)系。
WEBSTART要通過多次從服務(wù)端交互才會真正下載JNLP文件,這主要是驗證一些時間等相關(guān)的屬性(具體我沒有看代碼)。大至是三次才會真正的把JNLP下載下來(其實服務(wù)端會生成三次,真正下載的是第三個),由于我們的SESSIONID是從SERVLET內(nèi)部的REQUEST中直接得到,這樣一來,實際上只有第一個請求的SESSIONID是正確的(因為它是直接從瀏覽器中進入的),其它兩個都是WEBSTART用URLConnection建立的連接,SESSIONID都是新生成的,而下載的恰恰又是第三個,這樣一來,又黃了!!!
接下來的想法是自己設(shè)法傳SESSIONID,而不是從當(dāng)前REQUEST中取。所以,就剛才啟動WEBSTART的鏈接改為如下形式:
<a href="/myapp/swt/index.jnlp?sessionid=<%=request.getSession().getId()%>">啟動客戶端程序</a>
這樣,生成的URL會是:
http://localhost:8899/myapp/swt/index.jnlp?sessionid=F8864B2CDF60AE371CD6DFC189E80C78
按照前面的JNLP文件,下載下來的JNLP第一行是:
<jnlp spec="1.0 " codebase="http://127.0.0.1:8899/myapp/swt/" href=” http://localhost:8899/myapp/swt/index.jnlp?sessionid=F8864B2CDF60AE371CD6DFC189E80C78”>
既然有了SESSIONID(這意味著每個請求的URL都不會一樣!),我們就用不著將時間戳改為當(dāng)前時間了,還按原來的做就行了。
到此為止,好像問題解決的很徹底哦!但不要高興的太早!!!!!
我們同樣做實驗:
1、 將WEBSTART應(yīng)用清空
2、 登錄系統(tǒng),下載安裝應(yīng)用并運行,一切OK!
3、 退出該系統(tǒng)
4、 打開新的瀏覽器并登錄
5、 點相應(yīng)的鏈接啟動WEBSTART應(yīng)用
6、 怪了:SESSIONID怎么還是前面的一個呢?
查看jnlp-servlet日志,剛才說了,要經(jīng)過多次握手才會實際的下載JNLP,從流程中發(fā)現(xiàn),客戶端發(fā)的請求,第一個是對的即是http://localhost:8899/myapp/swt/index.jnlp?sessionid=F8864B2CDF60AE371CD6DFC189E80C78
SESSION是最新的,但第二個請求,SESSION怎么就是以前的呢?
原來,WEBSTART在經(jīng)過第一次握手之后,發(fā)現(xiàn)本地有該應(yīng)用,就用該應(yīng)用JNLP中的href字段發(fā)送下面的請求,導(dǎo)致了剛才的問題。
后面的解決辦法說起來就沒什么了,直接去掉href字段就行了,如下片段:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0 " codebase=" $ $codebase">
這樣,每次都用新的URL去請求了!!
說來說去,只是過程,其它代碼中改得并不多,主要是增加了SESSION參數(shù)。
在以后動態(tài)更改應(yīng)用的MAIN類時,思路也差不多。
其它人需地做的改動:
更改JNLP,去掉href項
換成新的jnlp_servlet
清除當(dāng)前已安裝的應(yīng)用。
將鏈接改為有SESSIONID為參數(shù)的鏈接。轉(zhuǎn)載:文章來自于http://java.linuxjiaocheng.com/applet-api/sdk-tutorial/xml-jsp-programming2601.html