利用docx4j完美导出word文档(标签替换、插入图片、生成表格)

举报
小米粒-biubiubiu 发表于 2020/11/30 23:48:24 2020/11/30
【摘要】 最近公司让我实现一个利用原有word模板,导出word文档的功能模块,发现docx4j是个很不错的工具,但是之前从来没有用过,对此并不了解,于是上网查找相关资料,也是非常少之,于是便自己开始摸索。 1、原有word模板内容如下: 2、在想要插入数据的地方,插入书签,之后会在代码中获取书签并遍历插入内容。 3、直接上代码。 (1)首先我将word模板文件路径配置在confi...

最近公司让我实现一个利用原有word模板,导出word文档的功能模块,发现docx4j是个很不错的工具,但是之前从来没有用过,对此并不了解,于是上网查找相关资料,也是非常少之,于是便自己开始摸索。

1、原有word模板内容如下:

2、在想要插入数据的地方,插入书签,之后会在代码中获取书签并遍历插入内容。


3、直接上代码。

(1)首先我将word模板文件路径配置在config.properties文件中


  
  1. soil_word_template=/template/soil-report.docx
  2. soil_word_filename=soil-report.docx


  
  1. /**
  2. * 根据表名统计土壤墒情数据并导出word文档
  3. *
  4. * @param table
  5. * 表名
  6. * @param cropDate
  7. * 监测日期
  8. * @param file
  9. * BASE64编码的图片文件
  10. * @param request
  11. * @param response
  12. * @return
  13. */
  14. @ApiOperation("根据表名统计土壤墒情数据并导出word文档")
  15. @RequestMapping(value = "/exportWordReport", method = RequestMethod.POST)
  16. @ApiImplicitParams({ @ApiImplicitParam(name = "table", value = "表名",required=false,dataType="query"), @ApiImplicitParam(name="cropDate",value="监测日期",required=false,dataType="query"),
  17. @ApiImplicitParam(name = "file", value = "BASE64编码的图片字符",required=false,dataType="query")})
  18. public void exportWordReport(String table, String cropDate, String file, HttpServletRequest request,
  19. HttpServletResponse response) {
  20. // soil_word_template=/template/soil-report.docx
  21. // soil_word_filename=soil-report.docx
  22. ServletOutputStream out = null;
  23. InputStream in = null;
  24. File resultFile = null;
  25. try {
  26. // 土壤墒情word文档模板路径
  27. String path = request.getServletContext().getRealPath("") + PropertyUtil.get("soil_word_template");
  28. String tempPath = request.getServletContext().getRealPath("");
  29. WordprocessingMLPackage wPackage = soilService.exportWordReport(table, cropDate, file, path);
  30. // 设置文件属性
  31. // wPackage.save(new File("C:\\Users\\admin\\Desktop\\" +
  32. // PropertyUtil.get("soil_word_filename")));
  33. String fileName = PropertyUtil.get("soil_word_filename");
  34. String msg = new String((fileName).getBytes("UTF-8"), "ISO8859-1");
  35. response.setContentType("application/msword");
  36. response.addHeader("Content-Disposition", "attachment;filename=" + msg);
  37. // response.setContentType("application/octet-stream");
  38. // response.setContentType("application/vnd.ms-excel");
  39. response.setCharacterEncoding("UTF-8");
  40. // response.addHeader("result", "ok");
  41. // response.setContentType("multipart/form-data");
  42. out = response.getOutputStream();
  43. String strDate = DateUtil.date2String(new Date(), DateUtil.DATE_FORMAT2);
  44. resultFile = new File(tempPath + "/tempfile", "soil-report(" + strDate + ").docx");
  45. wPackage.save(resultFile);
  46. in = new FileInputStream(resultFile);
  47. byte[] buffer = new byte[1024];
  48. int len = 0;
  49. while ((len = in.read(buffer)) > 0) {
  50. out.write(buffer, 0, len);
  51. }
  52. // wPackage.save(out);
  53. // wPackage.save(new File("C:\\Users\\admin\\Desktop\\",
  54. // "dddd1111.docx"));
  55. } catch (Exception e) {
  56. Log.error(e);
  57. } finally {
  58. try {
  59. if (out != null) {
  60. out.flush();
  61. out.close();
  62. }
  63. if (in != null) {
  64. in.close();
  65. if (resultFile != null && resultFile.exists() && resultFile.isFile()) {
  66. resultFile.delete();
  67. }
  68. }
  69. } catch (IOException e) {
  70. // TODO Auto-generated catch block
  71. e.printStackTrace();
  72. }
  73. }
  74. }

