- 论坛徽章:
- 0
|
html内容生成为word文档实现思路
最近在做将HTML的内容转换成word文档,在处理html表格与图片的问题上还是花了一点心思。所以写这一篇文章将整个思路记录下来。
处理HTML标签我用的是Jsoup组件,生成word文档这方面我用的是Jacob组件。有兴趣的朋友可以去Google搜索一下这两个组件。大致思路如下:
先利用jsoup将得到的html代码“标准化”(Jsoup.parse(String html))方法,然后利用FileWiter将此html内容写到本地的template.doc文件中,此时如果文章中包含图片的话,template.doc就会依赖你的本地图片文件路径,如果你将图片更改一个名称或者将路径更改,再打开这个template.doc,图片就会显示不出来(出现一个叉叉)。为了解决此问题,利用jsoup组件循环遍历html文档的内容,将img元素替换成${image_自增值}的标识,取出img元素中的src属性,再以键值对的方式存储起来,例如:- ?123 Map<Integer,String> imgMap = new HashMap<Integer,String>(); imgMap.put(1,”D:\\lucene.png”);
复制代码 此时你的html内容会变成如下格式:(举个示例)- ?<html> <head></head> <body> <p>测试消息1</p> <p>${image_1}<p> <table> <tr> <td> <td> </tr> </table> <p>测试消息2</p> <a href="http://www.google.com.hk"><p>${image_2}</p></a> <p>测试消息3</p> </body> </html>
复制代码 保存到本地文件以后,利用MSOfficeGeneratorUtils类(工具类详见下面,基于开源组件Jacob)打开你保存的这个template.doc,调用replaceText2Image,将上面代码的图片标识替换为图片,这样就消除了本地图片路径的问题。 然后再调用copy方法,复制整篇文档,关闭template.doc文件,新建一个doc文件(createDocument),调用 paste方法粘贴你刚复制的template.doc里的内容,保存。基本上就ok了。
关于copy整个word文档的内容,也会出现一个隐式问题。就是当复制的内容太多时,关闭word程序的时候,会谈出一个对话框,问你是否将复制的数据应用于其它的程序。对于这个问题解决方法很简单,你可以在调用 quit(退出word程序方法)之前,新建一篇文档,输入一行字,然后调用 copy方法,对于复制的数据比较少时,关闭word程序时,它不会提示你的。见如下代码
?123456 //复制一个内容比较少的*.doc文档,防止在关闭word程序时提示有大量的copy内容在内存中,是否应用于其它程序对话框, msOfficeUtils.createNewDocument(); msOfficeUtils.insertText("测试消息"); msOfficeUtils.copy(); msOfficeUtils.close(); msOfficeUtils.quit();
Jacob在sourceforge上的链接
Jsoup官网- MsOfficeGeneratorUtils
- expand source?
- 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257 package com.topstar.test; import java.io.File; import java.io.IOException; import java.util.List; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.ComThread; import com.jacob.com.Dispatch; import com.jacob.com.Variant; /** * 利用JACOB对Microsoft Office Word 进行相关操作 * * @author xiaowu * @category topstar * @version 1.0 * @since 2011-12-5 */public class MSOfficeGeneratorUtils { /** * Microsoft Office Word 程序对象 */ private ActiveXComponent word = null; /** * Word 活动文档对象 */ private Dispatch document = null; /** * 所有 Word 文档对象 */ private Dispatch documents = null; /** * selection 代表当前活动文档窗口中的所选内容。如果文档中没有选中任何内容,则此对象代表插入点(即光标所在位置)。<br/> * 每个文档窗口中只能存在一个selection对象,并且在整个应用程序中,只能存在一个活动的selection对象 */ private Dispatch selection = null; /** * range 对象代表文档中的一个连续的区域。每个range对象由一个起始字符位置与结束字符位置定义。<br/> * range 对象独立于所选内容。你可以定义和处理一个范围而无需改变所选内容。还可以在文档中定义多个范围。但每个文档中只能有一个所选内容 */ private Dispatch range = null; /** * PageSetup 对象包含文档所有页面的设置属性(如纸张大小,左边距,下边距) */ private Dispatch pageSetup = null; /** * 文档中的所有表格对象 */ private Dispatch tables = null; /** 单个表格对象 */ private Dispatch table = null; /** 表格所有行对象 */ private Dispatch rows = null; /** 表格所有列对象 */ private Dispatch cols = null; /** 表格指定行对象 */ private Dispatch row = null; /** 表格指定列对象 */ private Dispatch col = null; /** 表格中指定的单元格 */ private Dispatch cell = null; /** 字体 */ private Dispatch font = null; /** 对齐方式 */ private Dispatch alignment = null; /** * 构造方法 * * @param visible * 设置在生成word文档时,程序是否可见 */ public MSOfficeGeneratorUtils(boolean visible) { if (this.word == null) { // 初始化Microsoft Office Word 实例 this.word = new ActiveXComponent("Word.Application"); this.word.setProperty("Visible", new Variant(visible)); // 禁用宏 this.word.setProperty("AutomationSecurity", new Variant(3)); } if (this.documents == null) this.documents = word.getProperty("Documents").toDispatch(); } /** * 设置页面方向与页边距 * * @param orientation * 页面方向 * <ul> * <li>0 横向</li> * <li>1 纵向</li> * </ul> * @param leftMargin * 左边距 * @param rightMargin * 右边距 * @param topMargin * 上边距 * @param buttomMargin * 下边距 */ public void setPageSetup(int orientation, int leftMargin, int rightMargin, int topMargin, int buttomMargin) { if (this.pageSetup == null) this.getPageSetup(); Dispatch.put(pageSetup, "Orientation", orientation); Dispatch.put(pageSetup, "LeftMargin", leftMargin); Dispatch.put(pageSetup, "RightMargin", rightMargin); Dispatch.put(pageSetup, "TopMargin", topMargin); Dispatch.put(pageSetup, "BottomMargin", buttomMargin); } /** * 打开word文档 * * @param docPath * word文档路径 * @return 打开的文档对象 */ public Dispatch openDocument(String docPath) { this.document = Dispatch.call(documents, "Open", docPath).toDispatch(); this.getSelection(); this.getRange(); this.getAlignment(); this.getFont(); this.getPageSetup(); return this.document; } /** * 创建一篇新文档 * * @return 文档对象 */ public Dispatch createNewDocument() { this.document = Dispatch.call(documents, "Add").toDispatch(); this.getSelection(); this.getRange(); this.getPageSetup(); this.getAlignment(); this.getFont(); return this.document; } /** * 获取选定的内容或插入点 * * @return selection */ public Dispatch getSelection() { this.selection = word.getProperty("Selection").toDispatch(); return this.selection; } /** * 获取当前文档中可以修改的部分,前提是必须存在选中内容 * * @return range */ public Dispatch getRange() { this.range = Dispatch.get(this.selection, "Range").toDispatch(); return this.range; } /** * 获得当前文档的页面属性 */ public Dispatch getPageSetup() { if (this.document == null) return this.pageSetup; this.pageSetup = Dispatch.get(this.document, "PageSetup").toDispatch(); return this.pageSetup; } /** * 把选中内容或插入点向上移动 * * @param count * 移动的距离 */ public void moveUp(int count) { for (int i = 0; i < count; i++) Dispatch.call(this.selection, "MoveUp"); } /** * 把选中内容或插入点向下移动 * * @param count * 移动的距离 */ public void moveDown(int count) { for (int i = 0; i < count; i++) Dispatch.call(this.selection, "MoveDown"); } /** * 把选中内容或插入点向左移动 * * @param count * 移动的距离 */ public void moveLeft(int count) { for (int i = 0; i < count; i++) Dispatch.call(this.selection, "MoveLeft"); } /** * 把选中内容或插入点向右移动 * * @param count * 移动的距离 */ public void moveRight(int count) { for (int i = 0; i < count; i++) Dispatch.call(this.selection, "MoveRight"); } /** * 执行硬换行(回车键) * * @param count * 换行数 */ public void enterDown(int count) { for (int i = 0; i < count; i++) Dispatch.call(this.selection, "TypeParagraph"); } /** * 把插入点移动到文件首位置 */ public void moveStart() { Dispatch.call(this.selection, "HomeKey", new Variant(6)); } /** * 把插入点移动到文件末尾 */ public void moveEnd() { Dispatch.call(selection, "EndKey", new Variant(6)); } /** * 从选定内容或插入点开始查找文本 * * @param toFindText * 要查找的内容 * @return 查询到的内容并选中 */ public boolean find(String toFindText) { // 从selection所在位置开始查询 Dispatch find = Dispatch.call(this.selection, "Find").toDispatch(); // 设置要查找的內容 Dispatch.put(find, "Text", toFindText); // 向前查找 Dispatch.put(find, "Forward", "True"); // 设置格式 Dispatch.put(find, "Format", "True"); // 大小写匹配 Dispatch.put(find, "MatchCase", "True"); // 全字匹配 Dispatch.put(find, "MatchWholeWord", "True"); // 查找并选中 return Dispatch.call(find, "Execute").getBoolean(); } /** * 替换选定的内容 * * @param newText * 要替换的内容 */ public void replace(String newText) { // 设置替换文本 Dispatch.put(this.selection, "Text", newText); } /** * 全局替换 * * @param oldText * 要替换的内容 * @param replaceObj * 被替换的内容 */ public void replaceAll(String oldText, Object replaceObj) { // 将插入点移到文件开头 moveStart(); // 表格替换方式 String newText = (String) replaceObj; // 图片替换方式 if (oldText.indexOf("image") != -1 || newText.lastIndexOf(".bmp") != -1 || newText.lastIndexOf(".jpg") != -1 || newText.lastIndexOf(".gif") != -1) { while (find(oldText)) { insertImage(newText); Dispatch.call(this.selection, "MoveRight"); } // 文本方式 } else { while (find(oldText)) { replace(newText); Dispatch.call(this.selection, "MoveRight"); } } } /** * 将指定的内容替换成图片 * @param replaceText 指定的内容 * @param imgPath 图片路径 */ public void replaceText2Image(String replaceText,String imgPath){ moveStart(); while(find(replaceText)){ insertImage(imgPath); moveEnd(); enterDown(1); } } /** * 向当前插入点替换图片 * * @param imagePath * 图片的路径 */ public void insertImage(String imagePath) { Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(), "AddPicture", imagePath); } /** * 合并单元格 * * @param tableIndex * 表格下标,从1开始 * @param fstCellRowIdx * 开始行 * @param fstCellColIdx * 开始列 * @param secCellRowIdx * 结束行 * @param secCellColIdx * 结束列 */ public void mergeCell(int tableIndex, int fstCellRowIdx, int fstCellColIdx, int secCellRowIdx, int secCellColIdx) { getTable(tableIndex); Dispatch fstCell = Dispatch.call(table, "Cell", new Variant(fstCellRowIdx), new Variant(fstCellColIdx)) .toDispatch(); Dispatch secCell = Dispatch.call(table, "Cell", new Variant(secCellRowIdx), new Variant(secCellColIdx)) .toDispatch(); Dispatch.call(fstCell, "Merge", secCell); } /** * 拆分当前单元格 * * @param numRows * 拆分的行数,如果不想拆分行,请指定为1 * @param numColumns * 拆分的列数,如果不想拆分列,请指定为1 */ public void splitCell(int numRows, int numColumns) { Dispatch.call(this.cell, "Split", new Variant(numRows), new Variant( numColumns)); } /** * 向表格中写入内容 * * @param list * 要写入的内容<br/> * 注:list.size() 应该与表格的rows一致,String数组的length属性应与表格的columns一致 */ public void insertToTable(List<String[]> list) { if (list == null || list.size() <= 0) return; if (this.table == null) return; for (int i = 0; i < list.size(); i++) { String[] strs = list.get(i); for (int j = 0; j < strs.length; j++) { // 遍历表格中每一個单元格,遍历次数所要填入的內容数量相同 Dispatch cell = this.getCell(i + 1, j + 1); // 选中此单元格 Dispatch.call(cell, "Select"); // 写入內容到此单元格中 Dispatch.put(this.selection, "Text", strs[j]); // 将插入点移动至下一個位置 } this.moveDown(1); } // 换行 this.enterDown(1); } /** * 向当前插入点插入文本内容 * * @param list * 要插入的内容,list.size()代表行数 */ public void insertToDocument(List<String> list) { if (list == null || list.size() <= 0) return; if (this.document == null) return; for (String str : list) { Dispatch.put(this.selection, "Text", str); this.moveDown(1); this.enterDown(1); } } /** * 在当前插入点插入文本 * * @param insertText * 要插入的文本 */ public void insertToText(String insertText) { Dispatch.put(this.selection, "Text", insertText); } /** * 在当前插入点插入字符串,利用此方法插入一行text后,Word会默认选中它,如果再调用此方法,会将原来的内容覆盖掉,所以调用此方法后,记得调用moveRight,将偏移量向右边移动一个位置 。 * @param newText 要插入的新字符串 */ public void insertText(String newText) { Dispatch.put(selection, "Text", newText); } /** * 创建新的表格 * * @param rowCount * 行 * @param colCount * 列 * @param width * 表格边框 * <ul> * <li>0 无边框</li> * <li>1 有边框</li> * </ul> * @return 表格对象 */ public Dispatch createNewTable(int rowCount, int colCount, int width) { if (this.tables == null) this.getTables(); this.getRange(); if (rowCount > 0 && colCount > 0) this.table = Dispatch.call(this.tables, "Add", this.range, new Variant(rowCount), new Variant(colCount), new Variant(width)).toDispatch(); return this.table; } /** * 获取当前document对象中的所有表格对象 * * @return tables */ public Dispatch getTables() { if (this.document == null)
复制代码 |
|