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

来源:互联网 发布:多益网络ceo徐宥箴 编辑:程序博客网 时间:2024/06/05 17:22

了方便更多的人了解、使用 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流,以返还给请求客户端。源码:

view plaincopy to clipboardprint?
package com.defonds.test;  
 
import java.io.File;  
import java.io.IOException;  
import java.io.ObjectOutputStream;  
 
import javax.servlet.RequestDispatcher;  
import javax.servlet.ServletException;  
import javax.servlet.ServletOutputStream;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.sql.Connection;  
import java.sql.DriverManager;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.sql.Statement;  
import java.util.Calendar;  
import java.util.HashMap;  
import java.util.Map;  
 
import net.sf.jasperreports.engine.JRResultSetDataSource;  
import net.sf.jasperreports.engine.JasperCompileManager;  
import net.sf.jasperreports.engine.JasperExportManager;  
import net.sf.jasperreports.engine.JasperFillManager;  
import net.sf.jasperreports.engine.JasperPrint;  
import net.sf.jasperreports.engine.JasperReport;  
import net.sf.jasperreports.engine.JasperRunManager;  
 
/** 
 * 建立数据库链接 
 * 由 sql 语法取出资料,准备好传入的 parameters 
 * 将 parameters 及取出的资料传入 Jasper 中。会由 .jasper 文档生出 .jrprint 文档 
 * 再由 .jrprint 文档生出 .pdf 目的文档给调用页面下载 
 * @author Defonds 
 * 
 */ 
public class TestServlet3 extends HttpServlet {  
   
 private static final String CONTENTTYPE = "application/octet-stream";   
 
    /** 
     * Constructor of the object. 
     */ 
    public TestServlet3() {  
        super();  
    }  
 
    /** 
     * Destruction of the servlet. <br> 
     */ 
    public void destroy() {  
        super.destroy(); // Just puts "destroy" string in log  
        // Put your code here  
    }  
 
    /** 
     * The doGet method of the servlet. <br> 
     * 
     * This method is called when a form has its tag value method equals to get. 
     *  
     * @param request the request send by the client to the server 
     * @param response the response send by the server to the client 
     * @throws ServletException if an error occurred 
     * @throws IOException if an error occurred 
     */ 
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
     String fileName = "";  
     String sql = "";  
     Map parameters = new HashMap();  
     //parameters.put("rptToday", strDate);//传入的 prameters 引数  
     sql = "select * from tab_channel_car_basic t";  
       
     Connection conn = this.createConnection();//建立连接  
     try {  
      Statement stmt = conn.createStatement();  
      ResultSet rs = stmt.executeQuery(sql);  
      response.setContentType(CONTENTTYPE);    
      ServletOutputStream ouputStream = response.getOutputStream();    
      fileName="D://iReport//iReport-0.4.0//Work//carBasic3.jrxml";  
      JasperReport jrt = JasperCompileManager.compileReport(fileName);//编译报表格式   
      JasperPrint jpt = JasperFillManager.fillReport(jrt, parameters, new JRResultSetDataSource(rs));//匹配数据源,生成JasperPrint  
      ObjectOutputStream oos = new ObjectOutputStream(ouputStream);   
      oos.writeObject(jpt);      
            oos.flush();      
            oos.close();   
 
 
     }catch(Exception e) {  
      System.out.println("Error:" + e.toString());  
      e.printStackTrace();  
     }finally {  
      CloseConnect(conn);  
      conn = null;  
     }  
       
    }  
       
    /** 
     * 建立连接方法 
     * @return Connection 
     */ 
     public Connection createConnection() {  
      Connection conn;  
      try {  
       String driver = "oracle.jdbc.driver.OracleDriver";  
       String url = "jdbc:oracle:thin:@localhost:1521:CUC";  
       Class.forName(driver);  
       conn = DriverManager.getConnection(url,"sybj","sybj");  
       conn.setAutoCommit(false);  
       return conn;  
      }catch(SQLException e1) {  
       System.out.println("建立连接错误 = " + e1.toString());  
       e1.printStackTrace();  
      }catch(ClassNotFoundException e2) {  
       System.out.println("建立连接错误 = " + e2.toString());  
       e2.printStackTrace();  
      }  
      return null;  
     }  
       
    /** 
     * 关闭连接方法 
     * @param conn 
     */   
    public void CloseConnect(Connection conn) {  
     try {  
      conn.commit();  
      conn.setAutoCommit(true);  
      conn.close();  
     }catch(Exception e) {  
      System.out.println("关闭连接错误 = " + e.toString());  
     }  
    }  
      
 