controller 层中需要注意的地方的是,最开始我用

wPackage.save(out);//直接输出到response的ServletOutPutStream流中,但是这种方式会报错,好像是socket异常之类的问题。
 

后来改成了代码中的方式,先将文件导出到项目src的webapp文件夹的tempfile文件夹中,然后再从此文件夹中读取该文件,并用out.write()方式输出便能成功执行导出word,前端紧接着下载该word即可。


  
  1. int len = 0;
  2. while ((len = in.read(buffer)) > 0) {
  3. out.write(buffer, 0, len);
  4. }

(3)service层以及serviceImpl层代码

首先来看看咱们需要

是SoilService层代码:


  
  1. /**SoilService层
  2. * 根据表名进行统计并导出word报告文档
  3. *
  4. * @param tableName 表名
  5. * @param cropDate 监测日期
  6. * @param file base64编码的图片文件字符串
  7. * @param path word模板文件路径
  8. * @return Map<String, Object>
  9. */
  10. WordprocessingMLPackage exportWordReport(String tableName, String cropDate, String file, String path);

然后贴上SoilServiceImpl代码:


  
  1. /**
  2. * 根据表名进行统计并导出word报告文档
  3. *
  4. * @param tableName
  5. * @param where
  6. * @param file
  7. * @return Map<String, Object>
  8. */
  9. @Override
  10. public WordprocessingMLPackage exportWordReport(String tableName, String cropDate, String file, String path) {
  11. // TODO Auto-generated method stub
  12. Map<String, Object> resultMap = new HashMap<String, Object>();
  13. // DecimalFormat decimalFormat = new DecimalFormat("0.00");
  14. // 此处可能添加过滤非监测区的条件
  15. String where = " \"GRIDCODE\"<8 ";
  16. resultMap = findStatisticsDateByTableName(tableName, where);
  17. JSONArray jsonArray = (JSONArray) resultMap.get("data1");
  18. double totalArea = 0.0; // 有效监测区面积
  19. double tooMuchArea = 0.0; // 过多面积1
  20. double suitableArea = 0.0;// 适宜面积2
  21. double notEnoughArea = 0.0;// 不足面积3
  22. double lightDroughtArea = 0.0;// 轻旱面积4
  23. double middleDroughtArea = 0.0;// 中旱面积5
  24. double heavyDroughtArea = 0.0;// 重旱面积6
  25. double extremeDroughtArea = 0.0;// 极旱面积7
  26. // double notMonitorArea =0.0; //非监测区8
  27. double tooMuchRate = 0.0; // 过多面积占比1
  28. double suitableRate = 0.0;// 适宜面积2
  29. double notEnoughRate = 0.0;// 不足面积3
  30. double lightDroughtRate = 0.0;// 轻旱面积4
  31. double middleDroughtRate = 0.0;// 中旱面积5
  32. double heavyDroughtRate = 0.0;// 重旱面积6
  33. double extremeDroughtRate = 0.0;// 极旱面积7
  34. // double notMonitorRate =0.0; //非监测区8
  35. for (Object obj : jsonArray) {
  36. JSONObject jsonObject = (JSONObject) obj;
  37. String gridcode = jsonObject.getString("gridcode");
  38. double area = jsonObject.getDoubleValue("area");
  39. if ("1".equals(gridcode)) {
  40. tooMuchArea = area * Constant.I;
  41. } else if ("2".equals(gridcode)) {
  42. suitableArea = area * Constant.I;
  43. } else if ("3".equals(gridcode)) {
  44. notEnoughArea = area * Constant.I;
  45. } else if ("4".equals(gridcode)) {
  46. lightDroughtArea = area * Constant.I;
  47. } else if ("5".equals(gridcode)) {
  48. middleDroughtArea = area * Constant.I;
  49. } else if ("6".equals(gridcode)) {
  50. heavyDroughtArea = area * Constant.I;
  51. } else if ("7".equals(gridcode)) {
  52. extremeDroughtArea = area * Constant.I;
  53. }
  54. // }else if("8".equals(gridcode)){
  55. // notMonitorArea =area;
  56. // }
  57. totalArea += area * Constant.I;
  58. }
  59. if (totalArea != 0.0) {
  60. tooMuchRate = Double.valueOf(DECIMAL_FORMAT.format((tooMuchArea / totalArea) * 100));
  61. suitableRate = Double.valueOf(DECIMAL_FORMAT.format((suitableArea / totalArea) * 100));
  62. notEnoughRate = Double.valueOf(DECIMAL_FORMAT.format((notEnoughArea / totalArea) * 100));
  63. lightDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((lightDroughtArea / totalArea) * 100));
  64. middleDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((middleDroughtArea / totalArea) * 100));
  65. heavyDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((heavyDroughtArea / totalArea) * 100));
  66. extremeDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((extremeDroughtArea / totalArea) * 100));
  67. }
  68. Map<String, Object> map = new HashMap<String, Object>();
  69. map.put("cropDate", cropDate);
  70. map.put("totalArea", DECIMAL_FORMAT.format(totalArea));
  71. map.put("mTotalArea", DECIMAL_FORMAT.format(totalArea / Constant.I * Constant.M));
  72. map.put("tooMuchArea", DECIMAL_FORMAT.format(tooMuchArea));
  73. map.put("suitableArea", DECIMAL_FORMAT.format(suitableArea));
  74. map.put("notEnoughArea", DECIMAL_FORMAT.format(notEnoughArea));
  75. map.put("lightDroughtArea", DECIMAL_FORMAT.format(lightDroughtArea));
  76. map.put("middleDroughtArea", DECIMAL_FORMAT.format(middleDroughtArea));
  77. map.put("heavyDroughtArea", DECIMAL_FORMAT.format(heavyDroughtArea));
  78. map.put("extremeDroughtArea", DECIMAL_FORMAT.format(extremeDroughtArea));
  79. map.put("tooMuchAreaM", DECIMAL_FORMAT.format(tooMuchArea/ Constant.I * Constant.M));
  80. map.put("suitableAreaM", DECIMAL_FORMAT.format(suitableArea/ Constant.I * Constant.M));
  81. map.put("notEnoughAreaM", DECIMAL_FORMAT.format(notEnoughArea/ Constant.I * Constant.M));
  82. map.put("lightDroughtAreaM", DECIMAL_FORMAT.format(lightDroughtArea/ Constant.I * Constant.M));
  83. map.put("middleDroughtAreaM", DECIMAL_FORMAT.format(middleDroughtArea/ Constant.I * Constant.M));
  84. map.put("heavyDroughtAreaM", DECIMAL_FORMAT.format(heavyDroughtArea/ Constant.I * Constant.M));
  85. map.put("extremeDroughtAreaM", DECIMAL_FORMAT.format(extremeDroughtArea/ Constant.I * Constant.M));
  86. map.put("tooMuchRate", tooMuchRate);
  87. map.put("suitableRate", suitableRate);
  88. map.put("notEnoughRate", notEnoughRate);
  89. map.put("lightDroughtRate", lightDroughtRate);
  90. map.put("middleDroughtRate", middleDroughtRate);
  91. map.put("heavyDroughtRate", heavyDroughtRate);
  92. map.put("extremeDroughtRate", extremeDroughtRate);
  93. String sql = "SELECT * from (SELECT \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\",SUM(\"AREA\") \"AREA\" FROM \""
  94. + tableName
  95. + "\" WHERE \"GRIDCODE\"<8 AND \"GRIDCODE\" IS NOT NULL group by \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\") A "
  96. + "WHERE A.\"AREA\"!=0 AND A.\"AREA\" IS NOT NULL";
  97. String totalAreaSql = "SELECT SUM(\"AREA\") \"TOTALAREA\" from (SELECT \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\",SUM(\"AREA\") \"AREA\" FROM \""
  98. + tableName
  99. + "\" WHERE \"GRIDCODE\"<8 AND \"GRIDCODE\" IS NOT NULL group by \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\") A "
  100. + "WHERE A.\"AREA\"!=0 AND A.\"AREA\" IS NOT NULL";
  101. List<Object[]> list = getBySql(sql, null);
  102. double soilTotalArea = Double.valueOf(Objects.toString(getBySql(totalAreaSql, null).get(0), "0.0"))
  103. * Constant.M;
  104. List<SoilDtoEntityRate> soilList = list.parallelStream().map(x -> coverProperty(x, soilTotalArea))
  105. .collect(Collectors.toList());
  106. map.put("table", soilList);
  107. // map.put("soilTotalArea", soilTotalArea);
  108. map.put("img", file);
  109. try {
  110. WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(new FileInputStream(path));
  111. replaceContentByBookmark(wPackage, map);
  112. // wPackage.save(new File("C:\\Users\\admin\\Desktop\\" +
  113. // PropertyUtil.get("soil_word_filename")));
  114. return wPackage;
  115. } catch (FileNotFoundException e) {
  116. // TODO Auto-generated catch block
  117. e.printStackTrace();
  118. } catch (Docx4JException e) {
  119. // TODO Auto-generated catch block
  120. e.printStackTrace();
  121. }
  122. return null;
  123. }

  
  1. /**
  2. * 根据多个标签替换段落中的内容
  3. *
  4. * @param map
  5. */
  6. public void replaceContentByBookmark(WordprocessingMLPackage wPackage, Map<String, Object> map) {
  7. // 载入模板文件
  8. try {
  9. // 提取正文
  10. MainDocumentPart main = wPackage.getMainDocumentPart();
  11. Document doc = main.getContents();
  12. Body body = doc.getBody();
  13. // ObjectFactory factory = Context.getWmlObjectFactory();
  14. // 获取段落
  15. List<Object> paragraphs = body.getContent();
  16. // 提取书签并创建书签的游标
  17. RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
  18. new TraversalUtil(paragraphs, rt);
  19. // 遍历书签(在书签处插入文本内容和书签)
  20. for (CTBookmark bm : rt.getStarts()) {
  21. // 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理
  22. if (!bm.getName().equals(DocUtil.tableName)) {
  23. if (bm.getName().equals(DocUtil.imageBookMarkName)) { // 图片
  24. String file = (String) map.get(bm.getName());
  25. if (StringUtils.isNotBlank(file)) {
  26. // InputStream inputStream =file.getInputStream();
  27. DocUtil.addImage(wPackage, bm, file);
  28. }
  29. } else {
  30. DocUtil.replaceText(bm, map.get(bm.getName()));
  31. }
  32. } else { // 表格
  33. List<SoilDtoEntityRate> list = (List<SoilDtoEntityRate>) map.get(bm.getName());
  34. // 创建表格
  35. int rowIndex = 2; // 从第三行开始写起(表格从0开始)
  36. Tbl tbl = Doc4JUtil.createTable(wPackage, list.size() + rowIndex, 6);
  37. Doc4JUtil.mergeCellsHorizontal(tbl, 0, 0, 5);
  38. // 设置表格大标题
  39. P p = Doc4JUtil.createP("农作物墒情统计列表", "36");
  40. Doc4JUtil.setTcValue(tbl, 0, 0, p);
  41. // 设置表格副标题
  42. Doc4JUtil.setTcValue(tbl, 1, 0, "县区");
  43. Doc4JUtil.setTcValue(tbl, 1, 1, "乡镇");
  44. Doc4JUtil.setTcValue(tbl, 1, 2, "作物");
  45. Doc4JUtil.setTcValue(tbl, 1, 3, "墒情等级");
  46. Doc4JUtil.setTcValue(tbl, 1, 4, "面积(亩)");
  47. Doc4JUtil.setTcValue(tbl, 1, 5, "占比");
  48. Map<String, List<SoilDtoEntityRate>> provinceCollect = list.stream()
  49. .collect(Collectors.groupingBy(x -> x.getProvince() == null ? "" : x.getProvince()));
  50. for (Entry<String, List<SoilDtoEntityRate>> proEntry : provinceCollect.entrySet()) {
  51. Map<String, List<SoilDtoEntityRate>> cityCollect = proEntry.getValue().stream()
  52. .collect(Collectors.groupingBy(x -> x.getCity() == null ? "" : x.getCity()));
  53. for (Entry<String, List<SoilDtoEntityRate>> cityEntry : cityCollect.entrySet()) {
  54. Map<String, List<SoilDtoEntityRate>> countyCollect = cityEntry.getValue().stream()
  55. .collect(Collectors.groupingBy(x -> x.getCounty() == null ? "" : x.getCounty()));
  56. for (Entry<String, List<SoilDtoEntityRate>> countyEntry : countyCollect.entrySet()) {
  57. operateCounty(countyEntry, rowIndex, tbl);
  58. rowIndex += countyEntry.getValue().size();
  59. }
  60. }
  61. }
  62. Doc4JUtil.setTblAllJcAlign(tbl, JcEnumeration.CENTER);
  63. Doc4JUtil.setTblAllVAlign(tbl, STVerticalJc.CENTER);
  64. wPackage.getMainDocumentPart().addObject(tbl);
  65. }
  66. }
  67. } catch (Exception e) {
  68. // TODO Auto-generated catch block
  69. e.printStackTrace();
  70. }
  71. }
  72. /**
  73. * 写入县区数据
  74. *
  75. * @param countyEntry
  76. * @param rowIndex
  77. * @param tbl
  78. */
  79. private void operateCounty(Entry<String, List<SoilDtoEntityRate>> countyEntry, int rowIndex, Tbl tbl) {
  80. // TODO Auto-generated method stub
  81. // 获取每个entry的记录条数
  82. int beginRow = rowIndex;
  83. int size = countyEntry.getValue().size();
  84. // 处理县区
  85. // 合并单元格
  86. Doc4JUtil.mergeCellsVertically(tbl, 0, beginRow, beginRow + size);
  87. Doc4JUtil.setTcValue(tbl, beginRow, 0, countyEntry.getKey());
  88. // 处理镇
  89. Map<String, List<SoilDtoEntityRate>> townCollect = countyEntry.getValue().stream()
  90. .collect(Collectors.groupingBy(x -> x.getTown() == null ? "" : x.getTown()));
  91. for (Entry<String, List<SoilDtoEntityRate>> townEntry : townCollect.entrySet()) {
  92. operateTown(townEntry, beginRow, tbl);
  93. beginRow += townEntry.getValue().size();
  94. }
  95. }
  96. /**
  97. * 写入镇数据
  98. *
  99. * @param townEntry
  100. * @param rowIndex
  101. * @param tbl
  102. */
  103. private void operateTown(Entry<String, List<SoilDtoEntityRate>> townEntry, int rowIndex, Tbl tbl) {
  104. // TODO Auto-generated method stub
  105. // 获取每个entry的记录条数
  106. int beginRow = rowIndex;
  107. int size = townEntry.getValue().size();
  108. // 处理县区
  109. // 合并单元格
  110. Doc4JUtil.mergeCellsVertically(tbl, 1, beginRow, beginRow + size);
  111. Doc4JUtil.setTcValue(tbl, beginRow, 1, townEntry.getKey());
  112. Map<String, List<SoilDtoEntityRate>> cropCollect = townEntry.getValue().stream().sorted((x, j) -> {
  113. return (int) (x.getGridcode() - j.getGridcode());
  114. }).collect(Collectors.groupingBy(x -> x.getCroptype() == null ? "" : x.getCroptype()));
  115. for (Entry<String, List<SoilDtoEntityRate>> cropEntry : cropCollect.entrySet()) {
  116. operateCropType(cropEntry, beginRow, tbl);
  117. beginRow += cropEntry.getValue().size();
  118. }
  119. }
  120. /**
  121. * 写入种植类型、土壤墒情等级,面积,占比
  122. *
  123. * @param cropEntry
  124. * @param rowIndex
  125. * @param tbl
  126. */
  127. private void operateCropType(Entry<String, List<SoilDtoEntityRate>> cropEntry, int rowIndex, Tbl tbl) {
  128. // TODO Auto-generated method stub
  129. int beginRow = rowIndex;
  130. int size = cropEntry.getValue().size();
  131. // 处理县区
  132. // 合并单元格
  133. Doc4JUtil.mergeCellsVertically(tbl, 2, beginRow, beginRow + size);
  134. Doc4JUtil.setTcValue(tbl, beginRow, 2, cropEntry.getKey());
  135. List<SoilDtoEntityRate> soilList = cropEntry.getValue();
  136. for (int i = 0; i < size; i++) {
  137. Doc4JUtil.setTcValue(tbl, beginRow + i, 3, gridCodeMap.get(soilList.get(i).getGridcode()));
  138. Doc4JUtil.setTcValue(tbl, beginRow + i, 4, String.valueOf(soilList.get(i).getArea()));
  139. Doc4JUtil.setTcValue(tbl, beginRow + i, 5, soilList.get(i).getRate());
  140. }
  141. }

  
  1. public SoilDtoEntityRate coverProperty(Object[] x, double totalSoilArea) {
  2. String rate = "0.00%";
  3. double area = Double.valueOf(Objects.toString(x[6], "0")) * Constant.M;
  4. area = Double.valueOf(DECIMAL_FORMAT.format(area));
  5. if (totalSoilArea != 0) {
  6. rate = DECIMAL_FORMAT.format((area / totalSoilArea) * 100) + "%";
  7. }
  8. return new SoilDtoEntityRate(Objects.toString(x[0], ""), Objects.toString(x[1], ""), Objects.toString(x[2], ""),
  9. Objects.toString(x[3], ""), Objects.toString(x[4], ""), Double.valueOf(Objects.toString(x[5], "0")),
  10. area, rate);
  11. }

