当前位置: 代码迷 >> ASP >> [转]一次 applet 客户端打印 jasperreport 表格任务笔记
  详细解决方案

[转]一次 applet 客户端打印 jasperreport 表格任务笔记

热度:1007   发布时间:2013-06-25 23:45:41.0
[转]一次 applet 客户端打印 jasperreport 报表任务笔记

一次 applet 客户端打印 jasperreport 报表任务笔记


为了方便更多的人了解、使用 Java 打印,写了这个!也希望高手们不吝赐教,指出其中的不足之处,帮助我们提高项目性能,谢谢!
背景:.NET 项目中用 webprint3.0 破解版进行打印。客户反映可否不预览、不弹出打印机对话框,点击“打印”按钮后打印机直接打印?
要求:为了使打印精确,不可以使用 IE 的打印功能;另外打印的时候不可以弹出打印预览、打印机对话框,打印机直接打印。
环境:WindowsXP、IE6.0、JDK(JRE)1.6U14、MyEclipse6.5、Tomcat5.5、Oracle10gr2
使用工具:jasperreports-3.0.1、ireport3.1.0、iTextAsian.jar、apache-ant-1.7.1。
解决方案:使用 JasperReport + iReport 生成形如 *.jrxml 报表模板文件,servlet 调用这个 *.jrxml 文件根据指定 sql 语句生成 JasperReport 报表打印文件,客户端 applet 调用服务器 servlet 得到 JasperPrint 报表打印文件后使用 JasperReport 直接打印。
技术难点:pdf 报表的生成applet 与服务器 servlet 之间的通信pdf 报表文件的读写操作applet 打包及其签名
详细步骤及其关键部分源码展示:
1、JDK 的安装配置。
关于 JDK 的安装,JDK 环境变量 JAVA_HOME、系统环境变量 CLASSPATH、系统环境变量 Path 的配置笔者不再赘述。
2、ant 的安装和配置。
下载:
http://ant.apache.org(笔者使用的是apache-ant-1.7.1,已经将 apache-ant-1.7.1-bin.zip 包共享至 csdn 资源)。
配置:ant 无需安装,解压后就算安装完成。但要在系统变量中增加 ANT_HOME 环境变量,变量值为解压缩后的 ant 所在目录。在环境变量 Path 中增加 %ANT_HOME%/bin 目录。
3、JasperReport 的安装和配置。
下载:sf.net(笔者使用的是jasperreports-3.0.1,已经将jasperreports-3.0.1.rar 包共享至作者的 csdn 资源,解压缩后包含 jasperreports-3.0.1.jar、jasperreports-3.0.1-applet.jar、jasperreports-3.0.1-javaflow.jar 三个工具包,足够我们开发报表、打印报表使用了)。
配置:没有必要单独为 JasperReport.jar 文件包设置目录,直接放在 %JAVA_HOME%/lib 目录中即可。然后将 JasperReport-x.x.x.jar 文件添加到操作系统环境变量 CLASSPATH 中即可完成对 JasperReport 的配置。
4、iReport 的安装和配置。
下载:这个大一点,要有 40 M。iReport 比较成熟,很容易就可以下载到它的 zip 格式的文件包(作者使用的是 ireport3.1.0,已经共享 ireport3.1.0.zip 至 csdn 资源,大小 44 M)。iReport 也无需安装,直接解压后就算完成了安装,也无需配置。但是我们需要处理中文用到 iTextAsia.jar,需要从
http://itextpdf.sourceforge.net下载。下载后将 iTextAsia.jar 放到 iReport 的 lib 目录中即可(笔者共享的 ireport3.1.0.zip 包里自带了一个 iTextAsia.jar,无需单独下载。另外笔者也单独上传了一份 iTextAsia.jar 至 csdn 资源)。
iReport 在装了 ant 以后,直接运行 iReport 目录中的 ireport.bat 即可运行 iReport。
5、根据项目需要使用 iReport 生成 *.jrxml 报表模板文件。
PS:关于第 1-5 步,如果读者弄不太明白,可以去参考裴贺先写的《JasperReport 与 iReport 的配置与使用》。我有个 pdf 版的,已经共享至我的 csdn 资源。
6、新建一 web 项目 Test2。将 iReport 目录 lib 下的所有 jar 包导入。在 servlet 程序中把从数据库得到的数据传入 *.jrxml 文件得到 *.jrprint 文件(这才是我们想要的东西),并把这个对象写入 Stream流,以返还给请求客户端。源码:

?

[java] view plaincopyprint?
  1. package com.defonds.test;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.ObjectOutputStream;
  5. import javax.servlet.RequestDispatcher;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletOutputStream;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.sql.Connection;
  12. import java.sql.DriverManager;
  13. import java.sql.ResultSet;
  14. import java.sql.SQLException;
  15. import java.sql.Statement;
  16. import java.util.Calendar;
  17. import java.util.HashMap;
  18. import java.util.Map;
  19. import net.sf.jasperreports.engine.JRResultSetDataSource;
  20. import net.sf.jasperreports.engine.JasperCompileManager;
  21. import net.sf.jasperreports.engine.JasperExportManager;
  22. import net.sf.jasperreports.engine.JasperFillManager;
  23. import net.sf.jasperreports.engine.JasperPrint;
  24. import net.sf.jasperreports.engine.JasperReport;
  25. import net.sf.jasperreports.engine.JasperRunManager;
  26. /**
  27. * 建立数据库链接
  28. * 由 sql 语法取出资料,准备好传入的 parameters
  29. * 将 parameters 及取出的资料传入 Jasper 中。会由 .jasper 文档生出 .jrprint 文档
  30. * 再由 .jrprint 文档生出 .pdf 目的文档给调用页面下载
  31. * @author Defonds
  32. *
  33. */
  34. publicclass TestServlet3 extends HttpServlet {
  35. privatestaticfinal String CONTENTTYPE = "application/octet-stream";
  36. /**
  37. * Constructor of the object.
  38. */
  39. public TestServlet3() {
  40. super();
  41. }
  42. /**
  43. * Destruction of the servlet. <br>
  44. */
  45. publicvoid destroy() {
  46. super.destroy(); // Just puts "destroy" string in log
  47. // Put your code here
  48. }
  49. /**
  50. * The doGet method of the servlet. <br>
  51. *
  52. * This method is called when a form has its tag value method equals to get.
  53. *
  54. * @param request the request send by the client to the server
  55. * @param response the response send by the server to the client
  56. * @throws ServletException if an error occurred
  57. * @throws IOException if an error occurred
  58. */
  59. publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
  60. throws ServletException, IOException {
  61. String fileName = "";
  62. String sql = "";
  63. Map parameters = new HashMap();
  64. //parameters.put("rptToday", strDate);//传入的 prameters 引数
  65. sql = "select * from tab_channel_car_basic t";
  66. Connection conn = this.createConnection();//建立连接
  67. try {
  68. Statement stmt = conn.createStatement();
  69. ResultSet rs = stmt.executeQuery(sql);
  70. response.setContentType(CONTENTTYPE);
  71. ServletOutputStream ouputStream = response.getOutputStream();
  72. fileName="D://iReport//iReport-0.4.0//Work//carBasic3.jrxml";
  73. JasperReport jrt = JasperCompileManager.compileReport(fileName);//编译报表格式
  74. JasperPrint jpt = JasperFillManager.fillReport(jrt, parameters, new JRResultSetDataSource(rs));//匹配数据源,生成JasperPrint
  75. ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
  76. oos.writeObject(jpt);
  77. oos.flush();
  78. oos.close();
  79. }catch(Exception e) {
  80. System.out.println("Error:" + e.toString());
  81. e.printStackTrace();
  82. }finally {
  83. CloseConnect(conn);
  84. conn = null;
  85. }
  86. }
  87. /**
  88. * 建立连接方法
  89. * @return Connection
  90. */
  91. public Connection createConnection() {
  92. Connection conn;
  93. try {
  94. String driver = "oracle.jdbc.driver.OracleDriver";
  95. String url = "jdbc:oracle:thin:@localhost:1521:CUC";
  96. Class.forName(driver);
  97. conn = DriverManager.getConnection(url,"sybj","sybj");
  98. conn.setAutoCommit(false);
  99. return conn;
  100. }catch(SQLException e1) {
  101. System.out.println("建立连接错误 = " + e1.toString());
  102. e1.printStackTrace();
  103. }catch(ClassNotFoundException e2) {
  104. System.out.println("建立连接错误 = " + e2.toString());
  105. e2.printStackTrace();
  106. }
  107. returnnull;
  108. }
  109. /**
  110. * 关闭连接方法
  111. * @param conn
  112. */
  113. publicvoid CloseConnect(Connection conn) {
  114. try {
  115. conn.commit();
  116. conn.setAutoCommit(true);
  117. conn.close();
  118. }catch(Exception e) {
  119. System.out.println("关闭连接错误 = " + e.toString());
  120. }
  121. }
  122. }

?

?

PS:这里,关于 carBasic3.jrxml 文件的提取,笔者采用的是物理路径,读者可以把 *.jrxml 文件放到项目根目录下,然后采用其他方式提取。
如果输入
http://localhost:9999/Test2/testServlet3就弹出来一个下载窗口,证明这个 servlet 已经 ok(笔者 tomcat 端口号设置的是 9999,在 Test2 项目中进行测试)。
7、applet 请求服务器 servlet 得到 JasperPrint 对象并打印。源码:

?

[java] view plaincopyprint?
  1. package com.defonds.test;
  2. import java.applet.Applet;
  3. import java.io.PrintWriter;
  4. import java.io.StringWriter;
  5. import java.net.URL;
  6. import javax.swing.JOptionPane;
  7. import net.sf.jasperreports.engine.JasperPrint;
  8. import net.sf.jasperreports.engine.JasperPrintManager;
  9. import net.sf.jasperreports.engine.util.JRLoader;
  10. publicclass JRPrinterApplet extends javax.swing.JApplet
  11. {
  12. /**
  13. *
  14. */
  15. private URL url = null;
  16. private JasperPrint jasperPrint = null;
  17. /** Creates new form AppletViewer */
  18. public JRPrinterApplet()
  19. {
  20. }
  21. /**
  22. *
  23. */
  24. publicvoid init()
  25. {
  26. // String strUrl = getParameter("REPORT_URL");
  27. String strUrl = "http://localhost:9999/Test2/testServlet3";
  28. if (strUrl != null)
  29. {
  30. try
  31. {
  32. //url = new URL(getCodeBase(), strUrl);
  33. URL urll = new URL("http://localhost:9999/Test2/testServlet3");
  34. url = urll;
  35. System.out.println("url="+urll);
  36. }
  37. catch (Exception e)
  38. {
  39. StringWriter swriter = new StringWriter();
  40. PrintWriter pwriter = new PrintWriter(swriter);
  41. e.printStackTrace(pwriter);
  42. JOptionPane.showMessageDialog(this, swriter.toString());
  43. }
  44. }
  45. else
  46. {
  47. JOptionPane.showMessageDialog(this, "init():Source URL not specified");
  48. }
  49. }
  50. publicvoid start() {
  51. if (url != null)
  52. {
  53. if (jasperPrint == null)
  54. {
  55. try
  56. {
  57. System.out.println("进入start方法,即将下载pdf文件");
  58. jasperPrint = (JasperPrint)JRLoader.loadObject(url);
  59. System.out.println("进入start方法,下载pdf文件完毕");
  60. }
  61. catch (Exception e)
  62. {
  63. StringWriter swriter = new StringWriter();
  64. PrintWriter pwriter = new PrintWriter(swriter);
  65. e.printStackTrace(pwriter);
  66. JOptionPane.showMessageDialog(this, swriter.toString());
  67. }
  68. }
  69. if (jasperPrint != null)
  70. {
  71. final JasperPrint print = jasperPrint;
  72. Thread thread = new Thread
  73. (
  74. new Runnable()
  75. {
  76. publicvoid run()
  77. {
  78. try
  79. {
  80. System.out.println("进入start方法,即将打印pdf文件");
  81. JasperPrintManager.printReport(print, true);
  82. }
  83. catch (Exception e)
  84. {
  85. StringWriter swriter = new StringWriter();
  86. PrintWriter pwriter = new PrintWriter(swriter);
  87. e.printStackTrace(pwriter);
  88. JOptionPane.showMessageDialog(null, swriter.toString());
  89. }
  90. }
  91. }
  92. );
  93. thread.start();
  94. }
  95. else
  96. {
  97. JOptionPane.showMessageDialog(this, "Empty report.");
  98. }
  99. }
  100. else
  101. {
  102. JOptionPane.showMessageDialog(this, "start():Source URL not specified");
  103. }
  104. }
  105. }

