java使用poi操作word插入图片、段落、表格
其他链接准备工作创建word模板.docx文件编写模板格式.xml文件java上手poimaven依赖使用到的包具体应用对应封装方法 ----------图片插入指定位置操作图片操作使用到的工具类对应封装方法 ----------表格操作表格操作用到的工具类对应封装方法 ----------段落内容替换操作段落内容操作用到的工具类效果图如果想设置单独的样式其他链接
java使用poi操作world生成饼图,柱状图,折线图,组合图:一
java使用poi操作world生成饼图,柱状图,折线图,组合图:二
问题链接
准备工作
创建word模板.docx文件
使用模板操作,因为自己使用poi去写word过于麻烦,耦合性太高
${XXX}理解成占位符,会替换为填充的数据,可配置为其他比如*{xxx}*
编写模板格式.xml文件
创建的.docx文件顺序基本是乱的,需要另存为.xml格式手动更改格式
用编译器打开(我用的IDEA)找到要替换的占位符的位置
把所有要替换的位置都找到改为一行
以此类推改完所有替换内容的标识
改完之后在改成.docx格式
java上手poi
maven依赖
<dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>2.6.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.9</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>3.16</version></dependency>
使用到的包
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;import org.apache.poi.xwpf.usermodel.*;import org.openqa.selenium.JavascriptExecutor;import org.openqa.selenium.OutputType;import org.openqa.selenium.TakesScreenshot;import org.openqa.selenium.phantomjs.PhantomJSDriver;import org.openqa.selenium.phantomjs.PhantomJSDriverService;import org.openqa.selenium.remote.DesiredCapabilities;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import org.springframework.util.CollectionUtils;import org.springframework.util.StringUtils;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.text.DecimalFormat;import java.util.*;import java.util.List;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;
具体应用
/*** 读取模板* @param HttpServletResponse * @throws Exception*/public void operatorWord(HttpServletResponse response) throws Exception {//获得模板文件InputStream docis = new FileInputStream("C:\Users\16630\Desktop\模板A.docx");//转成wordCustomXWPFDocument document = new CustomXWPFDocument(docis);//写入图片this.insertImage(document);//写入表格this.insertTable(document);//段落替换对象this.insertText(document)//把doc输出到输出流response.setCharacterEncoding("UTF-8");response.setContentType("application/msword");//文件名String fileName = "考试成绩分析" + htmlDataTime.getStartData();response.setHeader("Content-Disposition", "attachment;fileName="+ new String(fileName.getBytes("UTF-8"),"ISO-8859-1"));ServletOutputStream responseOutputStream = response.getOutputStream();document.write(responseOutputStream);responseOutputStream.flush();responseOutputStream.close();in.close();}
对应封装方法 ----------图片插入指定位置操作
/*** 写入图片在word中* @param document* @throws IOException* @throws InvalidFormatException*/private void insertImage(CustomXWPFDocument document) throws IOException, InvalidFormatException {//图片FileInputStream in = new FileInputStream(new("C:\Users\16630\Desktop\image.jpg"));//段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//获取到段落中的所有文本内容String text = paragraph.getText();//判断此段落中是否有需要进行替换的文本if (WordUtil.checkText(text)) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置String key = "${image}";if (run.toString().indexOf(key) != -1) {byte[] ba = new byte[in.available()];int len = in.read(ba);ByteArrayInputStream byteInputStream = new ByteArrayInputStream(ba, 0, len);//设置图片document.addPictureData(byteInputStream, XWPFDocument.PICTURE_TYPE_PNG);//创建一个word图片,并插入到文档中-->像素可改document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);}break;}break;}}}
图片操作使用到的工具类
/*** @author BM_hyjw*/import java.io.IOException;import java.io.InputStream;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;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 = super.getRelationId(super.getAllPictures().get(id));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("图片名称");docPr.setDescr("描述信息");}}
对应封装方法 ----------表格操作
private void insertTable(CustomXWPFDocument document) {//创建表格接受参数-->外层list是行内层是列List<List<String>> tableList = new ArrayList();List<String> cells = new ArrayList<>();cells.add("1");cells.add("张三");cells.add("100");tableList.add(cells);List<String> cellList = new ArrayList<>();cellList.add("2");cellList.add("李四");cellList.add("10");tableList.add(cellList);//获取表格位置List<XWPFTable> tables = document.getTables();WordUtil.insertTable(tables.get(0),tableList);}
表格操作用到的工具类
/*** 为表格插入数据,行数不够添加新行** @param table需要插入数据的表格* @param tableList 插入数据集合*/public static void insertTable(XWPFTable table, List<List<String>> tableList) {//创建行,根据需要插入的数据添加新行,不处理表头for (int i = 1; i <= tableList.size(); i++) {table.createRow();}//遍历表格插入数据List<XWPFTableRow> rows = table.getRows();for (int i = 1; i < rows.size(); i++) {XWPFTableRow newRow = table.getRow(i);List<XWPFTableCell> cells = newRow.getTableCells();for (int j = 0; j < cells.size(); j++) {XWPFTableCell cell = cells.get(j);cell.setText(tableList.get(i - 1).get(j));//表格样式一致-->没有此段表格会默认左对齐//有此段会使表格格式一致CTTc cttc = cell.getCTTc();CTTcPr ctPr = cttc.addNewTcPr();ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);}}}
对应封装方法 ----------段落内容替换操作
private void insertText(CustomXWPFDocument document) {//声明替换模板对象Map textMap = new HashMap();textMap.put("${maxName}","张三");textMap.put("${maxScore}", "100");textMap.put("${minName}","李四");textMap.put("${minScore}", "10");//替换模板数据WordUtil.changeText(document,textMap);}
段落内容操作用到的工具类
/*** 替换段落文本** @param document docx解析对象* @param textMap 需要替换的信息集合*/public static void changeText(XWPFDocument document, Map<String, Object> textMap) {//获取段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//获取到段落中的所有文本内容String text = paragraph.getText();//判断此段落中是否有需要进行替换的文本if (checkText(text)) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置run.setText(changeValue(run.toString(), textMap), 0);}}}}/*** 判断文本中是否包含$** @param text 文本* @return 包含返回true, 不包含返回false*/public static boolean checkText(String text) {boolean check = false;if (text.indexOf("$") != -1) {check = true;}return check;}/*** 替换模板${}*/private static Object changeValue(String value, Map<String, Object> textMap) {Set<Map.Entry<String, Object>> textSets = textMap.entrySet();Object valu = "";for (Map.Entry<String, Object> textSet : textSets) {// 匹配模板与替换值 格式${key}String key = textSet.getKey();if (value.contains(key)) {valu = textSet.getValue();}}return valu;}
效果图
如果想设置单独的样式
比如加颜色、居中等,要确保.xml中替换单位为一行
效果