java POI 导出到word文档 (附工具类)
1,导入poi相关依赖
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>4.0.1</version> </dependency>
2,直接附工具类,注解很详细
package com.hl.bluetooth.util; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; import org.apache.poi.xwpf.usermodel.*; import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author hwx * @date 2021-9-22 11:31:09 */ public class WordUtils { /** * 根据模板生成word * * @param path 模板的路径 * @param params 需要替换的参数 (静态替换 格式 params.put("${releaeTime}", releaeTime);) * @param tableList 需要插入的参数 (动态替换) * @param fileName 生成word文件的文件名 * @param response */ public void getWord(String path, Map<String, Object> params, List<String[]> tableList, String fileName, HttpServletResponse response) throws Exception { File file = new File(path); InputStream is = new FileInputStream(file); XWPFDocument doc = new XWPFDocument(is); this.createHeader(doc, (String) params.get("${id}")); //设置页眉 this.replaceInPara(doc, params); //替换文本里面的变量 this.replaceInTable(doc, params, tableList); //替换表格里面的变量 List<XWPFTable> tables = doc.getTables(); XWPFTable xwpfTable = tables.get(4); insertTable(xwpfTable, tableList); //插入数据 OutputStream os = response.getOutputStream(); response.setHeader("Content-disposition", "attachment; filename=" + fileName); doc.write(os); this.close(os); this.close(is); } /** * description: 添加不带图片的页眉 * create by: hwx * create time: 2021-10-8 15:01:16 */ public void createHeader(XWPFDocument docx, String orgFullName) throws Exception { CTP ctp = CTP.Factory.newInstance(); XWPFParagraph paragraph = new XWPFParagraph(ctp, docx);//段落对象 // ctp.addNewR().addNewT().setStringValue("山东电力研究院检测报告 报告编号:"+orgFullName);//设置页眉参数 if (StringUtils.isNotEmpty(orgFullName)) { XWPFRun run = paragraph.createRun(); run.setText(" 山东电力研究院检测报告 报告编号:" + orgFullName); setXWPFRunStyle(run, "黑体", 11); } ctp.addNewR().addNewT().setSpace(SpaceAttribute.Space.PRESERVE); CTSectPr sectPr = docx.getDocument().getBody().isSetSectPr() ? docx.getDocument().getBody().getSectPr() : docx.getDocument().getBody().addNewSectPr(); XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(docx, sectPr); XWPFHeader header = policy.createHeader(STHdrFtr.DEFAULT, new XWPFParagraph[]{paragraph}); header.setXWPFDocument(docx); } /** * 设置页脚的字体样式 * * @param r1 段落元素 */ private void setXWPFRunStyle(XWPFRun r1, String font, int fontSize) { r1.setFontSize(fontSize); CTRPr rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr(); CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts(); fonts.setAscii(font); fonts.setEastAsia(font); fonts.setHAnsi(font); } /** * 替换段落里面的变量 * * @param doc 要替换的文档 * @param params 参数 */ private void replaceInPara(XWPFDocument doc, Map<String, Object> params) { Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator(); XWPFParagraph para; while (iterator.hasNext()) { para = iterator.next(); this.replaceInPara(para, params, doc); } } /** * 替换段落里面的变量 * * @param para 要替换的段落 * @param params 参数 */ private void replaceInPara(XWPFParagraph para, Map<String, Object> params, XWPFDocument doc) { List<XWPFRun> runs; Matcher matcher; if (this.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.charAt(0) && '{' == runText.charAt(1)) { start = i; } if ((start != -1)) { str += runText; } if ('}' == runText.charAt(runText.length() - 1)) { if (start != -1) { end = i; break; } } } for (int i = start; 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.createRun().setText(str, 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); // doc.createPicture(doc.getAllPictures().size() - 1, width, height, para); para.createRun().setText(str, 0); break; } catch (Exception e) { e.printStackTrace(); } } } } } } /** * 为表格插入数据,行数不够添加新行 * * @param table 需要插入数据的表格 * @param tableList 插入数据集合 */ private static void insertTable(XWPFTable table, List<String[]> tableList) { //创建行,根据需要插入的数据添加新行,不处理表头 /* for (int i = 0; i < tableList.size(); i++) { XWPFTableRow row = table.createRow(); } //遍历表格插入数据 List<XWPFTableRow> rows = table.getRows(); int length = table.getRows().size(); for (int i = 1; i < length - 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 = tableList.get(i - 1)[j]; cell.setText(s); } }*/ //创建行和创建需要的列 for (int i = 1; i < tableList.size(); i++) { //添加一个新行 XWPFTableRow row = table.insertNewTableRow(1); for (int k = 0; k < tableList.get(0).length; k++) { row.createCell();//根据String数组第一条数据的长度动态创建列 } } //创建行,根据需要插入的数据添加新行,不处理表头 for (int i = 0; i < tableList.size(); i++) { List<XWPFTableCell> cells = table.getRow(i + 1).getTableCells(); for (int j = 0; j < cells.size(); j++) { XWPFTableCell cell02 = cells.get(j); cell02.setText(tableList.get(i)[j]); } } } /** * 替换表格里面的变量 * * @param doc 要替换的文档 * @param params 参数 */ private void replaceInTable(XWPFDocument doc, Map<String, Object> params, List<String[]> tableList) { 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() > 0) { //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 if (this.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) { this.replaceInPara(para, params, doc); } } } } else { insertTable(table, tableList); //插入数据 } } } } /** * 正则匹配字符串 * * @param str * @return */ private Matcher matcher(String str) { Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(str); return matcher; } /** * 根据图片类型,取得对应的图片类型代码 * * @param picType * @return int */ private static int getPictureType(String picType) { int res = XWPFDocument.PICTURE_TYPE_PICT; if (picType != null) { if (picType.equalsIgnoreCase("png")) { res = XWPFDocument.PICTURE_TYPE_PNG; } else if (picType.equalsIgnoreCase("dib")) { res = XWPFDocument.PICTURE_TYPE_DIB; } else if (picType.equalsIgnoreCase("emf")) { res = XWPFDocument.PICTURE_TYPE_EMF; } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) { res = XWPFDocument.PICTURE_TYPE_JPEG; } else if (picType.equalsIgnoreCase("wmf")) { res = XWPFDocument.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 void close(InputStream is) { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 关闭输出流 * * @param os */ private void close(OutputStream os) { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3,对应的模板