12、借助Jacob实现Java打印报表(Excel、Word)

12、使用Jacob来处理文档

  Word或Excel程序是以一种COM组件形式存在的。如果能够在Java中调用相应组件,便能使用它的方法来获取文档中的文本信息。Jacob是一个JAVA到微软的COM接口的桥梁。Jacob允许任何JVM访问COM对象,从而使JAVA应用程序能够调用COM对象。如果要对 MS Word、Excel 进行处理,Jacob 是一个好的选择。

12.1、Jacob的下载

        Jacob 是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。使用Jacob自带的DLL动态链接库,并通过JNI的方式实现了在Java平台上对COM程序的调用。Jacob下载的地址为:

http://sourceforge.net/project/showfiles.php?group_id=109543&package_id=118368。

12.2、在Eclipse中的配置

  (1) 将jacob.jar导入工程的Build Path,然后确认自己机器的CPU类型(X86或AMD64),并选择不同目录下的jacob.dll文件。

  (2) 将jacob.dll放到%JAVA_HOME%\jre\bin目录下,其中,%JAVA_HOME%就是JDK的安装目录。注意这个的jre目录必须是Eclipse当前正在使用的目录,在Eclipse中选择“window->Preferences”菜单,在弹出的对话框中选择“Java->Installed JREs”项。

  (3) 当前选择的JRE是“C:\Program Files\Java\jdk1.5.0_07\jre”目录下的,所以需要把jacob.dll复制到“C:\Program Files\Java\jdk1.5.0_07\jre\bin”目录下面。

  (4) 在工程中新建一个ch7.jacob包,并在包中创建WordReader类。该类将提供一个静态的extractDoc()方法。它接收两个参数,一个是要处理的DOC文件名,另一个则是输出的文件名,然后通过JNI调用Word的API转换内容,该函数的代码如下。

 1 public static void extractDoc(String inputFIle, String outputFile) {
 2 
 3    boolean flag = false;
 4 
 5   
 6 
 7    // 打开Word应用程序
 8 
 9    ActiveXComponent app = new ActiveXComponent("Word.Application");
10 
11    try {
12 
13       // 设置word不可见
14 
15       app.setProperty("Visible", new Variant(false));
16 
17       // 打开word文件
18 
19       Dispatch doc1 = app.getProperty("Documents").toDispatch();
20 
21       Dispatch doc2 = Dispatch.invoke(
22 
23             doc1,
24 
25             "Open",
26 
27             Dispatch.Method,
28 
29             new Object[] { inputFIle, new Variant(false),
30 
31                   new Variant(true) }, new int[1]).toDispatch();
32 
33       // 作为txt格式保存到临时文件
34 
35       Dispatch.invoke(doc2, "SaveAs", Dispatch.Method, new Object[] {
36 
37             outputFile, new Variant(7) }, new int[1]);
38 
39       // 关闭word
40 
41       Variant f = new Variant(false);
42 
43       Dispatch.call(doc2, "Close", f);
44 
45       flag = true;
46 
47    } catch (Exception e) {
48 
49       e.printStackTrace();
50 
51    } finally {
52 
53       app.invoke("Quit", new Variant[] {});
54 
55    }
56 
57    if (flag == true) {
58 
59       System.out.println("Transformed Successfully");
60 
61    } else {
62 
63       System.out.println("Transform Failed");
64 
65    }
66 
67 }

注意:在使用Jacob时,很重要的一点是,用户本地系统中必须安装有Word的应用程序。否则也就无法建立Java-COM桥,进而无法解析了。

12.3、Jacob中常用方法

  (1) 初始化com的线程,很重要,否则第二次创建com对象的时候会出现can't co-create object异常,完成操作com组件后要调用release方法。

ComThread.InitSTA();// 初始化com的线程

  (2) 初始化word应用程序,新建一个空白文档,取得文档内容对象

//Instantiate objWord //Declare word object

ActiveXComponent objWord = new ActiveXComponent("Word.Application");

//Assign a local word object

Dispatch wordObject = (Dispatch) objWord.getObject();

//Create a Dispatch Parameter to show the document that is opened

Dispatch.put((Dispatch) wordObject, "Visible", new Variant(true));

// new Variant(true)表示word应用程序可见

Tip:设置一个对象的属性的时候,利用Dispatch的put方法,给属性赋值。上面这行语句相当于vb的wordObject.Visible=true语句。

//Instantiate the Documents Property

Dispatch documents = objWord.getProperty("Documents").toDispatch();

//documents表示word的所有文档窗口。

//Add a new word document, Current Active Document

