最近公司让我实现一个利用原有word模板,导出word文档的功能模块,发现docx4j是个很不错的工具,但是之前从来没有用过,对此并不了解,于是上网查找相关资料,也是非常少之,于是便自己开始摸索。
1、原有word模板内容如下:
2、在想要插入数据的地方,插入书签,之后会在代码中获取书签并遍历插入内容。
3、直接上代码。
(1)首先我将word模板文件路径配置在config.properties文件中
soil_word_template=/template/soil-report.docx soil_word_filename=soil-report.docx(2)然后是controller层
/** * 根据表名统计土壤墒情数据并导出word文档 * * @param table * 表名 * @param cropDate * 监测日期 * @param file * BASE64编码的图片文件 * @param request * @param response * @return */ @ApiOperation("根据表名统计土壤墒情数据并导出word文档") @RequestMapping(value = "/exportWordReport", method = RequestMethod.POST) @ApiImplicitParams({ @ApiImplicitParam(name = "table", value = "表名",required=false,dataType="query"), @ApiImplicitParam(name="cropDate",value="监测日期",required=false,dataType="query"), @ApiImplicitParam(name = "file", value = "BASE64编码的图片字符",required=false,dataType="query")}) public void exportWordReport(String table, String cropDate, String file, HttpServletRequest request, HttpServletResponse response) { // soil_word_template=/template/soil-report.docx // soil_word_filename=soil-report.docx ServletOutputStream out = null; InputStream in = null; File resultFile = null; try { // 土壤墒情word文档模板路径 String path = request.getServletContext().getRealPath("") + PropertyUtil.get("soil_word_template"); String tempPath = request.getServletContext().getRealPath(""); WordprocessingMLPackage wPackage = soilService.exportWordReport(table, cropDate, file, path); // 设置文件属性 // wPackage.save(new File("C:\\Users\\admin\\Desktop\\" + // PropertyUtil.get("soil_word_filename"))); String fileName = PropertyUtil.get("soil_word_filename"); String msg = new String((fileName).getBytes("UTF-8"), "ISO8859-1"); response.setContentType("application/msword"); response.addHeader("Content-Disposition", "attachment;filename=" + msg); // response.setContentType("application/octet-stream"); // response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8"); // response.addHeader("result", "ok"); // response.setContentType("multipart/form-data"); out = response.getOutputStream(); String strDate = DateUtil.date2String(new Date(), DateUtil.DATE_FORMAT2); resultFile = new File(tempPath + "/tempfile", "soil-report(" + strDate + ").docx"); wPackage.save(resultFile); in = new FileInputStream(resultFile); byte[] buffer = new byte[1024]; int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } // wPackage.save(out); // wPackage.save(new File("C:\\Users\\admin\\Desktop\\", // "dddd1111.docx")); } catch (Exception e) { Log.error(e); } finally { try { if (out != null) { out.flush(); out.close(); } if (in != null) { in.close(); if (resultFile != null && resultFile.exists() && resultFile.isFile()) { resultFile.delete(); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
controller 层中需要注意的地方的是,最开始我用
wPackage.save(out);//直接输出到response的ServletOutPutStream流中,但是这种方式会报错,好像是socket异常之类的问题。
后来改成了代码中的方式,先将文件导出到项目src的webapp文件夹的tempfile文件夹中,然后再从此文件夹中读取该文件,并用out.write()方式输出便能成功执行导出word,前端紧接着下载该word即可。
int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); }
(3)service层以及serviceImpl层代码
首先来看看咱们需要
是SoilService层代码:
/**SoilService层 * 根据表名进行统计并导出word报告文档 * * @param tableName 表名 * @param cropDate 监测日期 * @param file base64编码的图片文件字符串 * @param path word模板文件路径 * @return Map<String, Object> */ WordprocessingMLPackage exportWordReport(String tableName, String cropDate, String file, String path);
然后贴上SoilServiceImpl代码:
/** * 根据表名进行统计并导出word报告文档 * * @param tableName * @param where * @param file * @return Map<String, Object> */ @Override public WordprocessingMLPackage exportWordReport(String tableName, String cropDate, String file, String path) { // TODO Auto-generated method stub Map<String, Object> resultMap = new HashMap<String, Object>(); // DecimalFormat decimalFormat = new DecimalFormat("0.00"); // 此处可能添加过滤非监测区的条件 String where = " \"GRIDCODE\"<8 "; resultMap = findStatisticsDateByTableName(tableName, where); JSONArray jsonArray = (JSONArray) resultMap.get("data1"); double totalArea = 0.0; // 有效监测区面积 double tooMuchArea = 0.0; // 过多面积1 double suitableArea = 0.0;// 适宜面积2 double notEnoughArea = 0.0;// 不足面积3 double lightDroughtArea = 0.0;// 轻旱面积4 double middleDroughtArea = 0.0;// 中旱面积5 double heavyDroughtArea = 0.0;// 重旱面积6 double extremeDroughtArea = 0.0;// 极旱面积7 // double notMonitorArea =0.0; //非监测区8 double tooMuchRate = 0.0; // 过多面积占比1 double suitableRate = 0.0;// 适宜面积2 double notEnoughRate = 0.0;// 不足面积3 double lightDroughtRate = 0.0;// 轻旱面积4 double middleDroughtRate = 0.0;// 中旱面积5 double heavyDroughtRate = 0.0;// 重旱面积6 double extremeDroughtRate = 0.0;// 极旱面积7 // double notMonitorRate =0.0; //非监测区8 for (Object obj : jsonArray) { JSONObject jsonObject = (JSONObject) obj; String gridcode = jsonObject.getString("gridcode"); double area = jsonObject.getDoubleValue("area"); if ("1".equals(gridcode)) { tooMuchArea = area * Constant.I; } else if ("2".equals(gridcode)) { suitableArea = area * Constant.I; } else if ("3".equals(gridcode)) { notEnoughArea = area * Constant.I; } else if ("4".equals(gridcode)) { lightDroughtArea = area * Constant.I; } else if ("5".equals(gridcode)) { middleDroughtArea = area * Constant.I; } else if ("6".equals(gridcode)) { heavyDroughtArea = area * Constant.I; } else if ("7".equals(gridcode)) { extremeDroughtArea = area * Constant.I; } // }else if("8".equals(gridcode)){ // notMonitorArea =area; // } totalArea += area * Constant.I; } if (totalArea != 0.0) { tooMuchRate = Double.valueOf(DECIMAL_FORMAT.format((tooMuchArea / totalArea) * 100)); suitableRate = Double.valueOf(DECIMAL_FORMAT.format((suitableArea / totalArea) * 100)); notEnoughRate = Double.valueOf(DECIMAL_FORMAT.format((notEnoughArea / totalArea) * 100)); lightDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((lightDroughtArea / totalArea) * 100)); middleDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((middleDroughtArea / totalArea) * 100)); heavyDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((heavyDroughtArea / totalArea) * 100)); extremeDroughtRate = Double.valueOf(DECIMAL_FORMAT.format((extremeDroughtArea / totalArea) * 100)); } Map<String, Object> map = new HashMap<String, Object>(); map.put("cropDate", cropDate); map.put("totalArea", DECIMAL_FORMAT.format(totalArea)); map.put("mTotalArea", DECIMAL_FORMAT.format(totalArea / Constant.I * Constant.M)); map.put("tooMuchArea", DECIMAL_FORMAT.format(tooMuchArea)); map.put("suitableArea", DECIMAL_FORMAT.format(suitableArea)); map.put("notEnoughArea", DECIMAL_FORMAT.format(notEnoughArea)); map.put("lightDroughtArea", DECIMAL_FORMAT.format(lightDroughtArea)); map.put("middleDroughtArea", DECIMAL_FORMAT.format(middleDroughtArea)); map.put("heavyDroughtArea", DECIMAL_FORMAT.format(heavyDroughtArea)); map.put("extremeDroughtArea", DECIMAL_FORMAT.format(extremeDroughtArea)); map.put("tooMuchAreaM", DECIMAL_FORMAT.format(tooMuchArea/ Constant.I * Constant.M)); map.put("suitableAreaM", DECIMAL_FORMAT.format(suitableArea/ Constant.I * Constant.M)); map.put("notEnoughAreaM", DECIMAL_FORMAT.format(notEnoughArea/ Constant.I * Constant.M)); map.put("lightDroughtAreaM", DECIMAL_FORMAT.format(lightDroughtArea/ Constant.I * Constant.M)); map.put("middleDroughtAreaM", DECIMAL_FORMAT.format(middleDroughtArea/ Constant.I * Constant.M)); map.put("heavyDroughtAreaM", DECIMAL_FORMAT.format(heavyDroughtArea/ Constant.I * Constant.M)); map.put("extremeDroughtAreaM", DECIMAL_FORMAT.format(extremeDroughtArea/ Constant.I * Constant.M)); map.put("tooMuchRate", tooMuchRate); map.put("suitableRate", suitableRate); map.put("notEnoughRate", notEnoughRate); map.put("lightDroughtRate", lightDroughtRate); map.put("middleDroughtRate", middleDroughtRate); map.put("heavyDroughtRate", heavyDroughtRate); map.put("extremeDroughtRate", extremeDroughtRate); String sql = "SELECT * from (SELECT \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\",SUM(\"AREA\") \"AREA\" FROM \"" + tableName + "\" WHERE \"GRIDCODE\"<8 AND \"GRIDCODE\" IS NOT NULL group by \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\") A " + "WHERE A.\"AREA\"!=0 AND A.\"AREA\" IS NOT NULL"; String totalAreaSql = "SELECT SUM(\"AREA\") \"TOTALAREA\" from (SELECT \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\",SUM(\"AREA\") \"AREA\" FROM \"" + tableName + "\" WHERE \"GRIDCODE\"<8 AND \"GRIDCODE\" IS NOT NULL group by \"PROVINCE\",\"CITY\",\"COUNTY\",\"TOWN\",\"CROPTYPE\",\"GRIDCODE\") A " + "WHERE A.\"AREA\"!=0 AND A.\"AREA\" IS NOT NULL"; List<Object[]> list = getBySql(sql, null); double soilTotalArea = Double.valueOf(Objects.toString(getBySql(totalAreaSql, null).get(0), "0.0")) * Constant.M; List<SoilDtoEntityRate> soilList = list.parallelStream().map(x -> coverProperty(x, soilTotalArea)) .collect(Collectors.toList()); map.put("table", soilList); // map.put("soilTotalArea", soilTotalArea); map.put("img", file); try { WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(new FileInputStream(path)); replaceContentByBookmark(wPackage, map); // wPackage.save(new File("C:\\Users\\admin\\Desktop\\" + // PropertyUtil.get("soil_word_filename"))); return wPackage; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Docx4JException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
/** * 根据多个标签替换段落中的内容 * * @param map */ public void replaceContentByBookmark(WordprocessingMLPackage wPackage, Map<String, Object> map) { // 载入模板文件 try { // 提取正文 MainDocumentPart main = wPackage.getMainDocumentPart(); Document doc = main.getContents(); Body body = doc.getBody(); // ObjectFactory factory = Context.getWmlObjectFactory(); // 获取段落 List<Object> paragraphs = body.getContent(); // 提取书签并创建书签的游标 RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange"); new TraversalUtil(paragraphs, rt); // 遍历书签(在书签处插入文本内容和书签) for (CTBookmark bm : rt.getStarts()) { // 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理 if (!bm.getName().equals(DocUtil.tableName)) { if (bm.getName().equals(DocUtil.imageBookMarkName)) { // 图片 String file = (String) map.get(bm.getName()); if (StringUtils.isNotBlank(file)) { // InputStream inputStream =file.getInputStream(); DocUtil.addImage(wPackage, bm, file); } } else { DocUtil.replaceText(bm, map.get(bm.getName())); } } else { // 表格 List<SoilDtoEntityRate> list = (List<SoilDtoEntityRate>) map.get(bm.getName()); // 创建表格 int rowIndex = 2; // 从第三行开始写起(表格从0开始) Tbl tbl = Doc4JUtil.createTable(wPackage, list.size() + rowIndex, 6); Doc4JUtil.mergeCellsHorizontal(tbl, 0, 0, 5); // 设置表格大标题 P p = Doc4JUtil.createP("农作物墒情统计列表", "36"); Doc4JUtil.setTcValue(tbl, 0, 0, p); // 设置表格副标题 Doc4JUtil.setTcValue(tbl, 1, 0, "县区"); Doc4JUtil.setTcValue(tbl, 1, 1, "乡镇"); Doc4JUtil.setTcValue(tbl, 1, 2, "作物"); Doc4JUtil.setTcValue(tbl, 1, 3, "墒情等级"); Doc4JUtil.setTcValue(tbl, 1, 4, "面积(亩)"); Doc4JUtil.setTcValue(tbl, 1, 5, "占比"); Map<String, List<SoilDtoEntityRate>> provinceCollect = list.stream() .collect(Collectors.groupingBy(x -> x.getProvince() == null ? "" : x.getProvince())); for (Entry<String, List<SoilDtoEntityRate>> proEntry : provinceCollect.entrySet()) { Map<String, List<SoilDtoEntityRate>> cityCollect = proEntry.getValue().stream() .collect(Collectors.groupingBy(x -> x.getCity() == null ? "" : x.getCity())); for (Entry<String, List<SoilDtoEntityRate>> cityEntry : cityCollect.entrySet()) { Map<String, List<SoilDtoEntityRate>> countyCollect = cityEntry.getValue().stream() .collect(Collectors.groupingBy(x -> x.getCounty() == null ? "" : x.getCounty())); for (Entry<String, List<SoilDtoEntityRate>> countyEntry : countyCollect.entrySet()) { operateCounty(countyEntry, rowIndex, tbl); rowIndex += countyEntry.getValue().size(); } } } Doc4JUtil.setTblAllJcAlign(tbl, JcEnumeration.CENTER); Doc4JUtil.setTblAllVAlign(tbl, STVerticalJc.CENTER); wPackage.getMainDocumentPart().addObject(tbl); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 写入县区数据 * * @param countyEntry * @param rowIndex * @param tbl */ private void operateCounty(Entry<String, List<SoilDtoEntityRate>> countyEntry, int rowIndex, Tbl tbl) { // TODO Auto-generated method stub // 获取每个entry的记录条数 int beginRow = rowIndex; int size = countyEntry.getValue().size(); // 处理县区 // 合并单元格 Doc4JUtil.mergeCellsVertically(tbl, 0, beginRow, beginRow + size); Doc4JUtil.setTcValue(tbl, beginRow, 0, countyEntry.getKey()); // 处理镇 Map<String, List<SoilDtoEntityRate>> townCollect = countyEntry.getValue().stream() .collect(Collectors.groupingBy(x -> x.getTown() == null ? "" : x.getTown())); for (Entry<String, List<SoilDtoEntityRate>> townEntry : townCollect.entrySet()) { operateTown(townEntry, beginRow, tbl); beginRow += townEntry.getValue().size(); } } /** * 写入镇数据 * * @param townEntry * @param rowIndex * @param tbl */ private void operateTown(Entry<String, List<SoilDtoEntityRate>> townEntry, int rowIndex, Tbl tbl) { // TODO Auto-generated method stub // 获取每个entry的记录条数 int beginRow = rowIndex; int size = townEntry.getValue().size(); // 处理县区 // 合并单元格 Doc4JUtil.mergeCellsVertically(tbl, 1, beginRow, beginRow + size); Doc4JUtil.setTcValue(tbl, beginRow, 1, townEntry.getKey()); Map<String, List<SoilDtoEntityRate>> cropCollect = townEntry.getValue().stream().sorted((x, j) -> { return (int) (x.getGridcode() - j.getGridcode()); }).collect(Collectors.groupingBy(x -> x.getCroptype() == null ? "" : x.getCroptype())); for (Entry<String, List<SoilDtoEntityRate>> cropEntry : cropCollect.entrySet()) { operateCropType(cropEntry, beginRow, tbl); beginRow += cropEntry.getValue().size(); } } /** * 写入种植类型、土壤墒情等级,面积,占比 * * @param cropEntry * @param rowIndex * @param tbl */ private void operateCropType(Entry<String, List<SoilDtoEntityRate>> cropEntry, int rowIndex, Tbl tbl) { // TODO Auto-generated method stub int beginRow = rowIndex; int size = cropEntry.getValue().size(); // 处理县区 // 合并单元格 Doc4JUtil.mergeCellsVertically(tbl, 2, beginRow, beginRow + size); Doc4JUtil.setTcValue(tbl, beginRow, 2, cropEntry.getKey()); List<SoilDtoEntityRate> soilList = cropEntry.getValue(); for (int i = 0; i < size; i++) { Doc4JUtil.setTcValue(tbl, beginRow + i, 3, gridCodeMap.get(soilList.get(i).getGridcode())); Doc4JUtil.setTcValue(tbl, beginRow + i, 4, String.valueOf(soilList.get(i).getArea())); Doc4JUtil.setTcValue(tbl, beginRow + i, 5, soilList.get(i).getRate()); } }
public SoilDtoEntityRate coverProperty(Object[] x, double totalSoilArea) { String rate = "0.00%"; double area = Double.valueOf(Objects.toString(x[6], "0")) * Constant.M; area = Double.valueOf(DECIMAL_FORMAT.format(area)); if (totalSoilArea != 0) { rate = DECIMAL_FORMAT.format((area / totalSoilArea) * 100) + "%"; } return new SoilDtoEntityRate(Objects.toString(x[0], ""), Objects.toString(x[1], ""), Objects.toString(x[2], ""), Objects.toString(x[3], ""), Objects.toString(x[4], ""), Double.valueOf(Objects.toString(x[5], "0")), area, rate); }
接下来是以上业务代码中用到的工具类中的方法:
/** * @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 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"); } } }
/** * 插入图片 * @param wPackage * @param bm * @param file */ public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file) { try { // 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理 // 获取该书签的父级段落 P p = (P) (bm.getParent()); // R对象是匿名的复杂类型,然而我并不知道具体啥意思,估计这个要好好去看看ooxml才知道 R run = factory.createR(); // 读入图片并转化为字节数组,因为docx4j只能字节数组的方式插入图片 byte[] bytes = FileUtil.getByteFormBase64DataByImage(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) { // TODO: handle exception Log.error(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(); Log.info("标签名称:"+bm.getName()); 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(cce); } }
/** * @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"); } } }
至此,大家就可以看到导出的word文档效果了,如下图: