XWPFHelper.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. package platform.common.util.word;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.OutputStream;
  8. import java.math.BigInteger;
  9. import java.util.List;
  10. import java.util.logging.Level;
  11. import java.util.logging.Logger;
  12. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  13. import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
  14. import org.apache.poi.xwpf.usermodel.TextAlignment;
  15. import org.apache.poi.xwpf.usermodel.XWPFDocument;
  16. import org.apache.poi.xwpf.usermodel.XWPFParagraph;
  17. import org.apache.poi.xwpf.usermodel.XWPFPicture;
  18. import org.apache.poi.xwpf.usermodel.XWPFPictureData;
  19. import org.apache.poi.xwpf.usermodel.XWPFRelation;
  20. import org.apache.poi.xwpf.usermodel.XWPFRun;
  21. import org.apache.poi.xwpf.usermodel.XWPFTable;
  22. import org.apache.poi.xwpf.usermodel.XWPFTableCell;
  23. import org.apache.poi.xwpf.usermodel.XWPFTableRow;
  24. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
  25. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
  26. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
  27. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
  28. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
  29. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
  30. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing;
  31. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
  32. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule;
  33. import javax.servlet.http.HttpServletResponse;
  34. /**
  35. * @Description 设置docx文档的样式及一些操作
  36. * @Author Huangxiaocong
  37. * 2018年12月1日 下午12:18:41
  38. * 基本概念说明:XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档
  39. * XWPFParagraph代表文档、表格、标题等种的段落,由多个XWPFRun组成
  40. * XWPFRun代表具有同样风格的一段文本
  41. * XWPFTable代表一个表格
  42. * XWPFTableRow代表表格的一行
  43. * XWPFTableCell代表表格的一个单元格
  44. * XWPFChar 表示.docx文件中的图表
  45. * XWPFHyperlink 表示超链接
  46. * XWPFPicture 代表图片
  47. *
  48. * 注意:直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun。
  49. */
  50. public class XWPFHelper {
  51. private static Logger logger = Logger.getLogger(XWPFHelper.class.toString());
  52. /**
  53. * 创建一个word对象
  54. * @return
  55. * @Author Huangxiaocong 2018年12月1日 上午11:56:35
  56. */
  57. public XWPFDocument createDocument() {
  58. XWPFDocument document = new XWPFDocument();
  59. return document;
  60. }
  61. /**
  62. * 打开word文档
  63. * @param path 文档所在路径
  64. * @return
  65. * @throws IOException
  66. * @Author Huangxiaocong 2018年12月1日 下午12:30:07
  67. */
  68. public XWPFDocument openDoc(String path) throws IOException {
  69. InputStream is = new FileInputStream(path);
  70. return new XWPFDocument(is);
  71. }
  72. /**
  73. * 保存word文档
  74. * @param document 文档对象
  75. * @param savePath 保存路径
  76. * @throws IOException
  77. * @Author Huangxiaocong 2018年12月1日 下午12:32:37
  78. */
  79. public void saveDocument(XWPFDocument document, String savePath) throws IOException {
  80. OutputStream os = new FileOutputStream(savePath);
  81. document.write(os);
  82. os.close();
  83. }
  84. public void saveDocument(XWPFDocument document, HttpServletResponse response) throws IOException {
  85. OutputStream os = response.getOutputStream();
  86. document.write(os);
  87. os.close();
  88. }
  89. /**
  90. * 设置段落文本样式 设置超链接及样式
  91. * @param paragraph
  92. * @param textStyle
  93. * @param url
  94. * @Author Huangxiaocong 2018年12月1日 下午3:56:32
  95. */
  96. public void addParagraphTextHyperlink(XWPFParagraph paragraph, TextStyle textStyle) {
  97. String id = paragraph.getDocument().getPackagePart().
  98. addExternalRelationship(textStyle.getUrl(),
  99. XWPFRelation.HYPERLINK.getRelation()).getId();
  100. //追加链接并将其绑定到关系中
  101. CTHyperlink cLink = paragraph.getCTP().addNewHyperlink();
  102. cLink.setId(id);
  103. //创建链接文本
  104. CTText ctText = CTText.Factory.newInstance();
  105. ctText.setStringValue(textStyle.getText());
  106. CTR ctr = CTR.Factory.newInstance();
  107. CTRPr rpr = ctr.addNewRPr();
  108. //以下设置各种样式 详情看TextStyle类
  109. if(textStyle.getFontFamily() != "" && textStyle.getFontFamily() != null ) {
  110. CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
  111. fonts.setAscii(textStyle.getFontFamily());
  112. //...
  113. }
  114. //设置字体大小
  115. }
  116. /**
  117. * 设置段落的基本样式 设置段落间距信息, 一行 = 100 一磅=20
  118. * @param paragraph
  119. * @param paragStyle
  120. * @Author Huangxiaocong 2018年12月1日 下午4:27:17
  121. */
  122. public void setParagraphSpacingInfo(XWPFParagraph paragraph, ParagraphStyle paragStyle, STLineSpacingRule.Enum lineValue) {
  123. CTPPr pPPr = getParagraphCTPPr(paragraph);
  124. CTSpacing pSpacing = pPPr.getSpacing() != null ? pPPr.getSpacing() : pPPr.addNewSpacing();
  125. if(paragStyle.isSpace()) {
  126. //段前磅数
  127. if(paragStyle.getBefore() != null) {
  128. pSpacing.setBefore(new BigInteger(paragStyle.getBefore()));
  129. }
  130. //段后磅数
  131. if(paragStyle.getAfter() != null) {
  132. pSpacing.setAfter(new BigInteger(paragStyle.getAfter()));
  133. }
  134. //依次设置段前行数、段后行数
  135. //...
  136. }
  137. //间距
  138. if(paragStyle.isLine()) {
  139. if(paragStyle.getLine() != null) {
  140. pSpacing.setLine(new BigInteger(paragStyle.getLine()));
  141. }
  142. if(lineValue != null) {
  143. pSpacing.setLineRule(lineValue); //
  144. }
  145. }
  146. }
  147. /**
  148. * 设置段落缩进信息 1厘米 约等于 567
  149. * @param paragraph
  150. * @param paragStyle
  151. * @Author Huangxiaocong 2018年12月1日 下午7:59:35
  152. */
  153. public void setParagraphIndInfo(XWPFParagraph paragraph, ParagraphStyle paragStyle) {
  154. CTPPr pPPr = getParagraphCTPPr(paragraph);
  155. CTInd pInd = pPPr.getInd() != null ? pPPr.getInd() : pPPr.addNewInd();
  156. if(paragStyle.getFirstLine() != null) {
  157. pInd.setFirstLine(new BigInteger(paragStyle.getFirstLine()));
  158. }
  159. //再进行其他设置
  160. //...
  161. }
  162. /**
  163. * 设置段落对齐 方式
  164. * @param paragraph
  165. * @param pAlign
  166. * @param valign
  167. * @Author Huangxiaocong 2018年12月1日 下午8:54:43
  168. */
  169. public void setParagraphAlignInfo(XWPFParagraph paragraph, ParagraphAlignment pAlign, TextAlignment valign) {
  170. if(pAlign != null) {
  171. paragraph.setAlignment(pAlign);
  172. }
  173. if(valign != null) {
  174. paragraph.setVerticalAlignment(valign);
  175. }
  176. }
  177. /**
  178. * 得到段落的CTPPr
  179. * @param paragraph
  180. * @return
  181. * @Author Huangxiaocong 2018年12月1日 下午7:36:10
  182. */
  183. public CTPPr getParagraphCTPPr(XWPFParagraph paragraph) {
  184. CTPPr pPPr = null;
  185. if(paragraph.getCTP() != null) {
  186. if(paragraph.getCTP().getPPr() != null) {
  187. pPPr = paragraph.getCTP().getPPr();
  188. } else {
  189. pPPr = paragraph.getCTP().addNewPPr();
  190. }
  191. }
  192. return pPPr;
  193. }
  194. /**
  195. * 得到XWPFRun的CTRPr
  196. * @param paragraph
  197. * @param pRun
  198. * @return
  199. * @Author Huangxiaocong 2018年12月1日 下午7:46:01
  200. */
  201. public CTRPr getRunCTRPr(XWPFParagraph paragraph, XWPFRun pRun) {
  202. CTRPr ctrPr = null;
  203. if(pRun.getCTR() != null) {
  204. ctrPr = pRun.getCTR().getRPr();
  205. if(ctrPr == null) {
  206. ctrPr = pRun.getCTR().addNewRPr();
  207. }
  208. } else {
  209. ctrPr = paragraph.getCTP().addNewR().addNewRPr();
  210. }
  211. return ctrPr;
  212. }
  213. /**
  214. * 复制表格
  215. * @param targetTable
  216. * @param sourceTable
  217. * @Author Huangxiaocong 2018年12月1日 下午1:40:01
  218. */
  219. public void copyTable(XWPFTable targetTable, XWPFTable sourceTable) {
  220. //复制表格属性
  221. targetTable.getCTTbl().setTblPr(sourceTable.getCTTbl().getTblPr());
  222. //复制行
  223. for(int i = 0; i < sourceTable.getRows().size(); i++) {
  224. XWPFTableRow targetRow = targetTable.getRow(i);
  225. XWPFTableRow sourceRow = sourceTable.getRow(i);
  226. if(targetRow == null) {
  227. targetTable.addRow(sourceRow);
  228. } else {
  229. copyTableRow(targetRow, sourceRow);
  230. }
  231. }
  232. }
  233. /**
  234. * 复制单元格
  235. * @param targetRow
  236. * @param sourceRow
  237. * @Author Huangxiaocong 2018年12月1日 下午1:33:22
  238. */
  239. public void copyTableRow(XWPFTableRow targetRow, XWPFTableRow sourceRow) {
  240. //复制样式
  241. if(sourceRow != null) {
  242. targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
  243. }
  244. //复制单元格
  245. for(int i = 0; i < sourceRow.getTableCells().size(); i++) {
  246. XWPFTableCell tCell = targetRow.getCell(i);
  247. XWPFTableCell sCell = sourceRow.getCell(i);
  248. if(tCell == sCell) {
  249. tCell = targetRow.addNewTableCell();
  250. }
  251. copyTableCell(tCell, sCell);
  252. }
  253. }
  254. /**
  255. * 复制单元格(列) 从sourceCell到targetCell
  256. * @param targetCell
  257. * @param sourceCell
  258. * @Author Huangxiaocong 2018年12月1日 下午1:27:38
  259. */
  260. public void copyTableCell(XWPFTableCell targetCell, XWPFTableCell sourceCell) {
  261. //表格属性
  262. if(sourceCell.getCTTc() != null) {
  263. targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
  264. }
  265. //删除段落
  266. for(int pos = 0; pos < targetCell.getParagraphs().size(); pos++) {
  267. targetCell.removeParagraph(pos);
  268. }
  269. //添加段落
  270. for(XWPFParagraph sourceParag : sourceCell.getParagraphs()) {
  271. XWPFParagraph targetParag = targetCell.addParagraph();
  272. copyParagraph(targetParag, sourceParag);
  273. }
  274. }
  275. /**
  276. * 复制段落,从sourceParag到targetParag
  277. * @param targetParag
  278. * @param sourceParag
  279. * @Author Huangxiaocong 2018年12月1日 下午1:16:26
  280. */
  281. public void copyParagraph(XWPFParagraph targetParag, XWPFParagraph sourceParag) {
  282. targetParag.getCTP().setPPr(sourceParag.getCTP().getPPr()); //设置段落样式
  283. //移除所有的run
  284. for(int pos = targetParag.getRuns().size() - 1; pos >= 0; pos-- ) {
  285. targetParag.removeRun(pos);
  286. }
  287. //copy新的run
  288. for(XWPFRun sRun : sourceParag.getRuns()) {
  289. XWPFRun tarRun = targetParag.createRun();
  290. copyRun(tarRun, sRun);
  291. }
  292. }
  293. /**
  294. * 复制XWPFRun 从sourceRun到targetRun
  295. * @param targetRun
  296. * @param sourceRun
  297. * @Author Huangxiaocong 2018年12月1日 下午12:56:53
  298. */
  299. public void copyRun(XWPFRun targetRun, XWPFRun sourceRun) {
  300. //设置targetRun属性
  301. targetRun.getCTR().setRPr(sourceRun.getCTR().getRPr());
  302. targetRun.setText(sourceRun.text());//设置文本
  303. //处理图片
  304. List<XWPFPicture> pictures = sourceRun.getEmbeddedPictures();
  305. for(XWPFPicture picture : pictures) {
  306. try {
  307. copyPicture(targetRun, picture);
  308. } catch (InvalidFormatException e) {
  309. e.printStackTrace();
  310. logger.log(Level.WARNING, "copyRun", e);
  311. } catch (IOException e) {
  312. e.printStackTrace();
  313. logger.log(Level.WARNING, "copyRun", e);
  314. }
  315. }
  316. }
  317. /**
  318. * 复制图片从sourcePicture到 targetRun(XWPFPicture --> XWPFRun)
  319. * @param targetRun
  320. * @param source
  321. * @throws IOException
  322. * @throws InvalidFormatException
  323. * @Author Huangxiaocong 2018年12月1日 下午12:57:33
  324. */
  325. public void copyPicture(XWPFRun targetRun, XWPFPicture sourcePicture) throws InvalidFormatException, IOException {
  326. XWPFPictureData picData = sourcePicture.getPictureData();
  327. String fileName = picData.getFileName(); //图片的名称
  328. InputStream picInIsData = new ByteArrayInputStream(picData.getData());
  329. int picType = picData.getPictureType();
  330. int width = (int) sourcePicture.getCTPicture().getSpPr().getXfrm().getExt().getCx();
  331. int height = (int) sourcePicture.getCTPicture().getSpPr().getXfrm().getExt().getCy();
  332. targetRun.addPicture(picInIsData, picType, fileName, width, height);
  333. // targetRun.addBreak();//分行
  334. }
  335. }