Dispatch document = Dispatch.call(documents, "Add").toDispatch();

// 使用Add命令创建一个新文档,用Open命令可以打开一个现有文档

Tip:调用一个对象的方法的时候,利用Dispatch的call方法,上面的语句相当于vb的document = documents.Add() 语句。

Dispatch wordContent = Dispatch.get(document, "Content").toDispatch();

// 取得word文件的内容

Tip:取得一个对象的成员变量(属性)时,利用Dispatch的get方法,上面的语句相当于vb的wordContent = document.Content语句。

  (3) 取得word文档的内容后,可以对其内容进行操作

Dispatch.call(wordContent, "InsertAfter", "这里是一个段落的内容");//插入一个段落

  (4) 设置刚插入的段落的文字格式

Dispatch paragraphs = Dispatch.get(wordContent, "Paragraphs").toDispatch();

// 获取所有段落

int  paragraphCount = Dispatch.get(paragraphs, "Count").toInt();

// 总的段落数

Dispatch lastParagraph = Dispatch.call(paragraphs, "Item",new Variant(paragraphCount)).toDispatch();

// 最后一段

Dispatch lastParagraphRange = Dispatch.get(lastParagraph, "Range").toDispatch();

Dispatch font = Dispatch.get(lastParagraphRange, "Font").toDispatch();

Dispatch.put(font, "Bold", new Variant(true));

// 设置为黑体

Dispatch.put(font, "Italic", new Variant(true));

// 设置为斜体

Dispatch.put(font, "Name", new Variant("宋体")); //

Dispatch.put(font, "Size", new Variant(12)); //小四

注意:如果想插入一个新的空白行,也需要设置段落的文字格式,否则新插入行的文字格式会于刚插入的段落的格式相同。

  (5) 将当前文档保存

Dispatch.call(document, "SaveAs", new Variant("C:abc.doc")); // 保存一个新文档

  (6) 释放COM线程

ComThread.Release();//释放com线程。根据Jacob的帮助文档,com的线程回收不由java的垃圾回收器处理。

12.4、Jacob中常用模块

  (1) 打印模块

 1 ActiveXComponent axc = null;  
 2 try {  
 3     ComThread.InitSTA();  
 4     axc = new ActiveXComponent("Excel.Application");  
 5     Dispatch.put(axc, "Visible", new Variant(false));  
 6     Dispatch workbooks = axc.getProperty("Workbooks").toDispatch();  
 7     Dispatch workbook = Dispatch.call(workbooks, "Open", fileFullPath,  
 8                         new Integer(0), Boolean.FALSE).toDispatch();  
 9     Dispatch sheets = Dispatch.call(workbook, "Worksheets").toDispatch();  
10     Dispatch sheet = Dispatch.call(sheets, "Item", new Integer(1))  
11                         .toDispatch();  
12     Dispatch.call(sheet, "PrintOut", new Integer(beginPage), new Integer(endPage), new Integer(copys));  
13     Dispatch.call(workbook, "Close", Variant.VT_FALSE);  
14 } finally {  
15     axc.invoke("Quit", new Variant[] {});  
16     ComThread.Release();  
17 }

(2) 纸张大小设置

1 Dispatch pageSetup = Dispatch.call(sheet, "PageSetup").toDispatch();  
2 Dispatch.put(pageSetup, "PaperSize", new Integer(8));//A3是8,A4是9,A5是11等等

可通过如下方式获取纸张大小所对应的整数值

1 int ps = Dispatch.get(pageSetup, "PaperSize").toInt();  
2 System.out.println("ps=" + ps);

  (3)页边距设置

1 Dispatch.put(pageSetup, "LeftMargin", new Variant(left));     //左  
2 Dispatch.put(pageSetup, "TopMargin", new Variant(top));       //上  
3 Dispatch.put(pageSetup, "RightMargin", new Variant(right));   //右  
4 Dispatch.put(pageSetup, "BottomMargin", new Variant(bottom)); //下  
5 Dispatch.put(pageSetup, "HeaderMargin", new Variant(header)); //页眉  
6 Dispatch.put(pageSetup, "FooterMargin", new Variant(footer)); //页脚 

    注: left、top、right、bottom、header和footer是double类型的数值,并且如果单位是厘米的话,需乘以28.35。

  (4) 统计Excel已使用的行数

1 Dispatch userRange=Dispatch.call(sheet, "UsedRange").toDispatch();  
2 Dispatch row=Dispatch.call(userRange, "Rows").toDispatch();  
3 int rowCount=Dispatch.get(row,"Count").getInt();  
4 System.out.println("rowCount=" + rowCount);

  (5) 在指定的行号上插入一空行

