現(xiàn)有項(xiàng)目組用SUN JDK1.5中自帶的示例:jnlp-servlet作為WEBSTART版本管理的SERVLET。它可以很好的實(shí)現(xiàn)JNLP相關(guān)資源(JAR,圖片等)的基于版本的管理和增量更新。并有幾個(gè)類似 $ $codebase, $ $name的可替換關(guān)鍵字。(原來(lái)寫了一個(gè)簡(jiǎn)單的servlet,可以實(shí)現(xiàn)軟編碼,但沒法提供靈活的版本控制)

但現(xiàn)有項(xiàng)目的需求更高一些,即,JNLP中需要傳更多的參數(shù),比如,服務(wù)端IP,端口,上下文,用戶登錄的SESSIONID等,由于jnlp-servlet有源代碼,我們很快修改了JnlpFileHandler和specializeJnlpTemplate方法,并加入了這幾個(gè)自定義關(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得到。

一切好象即簡(jiǎn)單和明了,工作正常,但很快就發(fā)現(xiàn)了嚴(yán)重的問(wèn)題。

首先說(shuō)說(shuō)該應(yīng)用的使用模式如下:

1、 用戶從網(wǎng)頁(yè)登錄系統(tǒng),然后在里面點(diǎn)擊:http://host:port/myapp/swt/index.jnlp鏈接。

2、 啟動(dòng)應(yīng)用(因?yàn)閼?yīng)用是跟當(dāng)前登錄SESSION直接相關(guān)的)

按照設(shè)計(jì)本意,此時(shí),用戶的應(yīng)用應(yīng)通過(guò)JNLP中的參數(shù)得到了該用戶登錄后的SESSIONID才對(duì),但事實(shí)并非如此。這種情況只出現(xiàn)在WEBSTART第一次下載的時(shí)候,以后當(dāng)用戶重新打開瀏覽器登錄后(此時(shí)當(dāng)然是一個(gè)新的SESSION),在頁(yè)面中啟動(dòng)WEBSTART后,發(fā)現(xiàn),該SESSIONID還是以前的,并沒有想象中的將新SESSIONID傳了進(jìn)來(lái)。

后來(lái)還是看看JnlpFileHandler中的源代碼,發(fā)現(xiàn)主要在getJnlpFile(客戶端是JRE1.5以下時(shí)調(diào)用)和getJnlpFileEx(客戶端是JDK1.5以上時(shí)用)進(jìn)行了相關(guān)實(shí)現(xiàn)。原來(lái),它每生成一個(gè)JNLP,就將其緩存在HASHMAP中,下一次請(qǐng)求,如果請(qǐng)求的URL相關(guān)并且文件的timestamp(就是Web服務(wù)器中的jnlp文件的修改時(shí)間,可想而知,除了升級(jí),這個(gè)文件一般不會(huì)變)一樣,就從緩存中取,這樣一來(lái),我們也可以推測(cè),按照上面的設(shè)計(jì),如果有一個(gè)用戶下載了應(yīng)用,其它用戶從其它機(jī)器下載到的JNLP還是第一個(gè)用戶的JNLP,這是一個(gè)更加嚴(yán)重的問(wèn)題。

由于URL是一樣的,現(xiàn)在考慮更改時(shí)間戳,即在getJnlpFile中顯式的將timesstamp改為當(dāng)前的時(shí)間:

long lastModified = new java.util.Date().getTime();

這樣,任何一次請(qǐng)求都不會(huì)從緩存中獲得,而是重新生成一個(gè),好象這能很好的解決這個(gè)問(wèn)題了吧?

但事實(shí)遠(yuǎn)沒有想象的那么簡(jiǎn)單。這跟WEBSTART與服務(wù)端的交互過(guò)程有關(guān)系。

WEBSTART要通過(guò)多次從服務(wù)端交互才會(huì)真正下載JNLP文件,這主要是驗(yàn)證一些時(shí)間等相關(guān)的屬性(具體我沒有看代碼)。大至是三次才會(huì)真正的把JNLP下載下來(lái)(其實(shí)服務(wù)端會(huì)生成三次,真正下載的是第三個(gè)),由于我們的SESSIONID是從SERVLET內(nèi)部的REQUEST中直接得到,這樣一來(lái),實(shí)際上只有第一個(gè)請(qǐng)求的SESSIONID是正確的(因?yàn)樗侵苯訌臑g覽器中進(jìn)入的),其它兩個(gè)都是WEBSTART用URLConnection建立的連接,SESSIONID都是新生成的,而下載的恰恰又是第三個(gè),這樣一來(lái),又黃了!!!

接下來(lái)的想法是自己設(shè)法傳SESSIONID,而不是從當(dāng)前REQUEST中取。所以,就剛才啟動(dòng)WEBSTART的鏈接改為如下形式:

<a href="/myapp/swt/index.jnlp?sessionid=<%=request.getSession().getId()%>">啟動(dòng)客戶端程序</a>

這樣,生成的URL會(huì)是:

http://localhost:8899/myapp/swt/index.jnlp?sessionid=F8864B2CDF60AE371CD6DFC189E80C78

按照前面的JNLP文件,下載下來(lái)的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(這意味著每個(gè)請(qǐng)求的URL都不會(huì)一樣!),我們就用不著將時(shí)間戳改為當(dāng)前時(shí)間了,還按原來(lái)的做就行了。

到此為止,好像問(wèn)題解決的很徹底哦!但不要高興的太早!!!!!

我們同樣做實(shí)驗(yàn):

1、 將WEBSTART應(yīng)用清空

2、 登錄系統(tǒng),下載安裝應(yīng)用并運(yùn)行,一切OK!

3、 退出該系統(tǒng)

4、 打開新的瀏覽器并登錄

5、 點(diǎn)相應(yīng)的鏈接啟動(dòng)WEBSTART應(yīng)用

6、 怪了:SESSIONID怎么還是前面的一個(gè)呢?

 查看jnlp-servlet日志,剛才說(shuō)了,要經(jīng)過(guò)多次握手才會(huì)實(shí)際的下載JNLP,從流程中發(fā)現(xiàn),客戶端發(fā)的請(qǐng)求,第一個(gè)是對(duì)的即是http://localhost:8899/myapp/swt/index.jnlp?sessionid=F8864B2CDF60AE371CD6DFC189E80C78

 SESSION是最新的,但第二個(gè)請(qǐng)求,SESSION怎么就是以前的呢?

原來(lái),WEBSTART在經(jīng)過(guò)第一次握手之后,發(fā)現(xiàn)本地有該應(yīng)用,就用該應(yīng)用JNLP中的href字段發(fā)送下面的請(qǐng)求,導(dǎo)致了剛才的問(wèn)題。

后面的解決辦法說(shuō)起來(lái)就沒什么了,直接去掉href字段就行了,如下片段:

<?xml version="1.0" encoding="utf-8"?>

<jnlp spec="1.0 " codebase=" $ $codebase">

這樣,每次都用新的URL去請(qǐng)求了!!

說(shuō)來(lái)說(shuō)去,只是過(guò)程,其它代碼中改得并不多,主要是增加了SESSION參數(shù)。

在以后動(dòng)態(tài)更改應(yīng)用的MAIN類時(shí),思路也差不多。

其它人需地做的改動(dòng):

更改JNLP,去掉href項(xiàng)

換成新的jnlp_servlet

清除當(dāng)前已安裝的應(yīng)用。

將鏈接改為有SESSIONID為參數(shù)的鏈接。

轉(zhuǎn)載:文章來(lái)自于http://java.linuxjiaocheng.com/applet-api/sdk-tutorial/xml-jsp-programming2601.html