总结之数据导出到word模板——使用poi导出

    技术2022-07-10  143

    我们先看看需求: 我们要在模板标题插入内容,在多个表格中填充数据

    先看东西

    这里我写了个poi工具类方便操作

    import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.poi.POIXMLDocument; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; public class Word2007Util { /** * Description: 根据指定的参数值、模板,生成 word 文档 * @param replaceParamMap 需要替换的参数map * @param doc 文档对象 * @return 生成后的 word 文档对象 */ public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, XWPFDocument doc) { try { if (replaceParamMap != null && replaceParamMap.size() > 0) { // 处理段落 List<XWPFParagraph> paragraphList = doc.getParagraphs(); processParagraphs1(paragraphList, replaceParamMap, doc); // 处理表格 Iterator<XWPFTable> it = doc.getTablesIterator(); while (it.hasNext()) { XWPFTable table = it.next(); List<XWPFTableRow> rows = table.getRows(); for (XWPFTableRow row : rows) { List<XWPFTableCell> cells = row.getTableCells(); for (XWPFTableCell cell : cells) { List<XWPFParagraph> paragraphListTable = cell.getParagraphs(); processParagraphs1(paragraphListTable, replaceParamMap, doc); } } } } } catch (Exception e) { e.printStackTrace(); } return doc; } /** * Description: 根据指定的参数值、模板,生成 word 文档 * @param replaceParamMap 需要替换的参数map * @param is 文档输入流 * @return 生成后的 word 文档对象 */ public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, InputStream is) { try { return replaceWord(replaceParamMap, new XWPFDocument(is)); } catch (IOException e) { e.printStackTrace(); } return null; } /** * Description: 根据指定的参数值、模板,生成 word 文档 * @param replaceParamMap 需要替换的参数map * @param docTemplate 文档模版路径 * @return 生成后的 word 文档对象 */ public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, String docTemplate) { OPCPackage pack; try { pack = POIXMLDocument.openPackage(docTemplate); return replaceWord(replaceParamMap, new XWPFDocument(pack)); } catch (IOException e) { e.printStackTrace(); } return null; } /** * Description: 处理段落中的文字和图片替换 * @param paragraphList 段落集合 * @param replaceParamMap 需要替换的参数map * @param doc 文档对象 */ public static void processParagraphs1(List<XWPFParagraph> paragraphList, Map<String, Object> replaceParamMap, XWPFDocument doc) { if (paragraphList == null || paragraphList.size() <= 0) { return; } //循环段落 for (XWPFParagraph paragraph : paragraphList) { List<XWPFRun> runs = paragraph.getRuns(); //循环每个小节,拼接为一个字符串,避免拆分的时候,误把替换字段标记 拆分 StringBuffer buffer = new StringBuffer(); for (XWPFRun xwpfRun : runs) { String text = xwpfRun.getText(0); if (text == null) { continue; } buffer.append(text); } //循环替换字段map,替换内容 String textString = buffer.toString(); for (Entry<String, Object> entry : replaceParamMap.entrySet()) { String key = entry.getKey(); if (textString.indexOf(key) != -1) { //isSetText = true; Object value = entry.getValue(); if(value == null) { textString = textString.replace(key, ""); } if (value instanceof Map) {// 图片替换 // TODO 待实现 } else {//非map,则将值转换为string类型 textString = textString.replace(key, StringUtil.isNotEmpty(String.valueOf(value)) ? String.valueOf(value) : ""); } } } //再次循环 把替换后的字符串 赋值给每个段落的最后一个小节,前面的小节全部设为空 for(int i=0;i<runs.size();i++){ XWPFRun run = runs.get(i); if(i<(runs.size()-1)){ run.setText(null, 0); }else{ //如果内容里面有换行标签 需要替换掉换行标签 并加入换行功能 if(textString.indexOf("<br>") !=-1){ String s[] = textString.split("<br>"); for (int j = 0; j < s.length; j++) { run.setText(s[j],j); if(j<s.length-1){ run.addBreak(); //换行 } } }else{ run.setText(textString, 0); } } } } } /** * Description: 处理段落中的文字和图片替换 * @param paragraphList 段落集合 * @param replaceParamMap 需要替换的参数map * @param doc 文档对象 */ public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> replaceParamMap, XWPFDocument doc) { if (paragraphList == null || paragraphList.size() <= 0) { return; } for (XWPFParagraph paragraph : paragraphList) { List<XWPFRun> runs = paragraph.getRuns(); for (XWPFRun run : runs) { String text = run.getText(0); if (text == null) { continue; } boolean isSetText = false; for (Entry<String, Object> entry : replaceParamMap.entrySet()) { String key = entry.getKey(); if (text.indexOf(key) != -1) { isSetText = true; Object value = entry.getValue(); if(value == null) { text = text.replace(key, ""); } if (value instanceof String || value instanceof Integer || value instanceof Float || value instanceof Double) {// 文本替换 text = text.replace(key, StringUtil.isNotEmpty(value.toString()) ? value.toString() : "-"); } if (value instanceof Map) {// 图片替换 // TODO 待实现 } } } if (isSetText) { run.setText(text, 0); } } } } /** * Description: 将输入流中的数据写入字节数组 * @param in 输入流 * @param isClose 是否关闭输入流 * @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) { System.out.println("关闭流失败"); } } } return byteArray; } /** * 取消表格边框 */ public static void removeTableBroder(XWPFTable table){ /**************************************/ CTTblBorders borders=table.getCTTbl().getTblPr().addNewTblBorders(); CTBorder hBorder=borders.addNewInsideH(); hBorder.setVal(STBorder.Enum.forString("none")); hBorder.setSz(new BigInteger("1")); hBorder.setColor("0000FF"); CTBorder vBorder=borders.addNewInsideV(); vBorder.setVal(STBorder.Enum.forString("none")); vBorder.setSz(new BigInteger("1")); vBorder.setColor("00FF00"); CTBorder lBorder=borders.addNewLeft(); lBorder.setVal(STBorder.Enum.forString("none")); lBorder.setSz(new BigInteger("1")); lBorder.setColor("3399FF"); CTBorder rBorder=borders.addNewRight(); rBorder.setVal(STBorder.Enum.forString("none")); rBorder.setSz(new BigInteger("1")); rBorder.setColor("F2B11F"); CTBorder tBorder=borders.addNewTop(); tBorder.setVal(STBorder.Enum.forString("none")); tBorder.setSz(new BigInteger("1")); tBorder.setColor("C3599D"); CTBorder bBorder=borders.addNewBottom(); bBorder.setVal(STBorder.Enum.forString("none")); bBorder.setSz(new BigInteger("1")); bBorder.setColor("F7E415"); } /** * 设置单元格样式 */ public static void setCellStyle(XWPFTableCell cell,String text,String fontFamily){ cell.removeParagraph(0); cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中 XWPFParagraph paragraphX = cell.addParagraph(); paragraphX.setFontAlignment(2); XWPFRun run = paragraphX.createRun(); run.setFontFamily(fontFamily); run.setText(text); } }

    调用Controller

    public class ExportController { @Autowired private ProjectApplyFlowService projectApplyFlowService; @Autowired private SpecialInfoService specialInfoService; @Autowired private StartSpecialInfoService startSpecialInfoService; /*** * @Param [id, request, response] * @return void * @Description 导出项目汇总表 * @author liuzonghua * @date 2020/6/30 17:48 **/ @RequestMapping("exportSpecialProject") public void expertSpecialProject(String id, HttpServletRequest request, HttpServletResponse response){ try { InputStream in = ResourceUtil.getResourceAsStream("/doc/applyCollectTable.docx"); XWPFDocument doc = null; //数据 SearchCondition jqGridSearch = new JQGridSearch(); User currentUser = (User) this.getCurrentUser(request, response); ConditionGroupsBuilder conditionGroupsBuilder = new ConditionGroupsBuilder(); conditionGroupsBuilder.addConditionField(new ConditionField("", "areaDepartmentId", ConditionFieldOp.BASE_EQUAL, currentUser.getDepartmentId())); if(StringUtils.isNotBlank(id)) { conditionGroupsBuilder.addConditionField(new ConditionField("", "projectBatchId", ConditionFieldOp.BASE_EQUAL, id)); } jqGridSearch.addExtraConditionGroups(conditionGroupsBuilder.build()); //word多表结构(可再封装方法) List<List<Map<String, Object>>> data = new ArrayList<>(); List<Map<String, Object>> list = projectApplyFlowService.findCollectByProjectBatchIdAndAreaDepartmentId(id,currentUser.getDepartmentId()); data.add(list); StartSpecialInfo startSpecialInfo = startSpecialInfoService.findById(id); if(CollectionUtil.isNotEmpty(startSpecialInfo)){ SpecialInfo specialInfo = specialInfoService.findById(startSpecialInfo.getSpecialId()); if(CollectionUtil.isNotEmpty(specialInfo)){ doc = this.exportListDoc(in, data,specialInfo.getSpecialName()); } } String fileName = "项目申报汇总表"+ ".docx"; response.reset(); this.setDownloadResponse(request, response, fileName); ByteArrayOutputStream ostream = new ByteArrayOutputStream(); ServletOutputStream servletOS = response.getOutputStream(); doc.write(ostream); servletOS.write(ostream.toByteArray()); servletOS.flush(); servletOS.close(); } catch (Exception e) { e.printStackTrace(); } } /** * @Param [in, data, specialName] * @return org.apache.poi.xwpf.usermodel.XWPFDocument * @Description 导出doc * @author liuzonghua * @date 2020/6/30 17:49 **/ public XWPFDocument exportListDoc(InputStream in, List<List<Map<String, Object>>> data,String specialName) { Map<String, Object> map = new LinkedHashMap<String, Object>(); map.put("${special}", specialName); XWPFDocument doc = Word2007Util.replaceWord(map, in); docList(data, doc); return doc; } /** * 导出列表 * @param data * @param doc * Description: * Date: 2019年9月27日 * Time: 上午10:27:47 * @author liu.zonghua */ private void docList(List<List<Map<String, Object>>> data,XWPFDocument doc){ //得到表格对象列表 List<XWPFTable> tables = doc.getTables(); for(int j=0;j<data.size();j++) { if(CollectionUtil.isNotEmpty(data.get(j))){ int i = 0; for(Map<String, Object> map : data.get(j)){ //取第j+1个列表 XWPFTable table = tables.get(j); //获取表格行对象 XWPFTableRow row = null; row = table.createRow(); XWPFTableCell cell0 = row.getCell(0); Word2007Util.setCellStyle(cell0, StringUtil.parseString(i + 1),"仿宋"); XWPFTableCell cell1 = row.getCell(1); Word2007Util.setCellStyle(cell1, MapUtils.getString(map, "title","") ,"仿宋"); XWPFTableCell cell2 = row.getCell(2); Word2007Util.setCellStyle(cell2,MapUtils.getString(map, "startNum",""),"仿宋"); XWPFTableCell cell3 = row.getCell(3); Word2007Util.setCellStyle(cell3,MapUtils.getString(map, "projectLeader",""),"仿宋"); XWPFTableCell cell4 = row.getCell(4); Word2007Util.setCellStyle(cell4, MapUtils.getString(map, "phone",""),"仿宋"); XWPFTableCell cell5 = row.getCell(5); Word2007Util.setCellStyle(cell5, MapUtils.getString(map, "enterpriseStartTime",""),"仿宋"); XWPFTableCell cell6 = row.getCell(6); Word2007Util.setCellStyle(cell6, MapUtils.getString(map, "enterpriseEndTime",""),"仿宋"); i++; } }else { //取第j+1个列表 XWPFTable table = tables.get(j); //获取表格行对象 XWPFTableRow row = null; row = table.createRow(); XWPFTableCell cell0 = row.getCell(0); Word2007Util.setCellStyle(cell0,"","仿宋"); XWPFTableCell cell1 = row.createCell(); Word2007Util.setCellStyle(cell1, "","仿宋"); XWPFTableCell cell2 = row.createCell(); Word2007Util.setCellStyle(cell2, "","仿宋"); XWPFTableCell cell3 = row.createCell(); Word2007Util.setCellStyle(cell3, "","仿宋"); XWPFTableCell cell4 = row.createCell(); Word2007Util.setCellStyle(cell4, "","仿宋"); XWPFTableCell cell5 = row.createCell(); Word2007Util.setCellStyle(cell5, "","仿宋"); } } } /*** * @Param [request, response, fileName] * @return void * @Description 下载相关 * @author liuzonghua * @date 2020/6/30 17:49 **/ public void setDownloadResponse(HttpServletRequest request, HttpServletResponse response, String fileName) throws Exception { response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); String downloadFileName = ""; if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) { downloadFileName = URLEncoder.encode(fileName, "UTF-8"); } else { downloadFileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1"); } response.setHeader("Content-disposition", "attachment; filename=" + downloadFileName); } }

    解析

    public XWPFDocument exportListDoc(InputStream in, List<List<Map<String, Object>>> data,String specialName) { Map<String, Object> map = new LinkedHashMap<String, Object>(); map.put("${special}", specialName); XWPFDocument doc = Word2007Util.replaceWord(map, in); docList(data, doc); return doc; }

    这块来替换word中${}数据

    得到多个表格对象

    List<XWPFTable> tables = doc.getTables();

    通过List<List<Map<String, Object>>数据来与表格对应

    然后获取表格,填充内容,设置样式。

    //获取表格行对象 XWPFTableRow row = null; row = table.createRow(); XWPFTableCell cell0 = row.getCell(0); Word2007Util.setCellStyle(cell0, StringUtil.parseString(i + 1),"仿宋");
    Processed: 0.015, SQL: 9