1 Dispatch rowSheet = Dispatch.call(sheet, "Rows", new Variant(i)).toDispatch();//这里的i是行号,int类型  
2 rowSheet.call(rowSheet, "Insert");

  (6) 根据不同版本的Excel做不同的处理

1 System.out.println("version=" + axc.getProperty("Version"));

 

12.5、程序实例

(1)实例一:

 1 package com.xfzx.test.POI.main;
 2  
 3 import com.jacob.activeX.ActiveXComponent;
 4 import com.jacob.com.ComThread;
 5 import com.jacob.com.Dispatch;
 6 import com.jacob.com.Variant;
 7  
 8 public class JacobPress {
 9  
10     /**
11      * @param args
12      */
13     public static void main(String[] args) {
14         // TODO Auto-generated method stub
15         printWord("D:/txt.docx");
16     //  printExcel("D:/提醒通知明细通用模板.xlsx");
17     }
18  
19     public static void printExcel(String filePath) {
20         /**
21          * 功能:实现打印工作
22          */
23         ComThread.InitSTA();
24         ActiveXComponent xl = new ActiveXComponent("Excel.Application");
25         try {
26             // System.out.println("version=" + xl.getProperty("Version"));
27             // 不打开文档
28             Dispatch.put(xl, "Visible", new Variant(true));
29             Dispatch workbooks = xl.getProperty("Workbooks").toDispatch();
30             // 打开文档
31             Dispatch excel = Dispatch.call(workbooks, "Open", filePath)
32                     .toDispatch();
33             // 开始打印
34             Dispatch.call(excel, "PrintOut");
35             xl.invoke("Quit", new Variant[] {});
36         } catch (Exception e) {
37             e.printStackTrace();
38         } finally {
39             // 始终释放资源
40             ComThread.Release();
41         }
42     }
43  
44     public static void printWord(String filePath) {
45         ComThread.InitSTA();
46         ActiveXComponent wd = new ActiveXComponent("Word.Application");
47         try {
48             // 不打开文档
49             Dispatch.put(wd, "Visible", new Variant(true));
50             Dispatch document = wd.getProperty("Documents").toDispatch();
51             // 打开文档
52             Dispatch doc = Dispatch.invoke(document, "Open", Dispatch.Method,
53                     new Object[] { filePath }, new int[1]).toDispatch();
54             // 开始打印
55             Dispatch.callN(doc, "PrintOut");
56             wd.invoke("Quit", new Variant[] {});
57         } catch (Exception e) {
58             e.printStackTrace();
59         } finally {
60             // 始终释放资源
61             ComThread.Release();
62         }
63     }
64      
65     // 获得文件后缀名
66     public static String getPostfix(String inputFilePath) {
67         String[] p = inputFilePath.split("\\.");
68         if (p.length > 0) {// 判断文件有无扩展名
69             // 比较文件扩展名
70             return p[p.length - 1];
71         } else {
72             return null;
73         }
74     }
75  
76 }

 (2)实例二:

 1 public static boolean printOfficeFile(File f) {
 2   if (f != null && f.exists()) {
 3    String fileNameString = f.getName();
 4    String postfixString = Utils.getPostfix(fileNameString);
 5    if (postfixString.equalsIgnoreCase("xls")
 6      || postfixString.equalsIgnoreCase("xlsx")) {
 7     /**
 8      * 功能:实现excel打印工作
 9      */
10     ComThread.InitSTA();
11     ActiveXComponent xl = new ActiveXComponent("Excel.Application");
12     try {
13      // System.out.println("version=" +
14      // xl.getProperty("Version"));
15      // 不打开文档
16      Dispatch.put(xl, "Visible", new Variant(false));
17      Dispatch workbooks = xl.getProperty("Workbooks")
18        .toDispatch();
19      // 打开文档
20      Dispatch excel = Dispatch.call(workbooks, "Open",
21        f.getAbsolutePath()).toDispatch();
22      // 横向打印(2013/05/24)
23 //     Dispatch currentSheet = Dispatch.get(excel, "ActiveSheet")
24 //       .toDispatch();
25 //     Dispatch pageSetup = Dispatch
26 //       .get(currentSheet, "PageSetup").toDispatch();
27 //     Dispatch.put(pageSetup, "Orientation", new Variant(2));
28      //每张表都横向打印2013-10-31
29      Dispatch sheets = Dispatch.get((Dispatch) excel, "Sheets")
30        .toDispatch();
31      // 获得几个sheet
32      int count = Dispatch.get(sheets, "Count").getInt();
33 //     System.out.println(count);
34      for (int j = 1; j <=count; j++) {
35       Dispatch sheet = Dispatch.invoke(sheets, "Item",
36         Dispatch.Get, new Object[] { new Integer(j) },
37         new int[1]).toDispatch();
38       Dispatch pageSetup = Dispatch.get(sheet, "PageSetup").toDispatch();
39       Dispatch.put(pageSetup, "Orientation", new Variant(2));
40       Dispatch.call(sheet, "PrintOut");
41      }
42      // 开始打印
43      if (excel != null) {
44       //Dispatch.call(excel, "PrintOut");
45       //增加以下三行代码解决文件无法删除bug
46       Dispatch.call(excel, "save");
47       Dispatch.call(excel,  "Close" ,  new  Variant(true));
48       excel=null;
49      }
50      xl.invoke("Quit", new Variant[] {});
51      xl=null;
52      return true;
53     } catch (Exception e) {
54      e.printStackTrace();
55      return false;
56     } finally {
57      // 始终释放资源
58      ComThread.Release();
59     }
60    } else if (postfixString.equalsIgnoreCase("doc")
61      || postfixString.equalsIgnoreCase("docx")) {
62     ComThread.InitSTA();
63     ActiveXComponent wd = new ActiveXComponent("Word.Application");
64     try {
65      // 不打开文档
66      Dispatch.put(wd, "Visible", new Variant(false));
67      Dispatch document = wd.getProperty("Documents")
68        .toDispatch();
69      // 打开文档
70      Dispatch doc = Dispatch.invoke(document, "Open",
71        Dispatch.Method, new Object[] { f.getAbsolutePath() },
72        new int[1]).toDispatch();
73      // 开始打印
74      if (doc != null) {
75       Dispatch.call(doc, "PrintOut");
76       //增加以下三行代码解决文件无法删除bug
77       Dispatch.call(doc, "save");
78       Dispatch.call(doc,  "Close" ,  new  Variant(true));
79       doc=null;
80      }
81      wd.invoke("Quit", new Variant[] {});
82      wd=null;
83      return true;
84     } catch (Exception e) {
85      e.printStackTrace();
86      return false;
87     } finally {
88      // 始终释放资源
89      ComThread.Release();
90     }
91    } else {
92     return false;
93    }
94   } else {
95    return false;
96   }
97  }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

