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

 
在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("");     }

    1. 下面是页面的调用,是在一个jsp页面。<wbr style="LINE-HEIGHT: 1.3em">
    2. <object     classid = "clsid:CAFEEFAC-0015-0000-0000-ABCDEFFEDCBA"
    3.     codebase = "<%=request.getContextPath()%>/jre-1_5_0_16-windows-i586-p.exe"     WIDTH = "80" HEIGHT = "35" >
    4.     <PARAM NAME = CODE VALUE = "PrinterApplet.class" >     <PARAM NAME = CODEBASE VALUE = "applets" >
    5.     <PARAM NAME = ARCHIVE VALUE = "jasperreports-3.0.0-applet.jar" >     <param name = "type" value = "application/x-java-applet;jpi-version=1.5">
    6.     <param name = "scriptable" value = "false">     <PARAM NAME = "REPORT_URL" VALUE ="../printFromAppletAction.do?key_CARDID=<%=printID%>">
    7.     <PARAM NAME = "SHOW_DIALOG" VALUE ="true">      
    8.     <input type="button"  value="服务器端打印"  onclick="javascript:printPdf()">      
    9. </object>
    10. </wbr><wbr style="LINE-HEIGHT: 1.3em"></wbr>


        这个object标签大部分是转过来了,他的原型是这样的:<wbr style="LINE-HEIGHT: 1.3em">
      1. <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%>">
      2. <PARAM NAME = "SHOW_DIALOG" VALUE ="true">
      3. </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>
        1. ; Version number and signature of INF file. ;
        2. [version] signature="$CHICAGO$"
        3. AdvancedINF=2.0
        4. ; The order of files in this section defines the download order. ; Last in First download.
        5. [Add.Code] jinstall.exe
        6. jpiexp32jpiexp32.dll=jpiexp32.dll npjpi150npjpi150.dll=npjpi150.dll
        7. [jpiexp32.dll]
        8. FileVersion=1,5,0,0 RegisterServer=no
        9. clsid={8AD9C840-044E-11D1-B3E9-00805F499D93} hook=bridgeinstaller
        10. [npjpi150.dll]
        11. FileVersion=1,5,0,0 RegisterServer=no
        12. clsid={CAFEEFAC-0015-0000-0000-ABCDEFFEDCBA} hook=bridgeinstaller
        13. [jinstall.exe]
        14. file-win32-x86=thiscab FileVersion=1,5,0,0
        15. ; jinstall.exe will be executed.
        16. ; [bridgeinstaller]
        17. run=%EXTRACT_DIR%\jinstall.exe /installurl=http://java.sun.com/update/1.5.0/1.5.0-b64.xml

          1. 看到没,是用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>
          2. <title>Java 2 Runtime Environment, v1.5.0-b64</title>    <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>

            1. 按照里面的地址下载那个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,真是一个过时的东西。慢的要死。还不好看。

              你可能感兴趣的:(eclipse,sql,tomcat,IE,sun)