?

?

右键单击 JRPrinterApplet.java,选择 “Run as Java Applet”,弹出打印对话框,确认后打印机正常打印,证明 applet 已经编写成功。
8、jsp 页面嵌入 applet源码:

?

[xhtml] view plaincopyprint?
  1. <%@ page language="java"import="java.util.*"pageEncoding="GBK"%>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8. <head>
  9. <basehref="<%=basePath%>">
  10. <title>My JSP 'index.jsp' starting page</title>
  11. <metahttp-equiv="pragma"content="no-cache">
  12. <metahttp-equiv="cache-control"content="no-cache">
  13. <metahttp-equiv="expires"content="0">
  14. <metahttp-equiv="keywords"content="keyword1,keyword2,keyword3">
  15. <metahttp-equiv="description"content="This is my page">
  16. <!--
  17. <link rel="stylesheet" type="text/css" href="styles.css" mce_href="styles.css">
  18. -->
  19. </head>
  20. <mce:scriptlanguage="javascript"><!--
  21. function openApp()
  22. {
  23. var url = "/JRPrintServlet";
  24. document.write('<APPLETID="JrPrt"CODE="com.defonds.test.JRPrinterApplet.class"CODEBASE = "./"ARCHIVE = "reportprint.jar"WIDTH = "0"HEIGHT = "0">');
  25. document.write('<PARAMNAME = "type"VALUE="application/x-java-applet;version=1.2.2">');
  26. document.write('<PARAMNAME = "scriptable"VALUE="false">');
  27. document.write('<PARAMNAME = "REPORT_URL"VALUE ="'+url+'">');
  28. document.write('</APPLET>');
  29. }
  30. // --></mce:script>
  31. <bodybgcolor="#FFFFFF">
  32. <inputtype="button"value="测试打印"onclick="openApp();">
  33. </body>
  34. </html>

?

?

9、applet 打包并签名认证。
将 jasperreport 目录下的 jasperreports-3.0.1-applet.jar 解压。在任一磁盘根目录下新建一文件夹 temp,将 jasperreports-3.0.1-applet.jar 解压后的 META-INF、net、default.jasperreports.properties(这个一定要复制,不然会报 NullPointer 异常)全部复制到 temp下,将 test2 项目下的 WEB-INF 下 classes 中的文件 com 也复制到 temp 下。
CMD 命令, E:/temp>
下键入 jar -cvf reportprint.jar *
temp 目录下会生成 reportprint.jar 包。
用keytool生成证书:keytool -genkey -alias printkey -keystore printstore
还是用keytool导出证书:keytool -export -keystore printstore -alias printkey -file print.cer
用jarsigner给reportprint.jar加上数字签名:jarsigner -keystore printstore reportprint.jar printkey
以上都是在命令提示符下运行,printkey和printstore都可以以自己的命名方式来命名。现在在temp下已经有了一个reportprint.jar和一个print.cer,把这两个文件拷贝回项目中,记得还是放在同一个目录下(最好是根目录,即 Test2 项目的 WebRoot 下)。

完成。运行 test2 项目看看结果如何。如果 Java 控制台提示“ClassNotFoundException”,证明 applet 打包路径没有配置好:去查看 JasperReport 类是否被打包,以及 jsp 页面调用 reportprin.jar 是否正确。如果弹出对话框:该应用程序的数字签名无法验证,是否要运行该应用程序?证明数字签名已经可以使用。

PS: 关于第 7-9 步,作者已经共享了 Test2 applet 打印项目源码至 csdn 资源,代码注释的很详细,而且附带 数据库.sql 说明。如果读者读完本博文后对 applet 打印报表还不是很清楚,可以去下载下来看看。

遗留问题:一、不支持 jre 的自动安装。原因:jsp 嵌入 applet 使用的是 <applet> 标签。最好使用 <object> 标签,客户端没装 jre 的话,自动安装。二、Run as java applet 测试时,applet 没有任何问题,打包后运行时,Java 控制台报“Exception occurred during event dispatching:java.lang.NullPointerException: null pData at sun.awt.windows.WComponentPeer._requestFocus(Native Method)”异常。笔者查了下资料,没弄明白怎么回事。但这并不影响打印。

转自:

http://blog.csdn.net/defonds/article/details/4440697