在jasperreport中使用applet进行客户端打印以及jre在局域网中的自动安装

准备做一个基于jasperreport 的报表打印,之前实现了一版,调用的是服务器端的打印机,但是不太符合要求,准备改成applet方式,实现客户端本地打印。
我们的客户端软件用的是eclipse的插件开发。
所用的applet,使用的是jasperreport3.0的例子中的webapp。用ant编译后导出一个war包,然后放到tomcat下面即可运行。
我在运行例子的时候,我的ie不能显示,看了源码,例子中使用的是object标签,我把object标签删掉,用下面注掉的applet标签,可以正常使用。
下面把例子放到我自己的工程中,出现问题,在运行例子中的Servlet的时候,总是提不正常。先开始是提示jasperreport中使用的common-loggin和我工程中使用的log4j冲突,common-logging不能获取实例。在经历了换版本,jar包换位置(就是都放到tomcat的bin目录下去,删去工程目录中的。)等等,终于不报common-loggin的错了,又开始提示找不到jasperreport中的类,那个类明明在那里,而且是jasperreport运行到中间的时候的一个类,什么什么编译用的,具体名字忘了,所以肯定不是jasperreports-3.0.0-applet.jar的位置的问题。这个问题困扰我2天,然后有次无意中把Servlet换了个包。。好了。靠。。至今也不明白为什么。
下面给出部分主要代码:
applet代码就不贴了,基本上和例子中的一样,就是删去了一个按钮,并且去掉了打印机选择的那个对话框
servlet我没有用例子中的,而是改成了调用一个action,其实这里写什么都是一样的,因为在applet中主要是调用了jasperPrint = (JasperPrint)JRLoader.loadObject(url);这一句,这个url需要是一个装填好的jasperPrint,如果之前生成了这样的文件,那么哪怕直接写文件的地址都可以。
action中的主要代码是这样的。
PrintFromAppletAction.java
@Override public ActionForward ExecuteIt(FrameActionMapping mapping, FrameForm form, HttpServletRequest request, HttpServletResponse response, IActExcResult actExcResult)
throws IOException, ServletException { String cardid = request.getParameter("key_CARDID");
String showbackground="1"; // 构造传入报表的参数
HashMap param = new HashMap(); param.put("showbackground", showbackground);
// 获取数据库连接
Connection conn = null; try{
conn = DBConnectionMgr.getConnection(FrameConstant.MID_DATASOURCE_LEVEL); //构造查询sql
String sql="//一些sql,占地方,不写了"; //执行查询
DaoQryHelper objDaoQryHelper = DaoQryHelper.getInstance(); ArrayList spotList = objDaoQryHelper.getQueryStringList(conn,sql, null);
if (spotList != null && spotList.size() > 0) { spotList = (ArrayList) spotList.get(0);
if (spotList.size() > 0) { //将sql的查询结果put进param
} else { System.err.println("查询返回空:spotList.get(0)");
} } else {
System.err.println("查询返回空:spotList"); }
} catch (Throwable e) { e.printStackTrace();
request.getSession(true).setAttribute(Globals.ERROR_KEY, "查询数据库错误:<br>" + e.getMessage()); return mapping.findForward("error");
} finally { DBConnectionMgr.freeConn(conn);
}
String jasperFileName="prescription.jasper"; // 获取.jasper文件路径
EnsureFolderExist(getSysRootPath()+"reportCustomization"); String jasperFilePath = getSysRootPath()+"reportCustomization\\"+jasperFileName;
JasperPrint jasperPrint = null; try {
jasperPrint=JasperFillManager.fillReport(jasperFilePath, param, new JREmptyDataSource());//这句是关键,这句生成了这个jasperPrint就是要传给applet的。 } catch (JRException e) {
// TODO Auto-generated catch block e.printStackTrace();
return null; }
if (jasperPrint != null) {
response.setContentType("application/octet-stream"); ServletOutputStream ouputStream = response.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
oos.writeObject(jasperPrint); oos.flush();
oos.close();
ouputStream.flush(); ouputStream.close();
} else
{ System.err.println("jasperPrint为空");
return null; }
return mapping.findForward(""); }
下面是页面的调用,是在一个jsp页面。<wbr style="LINE-HEIGHT: 1.3em">
<object classid = "clsid:CAFEEFAC-0015-0000-0000-ABCDEFFEDCBA"
codebase = "<%=request.getContextPath()%>/jre-1_5_0_16-windows-i586-p.exe" WIDTH = "80" HEIGHT = "35" >
<PARAM NAME = CODE VALUE = "PrinterApplet.class" > <PARAM NAME = CODEBASE VALUE = "applets" >
<PARAM NAME = ARCHIVE VALUE = "jasperreports-3.0.0-applet.jar" > <param name = "type" value = "application/x-java-applet;jpi-version=1.5">
<param name = "scriptable" value = "false"> <PARAM NAME = "REPORT_URL" VALUE ="../printFromAppletAction.do?key_CARDID=<%=printID%>">
<PARAM NAME = "SHOW_DIALOG" VALUE ="true">
<input type="button" value="服务器端打印" onclick="javascript:printPdf()">
</object></wbr><wbr style="LINE-HEIGHT: 1.3em"></wbr>
这个object标签大部分是转过来了,他的原型是这样的:<wbr style="LINE-HEIGHT: 1.3em">
<APPLET CODE = "PrinterApplet.class" JAVA_CODEBASE = "applets" ARCHIVE = "jasperreports-3.0.0-applet.jar" WIDTH = "80" HEIGHT = "35"> <PARAM NAME = "REPORT_URL" VALUE ="../printFromAppletAction.do?key_CARDID=<%=printID%>">
<PARAM NAME = "SHOW_DIALOG" VALUE ="true"></wbr><wbr style="LINE-HEIGHT: 1.3em"></wbr>
在jdk的bin目录中有一个叫做HtmlConverter.exe的工具,在cmd中输入HtmlConverter -gui可以打开图形界面。<wbr style="LINE-HEIGHT: 1.3em">
选择好目录以后按转换,就可以将applet标签变成object标签。</wbr><wbr style="LINE-HEIGHT: 1.3em">
applet标签是ie以前用的,现在applet的标准很混乱,而且applet标签功能也比较少,所以现在sun推荐大家使用object标签。</wbr><wbr style="LINE-HEIGHT: 1.3em">
object标签的好处是可以检查你有没有jre,没有的话可以给你下一个。</wbr><wbr style="LINE-HEIGHT: 1.3em">
关于object 的codebase和code,要和项目中的路径对应好,否则很容易出现找不到类的问题。</wbr><wbr style="LINE-HEIGHT: 1.3em">
其中,applet虽然是类,但是不要放在eclipse的src目录下面,也不要有任何包。</wbr><wbr style="LINE-HEIGHT: 1.3em">
对于我这个,我的applet放在了工程根目录下面的applets文件夹,applets在codebase中指明。</wbr><wbr style="LINE-HEIGHT: 1.3em">
ARCHIVE</wbr><wbr style="LINE-HEIGHT: 1.3em"> 是指运行这个applet需要的一些环境,我加载了jasperreports-3.0.0-applet.jar,<wbr style="LINE-HEIGHT: 1.3em">这个类可以在jasperreport的例子中找到。</wbr><wbr style="LINE-HEIGHT: 1.3em"></wbr></wbr><wbr style="LINE-HEIGHT: 1.3em">
jasperreports-3.0.0-applet.jar也被窝放到了applets文件夹下面。</wbr><wbr style="LINE-HEIGHT: 1.3em">
下面要说自动安装jre的问题。</wbr><wbr style="LINE-HEIGHT: 1.3em">
因为我的应用环境是一个小型局域网,并且部署环境有可能不能上外网,所以,我希望把jre放在局域网中的服务器上。</wbr><wbr style="LINE-HEIGHT: 1.3em">
用htmlconverter转换完以后的object的codebase本应是这样的:codebase="
http://java.sun.com/update/1.5.0/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0<wbr>"</wbr></wbr><wbr style="LINE-HEIGHT: 1.3em">
这是sun提供的一个cab包,里面有一个jinstall-1_5_0.inf和一个jinstall.exe。其中jinstall-1_5_0.inf是这样写的:</wbr><wbr style="LINE-HEIGHT: 1.3em">
</wbr>
; Version number and signature of INF file. ;
[version] signature="$CHICAGO$"
AdvancedINF=2.0
; The order of files in this section defines the download order. ; Last in First download.
[Add.Code] jinstall.exe
jpiexp32jpiexp32.dll=jpiexp32.dll npjpi150npjpi150.dll=npjpi150.dll
[jpiexp32.dll]
FileVersion=1,5,0,0 RegisterServer=no
clsid={8AD9C840-044E-11D1-B3E9-00805F499D93} hook=bridgeinstaller
[npjpi150.dll]
FileVersion=1,5,0,0 RegisterServer=no
clsid={CAFEEFAC-0015-0000-0000-ABCDEFFEDCBA} hook=bridgeinstaller
[jinstall.exe]
file-win32-x86=thiscab FileVersion=1,5,0,0
; jinstall.exe will be executed.
; [bridgeinstaller]
run=%EXTRACT_DIR%\jinstall.exe /installurl=http://java.sun.com/update/1.5.0/1.5.0-b64.xml
看到没,是用jinstall.exe 根据
http<wbr></wbr><wbr style="LINE-HEIGHT: 1.3em">
://java.sun.com/update/1.5.0/1.5.0-b64.xml<wbr style="LINE-HEIGHT: 1.3em"></wbr></wbr><wbr>这个xml文件去下载的。其中1.5.0-b64.xml这个xml文件中有这样一句:</wbr><wbr style="LINE-HEIGHT: 1.3em">
</wbr>
<title>Java 2 Runtime Environment, v1.5.0-b64</title> <description>This is 1.5.0-b64.</description>
<url>http://javadl.sun.com/webapps/download/GetFile/1.5.0-b64/windows-i586-jre/jre-1_5_0-windows-i586-iftw.exe</url>
按照里面的地址下载那个exe,发现并不是一个offline版本的,而是一个online版本的。也就是说,需要联网才能下载的。
至此,有2种方法可以实现在局域网内的jre自动安装,一种,是我上面用的,直接在object的codebase中写一个jre的exe文件,这个jre放在工程目录下面。这个jre可以从sun的官网上下载。
第二种,是把上述的cab啊,xml啊都下载下来,部署在工程中,但是,最后的xml中,还是要写完整的jre而不是原版中提供的online版的。
这里有点小问题,如果使用sun提供的方式也就是在线下载jre,下载安装完成之后,页面上直接就可以显示出applet来,但是如果使用我的方式,下载完成后就必须重启ie。
算是一点小的瑕疵吧。。不知道怎么才能做到和sun提供的那个一样。
以下,在ie6和ie7下测试正常,其中ie7有时候需要在高级中把jre应用于applet这个选项选中,并且在加载项中把sun控制台启用(据说默认是停用的)。
如果用遨游,需要在设置的高级中,选择使用其它jre。不然它默认使用的微软的jre。
我使用的环境,tomcat5,jasperreport3.0,ie7/6
关于java plugin 可以看http://java.sun.com/javase/6/webnotes/family-clsid.html。
里面介绍了objcet标签的clsid怎么写。
另外,网上看到很多人提到要数字签名,这个我不太懂,我没用,貌似也能正常使用,用了一下,好像也没什么反应。
怎么签名就不写了,也是用jdk的bin中的工具,(keytool),很简单。
感觉,用applet,真是一个过时的东西。慢的要死。还不好看。