package com.defonds.test;

import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JRResultSetDataSource;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperRunManager;

/**
 * 建立数据库链接
 * 由 sql 语法取出资料,准备好传入的 parameters
 * 将 parameters 及取出的资料传入 Jasper 中。会由 .jasper 文档生出 .jrprint 文档
 * 再由 .jrprint 文档生出 .pdf 目的文档给调用页面下载
 * @author Defonds
 *
 */
public class TestServlet3 extends HttpServlet {
 
 private static final String CONTENTTYPE = "application/octet-stream";

    /**
     * Constructor of the object.
     */
    public TestServlet3() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }

    /**
     * The doGet method of the servlet. <br>
     *
     * This method is called when a form has its tag value method equals to get.
     *
     * @param request the request send by the client to the server
     * @param response the response send by the server to the client
     * @throws ServletException if an error occurred
     * @throws IOException if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     String fileName = "";
     String sql = "";
     Map parameters = new HashMap();
     //parameters.put("rptToday", strDate);//传入的 prameters 引数
     sql = "select * from tab_channel_car_basic t";
    
     Connection conn = this.createConnection();//建立连接
     try {
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery(sql);
      response.setContentType(CONTENTTYPE); 
      ServletOutputStream ouputStream = response.getOutputStream(); 
      fileName="D://iReport//iReport-0.4.0//Work//carBasic3.jrxml";
      JasperReport jrt = JasperCompileManager.compileReport(fileName);//编译报表格式
      JasperPrint jpt = JasperFillManager.fillReport(jrt, parameters, new JRResultSetDataSource(rs));//匹配数据源,生成JasperPrint
      ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
      oos.writeObject(jpt);   
            oos.flush();   
            oos.close();


     }catch(Exception e) {
      System.out.println("Error:" + e.toString());
      e.printStackTrace();
     }finally {
      CloseConnect(conn);
      conn = null;
     }
    
    }
    
    /**
     * 建立连接方法
     * @return Connection
     */
     public Connection createConnection() {
      Connection conn;
      try {
       String driver = "oracle.jdbc.driver.OracleDriver";
       String url = "jdbc:oracle:thin:@localhost:1521:CUC";
       Class.forName(driver);
       conn = DriverManager.getConnection(url,"sybj","sybj");
       conn.setAutoCommit(false);
       return conn;
      }catch(SQLException e1) {
       System.out.println("建立连接错误 = " + e1.toString());
       e1.printStackTrace();
      }catch(ClassNotFoundException e2) {
       System.out.println("建立连接错误 = " + e2.toString());
       e2.printStackTrace();
      }
      return null;
     }
    
    /**
     * 关闭连接方法
     * @param conn
     */
    public void CloseConnect(Connection conn) {
     try {
      conn.commit();
      conn.setAutoCommit(true);
      conn.close();
     }catch(Exception e) {
      System.out.println("关闭连接错误 = " + e.toString());
     }
    }
   

}
 

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

view plaincopy to clipboardprint?
package com.defonds.test;  
 
