Java Web Start实践:动态生成JNLP

Java很早就推出了Java Web Start(简称JWS)技术。这一技术的初衷很好:但愿将桌面程序和Web页面之间搭起一个无缝的桥梁。虽然Applet技术已经存在了十多年,可是它 日趋老迈衰落,因此JWS也就应运而生了。 可是JWS并未顺利实现它的初衷。从Java的几回大改版均可以看到,JWS的bug多多,漏洞频频,Sun和Oracle不得不频繁的进行打补丁修复。 能够看看Java 5和6每次大小版本升级变化中,有多少是和Java Web Start有关的。难怪不少人都这样感叹:“哥不再用Java Web Start部署应用了!”其实也未必,随着Java的不断完善,咱们只要了解更多的技巧,就能够有效的消除一些JWS潜在的问题,并顺利的应用在企业应用 中。 以2BizBox ERP项目为例,本文介绍如何在企业应用中利用动态生成JNLP文件的技术来实现应用的快速部署。html

 

你们知道,2BizBox ERP做为一个免费的高质量ERP软件,有成千上万的用户。就咱们开发团队负责维护的服务器,就有近千台。每台服务器都是一家企业,每家企业又有几十上百 的客户端。若是采用下载客户端安装程序进行安装的方式来维护诸多的客户端,无疑是巨大的工做量,用户和咱们开发团队都不会轻松方便。为了解决这一问题,采 用JWS无疑是必然的选择。 java

为了让客户端自动启动下载和安装程序,咱们在企业的2BizBox ERP服务器上部署如下JNLP文件内容:web

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://**.**.**.**/webstart/">
    <information>
        <title>2BizBox</title>
        <vendor>Serva Software</vendor>
        <homepage href="http://www.2bizbox.com" />
        <description>2BizBox ERP 3</description>
        <offline-allowed />
    </information>
    <security>
        <all-permissions />
    </security>
    <update check="always" policy="always" />
    <resources>
        <j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+" initial-heap-size="128m" max-heap-size="512m" />
        <jar href="2bizbox.jar" />
        <jar href=" lib1.jar" />
        <jar href="lib2.jar" />
        <jar href=" lib3.jar" />
        <jar href="lib4.jar" />
        <!-- more jar. -->
    </resources>
    <application-desc main-class=" com.serva.bb2.gui.Main ">
        <argument>**.**.**.**</argument>
    </application-desc>
</jnlp>

上面的JNLP文件定义了2BizBox ERP客户端启动所须要的jar包以及下载位置、jre版本等。后端

在实际应用中,效果良好。可是因为JNLP和JWS自己的bug,在某些状况下,后台jar程序更新升级后,用户侧启动jnlp并不能得到更新,须要强行 清空JWS缓存才行,这确定不是通常用户懂得的。还有一种状况,就是因为ERP自己的jar包发生了变化(例如发生了增减),此时至关于jnlp文件的内 容发生了变化。这时候,要求用户一侧机器必须意识到jnlp的变化并先将jnlp进行更新。在不少java版本中(例如jre6的早期版本——例如 jre6 update20以前),因为潜在的一些bug等缘由,都不能顺利的进行更新,致使程序启动失败。浏览器

如何解决这一状况呢?采用动态jnlp是一个有效的方法。缓存

动态jnlp的思路是:在服务器的后端,经过jsp或servlet来动态的生成一个jnlp文件,而不是放置一个静态的固定不变的jnlp文件。这样,jnlp文件内容就能够经过后台应用的逻辑进行动态生成建立:须要什么jar包、须要什么jre版本等等。服务器

以jsp为例。在这个jsp中,首先要注意的几个技术点是:要设置本页面不要被浏览器缓存,放置jnlp内容变化没法及时被更新;其次要设置mime类型 让浏览器认为它是一个jnlp文件,以便下载执行而不是直接在浏览器中显示出来。经过设置response便可达到这些目的: app

