900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 使用poi根据模版生成word文档 支持插入图片 复制表格 插入 循环插入数据 继承模

使用poi根据模版生成word文档 支持插入图片 复制表格 插入 循环插入数据 继承模

时间:2019-05-25 09:51:18

相关推荐

使用poi根据模版生成word文档 支持插入图片 复制表格 插入 循环插入数据 继承模

一、制作word模版,${xxxx}是一会要替换的内容,最下面的表格是要插入数据,根据是否以$开头来判断是需要替换还是插入数据,

注意如果是需要循环插入数据,制作的表格模版需要一行全部输入井号#,格式样式可以对#设置表格中${header}和${hearder2}是放入需要替换的图片替换数据的格式样式同$的一样如果需要根据数据再确定需要在哪替换图片,可以使用带ImgAgain的方法,原理是数据先替换为*{}占位符,再替换一遍一些设置参数,看getWord方法参数支持:段落插表格(有两个插入表格的方法)支持公式:看六,得具体分析不支持特殊格式:如上下标、双行合一等复制表格时及循环插入不支持特殊样式:如高亮、艺术字体、快速样式(复制表格,循环时无法复制高亮样式)等复制表格时,若字体原来为默认五号,则复制是变为10号字体,应为10.5,但只支持传整数 :(表格中特殊符号:#、$、{、}、,使用时需注意,在循环插入数据的单元格内 [ ] 中括号也是特殊符号循环插数据的表格列数支持多或少;支持调换列的顺序循环插数据的表格行中每个单元格都要有#在循环单元格内允许有多个段落,单插入数据的段落需是单独段落,且#号开头循环插数据的以#开头,后面跟 [ ] ,里面写数据顺序的序号(注意第一列是以零0开头),若按默认循序则不用加 [ ] ,若在数据长度内的单元格又不想填数据则中括号没填-1及 [-1]循环插数据的数据格式样式同#,所以模板可以自定义#格式样式

循环数据行举例:

结果:

下面是测试模板

二、添加poi所需要的jar包文件,我用的maven对jar包进行管理

<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.15</version></dependency>

三、由于poi自身bug,会出现图片无法显示问题,这里需要自定义一个类继承XWPFDocument类,接下来使用的都是我们自己创建的这个类来操作word对象,这个

类对XWPFDocument进行了继承,所以不用担心会有什么问题

import org.apache.poi.openxml4j.opc.OPCPackage;import org.apache.poi.xwpf.usermodel.XWPFDocument;import org.apache.poi.xwpf.usermodel.XWPFParagraph;import org.apache.xmlbeans.XmlException;import org.apache.xmlbeans.XmlToken;import org.openxmlformats.schemas.drawingml.x.main.CTNonVisualDrawingProps;import org.openxmlformats.schemas.drawingml.x.main.CTPositiveSize2D;import org.openxmlformats.schemas.drawingml.x.wordprocessingDrawing.CTInline;import java.io.IOException;import java.io.InputStream;/******************************************* ** @Package cuu.project.myUtils* @Author duan* @Date /3/29 17:55* @Version V1.0*******************************************/public class CustomXWPFDocument extends XWPFDocument {public CustomXWPFDocument(InputStream in) throws IOException {super(in);}public CustomXWPFDocument() {super();}public CustomXWPFDocument(OPCPackage pkg) throws IOException {super(pkg);}/*** @param id* @param width 宽* @param height 高* @param paragraph 段落*/public void createPicture(int id, int width, int height,XWPFParagraph paragraph) {final int EMU = 9525;width *= EMU;height *= EMU;String blipId = getAllPictures().get(id).getPackageRelationship().getId();CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();String picXml = ""+"<a:graphic xmlns:a=\"/drawingml//main\">"+" <a:graphicData uri=\"/drawingml//picture\">"+"<pic:pic xmlns:pic=\"/drawingml//picture\">"+" <pic:nvPicPr>" + " <pic:cNvPr id=\""+ id+"\" name=\"Generated\"/>"+" <pic:cNvPicPr/>"+" </pic:nvPicPr>"+" <pic:blipFill>"+" <a:blip r:embed=\""+ blipId+"\" xmlns:r=\"/officeDocument//relationships\"/>"+" <a:stretch>"+"<a:fillRect/>"+" </a:stretch>"+" </pic:blipFill>"+" <pic:spPr>"+" <a:xfrm>"+"<a:off x=\"0\" y=\"0\"/>"+"<a:ext cx=\""+ width+"\" cy=\""+ height+"\"/>"+" </a:xfrm>"+" <a:prstGeom prst=\"rect\">"+"<a:avLst/>"+" </a:prstGeom>"+" </pic:spPr>"+"</pic:pic>"+" </a:graphicData>" + "</a:graphic>";inline.addNewGraphic().addNewGraphicData();XmlToken xmlToken = null;try{xmlToken = XmlToken.Factory.parse(picXml);}catch(XmlException xe) {xe.printStackTrace();}inline.set(xmlToken);inline.setDistT(0);inline.setDistB(0);inline.setDistL(0);inline.setDistR(0);CTPositiveSize2D extent = inline.addNewExtent();extent.setCx(width);extent.setCy(height);CTNonVisualDrawingProps docPr = inline.addNewDocPr();docPr.setId(id);docPr.setName("图片"+ id);docPr.setDescr("测试");}}

四、接下来就是导出word的工具类了

import org.apache.poi.xwpf.usermodel.*;import org.apache.xmlbeans.XmlCursor;import org.openxmlformats.schemas.wordprocessingml.x.main.STMerge;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.util.*;import java.util.regex.Matcher;import java.util.regex.Pattern;/*** <b> 通过word模板生成新的word工具类* </b><br><br><i>Description</i> :* <br><br>Date: /12/9 ${time} <br>Author : dxl*/public class WordGrtUtil {public static void main(String[] args) throws Exception {// wordGrtUtil.copyTbaleByLoop("C:\\Users\\00\\Desktop\\baogao\\testmodel.docx",0,4,"C:\\Users\\00\\Desktop\\baogao\\testmodel-copy.docx");// WordGrtUtil wordGrtUtil=new WordGrtUtil();Map<String, Object> params = new HashMap<String, Object>();params.put("${position}", "*{aaa}");params.put("${name}", "222段然涛222");params.put("${sex}", "男");params.put("${national}", "汉族");params.put("${birthday}", "生日");params.put("${address}", "许昌");params.put("${height}", "165cm");params.put("${biYeDate}", "1994-02-03");params.put("${landscape}", "团员");params.put("${zhuanYe}", "社会工作");params.put("${xueLi}", "本科");params.put("${school}", "江西科技师范大学");params.put("${phone}", "177");params.put("${eMail}", "157");try{Map<String,Object> header = new HashMap<String, Object>();header.put("width", 50);header.put("height", 50);header.put("type", "jpg");header.put("content", inputStream2ByteArray(new FileInputStream("C:\\Users\\00\\Desktop\\baogao\\tupian\\垂直度.jpg"), true));params.put("${tihuan}",header);params.put("*{aaa}",header);// Map<String,Object> header2 = new HashMap<String, Object>();// header2.put("width", 100);// header2.put("height", 150);// header2.put("type", "jpg");// header2.put("content", WordUtils.inputStream2ByteArray(new FileInputStream("C:/Users/Administrator/Desktop/jar包/22.jpg"), true));// params.put("${header2}",header2);List<String[]> testList = new ArrayList<String[]>();testList.add(new String[]{"1","1AA","1BB","1CC"});testList.add(new String[]{"2","2AA","2BB","2CC"});testList.add(new String[]{"3","3AA","3BB","3CC"});testList.add(new String[]{"4","4AA","4BB","4CC"});String modelPath="C:\\Users\\00\\Desktop\\baogao\\testmodel3.docx"; //模板文件位置String stroePath="C:\\Users\\00\\Desktop\\baogao\\aaaa.docx"; //模板文件位置String fileName= new String("测试文档.docx".getBytes("UTF-8"),"iso-8859-1"); //生成word文件的文件名List<List<Integer>> mergeRowLists = new ArrayList<>();WordGrtUtil.getWordStore(modelPath,params,testList,stroePath,false,0,2,false,null);// wordGrtUtil.getWord(path,params,testList,fileName);}catch(Exception e){e.printStackTrace();}}/*** 根据模板生成word 并存储* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要循环插入的参数* @param storePath 生成的word文件存储路径,包含文件名全称* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordStore(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInPara(doc, params); //替换文本里面的变量OutputStream os = new FileOutputStream(storePath);doc.write(os);close(os);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInPara(doc, params); //替换文本里面的变量OutputStream os = new FileOutputStream(storePath);doc.write(os);close(os);close(is);}}/*** 根据模板生成word 不存储直接下载* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要插入的参数* @param fileName 生成word文件的文件名* @param response* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordDown(String srcPath, Map<String, Object> params, List<String[]> tableList, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInPara(doc, params); //替换文本里面的变量OutputStream os = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(os);close(os);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInPara(doc, params); //替换文本里面的变量replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量OutputStream os = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(os);close(os);close(is);}}/*** 根据模板生成word 存储并下载* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要插入的参数* @param fileName 生成word文件的文件名* @param response* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordStoreAndDown(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInPara(doc, params); //替换文本里面的变量OutputStream oss = new FileOutputStream(temPath);OutputStream osd = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(oss);doc.write(osd);close(oss);close(osd);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInPara(doc, params); //替换文本里面的变量replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量OutputStream oss = new FileOutputStream(storePath);OutputStream osd = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(oss);doc.write(osd);close(oss);close(osd);close(is);}}/*** 根据模板生成word 并存储* 因为有的地方替换图片不确定,先替换成其他占位符,在替换掉* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要循环插入的参数* @param storePath 生成的word文件存储路径,包含文件名全称* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordStoreImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInParaImgAgain(doc, params); //替换文本里面的变量OutputStream os = new FileOutputStream(storePath);doc.write(os);close(os);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInParaImgAgain(doc, params); //替换文本里面的变量OutputStream os = new FileOutputStream(storePath);doc.write(os);close(os);close(is);}}/*** 根据模板生成word 不存储直接下载* 因为有的地方替换图片不确定,先替换成其他占位符,在替换掉* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要插入的参数* @param fileName 生成word文件的文件名* @param response* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordDownImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInParaImgAgain(doc, params); //替换文本里面的变量OutputStream os = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(os);close(os);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInParaImgAgain(doc, params); //替换文本里面的变量replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量OutputStream os = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(os);close(os);close(is);}}/*** 根据模板生成word 存储并下载* 因为有的地方替换图片不确定,先替换成其他占位符,在替换掉* @param srcPath模板的路径* @param params 需要替换的参数* @param tableList 需要插入的参数* @param fileName 生成word文件的文件名* @param response* @param isCopyTable 是否需要循环复制表格,* @param copyTableIndex 复制第几个表格,若copyTable为false,后两个参数随便填* @param copyTableNum 复制几个表格* @param isMergeRow 是否自动合并行* @param mergeRowLists List<Integer>应包含三个,第一个为要合并的列,第二个合并的起始行,第三个合并的结束行*/public static void getWordStoreAndDownImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");File file = new File(srcPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(isCopyTable){String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);File fileTem = new File(temPath);InputStream is = new FileInputStream(fileTem);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量replaceInParaImgAgain(doc, params); //替换文本里面的变量OutputStream oss = new FileOutputStream(temPath);OutputStream osd = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(oss);doc.write(osd);close(oss);close(osd);close(is);File fileDel = new File(temPath);if(fileDel.exists()){fileDel.delete();}}else {InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);replaceInParaImgAgain(doc, params); //替换文本里面的变量replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替换表格里面的变量OutputStream oss = new FileOutputStream(storePath);OutputStream osd = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(oss);doc.write(osd);close(oss);close(osd);close(is);}}/*** <b> 循环复制Word中的表格* </b><br><br><i>Description</i> :* @param srcPath 模板路径, srcTableIndex 模板中复制目标表格的下标, copyNum 复制个数, storePath 存储路径(包含文件名全称)* @return void* <br><br>Date: /12/9 13:21<br>Author : dxl*/public static void copyTbaleByLoop(String srcPath, int srcTableIndex,int copyNum,String storePath) throws Exception {File file = new File(srcPath);InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);XWPFTable sourceTable = doc.getTableArray(srcTableIndex);for(int j = 0; j < copyNum; j++){XWPFTable tableOne = doc.createTable();for(int i = 0; i < sourceTable.getRows().size(); i++){copy(tableOne,sourceTable.getRow(i),i);}doc.createParagraph();tableOne.removeRow(tableOne.getRows().size()-1);}OutputStream os = new FileOutputStream(storePath);doc.write(os);close(os);close(is);}/*** 替换段落里面的变量* @param doc 要替换的文档* @param params 参数*/private static void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) throws IOException {Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();// List<XWPFParagraph> paragraphs = doc.getParagraphs();// for(int i = paragraphs.size()-1; i >= 0; i--){// replaceInPara(paragraphs.get(i), params, doc);// insertTableInParaFromAtherDoc("C:\\Users\\00\\Desktop\\baogao\\testmodel4.docx",0,doc,paragraphs.get(i),false);// }XWPFParagraph para;while (iterator.hasNext()) {para = iterator.next();replaceInPara(para, params, doc);}}/*** 替换段落里面的变量* @param doc 要替换的文档* @param params 参数*/private static void replaceInParaImgAgain(CustomXWPFDocument doc, Map<String, Object> params) {Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();XWPFParagraph para;while (iterator.hasNext()) {para = iterator.next();replaceInPara(para, params, doc);replaceImgAgain(para, params, doc);}}/*** 替换段落里面的变量** @param para 要替换的段落* @param params 参数*/private static void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {List<XWPFRun> runs;Matcher matcher;if (matcher(para.getParagraphText()).find()) {runs = para.getRuns();int start = -1;int end = -1;String str = "";for (int i = 0; i < runs.size(); i++) {XWPFRun run = runs.get(i);String runText = run.toString();if ((runText.length() > 0 && runText.contains("${"))|| (runText.length() > 0 && '$' == runText.charAt(runText.length() - 1) && i+1 <runs.size() && '$' == runs.get(i+1).toString().charAt(0))) {start = i;}if (runText.length() > 0 && runText.contains("}")) {if (start != -1) {end = i;break;}}}for(int i = start; i <= end; i++){str = str + runs.get(i).toString();}//去掉标识符开始之后到结束的run,保留第一个run是为了使用run的样式for (int i = start+1; i <= end; i++) {para.removeRun(i);i--;end--;}for (Map.Entry<String, Object> entry : params.entrySet()) {String key = entry.getKey();if (str.indexOf(key) != -1) {Object value = entry.getValue();if (value instanceof String) {str = str.replace(key, value.toString());para.getRuns().get(start).setText(str,0);//替换保留的第一个run中的内容,若没有0就变为插入了break;} else if (value instanceof Map) {str = str.replace(key, "");Map pic = (Map) value;int width = Integer.parseInt(pic.get("width").toString());int height = Integer.parseInt(pic.get("height").toString());int picType = getPictureType(pic.get("type").toString());byte[] byteArray = (byte[]) pic.get("content");ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);try {//int ind = doc.addPicture(byteInputStream,picType);//doc.createPicture(ind, width , height,para);doc.addPictureData(byteInputStream, picType);if(start == 0){para.getRuns().get(0).setText("",0);doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start);}else {para.removeRun(start);doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start-1);}break;} catch (Exception e) {e.printStackTrace();}}}}}if (matcher(para.getParagraphText()).find()) {replaceInPara(para, params, doc);}}/*** 为表格插入数据,行数不够添加新行* 说明:当表格中出现一行中每一个单元格都为'#'时,认为需要循环插入* @param tableList 插入数据集合*/private static void insertTable(XWPFTable table, List<String[]> tableList,boolean isMergeRow,List<List<Integer>> mergeRowLists) {int headRowNum = 0;int tailRowNum = 0;List<XWPFTableRow> rows = table.getRows();List<Integer> cellOrder = new ArrayList<>();for(int i = 0; i < rows.size(); i++){String flagHead = "";String flagFor = "";for(int j = 0; j < rows.get(i).getTableCells().size(); j++){String cellText = rows.get(i).getTableCells().get(j).getText().replace(" ","");if(cellText.length() > 0){if(cellText.contains("#")){flagHead = flagHead + "#";}if(cellText.contains("#[") && cellText.contains("]") && cellText.indexOf("]") > cellText.indexOf("[")+1&& cellOrder.size() < rows.get(i).getTableCells().size()){cellOrder.add(Integer.valueOf(cellText.substring(cellText.indexOf("[")+1,cellText.indexOf("]"))));}else if(cellText.contains("#") && cellOrder.size() < rows.get(i).getTableCells().size()){cellOrder.add(null);}}//删除循环单元格内多余段落,不想单元格内有默认数据放开注释//List<XWPFParagraph> paragraphs = rows.get(i).getTableCells().get(j).getParagraphs();//if(paragraphs.size() > 1){//for(int k = paragraphs.size()-1; k >= 0; k--){// if(!paragraphs.get(k).getText().contains("#")){// rows.get(i).getTableCells().get(j).removeParagraph(k);// }//}//}//删除循环单元格内要替换段落后的多余runif(rows.get(i).getTableCells().get(j).getParagraphs().size() > 0){for(XWPFParagraph paragraph : rows.get(i).getTableCells().get(j).getParagraphs()){if(paragraph.getText().indexOf("#") == 0){for(int k = paragraph.getRuns().size()-1; k > 0; k--){paragraph.removeRun(k);}}}}flagFor = flagFor + "#";}if(flagFor.equals(flagHead)){headRowNum = i;break;}}if(headRowNum > 0){tailRowNum = rows.size()- headRowNum - 1;//创建行,根据需要插入的数据添加新行,不处理表头for (int i = 0; i < tableList.size(); i++) {copy(table,table.getRow(headRowNum),headRowNum+1+i);}//遍历表格插入数据int length = table.getRows().size();for (int i = headRowNum; i < length - tailRowNum - 1; i++) {XWPFTableRow newRow = table.getRow(i);List<XWPFTableCell> cells = newRow.getTableCells();for (int j = 0; j < cells.size(); j++) {XWPFTableCell cell = cells.get(j);String s ="";if(j < tableList.get(i - headRowNum).length){if(cellOrder.get(j) != null && !cellOrder.get(j).equals(-1)){s = tableList.get(i - headRowNum)[cellOrder.get(j)];}else if(cellOrder.get(j) != null &&cellOrder.get(j).equals(-1)){s = "";}else {s = tableList.get(i - headRowNum)[j];}}else if(cellOrder.get(j) != null && !cellOrder.get(j).equals(-1)){s = tableList.get(i - headRowNum)[cellOrder.get(j)];}for(XWPFParagraph paragraph : cell.getParagraphs()){if(paragraph.getText().contains("#")){paragraph.getRuns().get(0).setText(s,0);}}}}table.removeRow(table.getRows().size()-1-tailRowNum);if(isMergeRow && mergeRowLists.size() > 0){for(List<Integer> listInts : mergeRowLists){mergeCellsRow(table,listInts.get(0),listInts.get(1),listInts.get(2));}}// mergeCellsCol(table,1,2,3);}}/*** 替换表格里面的变量* @param doc 要替换的文档* @param params 参数*/private static void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList,boolean isMergeRow,List<List<Integer>> mergeRowLists) {Iterator<XWPFTable> iterator = doc.getTablesIterator();XWPFTable table;List<XWPFTableRow> rows;List<XWPFTableCell> cells;List<XWPFParagraph> paras;while (iterator.hasNext()) {table = iterator.next();if (table.getRows().size() > 1) {insertTable(table,tableList,isMergeRow,mergeRowLists);//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入//if (matcher(table.getText()).find()) {rows = table.getRows();for (XWPFTableRow row : rows) {cells = row.getTableCells();for (XWPFTableCell cell : cells) {paras = cell.getParagraphs();for (XWPFParagraph para : paras) {replaceInPara(para, params, doc);}}}}}}/*** <b> 再次替换图片* </b><br><br><i>Description</i> : 因为有的地方替换图片不确定,先替换成其他占位符,在替换掉* @param para 要替换的段落* @param params 参数* @param doc 文档* @return void* <br><br>Date: /12/9 15:54<br>Author : dxl*/private static void replaceImgAgain(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {List<XWPFRun> runs;if (matcherStar(para.getParagraphText()).find()) {runs = para.getRuns();int start = -1;int end = -1;String str = "";for (int i = 0; i < runs.size(); i++) {XWPFRun run = runs.get(i);String runText = run.toString();if ((runText.length() > 0 && runText.contains("*{"))|| (runText.length() > 0 && '*' == runText.charAt(runText.length() - 1) && i+1 <runs.size() && '$' == runs.get(i+1).toString().charAt(0))) {start = i;}if (runText.length() > 0 && runText.contains("}")) {if (start != -1) {end = i;break;}}}for(int i = start; i <= end; i++){str = str + runs.get(i).toString();}//去掉标识符开始之后到结束的run,保留第一个run是为了使用run的样式for (int i = start+1; i <= end; i++) {para.removeRun(i);i--;end--;}for (Map.Entry<String, Object> entry : params.entrySet()) {String key = entry.getKey();if (str.indexOf(key) != -1) {Object value = entry.getValue();if (value instanceof String) {str = str.replace(key, value.toString());para.getRuns().get(start).setText(str,0);//替换保留的第一个run中的内容,若没有0就变为插入了break;} else if (value instanceof Map) {str = str.replace(key, "");Map pic = (Map) value;int width = Integer.parseInt(pic.get("width").toString());int height = Integer.parseInt(pic.get("height").toString());int picType = getPictureType(pic.get("type").toString());byte[] byteArray = (byte[]) pic.get("content");ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);try {//int ind = doc.addPicture(byteInputStream,picType);//doc.createPicture(ind, width , height,para);doc.addPictureData(byteInputStream, picType);if(start == 0){para.getRuns().get(0).setText("",0);doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start);}else {para.removeRun(start);doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start-1);}break;} catch (Exception e) {e.printStackTrace();}}}}}if (matcher(para.getParagraphText()).find()) {replaceInPara(para, params, doc);}}/*** 正则匹配字符串** @param str* @return*/private static Matcher matcher(String str) {Pattern pattern = pile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(str);return matcher;}/*** 正则匹配字符串** @param str* @return*/private static Matcher matcherStar(String str) {Pattern pattern = pile("\\*\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(str);return matcher;}/*** 根据图片类型,取得对应的图片类型代码** @param picType* @return int*/private static int getPictureType(String picType) {int res = CustomXWPFDocument.PICTURE_TYPE_PICT;if (picType != null) {if (picType.equalsIgnoreCase("png")) {res = CustomXWPFDocument.PICTURE_TYPE_PNG;} else if (picType.equalsIgnoreCase("dib")) {res = CustomXWPFDocument.PICTURE_TYPE_DIB;} else if (picType.equalsIgnoreCase("emf")) {res = CustomXWPFDocument.PICTURE_TYPE_EMF;} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {res = CustomXWPFDocument.PICTURE_TYPE_JPEG;} else if (picType.equalsIgnoreCase("wmf")) {res = CustomXWPFDocument.PICTURE_TYPE_WMF;}}return res;}/*** 将输入流中的数据写入字节数组** @param in* @return*/public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {byte[] byteArray = null;try {int total = in.available();byteArray = new byte[total];in.read(byteArray);} catch (IOException e) {e.printStackTrace();} finally {if (isClose) {try {in.close();} catch (Exception e2) {e2.getStackTrace();}}}return byteArray;}/*** 关闭输入流** @param is*/private static void close(InputStream is) {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}/*** 关闭输出流** @param os*/private static void close(OutputStream os) {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}/*** <b> 复制表格* </b><br><br><i>Description</i> :* @param table, sourceRow, rowIndex* @return void* <br><br>Date: /12/9 13:23<br>Author : dxl*/public static void copy(XWPFTable table,XWPFTableRow sourceRow,int rowIndex){//在表格指定位置新增一行XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);//复制行属性targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());List<XWPFTableCell> cellList = sourceRow.getTableCells();if (null == cellList) {return;}//复制列及其属性和内容XWPFTableCell targetCell = null;for (XWPFTableCell sourceCell : cellList) {targetCell = targetRow.addNewTableCell();//处理一个单元格内有多个段落List<XWPFParagraph> paragraphs = sourceCell.getParagraphs();if(paragraphs.size() > 1){for(int i = 1; i < paragraphs.size(); i++){targetCell.addParagraph();}}//列属性targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());//段落属性if(sourceCell.getParagraphs()!=null&&sourceCell.getParagraphs().size()>0){for(int i = 0; i < sourceCell.getParagraphs().size();i++){targetCell.getParagraphs().get(i).getCTP().setPPr(sourceCell.getParagraphs().get(i).getCTP().getPPr());if(sourceCell.getParagraphs().get(i).getRuns()!=null&&sourceCell.getParagraphs().get(i).getRuns().size()>0){for(int j = 0; j < sourceCell.getParagraphs().get(i).getRuns().size(); j++){XWPFRun cellR = targetCell.getParagraphs().get(i).createRun();cellR.setText(sourceCell.getParagraphs().get(i).getRuns().get(j).getText(0));cellR.setBold(sourceCell.getParagraphs().get(i).getRuns().get(j).isBold());cellR.setColor(sourceCell.getParagraphs().get(i).getRuns().get(j).getColor());if(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontSize() == -1){cellR.setFontSize(10);}else {cellR.setFontSize(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontSize());}cellR.setCapitalized(sourceCell.getParagraphs().get(i).getRuns().get(j).isCapitalized());cellR.setDoubleStrikethrough(sourceCell.getParagraphs().get(i).getRuns().get(j).isDoubleStrikeThrough());cellR.setEmbossed(sourceCell.getParagraphs().get(i).getRuns().get(j).isEmbossed());cellR.setFontFamily(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontFamily());cellR.setImprinted(sourceCell.getParagraphs().get(i).getRuns().get(j).isImprinted());cellR.setItalic(sourceCell.getParagraphs().get(i).getRuns().get(j).isItalic());cellR.setKerning(sourceCell.getParagraphs().get(i).getRuns().get(j).getKerning());cellR.setShadow(sourceCell.getParagraphs().get(i).getRuns().get(j).isShadowed());cellR.setStrikeThrough(sourceCell.getParagraphs().get(i).getRuns().get(j).isStrikeThrough());cellR.setSmallCaps(sourceCell.getParagraphs().get(i).getRuns().get(j).isSmallCaps());cellR.setSubscript(sourceCell.getParagraphs().get(i).getRuns().get(j).getSubscript());cellR.setTextPosition(sourceCell.getParagraphs().get(i).getRuns().get(j).getTextPosition());cellR.setUnderline(sourceCell.getParagraphs().get(i).getRuns().get(j).getUnderline());}}else{targetCell.setText(sourceCell.getText());}}}else{targetCell.setText(sourceCell.getText());}}}/*** <b> 在段落中插入表格* </b><br><br><i>Description</i> : 表格单元格中建段落再插入表格,原段落会挤到下一个段落,用isDelNullPara控制删除空原段落,* isDelNullPara为true时要注意循环迭代,最好倒序循环para,插入表格后还有对para操作时也要注意,可能isDelNullPara要设为false* @param sourceTable 要插入的源表格* @param targetDoc 要插入的文档* @param para 要插入表格的段落* @param isDelNullPara 是否删除para为空是多出来的空段落* @return void* <br><br>Date: /12/12 11:39<br>Author : dxl*/public static void insertTableInPara(XWPFTable sourceTable,CustomXWPFDocument targetDoc,XWPFParagraph para,boolean isDelNullPara){XmlCursor cursor = para.getCTP().newCursor();XWPFTable tableOne = targetDoc.insertNewTbl(cursor);for(int i = 0; i < sourceTable.getRows().size(); i++){copy(tableOne,sourceTable.getRow(i),i+1);}if(isDelNullPara){if(para.getText() != null && para.getText().length() > 0){}else {targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(para));}}tableOne.removeRow(0);}/*** <b> 在段落中插入表格--源表格来源于其他Word* </b><br><br><i>Description</i> : 表格单元格中建段落再插入表格,原段落会挤到下一个段落,用isDelNullPara控制删除空原段落,* isDelNullPara为true时要注意循环迭代,最好倒序循环para,插入表格后还有对para操作时也要注意,可能isDelNullPara要设为false* @param srcPath 源表格所在源Word的路径* @param tableIndex 源表格所在源Word中是第几个,即下标* @param targetDoc 要插入的文档* @param para 要插入表格的段落* @param isDelNullPara 是否删除para为空是多出来的空段落* @return void* <br><br>Date: /12/12 11:39<br>Author : dxl*/public static void insertTableInParaFromAtherDoc(String srcPath,int tableIndex,CustomXWPFDocument targetDoc,XWPFParagraph para,boolean isDelNullPara) throws IOException {XmlCursor cursor = para.getCTP().newCursor();File file = new File(srcPath);InputStream is = new FileInputStream(file);CustomXWPFDocument srcDoc = new CustomXWPFDocument(is);XWPFTable sourceTable = srcDoc.getTableArray(tableIndex);XWPFTable tableOne = targetDoc.insertNewTbl(cursor);for(int i = 0; i < sourceTable.getRows().size(); i++){copy(tableOne,sourceTable.getRow(i),i+1);tableOne.removeRow(0);}if(isDelNullPara){if(para.getText() != null && para.getText().length() > 0){}else {targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(para));}}close(is);}/*** @Description: 跨列合并*/public static void mergeCellsCol(XWPFTable table, int row, int fromCell, int toCell) {for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(row).getCell(cellIndex);if ( cellIndex == fromCell ) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}}/*** @Description: 跨行合并*/public static void mergeCellsRow(XWPFTable table, int col, int fromRow, int toRow) {for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {XWPFTableCell cell = table.getRow(rowIndex).getCell(col);if ( rowIndex == fromRow ) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);} else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);}}}}

五、最后生成的word文档

六、Word中公式解析(好似得具体公式具体分析)

6.1需要在上面依赖基础上添加依赖

<dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.4</version></dependency>

6.2以最简单的公式为例:

在WordGrtUtil中的代码测试的

/*** 替换段落里面的变量* @param doc 要替换的文档* @param params 参数*/private static void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) {Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();XWPFParagraph para;while (iterator.hasNext()) {para = iterator.next();System.out.println(".........000.......: "+para.getCTP().getOMathList());if(para.getCTP().getOMathList().size() > 0){System.out.println("..........111......: "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getE().getRList().get(0).getT2List().get(0).getStringValue());System.out.println("........222........: "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSub().getRList().get(0).getT2List().get(0).getStringValue());System.out.println("........333........: "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).getStringValue());para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).setStringValue("www");}replaceInPara(para, params, doc);}}

6.3打印为:

.........000.......: [].........000.......: [<m:sSubSup xmlns:m="/officeDocument//math" xmlns:mc="/markup-compatibility/" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="/officeDocument//relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="/wordprocessingml//main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="/office/word//wordml" xmlns:wne="/office/word//wordml" xmlns:wp="/drawingml//wordprocessingDrawing" xmlns:wp14="/office/word//wordprocessingDrawing" xmlns:wpc="/office/word//wordprocessingCanvas" xmlns:wpg="/office/word//wordprocessingGroup" xmlns:wpi="/office/word//wordprocessingInk" xmlns:wps="/office/word//wordprocessingShape"><m:sSubSupPr><m:ctrlPr><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr></m:ctrlPr></m:sSubSupPr><m:e><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>a</m:t></m:r></m:e><m:sub><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>n</m:t></m:r></m:sub><m:sup><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>m</m:t></m:r></m:sup></m:sSubSup>, <m:sSubSup xmlns:m="/officeDocument//math" xmlns:mc="/markup-compatibility/" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="/officeDocument//relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="/wordprocessingml//main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="/office/word//wordml" xmlns:wne="/office/word//wordml" xmlns:wp="/drawingml//wordprocessingDrawing" xmlns:wp14="/office/word//wordprocessingDrawing" xmlns:wpc="/office/word//wordprocessingCanvas" xmlns:wpg="/office/word//wordprocessingGroup" xmlns:wpi="/office/word//wordprocessingInk" xmlns:wps="/office/word//wordprocessingShape"><m:sSubSupPr><m:ctrlPr><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr></m:ctrlPr></m:sSubSupPr><m:e><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>b</m:t></m:r></m:e><m:sub><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>y</m:t></m:r></m:sub><m:sup><m:r><w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr><m:t>x</m:t></m:r></m:sup></m:sSubSup>]..........111......: a........222........: n........333........: m.........000.......: []

6.4分析:

第二个000行打印为有公式时的集合(两个),第一和第三000为空 [ ];公式是以<m:sSubSup开头的,所以para.getCTP().getOMathList()之后要拿到SSubSup集合,对应为如para.getCTP().getOMathList().get(0).getSSubSupList() ;可以看到公式中的 “a” 在<m:sSubSup标签下三层标签<m:e> <m:r><m:t>中,获得每一层都有对应的方法,如getE().getRList().get(0).getT2List(),其中有的方法返回是集合有的不是;拿到<m:t>后就可以拿到具体的公式中的值了(a),如getE().getRList().get(0).getT2List().get(0).getStringValue();111输出打印的就是..........111......: a同理 上标 “m” 在<m:sup> <m:r> <m:t>标签中,getSup().getRList().get(0).getT2List().get(0).getStringValue()拿到 “ m”值;同理拿到 “n”的值;注意:每个标签都有对应的获取方法,通常应为标签中冒号后字符的对应如<m:sup> 对应 getSup(), <m:r> 对应getRList();改变值时使用getStringValue() 对应的 setStringValue()即可,如:para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).setStringValue("www");新建公式是,应该是按照这个标签层层新增,方法以add开头,每个标签都有对应的方法,对应关系应该同 8;

6.5修改结果

七、段落(单元格)插入表格

7.1原word

7.2另外word制定表格

7.3插入表格

在方法replaceInPara中遍历段落时使用insertTableInParaFromAtherDoc方法插入7.2中的表格;具体解释看方法注释

结果如下:

使用poi根据模版生成word文档 支持插入图片 复制表格 插入 循环插入数据 继承模板大部分格式及样式(优化版)

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