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

本文介绍如何使用JasperReport 3.0通过Applet实现客户端本地打印功能,包括解决常见问题、配置JRE自动安装及兼容不同浏览器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

准备做一个基于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

  1. @Override
  2.     public ActionForward ExecuteIt(FrameActionMapping mapping, FrameForm form, HttpServletRequest request, HttpServletResponse response, IActExcResult actExcResult)
  3.     throws IOException, ServletException {
  4.         String cardid = request.getParameter("key_CARDID");
  5.         String showbackground="1";
  6. //      构造传入报表的参数
  7.         HashMap param = new HashMap();
  8.         param.put("showbackground", showbackground);
  9.         
  10. //      获取数据库连接
  11.         Connection conn = null;
  12.         try{
  13.             conn = DBConnectionMgr.getConnection(FrameConstant.MID_DATASOURCE_LEVEL);
  14.             //构造查询sql
  15.             String sql="//一些sql,占地方,不写了";
  16.             //执行查询
  17.             DaoQryHelper objDaoQryHelper = DaoQryHelper.getInstance();
  18.             ArrayList spotList = objDaoQryHelper.getQueryStringList(conn,sql, null);
  19.             if (spotList != null && spotList.size() > 0) {
  20.                 spotList = (ArrayList) spotList.get(0);
  21.                 if (spotList.size() > 0) {
  22.                     //将sql的查询结果put进param                
  23.                 } else {
  24.                     System.err.println("查询返回空:spotList.get(0)");
  25.                 }
  26.             } else {
  27.                 System.err.println("查询返回空:spotList");
  28.             }   
  29.         } catch (Throwable e) {
  30.             e.printStackTrace();
  31.             request.getSession(true).setAttribute(Globals.ERROR_KEY, "查询数据库错误:<br>" + e.getMessage());
  32.             return mapping.findForward("error");
  33.         } finally {
  34.             DBConnectionMgr.freeConn(conn);
  35.         }
  36.         
  37.         String jasperFileName="prescription.jasper";
  38. //      获取.jasper文件路径
  39.         EnsureFolderExist(getSysRootPath()+"reportCustomization");
  40.         String jasperFilePath = getSysRootPath()+"reportCustomization//"+jasperFileName;
  41.         JasperPrint jasperPrint = null;
  42.         try {
  43.             jasperPrint=JasperFillManager.fillReport(jasperFilePath, param, new JREmptyDataSource());//这句是关键,这句生成了这个jasperPrint就是要传给applet的。
  44.         } catch (JRException e) {
  45.             // TODO Auto-generated catch block
  46.             e.printStackTrace();
  47.             return null;
  48.         }
  49.         if (jasperPrint != null)
  50.         {
  51.             response.setContentType("application/octet-stream");
  52.             ServletOutputStream ouputStream = response.getOutputStream();
  53.             
  54.             ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
  55.             oos.writeObject(jasperPrint);
  56.             oos.flush();
  57.             oos.close();
  58.             ouputStream.flush();
  59.             ouputStream.close();
  60.         }
  61.         else
  62.         {
  63.             System.err.println("jasperPrint为空");
  64.             return null;
  65.         }
  66.         return mapping.findForward("");
  67.     }

下面是页面的调用,是在一个jsp页面。

    • <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>

 

这个object标签大部分是转过来了,他的原型是这样的:

    • <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">

 

在jdk的bin目录中有一个叫做HtmlConverter.exe的工具,在cmd中输入HtmlConverter -gui可以打开图形界面。

选择好目录以后按转换,就可以将applet标签变成object标签。

applet标签是ie以前用的,现在applet的标准很混乱,而且applet标签功能也比较少,所以现在sun推荐大家使用object标签。

object标签的好处是可以检查你有没有jre,没有的话可以给你下一个。

 

关于object 的codebase和code,要和项目中的路径对应好,否则很容易出现找不到类的问题。

其中,applet虽然是类,但是不要放在eclipse的src目录下面,也不要有任何包。

对于我这个,我的applet放在了工程根目录下面的applets文件夹,applets在codebase中指明。

ARCHIVE 是指运行这个applet需要的一些环境,我加载了jasperreports-3.0.0-applet.jar,这个类可以在jasperreport的例子中找到。

jasperreports-3.0.0-applet.jar也被窝放到了applets文件夹下面。

 

下面要说自动安装jre的问题。

因为我的应用环境是一个小型局域网,并且部署环境有可能不能上外网,所以,我希望把jre放在局域网中的服务器上。

用htmlconverter转换完以后的object的codebase本应是这样的:codebase="http://java.sun.com/update/1.5.0/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"

这是sun提供的一个cab包,里面有一个jinstall-1_5_0.inf和一个jinstall.exe。其中jinstall-1_5_0.inf是这样写的:

  1. ; Version number and signature of INF file.
  2. ;
  3. [version]
  4. signature="$CHICAGO$"
  5. AdvancedINF=2.0
  6. ; The order of files in this section defines the download order.
  7. ; Last in First download.
  8. [Add.Code]
  9. jinstall.exe
  10. jpiexp32jpiexp32.dll=jpiexp32.dll
  11. npjpi150npjpi150.dll=npjpi150.dll
  12. [jpiexp32.dll]
  13. FileVersion=1,5,0,0
  14. RegisterServer=no
  15. clsid={8AD9C840-044E-11D1-B3E9-00805F499D93}
  16. hook=bridgeinstaller
  17. [npjpi150.dll]
  18. FileVersion=1,5,0,0
  19. RegisterServer=no
  20. clsid={CAFEEFAC-0015-0000-0000-ABCDEFFEDCBA}
  21. hook=bridgeinstaller
  22. [jinstall.exe]
  23. file-win32-x86=thiscab
  24. FileVersion=1,5,0,0
  25. ; jinstall.exe will be executed.
  26. ;
  27. [bridgeinstaller]
  28. run=%EXTRACT_DIR%/jinstall.exe /installurl=http://java.sun.com/update/1.5.0/1.5.0-b64.xml

看到没,是用jinstall.exe 根据http://java.sun.com/update/1.5.0/1.5.0-b64.xml这个xml文件去下载的。其中1.5.0-b64.xml这个xml文件中有这样一句:

  1.  <title>Java 2 Runtime Environment, v1.5.0-b64</title> 
  2.   <description>This is 1.5.0-b64.</description> 
  3.   <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,真是一个过时的东西。慢的要死。还不好看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值