response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
response.setHeader("Content-Disposition", "filename=\"bb.jnlp\";");
response.setContentType("application/x-java-jnlp-file");

其中,禁止浏览器和webstart缓存jnlp内容,经过设置:response.setHeader("Pragma", "no-cache");和response.setHeader("Expires", "0"); jsp

设置文件类型,并给定一个动态的文件名。这个经过这个进行:response.setHeader("Content-Disposition", "filename=\"bb.jnlp\";");response.setContentType("application/x-java-jnlp-file");函数

一个须要注意的问题是,在动态生成jnlp文件时,要注意jnlp文件中的href标签不要进行设置。为何呢?看一下jnlp的格式文档是这样说的:http://lopica.sourceforge.net/ref.html#jnlp

The jnlp file's one and only root.

Attributes
spec=version , optional
Specifies what versions of the jnlp spec a jnlp file works with. The default value is 1.0+. Thus, you can typically leave it out.
version=version , optional
Specifies the version of the application as well as the version of the jnlp file itself.
codebase=url , optional
Specifies the codebase for the application. Codebase is also used as base URL for all relative URLs in href attributes.
href=url , optional
Contains the location of the jnlp file as a URL. If you leave out the href attribute, Web Start will disable the update check on your JNLP file, and Web Start will not treat each new JNLP file as an application update - only updated jar files will. Leaving out href usually makes only sense if your jnlp file is created dynamically (that is, throug a cgi-script, for example) and if your jnlp file's arguments or properties change from request to request (user to user).
Note, that Java Web Start needs href to list your app in the Web Start Application Manager.

可见在动态生成jnlp时候就不要设置href了,这样就能够保证每次浏览器会从新下载jnlp文件内容,不然可能会被缓存,没法及时更新程序。

另一个技巧是:jnlp文件中的jar包,能够进行动态检查文件jar包并动态生成。这样,若是之后程序的jar文件有增减,就没必要修改jnlp文件 了。方法也很简单:检查当前web在服务器的绝对路径,并list全部的jar文件,而后在jnlp生成时候输出便可:

<%
	String urlString=request.getRequestURL().toString();
	URL url=new URL(urlString);
	String host=url.getHost();
	String path = request.getSession().getServletContext().getRealPath("/");
	path=path.replace("\\.\\", "\\");
	File file=new File(path);
	String[] files = file.list();
	ArrayList jarNames=new ArrayList();
	for(int i=0;i<files.length;i++){
		String fileName=files[i];
		if(fileName.toLowerCase().endsWith(".jar")){
			jarNames.add(fileName);
		}
	}
%>

而后在jar的部分这样列出:

<resources>
	<j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+" initial-heap-size="128m" max-heap-size="512m"/>
	<%
		for(int i=0;i<jarNames.size();i++){
			out.write("\n");
			out.write("<jar href=\""+jarNames.get(i).toString()+"\"/>");
		}
	%>
</resources>

最后,若是须要在jnlp中指定当前服务器的ip地址或主机地址,也能够经过动态生成。例如jnlp文件中的codebase,就是如此。另 外,2BizBox ERP还须要在主函数中给出当前服务器的ip地址。而对于上千家的2BizBox服务器,每一个jnlp要手工维护ip地址,是不可想象的。这里经过动态生 成,就永远的解决了这个问题:

String urlString=request.getRequestURL().toString();
URL url=new URL(urlString);
String host=url.getHost();

而后在jnlp中:

<jnlp spec="1.0+" codebase="http://<%=host%>/webstart/">
<application-desc main-class="com.serva.bb2.gui.Main">
	<argument><%=host%></argument>
<application-desc>

这样,经过jsp动态生成jnlp的方案就完成了。它在2BizBox ERP中应用良好,方便的让上千家2BizBox ERP的云主机用户快速获得程序更新,而简化了程序的维护方式。

相关文章
相关标签/搜索