700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 利用docx4j完美导出word文档(标签替换 插入图片 生成表格)

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

时间:2020-02-06 07:00:56

相关推荐

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

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

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

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

3、直接上代码。

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

soil_word_template=/template/soil-report.docxsoil_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.docxServletOutputStream 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 blocke.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>*/@Overridepublic WordprocessingMLPackage exportWordReport(String tableName, String cropDate, String file, String path) {// TODO Auto-generated method stubMap<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; // 过多面积1double suitableArea = 0.0;// 适宜面积2double notEnoughArea = 0.0;// 不足面积3double lightDroughtArea = 0.0;// 轻旱面积4double middleDroughtArea = 0.0;// 中旱面积5double heavyDroughtArea = 0.0;// 重旱面积6double extremeDroughtArea = 0.0;// 极旱面积7// double notMonitorArea =0.0; //非监测区8double tooMuchRate = 0.0; // 过多面积占比1double suitableRate = 0.0;// 适宜面积2double notEnoughRate = 0.0;// 不足面积3double lightDroughtRate = 0.0;// 轻旱面积4double middleDroughtRate = 0.0;// 中旱面积5double heavyDroughtRate = 0.0;// 重旱面积6double extremeDroughtRate = 0.0;// 极旱面积7// double notMonitorRate =0.0; //非监测区8for (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 blocke.printStackTrace();} catch (Docx4JException e) {// TODO Auto-generated catch blocke.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 blocke.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 stubint 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 exceptionLog.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 JAXBElementList<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 rangefor (int j = x; j >= rangeStart; j--) {theList.remove(j);}// now add a runorg.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文档效果了,如下图:

最后,大家在遇到此类问题的时候也可参考本篇博客,同时本人初次发表博客,时间仓促,尚且还有不妥之处,欢迎指正!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。