import java.applet.Applet;  
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;  
 
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");      
     String strUrl = "http://localhost:9999/Test2/testServlet3";  
        if (strUrl != null)      
        {      
            try     
            {      
                //url = new URL(getCodeBase(), strUrl);      
             URL urll = new URL("http://localhost:9999/Test2/testServlet3");  
             url = urll;  
       System.out.println("url="+urll);  
            }      
            catch (Exception e)      
            {      
                StringWriter swriter = new StringWriter();      
                PrintWriter pwriter = new PrintWriter(swriter);      
                e.printStackTrace(pwriter);      
                JOptionPane.showMessageDialog(this, swriter.toString());      
            }      
        }      
        else     
        {      
        JOptionPane.showMessageDialog(this, "init():Source URL not specified");      
        }      
    }      
     
    public void start() {      
        if (url != null)      
        {      
            if (jasperPrint == null)      
            {      
                try     
                {      
                 System.out.println("进入start方法,即将下载pdf文件");  
                    jasperPrint = (JasperPrint)JRLoader.loadObject(url);    
                    System.out.println("进入start方法,下载pdf文件完毕");  
                }      
                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       
                                {      
                                 System.out.println("进入start方法,即将打印pdf文件");  
                                    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, "start():Source URL not specified");      
        }      
     
    }      
          

package com.defonds.test;

import java.applet.Applet;
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;

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");   
     String strUrl = "http://localhost:9999/Test2/testServlet3";
        if (strUrl != null)   
        {   
            try  
            {   
                //url = new URL(getCodeBase(), strUrl);   
             URL urll = new URL("http://localhost:9999/Test2/testServlet3");
             url = urll;
       System.out.println("url="+urll);
            }   
            catch (Exception e)   
            {   
                StringWriter swriter = new StringWriter();   
                PrintWriter pwriter = new PrintWriter(swriter);   
                e.printStackTrace(pwriter);   
                JOptionPane.showMessageDialog(this, swriter.toString());   
            }   
        }   
        else  
        {   
        JOptionPane.showMessageDialog(this, "init():Source URL not specified");   
        }   
    }   
  
    public void start() {   
        if (url != null)   
        {   
            if (jasperPrint == null)   
            {   
                try  
                {   
                 System.out.println("进入start方法,即将下载pdf文件");
                    jasperPrint = (JasperPrint)JRLoader.loadObject(url); 
                    System.out.println("进入start方法,下载pdf文件完毕");
                }   
                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    
                                {   
                                 System.out.println("进入start方法,即将打印pdf文件");
                                    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, "start():Source URL not specified");   
        }   
  
    }   
       
}
 

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

view plaincopy to clipboardprint?
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%> 
<%  
String path = request.getContextPath();  
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
%> 
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
  <head> 
    <base href="<%=basePath%>"> 
      
    <title>My JSP 'index.jsp' starting page</title> 
 <meta http-equiv="pragma" content="no-cache"> 
 <meta http-equiv="cache-control" content="no-cache"> 
 <meta http-equiv="expires" content="0">      
 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
 <meta http-equiv="description" content="This is my page"> 
 <!-- 
 <link rel="stylesheet" type="text/css" href="styles.css" mce_href="styles.css"> 
 --> 
</head>   
<mce:script language="javascript"><!--  
   
function openApp()   
{   
var url = "/JRPrintServlet";   
document.write('<APPLET ID="JrPrt" CODE="com.defonds.test.JRPrinterApplet.class" CODEBASE = "./" ARCHIVE = "reportprint.jar" WIDTH = "0" HEIGHT = "0">');   
document.write('<PARAM NAME = "type" VALUE="application/x-java-applet;version=1.2.2">');   
document.write('<PARAM NAME = "scriptable" VALUE="false">');   
document.write('<PARAM NAME = "REPORT_URL" VALUE ="'+url+'">');   
document.write('</APPLET>');   
}  
// --></mce:script>   
<body bgcolor="#FFFFFF">   
<input type="button" value="测试打印" onclick="openApp();">   
 
</body>   
</html>  
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
   
    <title>My JSP 'index.jsp' starting page</title>
 <meta http-equiv="pragma" content="no-cache">
 <meta http-equiv="cache-control" content="no-cache">
 <meta http-equiv="expires" content="0">   
 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
 <meta http-equiv="description" content="This is my page">
 <!--
 <link rel="stylesheet" type="text/css" href="styles.css" mce_href="styles.css">
 -->
</head>
<mce:script language="javascript"><!--
 
function openApp()
{
var url = "/JRPrintServlet";
document.write('<APPLET ID="JrPrt" CODE="com.defonds.test.JRPrinterApplet.class" CODEBASE = "./" ARCHIVE = "reportprint.jar" WIDTH = "0" HEIGHT = "0">');
document.write('<PARAM NAME = "type" VALUE="application/x-java-applet;version=1.2.2">');
document.write('<PARAM NAME = "scriptable" VALUE="false">');
document.write('<PARAM NAME = "REPORT_URL" VALUE ="'+url+'">');
document.write('</APPLET>');
}
// --></mce:script>
<body bgcolor="#FFFFFF">
<input type="button" value="测试打印" onclick="openApp();">

</body>
</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)”异常。笔者查了下资料,没弄明白怎么回事。但这并不影响打印。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/defonds/archive/2009/08/13/4440697.aspx