8.1 Spring Boot集成Groovy混合Java开发小结

本章节我们使用SpringBoot集成Groovy混合Java开发一个极简的RestAPI。 数据库使用mysql,ORM层使用mybatis,模板引擎使用fr...

942
来自专栏SDNLAB

源码解读ODL的MAC地址学习(一)

1 简介 我们知道同一子网中主机之间互相传送信息需要用到MAC地址,而我们第一次发送信息的时候只有IP地址而没有MAC地址,所以我们就要进行MAC地址自学习。 ...

6126
来自专栏听雨堂

加点的心得

加点的一般方法:    Catalog _catalog=MapInfo.Engine.Session.Current.Catalog;    MapInf...

17810
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多。主要集中增删该查每个模块都有,所以本次是为封装相同接口方法    如果你...

2216
来自专栏吴小龙同學

android之获取手机信息

android获取手机信息(号码,内存,CPU,分辨率,MAC,IP,SD卡,IMEI,经纬度,信号强度等等) 1 2 3 4 5 6 7 8 9 10 11 ...

3577
来自专栏跟着阿笨一起玩NET

违反并发性: UpdateCommand影响了预期 1 条记录中的 0 条 解决办法

本文转载:http://www.cnblogs.com/litianfei/archive/2007/08/16/858866.html

1192
来自专栏xingoo, 一个梦想做发明家的程序员

Zookeeper学习笔记——2 Shell和Java API的使用

ZooKeeper的使用一般都接触不到,因为平时工作甚少直接使用ZK。但是通过手动操作一下ZK,还是能对其中的门道了解各一二。 shell 常用命令 he...

2705
来自专栏菩提树下的杨过

WebService又一个不爽的地方

昨天在做项目时,发现了WebService又一个不人性化的地方,记录于此,希望能帮到遇到类似问题的同学们。 很多大型b/s项目,通常会分成几层,为了重现问题,这...

1908
来自专栏cmazxiaoma的架构师之路

C#学习之路(1)--数据库技术

1834
来自专栏Android 研究

APK安装流程详解14——PMS中的新安装流程上(拷贝)补充

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACK...

1231

扫码关注云+社区