接下来是以上业务代码中用到的工具类中的方法:


  
  1. /**
  2. * @Description:创建表格(默认水平居中,垂直居中)
  3. */
  4. public static Tbl createTable(WordprocessingMLPackage wordPackage, int rowNum,
  5. int colsNum) throws Exception {
  6. colsNum = Math.max(1, colsNum);
  7. rowNum = Math.max(1, rowNum);
  8. int widthTwips = getWritableWidth(wordPackage);
  9. int colWidth = widthTwips / colsNum;
  10. int[] widthArr = new int[colsNum];
  11. for (int i = 0; i < colsNum; i++) {
  12. widthArr[i] = colWidth;
  13. }
  14. return createTable(rowNum, colsNum, widthArr);
  15. }
  16. /**
  17. * @Description:创建表格(默认水平居中,垂直居中)
  18. */
  19. public static Tbl createTable(int rowNum, int colsNum, int[] widthArr)
  20. throws Exception {
  21. colsNum = Math.max(1, Math.min(colsNum, widthArr.length));
  22. rowNum = Math.max(1, rowNum);
  23. Tbl tbl = new Tbl();
  24. StringBuffer tblSb = new StringBuffer();
  25. tblSb.append("<w:tblPr ").append(Namespaces.W_NAMESPACE_DECLARATION)
  26. .append(">");
  27. tblSb.append("<w:tblStyle w:val=\"TableGrid\"/>");
  28. tblSb.append("<w:tblW w:w=\"0\" w:type=\"auto\"/>");
  29. // 上边框
  30. tblSb.append("<w:tblBorders>");
  31. tblSb.append("<w:top w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  32. // 左边框
  33. tblSb.append("<w:left w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  34. // 下边框
  35. tblSb.append("<w:bottom w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  36. // 右边框
  37. tblSb.append("<w:right w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  38. tblSb.append("<w:insideH w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  39. tblSb.append("<w:insideV w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>");
  40. tblSb.append("</w:tblBorders>");
  41. tblSb.append("</w:tblPr>");
  42. TblPr tblPr = null;
  43. tblPr = (TblPr) XmlUtils.unmarshalString(tblSb.toString());
  44. Jc jc = new Jc();
  45. // 单元格居中对齐
  46. jc.setVal(JcEnumeration.CENTER);
  47. tblPr.setJc(jc);
  48. tbl.setTblPr(tblPr);
  49. // 设定各单元格宽度
  50. TblGrid tblGrid = new TblGrid();
  51. tbl.setTblGrid(tblGrid);
  52. for (int i = 0; i < colsNum; i++) {
  53. TblGridCol gridCol = new TblGridCol();
  54. gridCol.setW(BigInteger.valueOf(widthArr[i]));
  55. tblGrid.getGridCol().add(gridCol);
  56. }
  57. // 新增行
  58. for (int j = 0; j < rowNum; j++) {
  59. Tr tr = new Tr();
  60. tbl.getContent().add(tr);
  61. // 列
  62. for (int i = 0; i < colsNum; i++) {
  63. Tc tc = new Tc();
  64. tr.getContent().add(tc);
  65. TcPr tcPr = new TcPr();
  66. TblWidth cellWidth = new TblWidth();
  67. cellWidth.setType("dxa");
  68. cellWidth.setW(BigInteger.valueOf(widthArr[i]));
  69. tcPr.setTcW(cellWidth);
  70. tc.setTcPr(tcPr);
  71. // 垂直居中
  72. setTcVAlign(tc, STVerticalJc.CENTER);
  73. P p = new P();
  74. PPr pPr = new PPr();
  75. pPr.setJc(jc);
  76. p.setPPr(pPr);
  77. R run = new R();
  78. p.getContent().add(run);
  79. tc.getContent().add(p);
  80. }
  81. }
  82. return tbl;
  83. }

  
  1. /**
  2. * @Description: 跨列合并
  3. */
  4. public static void mergeCellsHorizontal(Tbl tbl, int row, int fromCell, int toCell) {
  5. if (row < 0 || fromCell < 0 || toCell < 0) {
  6. return;
  7. }
  8. List<Tr> trList = getTblAllTr(tbl);
  9. if (row > trList.size()) {
  10. return;
  11. }
  12. Tr tr = trList.get(row);
  13. List<Tc> tcList = getTrAllCell(tr);
  14. for (int cellIndex = fromCell, len = Math
  15. .min(tcList.size() - 1, toCell); cellIndex <= len; cellIndex++) {
  16. Tc tc = tcList.get(cellIndex);
  17. TcPr tcPr = getTcPr(tc);
  18. HMerge hMerge = tcPr.getHMerge();
  19. if (hMerge == null) {
  20. hMerge = new HMerge();
  21. tcPr.setHMerge(hMerge);
  22. }
  23. if (cellIndex == fromCell) {
  24. hMerge.setVal("restart");
  25. } else {
  26. hMerge.setVal("continue");
  27. }
  28. }
  29. }

  
  1. /**
  2. * 插入图片
  3. * @param wPackage
  4. * @param bm
  5. * @param file
  6. */
  7. public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file) {
  8. try {
  9. // 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理
  10. // 获取该书签的父级段落
  11. P p = (P) (bm.getParent());
  12. // R对象是匿名的复杂类型,然而我并不知道具体啥意思,估计这个要好好去看看ooxml才知道
  13. R run = factory.createR();
  14. // 读入图片并转化为字节数组,因为docx4j只能字节数组的方式插入图片
  15. byte[] bytes = FileUtil.getByteFormBase64DataByImage(file);
  16. // InputStream is = new FileInputStream;
  17. // byte[] bytes = IOUtils.toByteArray(inputStream);
  18. // byte[] bytes = FileUtil.getByteFormBase64DataByImage("");
  19. // 开始创建一个行内图片
  20. BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes);
  21. // createImageInline函数的前四个参数我都没有找到具体啥意思,,,,
  22. // 最有一个是限制图片的宽度,缩放的依据
  23. Inline inline = imagePart.createImageInline(null, null, 0, 1, false, 0);
  24. // 获取该书签的父级段落
  25. // drawing理解为画布?
  26. Drawing drawing = factory.createDrawing();
  27. drawing.getAnchorOrInline().add(inline);
  28. run.getContent().add(drawing);
  29. p.getContent().add(run);
  30. } catch (Exception e) {
  31. // TODO: handle exception
  32. Log.error(e);
  33. }
  34. }


  
  1. /**
  2. * 在标签处插入内容
  3. *
  4. * @param bm
  5. * @param wPackage
  6. * @param object
  7. * @throws Exception
  8. */
  9. public static void replaceText(CTBookmark bm, Object object) throws Exception {
  10. if (object == null) {
  11. return;
  12. }
  13. // do we have data for this one?
  14. if (bm.getName() == null)
  15. return;
  16. String value = object.toString();
  17. Log.info("标签名称:"+bm.getName());
  18. try {
  19. // Can't just remove the object from the parent,
  20. // since in the parent, it may be wrapped in a JAXBElement
  21. List<Object> theList = null;
  22. ParaRPr rpr = null;
  23. if (bm.getParent() instanceof P) {
  24. PPr pprTemp = ((P) (bm.getParent())).getPPr();
  25. if (pprTemp == null) {
  26. rpr = null;
  27. } else {
  28. rpr = ((P) (bm.getParent())).getPPr().getRPr();
  29. }
  30. theList = ((ContentAccessor) (bm.getParent())).getContent();
  31. } else {
  32. return;
  33. }
  34. int rangeStart = -1;
  35. int rangeEnd = -1;
  36. int i = 0;
  37. for (Object ox : theList) {
  38. Object listEntry = XmlUtils.unwrap(ox);
  39. if (listEntry.equals(bm)) {
  40. if (((CTBookmark) listEntry).getName() != null) {
  41. rangeStart = i + 1;
  42. }
  43. } else if (listEntry instanceof CTMarkupRange) {
  44. if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) {
  45. rangeEnd = i - 1;
  46. break;
  47. }
  48. }
  49. i++;
  50. }
  51. int x = i - 1;
  52. //if (rangeStart > 0 && x >= rangeStart) {
  53. // Delete the bookmark range
  54. for (int j = x; j >= rangeStart; j--) {
  55. theList.remove(j);
  56. }
  57. // now add a run
  58. org.docx4j.wml.R run = factory.createR();
  59. org.docx4j.wml.Text t = factory.createText();
  60. // if (rpr != null)
  61. // run.setRPr(paraRPr2RPr(rpr));
  62. t.setValue(value);
  63. run.getContent().add(t);
  64. //t.setValue(value);
  65. theList.add(rangeStart, run);
  66. //}
  67. } catch (ClassCastException cce) {
  68. Log.error(cce);
  69. }
  70. }

  
  1. /**
  2. * @Description: 跨行合并
  3. */
  4. public static void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) {
  5. if (col < 0 || fromRow < 0 || toRow < 0) {
  6. return;
  7. }
  8. for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
  9. Tc tc = getTc(tbl, rowIndex, col);
  10. if (tc == null) {
  11. break;
  12. }
  13. TcPr tcPr = getTcPr(tc);
  14. VMerge vMerge = tcPr.getVMerge();
  15. if (vMerge == null) {
  16. vMerge = new VMerge();
  17. tcPr.setVMerge(vMerge);
  18. }
  19. if (rowIndex == fromRow) {
  20. vMerge.setVal("restart");
  21. } else {
  22. vMerge.setVal("continue");
  23. }
  24. }
  25. }

至此,大家就可以看到导出的word文档效果了,如下图:




文章来源: blog.csdn.net,作者:血煞风雨城2018,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_31905135/article/details/80431042

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。