公司的项目需要在客户端直接打印出报表,之前还很轻松地认为这个实现起来不难,Jasper的api里不就有直接打印的方法吗?等照着api把方法用上测试的时候才发现,在客户端点“打印”按钮结果去调服务器的打印机,当时就知道自己高兴得太早了。没办法只好去百度,找来找去发现都是同一篇,在想了很久之后以自己目前的水平实在想不出除了那篇教程上说的用applet接收服务端的输出流之外还有别的什么能做到,于是决定照着例子做。然而结果比前次更凄惨,applet完全不运作。那时候一边想着自己是不是太笨了连依样画葫芦都干不好一边嘀咕那些转载例子的人到底有没有真正实践过那方法到底能不能用呀?
如此郁闷了一个晚上之后,第二天早上起来突然想到为什么不去看Jasper自带的例子?兴冲冲赶到公司一试,哎,真的弹出权限错误提示了。于是再骂一次自己是笨蛋,把例子改改套到程序上去了,这次终于搞定了。
总结这次的任务,一是遇到难题的时候最好找官方的资料,尤其是java的开源项目,那些domo大多都是精华;二是一定要多想想为什么,为什么demo会这么写?有什么道理?三是多动手实践,“实践是检验真理的唯一标准”,尤其是对我这个非计算机专业毕业的初学者来说:)
好了,废话说的够多了,下面来整理一下《实现JasperReport客户端本地打印》的要点(貌似这个才是我写这篇的重点,呵呵)
一、项目需求
点击打印图标弹出小窗口,窗口中有两个按钮,一个是“打印”,一个是“完成”,两个按钮上方是提示语句和提示图标。按下打印按钮后提示语句和提示图标改变,同时本地打印机开始打印。打印结束后按完成按钮完成本次打印。
(其实我的工作重点在于按下打印按钮之后到打印开始打印为止,其他的活是其他组员的任务)
二、实现过程
1、在servlet中得到JasperPrint对象,并将之写入ObjectOutputStream中
这一步没什么好说的,想怎么实现就怎么实现,总之得到一个JasperPrint对象,然后放进Objuect输出流里输出,最后达到运行servlet会弹出一个下载窗口的结果就OK。
这里给出比较关键的步骤:
- /*
- *这只是一些重点提示,甚至不是一个例子
- */
- private static final String CONTENTTYPE = "application/octet-stream";
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType(CONTENTTYPE);
- ServletOutputStream ouputStream = response.getOutputStream();
- try {
- ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
- //这里是调用了另外一个servlet,其结果也是返回一个JasperPrint对象
- JasperPrint jpt = rst.getReportPrint(rptCode, context,object, tradeTypeInput);
- oos.writeObject(jpt);
- oos.flush();
- oos.close();
- } catch (ReportException e) {
- //处理
- }
2、用applet接收servlet传出的JasperPrint对象
这个,根本就是照抄JapserReport的demo源码了,稍微做了一些改动(比如去掉了预览、不需要按打印按钮直接打印)
代码如下:
- package report.web;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import java.net.URL;
- import javax.swing.JOptionPane;
- import net.sf.jasperreports.engine.JasperPrint;
- import net.sf.jasperreports.engine.JasperPrintManager;
- import net.sf.jasperreports.engine.util.JRLoader;
- /**
- * @author Teodor Danciu (teodord@users.sourceforge.net)
- * @version $Id: PrinterApplet.java 1229 2006-04-19 13:27:35 +0300 (Wed, 19 Apr 2006) teodord $
- */
- public class JRPrinterApplet extends javax.swing.JApplet
- {
- /**
- *
- */
- private URL url = null;
- private JasperPrint jasperPrint = null;
- /** Creates new form AppletViewer */
- public JRPrinterApplet()
- {
- }
- /**
- *
- */
- public void init()
- {
- String strUrl = getParameter("REPORT_URL");
- if (strUrl != null)
- {
- try
- {
- url = new URL(getCodeBase(), strUrl);
- }
- catch (Exception e)
- {
- StringWriter swriter = new StringWriter();
- PrintWriter pwriter = new PrintWriter(swriter);
- e.printStackTrace(pwriter);
- JOptionPane.showMessageDialog(this, swriter.toString());
- }
- }
- else
- {
- JOptionPane.showMessageDialog(this, "Source URL not specified");
- }
- }
- public void start() {
- if (url != null)
- {
- if (jasperPrint == null)
- {
- try
- {
- jasperPrint = (JasperPrint)JRLoader.loadObject(url);
- }
- catch (Exception e)
- {
- StringWriter swriter = new StringWriter();
- PrintWriter pwriter = new PrintWriter(swriter);
- e.printStackTrace(pwriter);
- JOptionPane.showMessageDialog(this, swriter.toString());
- }
- }
- if (jasperPrint != null)
- {
- final JasperPrint print = jasperPrint;
- Thread thread = new Thread
- (
- new Runnable()
- {
- public void run()
- {
- try
- {
- JasperPrintManager.printReport(print, true);
- }
- catch (Exception e)
- {
- StringWriter swriter = new StringWriter();
- PrintWriter pwriter = new PrintWriter(swriter);
- e.printStackTrace(pwriter);
- JOptionPane.showMessageDialog(null, swriter.toString());
- }
- }
- }
- );
- thread.start();
- }
- else
- {
- JOptionPane.showMessageDialog(this, "Empty report.");
- }
- }
- else
- {
- JOptionPane.showMessageDialog(this, "Source URL not specified");
- }
- }
- }
3、打包applet的class和所需的jar包,并加上数字签名
要运行这个applet需要jasperreports-1.2.8-applet.jar(后来我想了一下,之所以照抄网上的例子不能成功的原因,很有可能是导入的jar包不对,这个工作是之前的程序员做的,他导入的包当中没有applet这个),可以用winrar直接解压缩了,然后把applet编辑后的class和解压缩后的文件放在同一个目录(比如temp),在命令提示符中输入 jar 命令打成一个包,例如:jar -cvf reportprint.jar *
接着开始做数字签名:
1)用keytool生成证书:keytool -genkey -alias mykey -keystore mystore
2)还是用keytool导出证书:keytool -export -keystore mystore -alias mykey -file my.cer
3)用jarsigner给reportprint.jar加上数字签名:jarsigner -keystore mystore reportprint.jar mykey
以上都是在命令提示符下运行,mykey和mystore都可以以自己的命名方式来命名
现在在temp下已经有了一个reportprint.jar和一个my.cer,把这两个文件拷贝回项目中,记得还是放在同一个目录下
4、用Ajax连接页面和servlet
弹出的打印小窗口中不需要把applet加载进去,等按下打印按钮之后再用innerHTML的方式加载,比如:
- //还是一样,这个不是例子,只是重点提示
- var print = document.getElementById("printtest");
- var path = //这里是servlet的地址;
- print.innerHTML = "……" //这里是加载applet的代码,貌似这里直接给出会出错,那么去看JasperReport给的例子好了,例子名称是webapp<noembed></noembed>
5、测试打印
按下打印按钮后会出现是否运行签名的提示,允许之后就会弹出系统自带的打印对话框。如果不想弹出打印对话框直接在打印机上打印,那么在applet中把JasperPrintManager.printReport(print, true); 改成JasperPrintManager.printReport(print, false);就好,JasperReport的api里有说明
三、环境要求
需要客户端安装Jre1.5,并且IE选项高级里,必须将“将JRE1.5.x.xx用于applet(需要重启动)”勾选上才行。
在window+IE6.0中运行通过。
至此,用JasperReport在客户端实现本地打印完成。
(其实是组长要求我写技术文档,一开始根本毫无头绪,想拿写blog练练手,写完之后发现思路清晰多了,现在继续和文档搏斗去了,呵呵)