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 条评论
登录 后参与评论

相关文章

来自专栏别先生

Spring之hello world(Spring入门)

spring各个版本中: 在3.0以下的版本,源码有spring中相关的所有包【spring功能 + 依赖包】 如2.5版本; 在3.0以上的版本,源...

17810
来自专栏Java编程技术

高性能网络通信框架Netty-Netty客户端底层与Java NIO对应关系

在讲解Netty客户端程序时候我们提到指定NioSocketChannel用于创建客户端NIO套接字通道的实例,下面我们来看NioSocketChannel是如...

663
来自专栏Netkiller

Spring boot with Git version

本文节选自《Netkiller Java 手札》 5.23. Spring boot with Git version Spring boot 每次升级打包发给...

2828
来自专栏温安适的blog

2个小bug,有点小门道

2564
来自专栏lgp20151222

Java 读取 json文件

和this.getClass().getClassloader().getResource("") 区别??

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

《Spring Boot极简教程》第16章 Spring Boot安全集成Spring Security小结

开发Web应用,对页面的安全控制通常是必须的。比如:对于没有访问权限的用户需要转到登录表单页面。要实现访问控制的方法多种多样,可以通过Aop、拦截器实现,也可以...

673
来自专栏xiaoheike

Spring MVC 上下文(ApplicationContext)初始化入口

应该来说是很少使用这种方法用于生产开发,常常在学习Spring做demo的时候会使用到。更有可能出现在Spring项目的代码测试,不过呢,单元测试的框架(比如 ...

761
来自专栏纯洁的微笑

Spring Boot 2.0(七):Spring Boot 如何解决项目启动时初始化资源

823
来自专栏Java技术分享

第八章:Shiro和Spring的集成——深入浅出学Shiro细粒度权限开发框架

Standalone Applications nShiro 应用程序需要一个具有单例SecurityManager 实例的应用程序。请注意,这不会是一个静态的...

4195
来自专栏coolblog.xyz技术专栏

Spring MVC 原理探秘 - 容器的创建过程

1123

扫码关注云+社区