主要是想要用此功插件操作docx,主要的操作就是操作段落等信息,另外,也想實現替換docx的內容,實現根據模板動態生成內容的效果,也想用此插件實現docx轉換pdf。
word的格式其實可以用xml來表現,docx4j也應該是基於xml來操作docx文檔的。xml就比較好理解了。我們都是通過doc樹的形式操作docx,只不過對於docx4j來說根節點是一個package,我們可以從根節點獲取所有的內容,也可以指定元素的類型從document中查找元素集合,用下標訪問指定位置的元素。
docx4j官網下載的包本身缺slf4j的支持包,而且轉換pdf的時候fop-2.3的包與docx4j的包沖突,在文章最后會將最終整理過的docx4j及其相關依賴包附上下載鏈接。
1.docx的下載
到官網下載即可,下載的zip包里面有jar包,也有examples,下面的例子就是出自官網的examples。但是官網下載的lib里面日志記錄缺失log4j的包和slf4j-log4j包。
官網下載地址:https://www.docx4java.org/downloads.html
2.簡單的使用
0. docx4j.properties 可以指定docx的一些全局屬性,包括文字方向,紙張大小等。下面是官網給出的一個配置
# Page size: use a value from org.docx4j.model.structure.PageSizePaper enum
# eg A4, LETTER
docx4j.PageSize=LETTER
# Page size: use a value from org.docx4j.model.structure.MarginsWellKnown enum
docx4j.PageMargins=NORMAL
docx4j.PageOrientationLandscape=false
# Page size: use a value from org.pptx4j.model.SlideSizesWellKnown enum
# eg A4, LETTER
pptx4j.PageSize=LETTER
pptx4j.PageOrientationLandscape=false
# These will be injected into docProps/app.xml
# if App.Write=true
docx4j.App.write=true
docx4j.Application=docx4j
docx4j.AppVersion=2.7
# of the form XX.YYYY where X and Y represent numerical values
# These will be injected into docProps/core.xml
docx4j.dc.write=true
docx4j.dc.creator.value=docx4j
docx4j.dc.lastModifiedBy.value=docx4j
#
#docx4j.McPreprocessor=true
# If you haven't configured log4j yourself
# docx4j will autoconfigure it. Set this to true to disable that
docx4j.Log4j.Configurator.disabled=false
1.創建一個新的docx文檔
/** * 創建一個簡單的docx */ private static void createDocx() { // Create the package WordprocessingMLPackage wordMLPackage; try { wordMLPackage = WordprocessingMLPackage.createPackage(); // 另存為新的文件 wordMLPackage.save(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (InvalidFormatException e) { log.error("createDocx error:InvalidFormatException", e); } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } }
調用 WordprocessingMLPackage.createPackage(); 創建一個包,並且調用其save(file)就是生成一個新的文件
補充:還有另一種常用的保存方法是:
Docx4J.save(wordMLPackage, new File("C:/Users/liqiang/Desktop/docx4j/helloworld_2.docx"));
2.向文件中增加段落
/** * 增加一個段落,增加完成記得保存,否則不生效 */ public static void addParagraph() { WordprocessingMLPackage wordprocessingMLPackage; try { wordprocessingMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); wordprocessingMLPackage.getMainDocumentPart().addParagraphOfText("Hello Word!"); wordprocessingMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title", "Hello Word!"); wordprocessingMLPackage.getMainDocumentPart().addStyledParagraphOfText("Subtitle", " a subtitle!"); wordprocessingMLPackage.save(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Docx4JException e) { log.error("addParagraph to docx error: Docx4JException", e); } }
調用 WordprocessingMLPackage.load(file) 加載一個已經存在的docx,最后記得調用其save方法進行保存,否則修改不生效。
最后文件內容:
3.第二種采用工廠類增加段落的方法(工廠類的使用,工廠類也是一種通用的方法)
/** * 增加一個段落,增加完成記得保存,否則不生效 */ public static void addParagraph2(String simpleText) { try { WordprocessingMLPackage wordprocessingMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory(); org.docx4j.wml.P para = factory.createP(); if (simpleText != null) { org.docx4j.wml.Text t = factory.createText(); t.setValue(simpleText); org.docx4j.wml.R run = factory.createR(); run.getContent().add(t); para.getContent().add(run); } wordprocessingMLPackage.getMainDocumentPart().getContent().add(para); wordprocessingMLPackage.save(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Exception e) { log.error("addParagraph to docx error: Docx4JException", e); } }
先創建一個工廠,(需要導入的包是org.docx4j.wml,導錯的的話下面全錯)。
R是一個運行塊,負責便於將多個屬性相同的Object對象統一操作,通過其內部的content成員變量可以添加內容,RPr是運行塊的屬性(屬於類R的一個成員變量),可以對R對象進行操作。R通過被作為其他對象的content內容。所以通過R在A元素中加一個B元素的操作的一般步驟是:(1)創建R;(2)將內容元素B加到R中;(3)將R增加到A元素中;(4)將A元素加到mainDocumentPart內容中。
補充:工廠類的一些通用方法:
4.讀取文件的內容
private static void readParagraph() { try { WordprocessingMLPackage wordprocessingMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); String contentType = wordprocessingMLPackage.getContentType(); log.info("contentType -> {}", contentType); MainDocumentPart mainDocumentPart = wordprocessingMLPackage.getMainDocumentPart(); List<Object> content = mainDocumentPart.getContent(); for (Object ob : content) { log.info("ob -> {}", ob); } } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } }
結果:
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] contentType -> application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> a subtitle!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> a subtitle!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> Hello Word!
2018-10-28 13:13:16 [cn.qlq.docx4j.Docx4jTest]-[INFO] ob -> a subtitle!
5.創建表格
(1)創建一個普通的表格
public static void addTable() { try { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); ObjectFactory factory = Context.getWmlObjectFactory(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 創建表格元素 Tbl table = factory.createTbl(); addBorders(table); for (int i = 0; i < 3; i++) { Tr tr = factory.createTr(); for (int j = 0; j < 3; j++) { Tc tc = factory.createTc(); P p = mainDocumentPart.createParagraphOfText("---row" + i + "---column" + j + "---"); tc.getContent().add(p); tr.getContent().add(tc); } table.getContent().add(tr); } mainDocumentPart.addObject(table); wordMLPackage.save(new java.io.File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } }
查看createParagraphOfText(str)的源碼:(1.創建一個text,並設置其值,2.創建一個R並將text增加到R中,3.創建一個P將R加到P中)
public org.docx4j.wml.P createParagraphOfText(String simpleText) { org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory(); org.docx4j.wml.P para = factory.createP(); if (simpleText!=null) { org.docx4j.wml.Text t = factory.createText(); t.setValue(simpleText); org.docx4j.wml.R run = factory.createR(); run.getContent().add(t); // ContentAccessor para.getContent().add(run); // ContentAccessor } return para; }
結果:
上面的表格創建出來了,但是表格的邊框也沒有,接下來研究更復雜的操作,包括顯示邊框,合並單元格,設置單元格樣式。
(2)顯示表格的邊框
public static void addTable() { try { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); ObjectFactory factory = Context.getWmlObjectFactory(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 0. 創建表格元素 Tbl table = factory.createTbl(); // 1.顯示表格的邊框 addBorders(table); // 2.添加表格內容(創建行和列) for (int i = 0; i < 3; i++) { Tr tr = factory.createTr(); for (int j = 0; j < 3; j++) { Tc tc = factory.createTc(); P p = mainDocumentPart.createParagraphOfText("---row" + i + "---column" + j + "---");// tc.getContent().add(p); tr.getContent().add(tc); } table.getContent().add(tr); } // 3.加表格加到主要內容中 mainDocumentPart.addObject(table); wordMLPackage.save(new java.io.File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } } /** * 設置邊框樣式 * * @param table * 需要設置表格邊框的單元格 */ private static void addBorders(Tbl table) { table.setTblPr(new TblPr());// 必須設置一個TblPr,否則最后會報空指針異常 CTBorder border = new CTBorder(); border.setColor("auto"); border.setSz(new BigInteger("4")); border.setSpace(new BigInteger("0")); border.setVal(STBorder.SINGLE); TblBorders borders = new TblBorders(); borders.setBottom(border); borders.setLeft(border); borders.setRight(border); borders.setTop(border); borders.setInsideH(border); borders.setInsideV(border); // 獲取其內部的TblPr屬性設置屬性 table.getTblPr().setTblBorders(borders); }
結果:
(3)設置表格居中顯示,而且內容部分字體加粗,設置列寬等操作
public static void addTable() { try { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); ObjectFactory factory = Context.getWmlObjectFactory(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 0. 創建表格元素 Tbl table = factory.createTbl(); // 1.顯示表格的邊框 addBorders(table); // 2.添加表格內容(創建行和列) for (int i = 0; i < 3; i++) { Tr tr = factory.createTr(); for (int j = 0; j < 3; j++) { Tc tc = factory.createTc(); // P p = mainDocumentPart.createParagraphOfText("---row" + i // + "---column" + j + "---"); // 第二種創建P並設置樣式的方法 P p1 = factory.createP(); R r = factory.createR(); Text text = factory.createText(); text.setValue("---row" + i + "---column" + j + "---"); r.getContent().add(text); p1.getContent().add(r); // 2.1通過R設置字體加粗等屬性 setRStyle(r); // 2.2設置列寬 if (j == 1) { setCellWidth(tc, 1250); } else { setCellWidth(tc, 2500); } tc.getContent().add(p1); tr.getContent().add(tc); } table.getContent().add(tr); } // 3.合並單元格 // 3.加表格加到主要內容中 mainDocumentPart.addObject(table); wordMLPackage.save(new java.io.File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } } /** * 設置列寬 * * @param tc * @param width */ private static void setCellWidth(Tc tc, int width) { TcPr tableCellProperties = new TcPr(); TblWidth tableWidth = new TblWidth(); tableWidth.setW(BigInteger.valueOf(width)); tableCellProperties.setTcW(tableWidth); tc.setTcPr(tableCellProperties); } /** * 通過設置R設置表格中屬性字體加粗,大小為25 * * @param */ private static void setRStyle(R r) { // 1.創建一個RPr RPr rpr = new RPr(); // 2.設置RPr // 2.1設置字體大小 HpsMeasure size = new HpsMeasure(); size.setVal(new BigInteger("25")); rpr.setSz(size); // 2.2設置加粗 BooleanDefaultTrue bold = new BooleanDefaultTrue(); bold.setVal(true); rpr.setB(bold); // 3.將RPr設置為R的屬性 r.setRPr(rpr); } /** * 設置邊框樣式 * * @param table * 需要設置表格邊框的單元格 */ private static void addBorders(Tbl table) { table.setTblPr(new TblPr());// 必須設置一個TblPr,否則最后會報空指針異常 CTBorder border = new CTBorder(); border.setColor("auto"); border.setSz(new BigInteger("4")); border.setSpace(new BigInteger("0")); border.setVal(STBorder.SINGLE); TblBorders borders = new TblBorders(); borders.setBottom(border); borders.setLeft(border); borders.setRight(border); borders.setTop(border); borders.setInsideH(border); borders.setInsideV(border); // 獲取其內部的TblPr屬性設置屬性 table.getTblPr().setTblBorders(borders); }
結果:
關於表格合並或者更加復雜的操作參考:https://www.cnblogs.com/cxxjohnson/p/7886275.html
6.讀取表格內容:(解析docx4j的樹結構---獲取指定類型的元素)
表格內容:
代碼:(有時候我們調用getContent()獲取的元素類型是Tr之類的直接元素,可以強轉;有時候不可以直接強轉,其類型是JAXBElement,需要進行提取---getAllElementFromObject方法)
package cn.qlq.docx4j; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import org.docx4j.TraversalUtil; import org.docx4j.finders.ClassFinder; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Tbl; import org.docx4j.wml.Tc; import org.docx4j.wml.Tr; /** * 循環替換表格內容 * * @author QiaoLiQiang * @time 2018年10月28日下午8:51:41 */ public class ReplaceTable { public static void main(String[] args) throws JAXBException { String template = "C:/Users/liqiang/Desktop/docx4j/helloworld_1.docx"; WordprocessingMLPackage wordMLPackage; try { wordMLPackage = WordprocessingMLPackage.load(new java.io.File(template)); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); // 1. ClassFinder 構造類型查詢器獲取指定元素 ClassFinder find = new ClassFinder(Tbl.class); new TraversalUtil(documentPart.getContent(), find); Tbl table = (Tbl) find.results.get(0);// 獲取到第一個表格元素 List<Object> trs = table.getContent(); System.out.println(trs); System.out.println("====================="); for (Object obj : trs) { Tr tr = (Tr) obj;// 獲取到tr List<Object> content = tr.getContent(); System.out.println(content); List<Object> objList = getAllElementFromObject(tr, Tc.class);// 獲取所有的Tc元素 for (Object obj1 : objList) { Tc tc = (Tc) obj1; System.out.println(tc.getContent()); } System.out.println("==============="); } } catch (Docx4JException e) { e.printStackTrace(); } } private static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) { List<Object> result = new ArrayList<Object>(); if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue(); if (obj.getClass().equals(toSearch)) result.add(obj); else if (obj instanceof ContentAccessor) { List<?> children = ((ContentAccessor) obj).getContent(); for (Object child : children) { result.addAll(getAllElementFromObject(child, toSearch)); } } return result; } }
結果:
[org.docx4j.wml.Tr@234f18c8, org.docx4j.wml.Tr@1de40494, org.docx4j.wml.Tr@64e89fe0, org.docx4j.wml.Tr@64585ee1, org.docx4j.wml.Tr@65bd393e, org.docx4j.wml.Tr@69f949a0] ===================== [javax.xml.bind.JAXBElement@6d50ddba, javax.xml.bind.JAXBElement@580d1667, javax.xml.bind.JAXBElement@4339f15a] [姓名] [性別] [年齡] =============== [javax.xml.bind.JAXBElement@11146e31, javax.xml.bind.JAXBElement@544e5bb9, javax.xml.bind.JAXBElement@6467f9ec] [name0] [sex0] [age0] =============== [javax.xml.bind.JAXBElement@66492873, javax.xml.bind.JAXBElement@4cfeca7b, javax.xml.bind.JAXBElement@6b9f78ba] [name1] [sex1] [age1] =============== [javax.xml.bind.JAXBElement@32af3289, javax.xml.bind.JAXBElement@c1eda5e, javax.xml.bind.JAXBElement@3d925789] [name2] [sex2] [age2] =============== [javax.xml.bind.JAXBElement@52b102f3, javax.xml.bind.JAXBElement@6338c9ee, javax.xml.bind.JAXBElement@25515b26] [name3] [sex3] [age3] =============== [javax.xml.bind.JAXBElement@372eee, javax.xml.bind.JAXBElement@26ea0b5e, javax.xml.bind.JAXBElement@4f905c47] [name4] [sex4] [age4] ===============
7.格式化樣式的操作:
有時候我們需要格式化一些樣式,每個元素內部都有一個XXXpr屬性用於操作樣式,Pr表示Properties,如下:
3.docx4j高級用法
1.docx轉換為html
package cn.qlq.docx4j; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import org.docx4j.Docx4J; import org.docx4j.Docx4jProperties; import org.docx4j.convert.out.HTMLSettings; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.samples.AbstractSample; public class Docx2Html extends AbstractSample { static { inputfilepath = "C:/Users/liqiang/Desktop/docx4j/helloworld.docx"; save = true; nestLists = true; } static boolean save; static boolean nestLists; public static void main(String[] args) throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); HTMLSettings htmlSettings = Docx4J.createHTMLSettings(); htmlSettings.setImageDirPath(inputfilepath + "_files"); htmlSettings.setImageTargetUri(inputfilepath.substring(inputfilepath.lastIndexOf("/") + 1) + "_files"); htmlSettings.setWmlPackage(wordMLPackage); String userCSS = null; if (nestLists) { userCSS = "html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, img, table, caption, tbody, tfoot, thead, tr, th, td " + "{ margin: 0; padding: 0; border: 0;}" + "body {line-height: 1;} "; } else { userCSS = "html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, img, ol, ul, li, table, caption, tbody, tfoot, thead, tr, th, td " + "{ margin: 0; padding: 0; border: 0;}" + "body {line-height: 1;} "; } htmlSettings.setUserCSS(userCSS); OutputStream os; if (save) { os = new FileOutputStream(inputfilepath + ".html"); } else { os = new ByteArrayOutputStream(); } Docx4jProperties.setProperty("docx4j.Convert.Out.HTML.OutputMethodXML", true); Docx4J.toHTML(htmlSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL); if (save) { System.out.println("Saved: " + inputfilepath + ".html "); } else { System.out.println(((ByteArrayOutputStream) os).toString()); } if (wordMLPackage.getMainDocumentPart().getFontTablePart() != null) { wordMLPackage.getMainDocumentPart().getFontTablePart().deleteEmbeddedFontTempFiles(); } htmlSettings = null; wordMLPackage = null; } }
封裝為一個更簡單的工具類的代碼如下:(userCSS是生成的html的樣式,可以手動設置,使用此參數可以靈活的設置邊距字體等信息)
package cn.qlq.docx4j; import java.io.File; import java.io.FileOutputStream; import org.docx4j.Docx4J; import org.docx4j.Docx4jProperties; import org.docx4j.convert.out.HTMLSettings; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.samples.AbstractSample; public class Docx2Html extends AbstractSample { public static void main(String[] args) throws Exception { String inputfilepath = "C:/Users/liqiang/Desktop/docx4j/helloworld.docx"; boolean nestLists = true; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); HTMLSettings htmlSettings = Docx4J.createHTMLSettings(); htmlSettings.setImageDirPath(inputfilepath + "_files"); htmlSettings.setImageTargetUri(inputfilepath.substring(inputfilepath.lastIndexOf("/") + 1) + "_files"); htmlSettings.setWmlPackage(wordMLPackage); String userCSS = null; if (nestLists) { userCSS = "html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, img, table, caption, tbody, tfoot, thead, tr, th, td " + "{ margin: 0; padding: 0; border: 0;}" + "body {line-height: 1;} "; } else { userCSS = "html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, img, ol, ul, li, table, caption, tbody, tfoot, thead, tr, th, td " + "{ margin: 0; padding: 0; border: 0;}" + "body {line-height: 1;} "; } htmlSettings.setUserCSS(userCSS); Docx4jProperties.setProperty("docx4j.Convert.Out.HTML.OutputMethodXML", true); Docx4J.toHTML(htmlSettings, new FileOutputStream(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.html")), Docx4J.FLAG_EXPORT_PREFER_XSL); if (wordMLPackage.getMainDocumentPart().getFontTablePart() != null) { wordMLPackage.getMainDocumentPart().getFontTablePart().deleteEmbeddedFontTempFiles(); } htmlSettings = null; wordMLPackage = null; } }
2.docx轉換為pdf
代碼簡單,但是依賴的包比較多,依賴了batik解析SVG的項目包,也依賴fop包,而且docx4j-community-6.0.1.zip里面自帶的optional\export-fo下面的fop-2.3.jar與docx沖突,所以需要fop-2.1版本才可以轉換。所以需要刪掉自帶的2.3版本,自行下載2.1版本。
public static void main(String[] args) throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage .load(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); Docx4J.toPDF(wordMLPackage, new FileOutputStream(new File("C:/Users/liqiang/Desktop/docx4j/helloworld.pdf"))); }
3.docx中寫入圖片
package cn.qlq.docx4j; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage; import org.docx4j.wml.Drawing; import org.docx4j.wml.ObjectFactory; import org.docx4j.wml.P; import org.docx4j.wml.R; public class ImageHandle { /** * 像往常一樣, 我們創建了一個包(package)來容納文檔. 然后我們創建了一個指向將要添加到文檔的圖片的文件對象.為了能夠對圖片做一些操作, * 我們將它轉換 為字節數組. 最后我們將圖片添加到包中並保存這個包(package). */ public static void main(String[] args) throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); File file = new File("C:/Users/liqiang/Desktop/docx4j/3.jpg"); byte[] bytes = convertImageToByteArray(file); addImageToPackage(wordMLPackage, bytes); wordMLPackage.save(new java.io.File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } /** * Docx4j擁有一個由字節數組創建圖片部件的工具方法, 隨后將其添加到給定的包中. 為了能將圖片添加 到一個段落中, * 我們需要將圖片轉換成內聯對象. 這也有一個方法, 方法需要文件名提示, 替換文本, 兩個id標識符和一個是嵌入還是鏈接到的指示作為參數. * 一個id用於文檔中繪圖對象不可見的屬性, 另一個id用於圖片本身不可見的繪制屬性. 最后我們將內聯 對象添加到段落中並將段落添加到包的主文檔部件. * * @param wordMLPackage * 要添加圖片的包 * @param bytes * 圖片對應的字節數組 * @throws Exception * 不幸的createImageInline方法拋出一個異常(沒有更多具體的異常類型) */ private static void addImageToPackage(WordprocessingMLPackage wordMLPackage, byte[] bytes) throws Exception { BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes); int docPrId = 1; int cNvPrId = 2; org.docx4j.dml.wordprocessingDrawing.Inline inline = imagePart.createImageInline("Filename hint", "Alternative text", docPrId, cNvPrId, false); P paragraph = addInlineImageToParagraph(inline); wordMLPackage.getMainDocumentPart().addObject(paragraph); } /** * 創建一個對象工廠並用它創建一個段落和一個可運行塊R. 然后將可運行塊添加到段落中. 接下來創建一個圖畫並將其添加到可運行塊R中. 最后我們將內聯 * 對象添加到圖畫中並返回段落對象. * * @param inline * 包含圖片的內聯對象. * @return 包含圖片的段落 */ private static P addInlineImageToParagraph(org.docx4j.dml.wordprocessingDrawing.Inline inline) { // 添加內聯對象到一個段落中 ObjectFactory factory = new ObjectFactory(); P paragraph = factory.createP(); R run = factory.createR(); paragraph.getContent().add(run); Drawing drawing = factory.createDrawing(); run.getContent().add(drawing); drawing.getAnchorOrInline().add(inline); return paragraph; } /** * 將圖片從文件對象轉換成字節數組. * * @param file * 將要轉換的文件 * @return 包含圖片字節數據的字節數組 * @throws FileNotFoundException * @throws IOException */ private static byte[] convertImageToByteArray(File file) throws FileNotFoundException, IOException { InputStream is = new FileInputStream(file); long length = file.length(); // 不能使用long類型創建數組, 需要用int類型. if (length > Integer.MAX_VALUE) { System.out.println("File too large!!"); } byte[] bytes = new byte[(int) length]; int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; } // 確認所有的字節都沒讀取 if (offset < bytes.length) { System.out.println("Could not completely read file " + file.getName()); } is.close(); return bytes; } }
4.按指定變量替換docx中的內容 ${var}替換
注意:模板的${var}在書寫的時候必須從左向右書寫(不能直接{},然后在中間寫括號),也就是轉換成XML之后${var}必須是連續的,否則取不到變量。有時候取不到變量的時候可以抓換為xml然后查看你的變量是否是連續的。
public static void main(String[] args) throws Exception { org.docx4j.wml.ObjectFactory foo = Context.getWmlObjectFactory(); String template = "C:/Users/liqiang/Desktop/docx4j/helloworld.docx"; boolean save = true; String outputfilepath = "C:/Users/liqiang/Desktop/docx4j/helloworld_1.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(template)); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); //需要替換的map HashMap<String, String> mappings = new HashMap<String, String>(); mappings.put("sex", "男"); mappings.put("age", "25"); mappings.put("username", "qlq"); long start = System.currentTimeMillis(); documentPart.variableReplace(mappings); long end = System.currentTimeMillis(); long total = end - start; System.out.println("Time: " + total); // Save it if (save) { SaveToZipFile saver = new SaveToZipFile(wordMLPackage); saver.save(outputfilepath); } else { System.out.println(XmlUtils.marshaltoString(documentPart.getJaxbElement(), true, true)); } }
模板:
結果:
補充:在docx進行變量替換的時候其格式也生效,比如我的模板:
最后的結果:
5.替換模板里面的表格(循環替換標簽)
模板內容:
代碼:
package cn.qlq.docx4j; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBException; import org.docx4j.Docx4J; import org.docx4j.TraversalUtil; import org.docx4j.XmlUtils; import org.docx4j.finders.ClassFinder; import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.Tbl; import org.docx4j.wml.Tr; /** * 循環替換表格內容 * * @author QiaoLiQiang * @time 2018年10月28日下午8:51:41 */ public class ReplaceTable { public static void main(String[] args) throws JAXBException { org.docx4j.wml.ObjectFactory objectFactory = Context.getWmlObjectFactory(); String template = "C:/Users/liqiang/Desktop/docx4j/helloworld.docx"; boolean save = true; String outputfilepath = "C:/Users/liqiang/Desktop/docx4j/helloworld_1.docx"; WordprocessingMLPackage wordMLPackage; try { wordMLPackage = WordprocessingMLPackage.load(new java.io.File(template)); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); // 構造循環列表的數據 ClassFinder find = new ClassFinder(Tbl.class); new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(), find); Tbl table = (Tbl) find.results.get(0);//獲取到第一個表格元素 Tr dynamicTr = (Tr) table.getContent().get(1);// 第二行約定為模板,獲取到第二行內容 String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);// 獲取模板行的xml數據 List<Map<String, Object>> dataList = getDataList(); for (Map<String, Object> dataMap : dataList) { Tr newTr = (Tr) XmlUtils.unmarshallFromTemplate(dynamicTrXml, dataMap);// 填充模板行數據 table.getContent().add(newTr); } // 刪除模板行的占位行 table.getContent().remove(1); Docx4J.save(wordMLPackage, new File(outputfilepath)); } catch (Docx4JException e) { e.printStackTrace(); } } private static List<Map<String, Object>> getDataList() { List list = new ArrayList(); for (int i = 0; i < 5; i++) { Map map = new HashMap(); map.put("name", "name" + i); map.put("sex", "sex" + i); map.put("age", "age" + i); list.add(map); } return list; } }
結果:
6.按書簽替換內容(替換變量、表格、圖片等格式數據)
這種方式比基於變量的方式靈活,而且操作簡單,我們只用在word中插入書簽,如下:(word中不能插入同名書簽)
代碼:
package cn.qlq.docx4j; import java.io.File; import java.io.FileInputStream; import java.util.List; import org.apache.commons.io.IOUtils; import org.docx4j.Docx4J; import org.docx4j.TraversalUtil; import org.docx4j.XmlUtils; import org.docx4j.dml.wordprocessingDrawing.Inline; import org.docx4j.finders.RangeFinder; import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.Body; import org.docx4j.wml.CTBookmark; import org.docx4j.wml.CTMarkupRange; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Document; import org.docx4j.wml.Drawing; import org.docx4j.wml.ObjectFactory; import org.docx4j.wml.P; import org.docx4j.wml.PPr; import org.docx4j.wml.ParaRPr; import org.docx4j.wml.R; import org.docx4j.wml.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 通過書簽替換變量 * * @author QiaoLiQiang * @time 2018年10月28日下午9:35:52 */ public class BooknameReplaceVar { private static final Logger log = LoggerFactory.getLogger(BooknameReplaceVar.class); private static WordprocessingMLPackage wordMLPackage; private static ObjectFactory factory; public static void main(String[] args) { bookReplaceVarText(); } private static void bookReplaceVarText() { String template = "C:/Users/liqiang/Desktop/docx4j/helloworld_1.docx"; try { wordMLPackage = WordprocessingMLPackage.load(new java.io.File(template)); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); factory = Context.getWmlObjectFactory(); Document wmlDoc = (Document) mainDocumentPart.getJaxbElement(); Body body = wmlDoc.getBody(); // 提取正文中所有段落 List<Object> paragraphs = body.getContent(); // 提取書簽並創建書簽的游標 RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange"); new TraversalUtil(paragraphs, rt); // 遍歷書簽 for (CTBookmark bm : rt.getStarts()) { log.info("標簽名稱:" + bm.getName()); // 這兒可以對單個書簽進行操作,也可以用一個map對所有的書簽進行處理 if (bm.getName().equals("name")) { replaceText(bm, "qlq"); } if (bm.getName().equals("pic")) { addImage(wordMLPackage, bm, "C:/Users/liqiang/Desktop/docx4j/3.jpg"); } } Docx4J.save(wordMLPackage, new File("C:/Users/liqiang/Desktop/docx4j/helloworld_2.docx")); } catch (Docx4JException e) { log.error("bookReplaceVarText error:Docx4JException ", e); } catch (Exception e) { log.error("bookReplaceVarText error:Docx4JException ", e); } } /** * 在標簽處插入內容 * * @param bm * @param wPackage * @param object * @throws Exception */ public static void replaceText(CTBookmark bm, Object object) throws Exception { if (object == null) { return; } // do we have data for this one? if (bm.getName() == null) return; String value = object.toString(); try { // Can't just remove the object from the parent, // since in the parent, it may be wrapped in a JAXBElement List<Object> theList = null; ParaRPr rpr = null; if (bm.getParent() instanceof P) { PPr pprTemp = ((P) (bm.getParent())).getPPr(); if (pprTemp == null) { rpr = null; } else { rpr = ((P) (bm.getParent())).getPPr().getRPr(); } theList = ((ContentAccessor) (bm.getParent())).getContent(); } else { return; } int rangeStart = -1; int rangeEnd = -1; int i = 0; for (Object ox : theList) { Object listEntry = XmlUtils.unwrap(ox); if (listEntry.equals(bm)) { if (((CTBookmark) listEntry).getName() != null) { rangeStart = i + 1; } } else if (listEntry instanceof CTMarkupRange) { if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) { rangeEnd = i - 1; break; } } i++; } int x = i - 1; // if (rangeStart > 0 && x >= rangeStart) { // Delete the bookmark range for (int j = x; j >= rangeStart; j--) { theList.remove(j); } // now add a run org.docx4j.wml.R run = factory.createR(); org.docx4j.wml.Text t = factory.createText(); // if (rpr != null) // run.setRPr(paraRPr2RPr(rpr)); t.setValue(value); run.getContent().add(t); // t.setValue(value); theList.add(rangeStart, run); // } } catch (ClassCastException cce) { log.error("error", cce); } } /** * 插入圖片 * * @param wPackage * @param bm * @param file */ public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file) { log.info("addImage :->{},{},{}", wPackage, bm,file); try { // 這兒可以對單個書簽進行操作,也可以用一個map對所有的書簽進行處理 // 獲取該書簽的父級段落 P p = (P) (bm.getParent()); // R對象是匿名的復雜類型,然而我並不知道具體啥意思,估計這個要好好去看看ooxml才知道 R run = factory.createR(); // 讀入圖片並轉化為字節數組,因為docx4j只能字節數組的方式插入圖片 byte[] bytes = IOUtils.toByteArray(new FileInputStream(file)); // InputStream is = new FileInputStream; // byte[] bytes = IOUtils.toByteArray(inputStream); // byte[] bytes = FileUtil.getByteFormBase64DataByImage(""); // 開始創建一個行內圖片 BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes); // createImageInline函數的前四個參數我都沒有找到具體啥意思,,,, // 最有一個是限制圖片的寬度,縮放的依據 Inline inline = imagePart.createImageInline(null, null, 0, 1, false, 0); // 獲取該書簽的父級段落 // drawing理解為畫布? Drawing drawing = factory.createDrawing(); drawing.getAnchorOrInline().add(inline); run.getContent().add(drawing); p.getContent().add(run); } catch (Exception e) { log.error("", e); } } }
結果:上面的文本內容可以被完美的替換掉。如果在一般項目中進行替換書簽為字符串變量已經足夠了,替換圖片還是有點格式問題。接下來還會繼續研究書簽的使用,嘗試更簡便的方式替換內容。
通過書簽和變量改變的內容的樣式會和自定義的樣式保持一致。
參考:https://github.com/plutext/docx4j/blob/master/src/samples
jar包下載地址:http://qiaoliqiang.cn/fileDown/docx4j-6.0.1-all.zip
補充:網上一位大哥寫的工具類,比較實用:
測試代碼;
/** * 增加一個表格 */ public static void addTable() { try { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); ObjectFactory factory = Context.getWmlObjectFactory(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 0. 創建表格元素 Tbl table = factory.createTbl(); // 1.顯示表格的邊框 addBorders(table); // 2.添加表格內容(創建行和列) for (int i = 0; i < 3; i++) { Tr tr = factory.createTr(); for (int j = 0; j < 3; j++) { Tc tc = factory.createTc(); // P p = mainDocumentPart.createParagraphOfText("---row" + i // + "---column" + j + "---"); // 第二種創建P並設置樣式的方法 P p1 = factory.createP(); R r = factory.createR(); Text text = factory.createText(); text.setValue("---row" + i + "---column" + j + "---"); r.getContent().add(text); p1.getContent().add(r); // 2.1通過R設置字體加粗等屬性 setRStyle(r); // 2.2設置列寬 if (j == 1) { setCellWidth(tc, 1250); } else { setCellWidth(tc, 2500); } tc.getContent().add(p1); tr.getContent().add(tc); } table.getContent().add(tr); } // 3.合並單元格 Docx4jUtil.mergeCellsHorizontal(table, 1, 0, 2); // 3.加表格加到主要內容中 mainDocumentPart.addObject(table); wordMLPackage.save(new java.io.File("C:/Users/liqiang/Desktop/docx4j/helloworld.docx")); } catch (Docx4JException e) { log.error("createDocx error: Docx4JException", e); } } /** * 設置列寬 * * @param tc * @param width */ private static void setCellWidth(Tc tc, int width) { TcPr tableCellProperties = new TcPr(); TblWidth tableWidth = new TblWidth(); tableWidth.setW(BigInteger.valueOf(width)); tableCellProperties.setTcW(tableWidth); tc.setTcPr(tableCellProperties); } /** * 通過設置R設置表格中屬性字體加粗,大小為25 * * @param */ private static void setRStyle(R r) { // 1.創建一個RPr RPr rpr = new RPr(); // 2.設置RPr // 2.1設置字體大小 HpsMeasure size = new HpsMeasure(); size.setVal(new BigInteger("25")); rpr.setSz(size); // 2.2設置加粗 BooleanDefaultTrue bold = new BooleanDefaultTrue(); bold.setVal(true); rpr.setB(bold); // 3.將RPr設置為R的屬性 r.setRPr(rpr); } /** * 設置邊框樣式 * * @param table * 需要設置表格邊框的單元格 */ private static void addBorders(Tbl table) { table.setTblPr(new TblPr());// 必須設置一個TblPr,否則最后會報空指針異常 CTBorder border = new CTBorder(); border.setColor("auto"); border.setSz(new BigInteger("4")); border.setSpace(new BigInteger("0")); border.setVal(STBorder.SINGLE); TblBorders borders = new TblBorders(); borders.setBottom(border); borders.setLeft(border); borders.setRight(border); borders.setTop(border); borders.setInsideH(border); borders.setInsideV(border); // 獲取其內部的TblPr屬性設置屬性 table.getTblPr().setTblBorders(borders); }
結果:
工具欄:
package cn.qlq.docx4j; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.StringWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBElement; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.docx4j.TextUtils; import org.docx4j.XmlUtils; import org.docx4j.dml.wordprocessingDrawing.Inline; import org.docx4j.model.properties.table.tr.TrHeight; import org.docx4j.openpackaging.packages.OpcPackage; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.openpackaging.parts.relationships.Namespaces; import org.docx4j.wml.BooleanDefaultTrue; import org.docx4j.wml.Br; import org.docx4j.wml.CTBackground; import org.docx4j.wml.CTBorder; import org.docx4j.wml.CTEm; import org.docx4j.wml.CTHeight; import org.docx4j.wml.CTLineNumber; import org.docx4j.wml.CTShd; import org.docx4j.wml.CTSignedHpsMeasure; import org.docx4j.wml.CTSignedTwipsMeasure; import org.docx4j.wml.CTTblCellMar; import org.docx4j.wml.CTTextScale; import org.docx4j.wml.CTVerticalAlignRun; import org.docx4j.wml.CTVerticalJc; import org.docx4j.wml.Color; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Drawing; import org.docx4j.wml.Highlight; import org.docx4j.wml.HpsMeasure; import org.docx4j.wml.Jc; import org.docx4j.wml.JcEnumeration; import org.docx4j.wml.ObjectFactory; import org.docx4j.wml.P; import org.docx4j.wml.P.Hyperlink; import org.docx4j.wml.PPr; import org.docx4j.wml.PPrBase.Ind; import org.docx4j.wml.PPrBase.PBdr; import org.docx4j.wml.PPrBase.Spacing; import org.docx4j.wml.ParaRPr; import org.docx4j.wml.R; import org.docx4j.wml.RFonts; import org.docx4j.wml.RPr; import org.docx4j.wml.STBorder; import org.docx4j.wml.STBrType; import org.docx4j.wml.STEm; import org.docx4j.wml.STLineNumberRestart; import org.docx4j.wml.STLineSpacingRule; import org.docx4j.wml.STPageOrientation; import org.docx4j.wml.STShd; import org.docx4j.wml.STVerticalAlignRun; import org.docx4j.wml.STVerticalJc; import org.docx4j.wml.SectPr; import org.docx4j.wml.SectPr.PgBorders; import org.docx4j.wml.SectPr.PgMar; import org.docx4j.wml.SectPr.PgSz; import org.docx4j.wml.SectPr.Type; import org.docx4j.wml.Tbl; import org.docx4j.wml.TblBorders; import org.docx4j.wml.TblGrid; import org.docx4j.wml.TblGridCol; import org.docx4j.wml.TblPr; import org.docx4j.wml.TblWidth; import org.docx4j.wml.Tc; import org.docx4j.wml.TcPr; import org.docx4j.wml.TcPrInner.GridSpan; import org.docx4j.wml.TcPrInner.HMerge; import org.docx4j.wml.TcPrInner.VMerge; import org.docx4j.wml.Text; import org.docx4j.wml.TextDirection; import org.docx4j.wml.Tr; import org.docx4j.wml.TrPr; import org.docx4j.wml.U; import org.docx4j.wml.UnderlineEnumeration; public class Docx4jUtil { /*------------------------------------other--------------------------------------------------- */ /** * @Description:新增超鏈接 */ public static void createHyperlink(WordprocessingMLPackage wordMLPackage, MainDocumentPart mainPart, ObjectFactory factory, P paragraph, String url, String value, String cnFontName, String enFontName, String fontSize) throws Exception { if (StringUtils.isBlank(enFontName)) { enFontName = "Times New Roman"; } if (StringUtils.isBlank(cnFontName)) { cnFontName = "微軟雅黑"; } if (StringUtils.isBlank(fontSize)) { fontSize = "22"; } org.docx4j.relationships.ObjectFactory reFactory = new org.docx4j.relationships.ObjectFactory(); org.docx4j.relationships.Relationship rel = reFactory.createRelationship(); rel.setType(Namespaces.HYPERLINK); rel.setTarget(url); rel.setTargetMode("External"); mainPart.getRelationshipsPart().addRelationship(rel); StringBuffer sb = new StringBuffer(); // addRelationship sets the rel's @Id sb.append("<w:hyperlink r:id=\""); sb.append(rel.getId()); sb.append("\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "); sb.append("xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" >"); sb.append("<w:r><w:rPr><w:rStyle w:val=\"Hyperlink\" />"); sb.append("<w:rFonts w:ascii=\""); sb.append(enFontName); sb.append("\" w:hAnsi=\""); sb.append(enFontName); sb.append("\" w:eastAsia=\""); sb.append(cnFontName); sb.append("\" w:hint=\"eastAsia\"/>"); sb.append("<w:sz w:val=\""); sb.append(fontSize); sb.append("\"/><w:szCs w:val=\""); sb.append(fontSize); sb.append("\"/></w:rPr><w:t>"); sb.append(value); sb.append("</w:t></w:r></w:hyperlink>"); Hyperlink link = (Hyperlink) XmlUtils.unmarshalString(sb.toString()); paragraph.getContent().add(link); } public static String getElementContent(Object obj) throws Exception { StringWriter stringWriter = new StringWriter(); TextUtils.extractText(obj, stringWriter); return stringWriter.toString(); } /** * @Description:得到指定類型的元素 */ public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) { List<Object> result = new ArrayList<Object>(); if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue(); if (obj.getClass().equals(toSearch)) result.add(obj); else if (obj instanceof ContentAccessor) { List<?> children = ((ContentAccessor) obj).getContent(); for (Object child : children) { result.addAll(getAllElementFromObject(child, toSearch)); } } return result; } /** * @Description:保存WordprocessingMLPackage */ public static void saveWordPackage(WordprocessingMLPackage wordPackage, File file) throws Exception { wordPackage.save(file); } /** * @Description:新建WordprocessingMLPackage */ public static WordprocessingMLPackage createWordprocessingMLPackage() throws Exception { return WordprocessingMLPackage.createPackage(); } /** * @Description:加載帶密碼WordprocessingMLPackage */ public static WordprocessingMLPackage loadWordprocessingMLPackageWithPwd(String filePath, String password) throws Exception { OpcPackage opcPackage = WordprocessingMLPackage.load(new java.io.File(filePath), password); WordprocessingMLPackage wordMLPackage = (WordprocessingMLPackage) opcPackage; return wordMLPackage; } /** * @Description:加載WordprocessingMLPackage */ public static WordprocessingMLPackage loadWordprocessingMLPackage(String filePath) throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(filePath)); return wordMLPackage; } /*------------------------------------Word 表格相關--------------------------------------------------- */ /** * @Description: 跨列合並 */ public static void mergeCellsHorizontalByGridSpan(Tbl tbl, int row, int fromCell, int toCell) { if (row < 0 || fromCell < 0 || toCell < 0) { return; } List<Tr> trList = getTblAllTr(tbl); if (row > trList.size()) { return; } Tr tr = trList.get(row); List<Tc> tcList = getTrAllCell(tr); for (int cellIndex = Math.min(tcList.size() - 1, toCell); cellIndex >= fromCell; cellIndex--) { Tc tc = tcList.get(cellIndex); TcPr tcPr = getTcPr(tc); if (cellIndex == fromCell) { GridSpan gridSpan = tcPr.getGridSpan(); if (gridSpan == null) { gridSpan = new GridSpan(); tcPr.setGridSpan(gridSpan); } gridSpan.setVal(BigInteger.valueOf(Math.min(tcList.size() - 1, toCell) - fromCell + 1)); } else { tr.getContent().remove(cellIndex); } } } /** * @Description: 跨列合並 */ public static void mergeCellsHorizontal(Tbl tbl, int row, int fromCell, int toCell) { if (row < 0 || fromCell < 0 || toCell < 0) { return; } List<Tr> trList = getTblAllTr(tbl); if (row > trList.size()) { return; } Tr tr = trList.get(row); List<Tc> tcList = getTrAllCell(tr); for (int cellIndex = fromCell, len = Math.min(tcList.size() - 1, toCell); cellIndex <= len; cellIndex++) { Tc tc = tcList.get(cellIndex); TcPr tcPr = getTcPr(tc); HMerge hMerge = tcPr.getHMerge(); if (hMerge == null) { hMerge = new HMerge(); tcPr.setHMerge(hMerge); } if (cellIndex == fromCell) { hMerge.setVal("restart"); } else { hMerge.setVal("continue"); } } } /** * @Description: 跨行合並 */ public static void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) { if (col < 0 || fromRow < 0 || toRow < 0) { return; } for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { Tc tc = getTc(tbl, rowIndex, col); if (tc == null) { break; } TcPr tcPr = getTcPr(tc); VMerge vMerge = tcPr.getVMerge(); if (vMerge == null) { vMerge = new VMerge(); tcPr.setVMerge(vMerge); } if (rowIndex == fromRow) { vMerge.setVal("restart"); } else { vMerge.setVal("continue"); } } } /** * @Description:得到指定位置的單元格 */ public static Tc getTc(Tbl tbl, int row, int cell) { if (row < 0 || cell < 0) { return null; } List<Tr> trList = getTblAllTr(tbl); if (row >= trList.size()) { return null; } List<Tc> tcList = getTrAllCell(trList.get(row)); if (cell >= tcList.size()) { return null; } return tcList.get(cell); } /** * @Description:得到所有表格 */ public static List<Tbl> getAllTbl(WordprocessingMLPackage wordMLPackage) { MainDocumentPart mainDocPart = wordMLPackage.getMainDocumentPart(); List<Object> objList = getAllElementFromObject(mainDocPart, Tbl.class); if (objList == null) { return null; } List<Tbl> tblList = new ArrayList<Tbl>(); for (Object obj : objList) { if (obj instanceof Tbl) { Tbl tbl = (Tbl) obj; tblList.add(tbl); } } return tblList; } /** * @Description:刪除指定位置的表格,刪除后表格數量減一 */ public static boolean removeTableByIndex(WordprocessingMLPackage wordMLPackage, int index) throws Exception { boolean flag = false; if (index < 0) { return flag; } List<Object> objList = wordMLPackage.getMainDocumentPart().getContent(); if (objList == null) { return flag; } int k = -1; for (int i = 0, len = objList.size(); i < len; i++) { Object obj = XmlUtils.unwrap(objList.get(i)); if (obj instanceof Tbl) { k++; if (k == index) { wordMLPackage.getMainDocumentPart().getContent().remove(i); flag = true; break; } } } return flag; } /** * @Description: 獲取單元格內容,無分割符 */ public static String getTblContentStr(Tbl tbl) throws Exception { return getElementContent(tbl); } /** * @Description: 獲取表格內容 */ public static List<String> getTblContentList(Tbl tbl) throws Exception { List<String> resultList = new ArrayList<String>(); List<Tr> trList = getTblAllTr(tbl); for (Tr tr : trList) { StringBuffer sb = new StringBuffer(); List<Tc> tcList = getTrAllCell(tr); for (Tc tc : tcList) { sb.append(getElementContent(tc) + ","); } resultList.add(sb.toString()); } return resultList; } public static TblPr getTblPr(Tbl tbl) { TblPr tblPr = tbl.getTblPr(); if (tblPr == null) { tblPr = new TblPr(); tbl.setTblPr(tblPr); } return tblPr; } /** * @Description: 設置表格總寬度 */ public static void setTableWidth(Tbl tbl, String width) { if (StringUtils.isNotBlank(width)) { TblPr tblPr = getTblPr(tbl); TblWidth tblW = tblPr.getTblW(); if (tblW == null) { tblW = new TblWidth(); tblPr.setTblW(tblW); } tblW.setW(new BigInteger(width)); tblW.setType("dxa"); } } /** * @Description:創建表格(默認水平居中,垂直居中) */ public static Tbl createTable(WordprocessingMLPackage wordPackage, int rowNum, int colsNum) throws Exception { colsNum = Math.max(1, colsNum); rowNum = Math.max(1, rowNum); int widthTwips = getWritableWidth(wordPackage); int colWidth = widthTwips / colsNum; int[] widthArr = new int[colsNum]; for (int i = 0; i < colsNum; i++) { widthArr[i] = colWidth; } return createTable(rowNum, colsNum, widthArr); } /** * @Description:創建表格(默認水平居中,垂直居中) */ public static Tbl createTable(int rowNum, int colsNum, int[] widthArr) throws Exception { colsNum = Math.max(1, Math.min(colsNum, widthArr.length)); rowNum = Math.max(1, rowNum); Tbl tbl = new Tbl(); StringBuffer tblSb = new StringBuffer(); tblSb.append("<w:tblPr ").append(Namespaces.W_NAMESPACE_DECLARATION).append(">"); tblSb.append("<w:tblStyle w:val=\"TableGrid\"/>"); tblSb.append("<w:tblW w:w=\"0\" w:type=\"auto\"/>"); // 上邊框 tblSb.append("<w:tblBorders>"); tblSb.append("<w:top w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); // 左邊框 tblSb.append("<w:left w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); // 下邊框 tblSb.append("<w:bottom w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); // 右邊框 tblSb.append("<w:right w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); tblSb.append("<w:insideH w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); tblSb.append("<w:insideV w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>"); tblSb.append("</w:tblBorders>"); tblSb.append("</w:tblPr>"); TblPr tblPr = null; tblPr = (TblPr) XmlUtils.unmarshalString(tblSb.toString()); Jc jc = new Jc(); // 單元格居中對齊 jc.setVal(JcEnumeration.CENTER); tblPr.setJc(jc); tbl.setTblPr(tblPr); // 設定各單元格寬度 TblGrid tblGrid = new TblGrid(); tbl.setTblGrid(tblGrid); for (int i = 0; i < colsNum; i++) { TblGridCol gridCol = new TblGridCol(); gridCol.setW(BigInteger.valueOf(widthArr[i])); tblGrid.getGridCol().add(gridCol); } // 新增行 for (int j = 0; j < rowNum; j++) { Tr tr = new Tr(); tbl.getContent().add(tr); // 列 for (int i = 0; i < colsNum; i++) { Tc tc = new Tc(); tr.getContent().add(tc); TcPr tcPr = new TcPr(); TblWidth cellWidth = new TblWidth(); cellWidth.setType("dxa"); cellWidth.setW(BigInteger.valueOf(widthArr[i])); tcPr.setTcW(cellWidth); tc.setTcPr(tcPr); // 垂直居中 setTcVAlign(tc, STVerticalJc.CENTER); P p = new P(); PPr pPr = new PPr(); pPr.setJc(jc); p.setPPr(pPr); R run = new R(); p.getContent().add(run); tc.getContent().add(p); } } return tbl; } /** * @Description:表格增加邊框 可以設置上下左右四個邊框樣式以及橫豎水平線樣式 */ public static void setTblBorders(TblPr tblPr, CTBorder topBorder, CTBorder rightBorder, CTBorder bottomBorder, CTBorder leftBorder, CTBorder hBorder, CTBorder vBorder) { TblBorders borders = tblPr.getTblBorders(); if (borders == null) { borders = new TblBorders(); tblPr.setTblBorders(borders); } if (topBorder != null) { borders.setTop(topBorder); } if (rightBorder != null) { borders.setRight(rightBorder); } if (bottomBorder != null) { borders.setBottom(bottomBorder); } if (leftBorder != null) { borders.setLeft(leftBorder); } if (hBorder != null) { borders.setInsideH(hBorder); } if (vBorder != null) { borders.setInsideV(vBorder); } } /** * @Description: 設置表格水平對齊方式(僅對表格起作用,單元格不一定水平對齊) */ public static void setTblJcAlign(Tbl tbl, JcEnumeration jcType) { if (jcType != null) { TblPr tblPr = getTblPr(tbl); Jc jc = tblPr.getJc(); if (jc == null) { jc = new Jc(); tblPr.setJc(jc); } jc.setVal(jcType); } } /** * @Description: 設置表格水平對齊方式(包括單元格),只對該方法前面產生的單元格起作用 */ public static void setTblAllJcAlign(Tbl tbl, JcEnumeration jcType) { if (jcType != null) { setTblJcAlign(tbl, jcType); List<Tr> trList = getTblAllTr(tbl); for (Tr tr : trList) { List<Tc> tcList = getTrAllCell(tr); for (Tc tc : tcList) { setTcJcAlign(tc, jcType); } } } } /** * @Description: 設置表格垂直對齊方式(包括單元格),只對該方法前面產生的單元格起作用 */ public static void setTblAllVAlign(Tbl tbl, STVerticalJc vAlignType) { if (vAlignType != null) { List<Tr> trList = getTblAllTr(tbl); for (Tr tr : trList) { List<Tc> tcList = getTrAllCell(tr); for (Tc tc : tcList) { setTcVAlign(tc, vAlignType); } } } } /** * @Description: 設置單元格Margin */ public static void setTableCellMargin(Tbl tbl, String top, String right, String bottom, String left) { TblPr tblPr = getTblPr(tbl); CTTblCellMar cellMar = tblPr.getTblCellMar(); if (cellMar == null) { cellMar = new CTTblCellMar(); tblPr.setTblCellMar(cellMar); } if (StringUtils.isNotBlank(top)) { TblWidth topW = new TblWidth(); topW.setW(new BigInteger(top)); topW.setType("dxa"); cellMar.setTop(topW); } if (StringUtils.isNotBlank(right)) { TblWidth rightW = new TblWidth(); rightW.setW(new BigInteger(right)); rightW.setType("dxa"); cellMar.setRight(rightW); } if (StringUtils.isNotBlank(bottom)) { TblWidth btW = new TblWidth(); btW.setW(new BigInteger(bottom)); btW.setType("dxa"); cellMar.setBottom(btW); } if (StringUtils.isNotBlank(left)) { TblWidth leftW = new TblWidth(); leftW.setW(new BigInteger(left)); leftW.setType("dxa"); cellMar.setLeft(leftW); } } /** * @Description: 得到表格所有的行 */ public static List<Tr> getTblAllTr(Tbl tbl) { List<Object> objList = getAllElementFromObject(tbl, Tr.class); List<Tr> trList = new ArrayList<Tr>(); if (objList == null) { return trList; } for (Object obj : objList) { if (obj instanceof Tr) { Tr tr = (Tr) obj; trList.add(tr); } } return trList; } /** * @Description:設置tr高度 */ public static void setTrHeight(Tr tr, String heigth) { TrPr trPr = getTrPr(tr); CTHeight ctHeight = new CTHeight(); ctHeight.setVal(new BigInteger(heigth)); TrHeight trHeight = new TrHeight(ctHeight); trHeight.set(trPr); } /** * @Description: 在表格指定位置新增一行,默認居中 */ public static void addTrByIndex(Tbl tbl, int index) { addTrByIndex(tbl, index, STVerticalJc.CENTER, JcEnumeration.CENTER); } /** * @Description: 在表格指定位置新增一行(默認按表格定義的列數添加) */ public static void addTrByIndex(Tbl tbl, int index, STVerticalJc vAlign, JcEnumeration hAlign) { TblGrid tblGrid = tbl.getTblGrid(); Tr tr = new Tr(); if (tblGrid != null) { List<TblGridCol> gridList = tblGrid.getGridCol(); for (TblGridCol tblGridCol : gridList) { Tc tc = new Tc(); setTcWidth(tc, tblGridCol.getW().toString()); if (vAlign != null) { // 垂直居中 setTcVAlign(tc, vAlign); } P p = new P(); if (hAlign != null) { PPr pPr = new PPr(); Jc jc = new Jc(); // 單元格居中對齊 jc.setVal(hAlign); pPr.setJc(jc); p.setPPr(pPr); } R run = new R(); p.getContent().add(run); tc.getContent().add(p); tr.getContent().add(tc); } } else { // 大部分情況都不會走到這一步 Tr firstTr = getTblAllTr(tbl).get(0); int cellSize = getTcCellSizeWithMergeNum(firstTr); for (int i = 0; i < cellSize; i++) { Tc tc = new Tc(); if (vAlign != null) { // 垂直居中 setTcVAlign(tc, vAlign); } P p = new P(); if (hAlign != null) { PPr pPr = new PPr(); Jc jc = new Jc(); // 單元格居中對齊 jc.setVal(hAlign); pPr.setJc(jc); p.setPPr(pPr); } R run = new R(); p.getContent().add(run); tc.getContent().add(p); tr.getContent().add(tc); } } if (index >= 0 && index < tbl.getContent().size()) { tbl.getContent().add(index, tr); } else { tbl.getContent().add(tr); } } /** * @Description: 得到行的列數 */ public static int getTcCellSizeWithMergeNum(Tr tr) { int cellSize = 1; List<Tc> tcList = getTrAllCell(tr); if (tcList == null || tcList.size() == 0) { return cellSize; } cellSize = tcList.size(); for (Tc tc : tcList) { TcPr tcPr = getTcPr(tc); GridSpan gridSpan = tcPr.getGridSpan(); if (gridSpan != null) { cellSize += gridSpan.getVal().intValue() - 1; } } return cellSize; } /** * @Description: 刪除指定行 刪除后行數減一 */ public static boolean removeTrByIndex(Tbl tbl, int index) { boolean flag = false; if (index < 0) { return flag; } List<Object> objList = tbl.getContent(); if (objList == null) { return flag; } int k = -1; for (int i = 0, len = objList.size(); i < len; i++) { Object obj = XmlUtils.unwrap(objList.get(i)); if (obj instanceof Tr) { k++; if (k == index) { tbl.getContent().remove(i); flag = true; break; } } } return flag; } public static TrPr getTrPr(Tr tr) { TrPr trPr = tr.getTrPr(); if (trPr == null) { trPr = new TrPr(); tr.setTrPr(trPr); } return trPr; } /** * @Description:隱藏行(只對表格中間的部分起作用,不包括首尾行) */ public static void setTrHidden(Tr tr, boolean hidden) { List<Tc> tcList = getTrAllCell(tr); for (Tc tc : tcList) { setTcHidden(tc, hidden); } } /** * @Description: 設置單元格寬度 */ public static void setTcWidth(Tc tc, String width) { if (StringUtils.isNotBlank(width)) { TcPr tcPr = getTcPr(tc); TblWidth tcW = tcPr.getTcW(); if (tcW == null) { tcW = new TblWidth(); tcPr.setTcW(tcW); } tcW.setW(new BigInteger(width)); tcW.setType("dxa"); } } /** * @Description: 隱藏單元格內容 */ public static void setTcHidden(Tc tc, boolean hidden) { List<P> pList = getTcAllP(tc); for (P p : pList) { PPr ppr = getPPr(p); List<Object> objRList = getAllElementFromObject(p, R.class); if (objRList == null) { continue; } for (Object objR : objRList) { if (objR instanceof R) { R r = (R) objR; RPr rpr = getRPr(r); setRPrVanishStyle(rpr, hidden); } } setParaVanish(ppr, hidden); } } public static List<P> getTcAllP(Tc tc) { List<Object> objList = getAllElementFromObject(tc, P.class); List<P> pList = new ArrayList<P>(); if (objList == null) { return pList; } for (Object obj : objList) { if (obj instanceof P) { P p = (P) obj; pList.add(p); } } return pList; } public static TcPr getTcPr(Tc tc) { TcPr tcPr = tc.getTcPr(); if (tcPr == null) { tcPr = new TcPr(); tc.setTcPr(tcPr); } return tcPr; } /** * @Description: 設置單元格垂直對齊方式 */ public static void setTcVAlign(Tc tc, STVerticalJc vAlignType) { if (vAlignType != null) { TcPr tcPr = getTcPr(tc); CTVerticalJc vAlign = new CTVerticalJc(); vAlign.setVal(vAlignType); tcPr.setVAlign(vAlign); } } /** * @Description: 設置單元格水平對齊方式 */ public static void setTcJcAlign(Tc tc, JcEnumeration jcType) { if (jcType != null) { List<P> pList = getTcAllP(tc); for (P p : pList) { setParaJcAlign(p, jcType); } } } public static RPr getRPr(R r) { RPr rpr = r.getRPr(); if (rpr == null) { rpr = new RPr(); r.setRPr(rpr); } return rpr; } /** * @Description: 獲取所有的單元格 */ public static List<Tc> getTrAllCell(Tr tr) { List<Object> objList = getAllElementFromObject(tr, Tc.class); List<Tc> tcList = new ArrayList<Tc>(); if (objList == null) { return tcList; } for (Object tcObj : objList) { if (tcObj instanceof Tc) { Tc objTc = (Tc) tcObj; tcList.add(objTc); } } return tcList; } /** * @Description: 獲取單元格內容 */ public static String getTcContent(Tc tc) throws Exception { return getElementContent(tc); } /** * @Description:設置單元格內容,content為null則清除單元格內容 */ public static void setTcContent(Tc tc, RPr rpr, String content) { List<Object> pList = tc.getContent(); P p = null; if (pList != null && pList.size() > 0) { if (pList.get(0) instanceof P) { p = (P) pList.get(0); } } else { p = new P(); tc.getContent().add(p); } R run = null; List<Object> rList = p.getContent(); if (rList != null && rList.size() > 0) { for (int i = 0, len = rList.size(); i < len; i++) { // 清除內容(所有的r p.getContent().remove(0); } } run = new R(); p.getContent().add(run); if (content != null) { String[] contentArr = content.split("\n"); Text text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[0]); run.setRPr(rpr); run.getContent().add(text); for (int i = 1, len = contentArr.length; i < len; i++) { Br br = new Br(); run.getContent().add(br);// 換行 text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[i]); run.setRPr(rpr); run.getContent().add(text); } } } /** * @Description:設置單元格內容,content為null則清除單元格內容 */ public static void removeTcContent(Tc tc) { List<Object> pList = tc.getContent(); P p = null; if (pList != null && pList.size() > 0) { if (pList.get(0) instanceof P) { p = (P) pList.get(0); } } else { return; } List<Object> rList = p.getContent(); if (rList != null && rList.size() > 0) { for (int i = 0, len = rList.size(); i < len; i++) { // 清除內容(所有的r p.getContent().remove(0); } } } /** * @Description:刪除指定位置的表格 * @deprecated */ public static void deleteTableByIndex2(WordprocessingMLPackage wordMLPackage, int index) throws Exception { if (index < 0) { return; } final String xpath = "(//w:tbl)[" + index + "]"; final List<Object> jaxbNodes = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath(xpath, true); if (jaxbNodes != null && jaxbNodes.size() > 0) { wordMLPackage.getMainDocumentPart().getContent().remove(jaxbNodes.get(0)); } } /** * @Description:獲取NodeList * @deprecated */ public static List<Object> getObjectByXpath(WordprocessingMLPackage wordMLPackage, String xpath) throws Exception { final List<Object> jaxbNodes = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath(xpath, true); return jaxbNodes; } /*------------------------------------Word 段落相關--------------------------------------------------- */ /** * @Description: 只刪除單獨的段落,不包括表格內或其他內的段落 */ public static boolean removeParaByIndex(WordprocessingMLPackage wordMLPackage, int index) { boolean flag = false; if (index < 0) { return flag; } List<Object> objList = wordMLPackage.getMainDocumentPart().getContent(); if (objList == null) { return flag; } int k = -1; for (int i = 0, len = objList.size(); i < len; i++) { if (objList.get(i) instanceof P) { k++; if (k == index) { wordMLPackage.getMainDocumentPart().getContent().remove(i); flag = true; break; } } } return flag; } /** * @Description: 設置段落水平對齊方式 */ public static void setParaJcAlign(P paragraph, JcEnumeration hAlign) { if (hAlign != null) { PPr pprop = paragraph.getPPr(); if (pprop == null) { pprop = new PPr(); paragraph.setPPr(pprop); } Jc align = new Jc(); align.setVal(hAlign); pprop.setJc(align); } } /** * @Description: 設置段落內容 */ public static void setParaRContent(P p, RPr runProperties, String content) { R run = null; List<Object> rList = p.getContent(); if (rList != null && rList.size() > 0) { for (int i = 0, len = rList.size(); i < len; i++) { // 清除內容(所有的r p.getContent().remove(0); } } run = new R(); p.getContent().add(run); if (content != null) { String[] contentArr = content.split("\n"); Text text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[0]); run.setRPr(runProperties); run.getContent().add(text); for (int i = 1, len = contentArr.length; i < len; i++) { Br br = new Br(); run.getContent().add(br);// 換行 text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[i]); run.setRPr(runProperties); run.getContent().add(text); } } } /** * @Description: 添加段落內容 */ public static void appendParaRContent(P p, RPr runProperties, String content) { if (content != null) { R run = new R(); p.getContent().add(run); String[] contentArr = content.split("\n"); Text text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[0]); run.setRPr(runProperties); run.getContent().add(text); for (int i = 1, len = contentArr.length; i < len; i++) { Br br = new Br(); run.getContent().add(br);// 換行 text = new Text(); text.setSpace("preserve"); text.setValue(contentArr[i]); run.setRPr(runProperties); run.getContent().add(text); } } } /** * @Description: 添加圖片到段落 */ public static void addImageToPara(WordprocessingMLPackage wordMLPackage, ObjectFactory factory, P paragraph, String filePath, String content, RPr rpr, String altText, int id1, int id2) throws Exception { R run = factory.createR(); if (content != null) { Text text = factory.createText(); text.setValue(content); text.setSpace("preserve"); run.setRPr(rpr); run.getContent().add(text); } InputStream is = new FileInputStream(filePath); byte[] bytes = IOUtils.toByteArray(is); BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes); Inline inline = imagePart.createImageInline(filePath, altText, id1, id2, false); Drawing drawing = factory.createDrawing(); drawing.getAnchorOrInline().add(inline); run.getContent().add(drawing); paragraph.getContent().add(run); } /** * @Description: 段落添加Br 頁面Break(分頁符) */ public static void addPageBreak(P para, STBrType sTBrType) { Br breakObj = new Br(); breakObj.setType(sTBrType); para.getContent().add(breakObj); } /** * @Description: 設置段落是否禁止行號(禁止用於當前行號) */ public static void setParagraphSuppressLineNum(P p) { PPr ppr = getPPr(p); BooleanDefaultTrue line = ppr.getSuppressLineNumbers(); if (line == null) { line = new BooleanDefaultTrue(); } line.setVal(true); ppr.setSuppressLineNumbers(line); } /** * @Description: 設置段落底紋(對整段文字起作用) */ public static void setParagraphShdStyle(P p, STShd shdType, String shdColor) { PPr ppr = getPPr(p); CTShd ctShd = ppr.getShd(); if (ctShd == null) { ctShd = new CTShd(); } if (StringUtils.isNotBlank(shdColor)) { ctShd.setColor(shdColor); } if (shdType != null) { ctShd.setVal(shdType); } ppr.setShd(ctShd); } /** * @param isSpace * 是否設置段前段后值 * @param before * 段前磅數 * @param after * 段后磅數 * @param beforeLines * 段前行數 * @param afterLines * 段后行數 * @param isLine * 是否設置行距 * @param lineValue * 行距值 * @param sTLineSpacingRule * 自動auto 固定exact 最小 atLeast 1磅=20 1行=100 單倍行距=240 */ public static void setParagraphSpacing(P p, boolean isSpace, String before, String after, String beforeLines, String afterLines, boolean isLine, String lineValue, STLineSpacingRule sTLineSpacingRule) { PPr pPr = getPPr(p); Spacing spacing = pPr.getSpacing(); if (spacing == null) { spacing = new Spacing(); pPr.setSpacing(spacing); } if (isSpace) { if (StringUtils.isNotBlank(before)) { // 段前磅數 spacing.setBefore(new BigInteger(before)); } if (StringUtils.isNotBlank(after)) { // 段后磅數 spacing.setAfter(new BigInteger(after)); } if (StringUtils.isNotBlank(beforeLines)) { // 段前行數 spacing.setBeforeLines(new BigInteger(beforeLines)); } if (StringUtils.isNotBlank(afterLines)) { // 段后行數 spacing.setAfterLines(new BigInteger(afterLines)); } } if (isLine) { if (StringUtils.isNotBlank(lineValue)) { spacing.setLine(new BigInteger(lineValue)); } if (sTLineSpacingRule != null) { spacing.setLineRule(sTLineSpacingRule); } } } /** * @Description: 設置段落縮進信息 1厘米≈567 */ public static void setParagraphIndInfo(P p, String firstLine, String firstLineChar, String hanging, String hangingChar, String right, String rigthChar, String left, String leftChar) { PPr ppr = getPPr(p); Ind ind = ppr.getInd(); if (ind == null) { ind = new Ind(); ppr.setInd(ind); } if (StringUtils.isNotBlank(firstLine)) { ind.setFirstLine(new BigInteger(firstLine)); } if (StringUtils.isNotBlank(firstLineChar)) { ind.setFirstLineChars(new BigInteger(firstLineChar)); } if (StringUtils.isNotBlank(hanging)) { ind.setHanging(new BigInteger(hanging)); } if (StringUtils.isNotBlank(hangingChar)) { ind.setHangingChars(new BigInteger(hangingChar)); } if (StringUtils.isNotBlank(left)) { ind.setLeft(new BigInteger(left)); } if (StringUtils.isNotBlank(leftChar)) { ind.setLeftChars(new BigInteger(leftChar)); } if (StringUtils.isNotBlank(right)) { ind.setRight(new BigInteger(right)); } if (StringUtils.isNotBlank(rigthChar)) { ind.setRightChars(new BigInteger(rigthChar)); } } public static PPr getPPr(P p) { PPr ppr = p.getPPr(); if (ppr == null) { ppr = new PPr(); p.setPPr(ppr); } return ppr; } public static ParaRPr getParaRPr(PPr ppr) { ParaRPr parRpr = ppr.getRPr(); if (parRpr == null) { parRpr = new ParaRPr(); ppr.setRPr(parRpr); } return parRpr; } public static void setParaVanish(PPr ppr, boolean isVanish) { ParaRPr parRpr = getParaRPr(ppr); BooleanDefaultTrue vanish = parRpr.getVanish(); if (vanish != null) { vanish.setVal(isVanish); } else { vanish = new BooleanDefaultTrue(); parRpr.setVanish(vanish); vanish.setVal(isVanish); } } /** * @Description: 設置段落邊框樣式 */ public static void setParagraghBorders(P p, CTBorder topBorder, CTBorder bottomBorder, CTBorder leftBorder, CTBorder rightBorder) { PPr ppr = getPPr(p); PBdr pBdr = new PBdr(); if (topBorder != null) { pBdr.setTop(topBorder); } if (bottomBorder != null) { pBdr.setBottom(bottomBorder); } if (leftBorder != null) { pBdr.setLeft(leftBorder); } if (rightBorder != null) { pBdr.setRight(rightBorder); } ppr.setPBdr(pBdr); } /** * @Description: 設置字體信息 */ public static void setFontStyle(RPr runProperties, String cnFontFamily, String enFontFamily, String fontSize, String color) { setFontFamily(runProperties, cnFontFamily, enFontFamily); setFontSize(runProperties, fontSize); setFontColor(runProperties, color); } /** * @Description: 設置字體大小 */ public static void setFontSize(RPr runProperties, String fontSize) { if (StringUtils.isNotBlank(fontSize)) { HpsMeasure size = new HpsMeasure(); size.setVal(new BigInteger(fontSize)); runProperties.setSz(size); runProperties.setSzCs(size); } } /** * @Description: 設置字體 */ public static void setFontFamily(RPr runProperties, String cnFontFamily, String enFontFamily) { if (StringUtils.isNotBlank(cnFontFamily) || StringUtils.isNotBlank(enFontFamily)) { RFonts rf = runProperties.getRFonts(); if (rf == null) { rf = new RFonts(); runProperties.setRFonts(rf); } if (cnFontFamily != null) { rf.setEastAsia(cnFontFamily); } if (enFontFamily != null) { rf.setAscii(enFontFamily); } } } /** * @Description: 設置字體顏色 */ public static void setFontColor(RPr runProperties, String color) { if (color != null) { Color c = new Color(); c.setVal(color); runProperties.setColor(c); } } /** * @Description: 設置字符邊框 */ public static void addRPrBorderStyle(RPr runProperties, String size, STBorder bordType, String space, String color) { CTBorder value = new CTBorder(); if (StringUtils.isNotBlank(color)) { value.setColor(color); } if (StringUtils.isNotBlank(size)) { value.setSz(new BigInteger(size)); } if (StringUtils.isNotBlank(space)) { value.setSpace(new BigInteger(space)); } if (bordType != null) { value.setVal(bordType); } runProperties.setBdr(value); } /** * @Description:着重號 */ public static void addRPrEmStyle(RPr runProperties, STEm emType) { if (emType != null) { CTEm em = new CTEm(); em.setVal(emType); runProperties.setEm(em); } } /** * @Description: 空心 */ public static void addRPrOutlineStyle(RPr runProperties) { BooleanDefaultTrue outline = new BooleanDefaultTrue(); outline.setVal(true); runProperties.setOutline(outline); } /** * @Description: 設置上標下標 */ public static void addRPrcaleStyle(RPr runProperties, STVerticalAlignRun vAlign) { if (vAlign != null) { CTVerticalAlignRun value = new CTVerticalAlignRun(); value.setVal(vAlign); runProperties.setVertAlign(value); } } /** * @Description: 設置字符間距縮進 */ public static void addRPrScaleStyle(RPr runProperties, int indent) { CTTextScale value = new CTTextScale(); value.setVal(indent); runProperties.setW(value); } /** * @Description: 設置字符間距信息 */ public static void addRPrtSpacingStyle(RPr runProperties, int spacing) { CTSignedTwipsMeasure value = new CTSignedTwipsMeasure(); value.setVal(BigInteger.valueOf(spacing)); runProperties.setSpacing(value); } /** * @Description: 設置文本位置 */ public static void addRPrtPositionStyle(RPr runProperties, int position) { CTSignedHpsMeasure ctPosition = new CTSignedHpsMeasure(); ctPosition.setVal(BigInteger.valueOf(position)); runProperties.setPosition(ctPosition); } /** * @Description: 陰文 */ public static void addRPrImprintStyle(RPr runProperties) { BooleanDefaultTrue imprint = new BooleanDefaultTrue(); imprint.setVal(true); runProperties.setImprint(imprint); } /** * @Description: 陽文 */ public static void addRPrEmbossStyle(RPr runProperties) { BooleanDefaultTrue emboss = new BooleanDefaultTrue(); emboss.setVal(true); runProperties.setEmboss(emboss); } /** * @Description: 設置隱藏 */ public static void setRPrVanishStyle(RPr runProperties, boolean isVanish) { BooleanDefaultTrue vanish = runProperties.getVanish(); if (vanish != null) { vanish.setVal(isVanish); } else { vanish = new BooleanDefaultTrue(); vanish.setVal(isVanish); runProperties.setVanish(vanish); } } /** * @Description: 設置陰影 */ public static void addRPrShadowStyle(RPr runProperties) { BooleanDefaultTrue shadow = new BooleanDefaultTrue(); shadow.setVal(true); runProperties.setShadow(shadow); } /** * @Description: 設置底紋 */ public static void addRPrShdStyle(RPr runProperties, STShd shdtype) { if (shdtype != null) { CTShd shd = new CTShd(); shd.setVal(shdtype); runProperties.setShd(shd); } } /** * @Description: 設置突出顯示文本 */ public static void addRPrHightLightStyle(RPr runProperties, String hightlight) { if (StringUtils.isNotBlank(hightlight)) { Highlight highlight = new Highlight(); highlight.setVal(hightlight); runProperties.setHighlight(highlight); } } /** * @Description: 設置刪除線樣式 */ public static void addRPrStrikeStyle(RPr runProperties, boolean isStrike, boolean isDStrike) { // 刪除線 if (isStrike) { BooleanDefaultTrue strike = new BooleanDefaultTrue(); strike.setVal(true); runProperties.setStrike(strike); } // 雙刪除線 if (isDStrike) { BooleanDefaultTrue dStrike = new BooleanDefaultTrue(); dStrike.setVal(true); runProperties.setDstrike(dStrike); } } /** * @Description: 加粗 */ public static void addRPrBoldStyle(RPr runProperties) { BooleanDefaultTrue b = new BooleanDefaultTrue(); b.setVal(true); runProperties.setB(b); } /** * @Description: 傾斜 */ public static void addRPrItalicStyle(RPr runProperties) { BooleanDefaultTrue b = new BooleanDefaultTrue(); b.setVal(true); runProperties.setI(b); } /** * @Description: 添加下划線 */ public static void addRPrUnderlineStyle(RPr runProperties, UnderlineEnumeration enumType) { U val = new U(); val.setVal(enumType); runProperties.setU(val); } /*------------------------------------Word 相關--------------------------------------------------- */ /** * @Description: 設置分節符 nextPage:下一頁 continuous:連續 evenPage:偶數頁 oddPage:奇數頁 */ public static void setDocSectionBreak(WordprocessingMLPackage wordPackage, String sectValType) { if (StringUtils.isNotBlank(sectValType)) { SectPr sectPr = getDocSectPr(wordPackage); Type sectType = sectPr.getType(); if (sectType == null) { sectType = new Type(); sectPr.setType(sectType); } sectType.setVal(sectValType); } } /** * @Description: 設置頁面背景色 */ public static void setDocumentBackGround(WordprocessingMLPackage wordPackage, ObjectFactory factory, String color) throws Exception { MainDocumentPart mdp = wordPackage.getMainDocumentPart(); CTBackground bkground = mdp.getContents().getBackground(); if (StringUtils.isNotBlank(color)) { if (bkground == null) { bkground = factory.createCTBackground(); bkground.setColor(color); } mdp.getContents().setBackground(bkground); } } /** * @Description: 設置頁面邊框 */ public static void setDocumentBorders(WordprocessingMLPackage wordPackage, ObjectFactory factory, CTBorder top, CTBorder right, CTBorder bottom, CTBorder left) { SectPr sectPr = getDocSectPr(wordPackage); PgBorders pgBorders = sectPr.getPgBorders(); if (pgBorders == null) { pgBorders = factory.createSectPrPgBorders(); sectPr.setPgBorders(pgBorders); } if (top != null) { pgBorders.setTop(top); } if (right != null) { pgBorders.setRight(right); } if (bottom != null) { pgBorders.setBottom(bottom); } if (left != null) { pgBorders.setLeft(left); } } /** * @Description: 設置頁面大小及紙張方向 landscape橫向 */ public static void setDocumentSize(WordprocessingMLPackage wordPackage, ObjectFactory factory, String width, String height, STPageOrientation stValue) { SectPr sectPr = getDocSectPr(wordPackage); PgSz pgSz = sectPr.getPgSz(); if (pgSz == null) { pgSz = factory.createSectPrPgSz(); sectPr.setPgSz(pgSz); } if (StringUtils.isNotBlank(width)) { pgSz.setW(new BigInteger(width)); } if (StringUtils.isNotBlank(height)) { pgSz.setH(new BigInteger(height)); } if (stValue != null) { pgSz.setOrient(stValue); } } public static SectPr getDocSectPr(WordprocessingMLPackage wordPackage) { SectPr sectPr = wordPackage.getDocumentModel().getSections().get(0).getSectPr(); return sectPr; } /** * @Description:設置頁邊距 */ public static void setDocMarginSpace(WordprocessingMLPackage wordPackage, ObjectFactory factory, String top, String left, String bottom, String right) { SectPr sectPr = getDocSectPr(wordPackage); PgMar pg = sectPr.getPgMar(); if (pg == null) { pg = factory.createSectPrPgMar(); sectPr.setPgMar(pg); } if (StringUtils.isNotBlank(top)) { pg.setTop(new BigInteger(top)); } if (StringUtils.isNotBlank(bottom)) { pg.setBottom(new BigInteger(bottom)); } if (StringUtils.isNotBlank(left)) { pg.setLeft(new BigInteger(left)); } if (StringUtils.isNotBlank(right)) { pg.setRight(new BigInteger(right)); } } /** * @Description: 設置行號 * @param distance * :距正文距離 1厘米=567 * @param start * :起始編號(0開始) * @param countBy * :行號間隔 * @param restartType * :STLineNumberRestart.CONTINUOUS(continuous連續編號)<br/> * STLineNumberRestart.NEW_PAGE(每頁重新編號)<br/> * STLineNumberRestart.NEW_SECTION(每節重新編號) */ public static void setDocInNumType(WordprocessingMLPackage wordPackage, String countBy, String distance, String start, STLineNumberRestart restartType) { SectPr sectPr = getDocSectPr(wordPackage); CTLineNumber lnNumType = sectPr.getLnNumType(); if (lnNumType == null) { lnNumType = new CTLineNumber(); sectPr.setLnNumType(lnNumType); } if (StringUtils.isNotBlank(countBy)) { lnNumType.setCountBy(new BigInteger(countBy)); } if (StringUtils.isNotBlank(distance)) { lnNumType.setDistance(new BigInteger(distance)); } if (StringUtils.isNotBlank(start)) { lnNumType.setStart(new BigInteger(start)); } if (restartType != null) { lnNumType.setRestart(restartType); } } /** * @Description:設置文字方向 tbRl 垂直 */ public static void setDocTextDirection(WordprocessingMLPackage wordPackage, String textDirection) { if (StringUtils.isNotBlank(textDirection)) { SectPr sectPr = getDocSectPr(wordPackage); TextDirection textDir = sectPr.getTextDirection(); if (textDir == null) { textDir = new TextDirection(); sectPr.setTextDirection(textDir); } textDir.setVal(textDirection); } } /** * @Description:設置word 垂直對齊方式(Word默認方式都是"頂端對齊") */ public static void setDocVAlign(WordprocessingMLPackage wordPackage, STVerticalJc valignType) { if (valignType != null) { SectPr sectPr = getDocSectPr(wordPackage); CTVerticalJc valign = sectPr.getVAlign(); if (valign == null) { valign = new CTVerticalJc(); sectPr.setVAlign(valign); } valign.setVal(valignType); } } /** * @Description:獲取文檔的可用寬度 */ public static int getWritableWidth(WordprocessingMLPackage wordPackage) throws Exception { return wordPackage.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips(); } }