背景:接到月末要自动生成报表,包含了文本模板描述,表格报表见图,每一个变量都是唯一

2:技术方案:

用Map<key,value>存储变量名和变量值,读word文本readbuffer遍历文本进行字符匹配用于替换

3:代码示例:

package com.extracme.hntask.oas.business.service;import com.alibaba.fastjson.JSON;
import com.extracme.hntask.common.BaseDto;
import com.extracme.hntask.common.OfficeBaseDto;
import com.extracme.hntask.common.OfficeCommonDefine;
import com.extracme.hntask.oas.business.domain.MonthlyReportInfo;
import com.extracme.hntask.oas.business.entity.CityStatisticsVo;
import com.extracme.hntask.oas.business.entity.ReportOperationalMonitoringDo;
import com.extracme.hntask.oas.business.entity.ReportStationTop10Do;
import com.extracme.hntask.oas.business.iservice.IServiceReport;
import com.extracme.hntask.oas.business.iservice.IServiceStatistics;
import com.extracme.hntask.oas.business.mapper.MonthlyReportInfoMapper;
import com.extracme.hntask.utils.CustomXWPFDocument;
import com.extracme.hntask.utils.OSSUtil;
import com.extracme.hntask.utils.OfficeUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.IOUtils;
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.XWPFTableRow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.io.*;
import java.math.BigInteger;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/* *** @title Extracme SH* @project* @note    自动月报* @author alex* @Date 2019/10/29*/
@Service
public class ServiceReport implements IServiceReport {private final Logger log = LoggerFactory.getLogger(this.getClass());@Autowiredprivate IServiceStatistics serviceStatistics;@Resourceprivate MonthlyReportInfoMapper monthlyReportInfoMapper;@Resourceprivate OSSUtil oSSUtil;@Value(value = "${monthlyReportUrl}")private String monthlyReportUrl;@Value(value = "${templatePath}")private String templatePath;/*** @param tempParam 封装 对应 模板字段 的参数 数据的map*/public Map<String, Object> EncapsulationTempParamDate2ReplaceText(Map<String, Object> tempParam) {/*** 一、全省充电设施情况*/tempParam = serviceStatistics.getHomeStatistics(tempParam);System.out.println("一:|"+JSON.toJSONString(tempParam));/*** 二、 运营监测情况*/tempParam = serviceStatistics.queryOperationMonitor(tempParam);System.out.println("二:|"+JSON.toJSONString(tempParam));/*** 三、排名情况*/tempParam = serviceStatistics.queryLMOrderTop10(tempParam);System.out.println("三:|"+JSON.toJSONString(tempParam));/*** 四、接入平台的充电桩市县分布情况*/tempParam = serviceStatistics.findAllOrgCityStatistics(tempParam);System.out.println("四:|"+JSON.toJSONString(tempParam));return tempParam;}@Overridepublic void generateMonthStatsReportByMonthly() throws IOException {InputStream isUpload = null;InputStream is = null;try {/*** 1:下载模板转化bytes 数据处理word*/URL url = new URL(monthlyReportUrl);//http://evready-test.oss-cn-shanghai.aliyuncs.com/hainan/template/MonthlyReport%28hnjk%29.docxis = url.openStream();byte[] templateBytes = IOUtils.toByteArray(is);//OSSUtil.downloadOssFileByUrl(null);//4.下载报告模板if (templateBytes == null) {log.error("下载的报告模板 is null,下载错误");return;}/*** 2:封装模板参数数据用于替换*/Map<String, Object> tempParam = new HashMap<String, Object>();tempParam = EncapsulationTempParamDate2ReplaceText(tempParam);if (tempParam.isEmpty()) {System.err.println("封装模板参数数据用于替换 map|" + null);log.error("封装模板参数数据用于替换 map is null,return");return;}SimpleDateFormat format = new SimpleDateFormat("yyyy");Date date = new Date();Calendar calendar = Calendar.getInstance();calendar.setTime(date); // 设置为当前时间calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1); // 设置为上一个月date = calendar.getTime();String year = format.format(date);SimpleDateFormat format2 = new SimpleDateFormat("MM");String lastMonth = format2.format(date);BaseDto dto = new BaseDto();dto.setYear(year);dto.setLastMonth(lastMonth);tempParam.put("${year}", year);tempParam.put("${lastMonth}", lastMonth);//替换word中的自定义字符串以及图片(适用于word2003+ 版本)byte[] byt = this.replaceAndGenerateWord(dto, templateBytes, tempParam);
//            //写本地
//            File cc = new File("C:\\Users\\alex\\Desktop\\extracme\\外部业务\\海南充电桩平台\\政府平台\\技术方案\\自动月报\\aa.docx");
//            OutputStream out = new FileOutputStream(cc);
//            out.write(byt);/*** 3:替换后数据的模板 上传到oss 供页面下载*/String fileName = year+lastMonth+"_reportMonthly.docx";String filePath=templatePath+fileName;isUpload = new ByteArrayInputStream(byt);oSSUtil.uploadFile(isUpload, filePath);/*** 4:数据处理word insert到mysql*///用此线程单独记录月报信息用(不影响generateReport)String report_body=JSON.toJSON(tempParam)+"";MonthlyReportInfo mr=new MonthlyReportInfo();mr.setYear(dto.getYear());mr.setMonth(dto.getLastMonth());mr.setReportUrl("https://evready-test.oss-cn-shanghai.aliyuncs.com/" + filePath);mr.setCreatedUser("job");mr.setReportBody(report_body);monthlyReportInfoMapper.insert(mr);} catch (Exception e) {log.error("generateMonthStatsReportByMonthly失败", e);e.printStackTrace();} finally {if (is != null) {is.close();}if (isUpload != null) {isUpload.close();}}}/*** 获取报告模板** @param templateUrl 模板oss地址* @return*/private byte[] reportTemplate(String templateUrl) {// 获取原始记录模版URL// 获取原始记录模版byte[] templateByte = null;try {templateByte = OSSUtil.downloadOssFileByUrl(templateUrl);} catch (Exception e) {log.error("get downloadOssFileByFileUrl err|" + e.getMessage());e.printStackTrace();}return templateByte;}/*** 替换word中的自定义字符串以及图片(适用于word2003+ 版本)* <p>* 注:2003版本word不支持替换图片,2007版本以上可以替换图片** @param bytes 模板文件流* @param param 原始记录map* @return byte[] 报告OSS保存地址* @throws Exception 异常*/public byte[] replaceAndGenerateWord(BaseDto dto, byte[] bytes, Map<String, Object> param) throws Exception {CustomXWPFDocument document = null;InputStream inputStream = new ByteArrayInputStream(bytes);OPCPackage pack = OPCPackage.open(inputStream);document = new CustomXWPFDocument(pack);document.getHeaderList();// 处理段落List<XWPFParagraph> paragraphList = document.getParagraphs();processParagraphs(dto, paragraphList, param, document);
//        // 处理表格
//        Iterator<XWPFTable> it = document.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) {
//                    final CustomXWPFDocument document2 = document;
//                    List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
//                    processParagraphs(dto, paragraphListTable, param, document2);
//                }
//            }
//        }
//        getExistsPlaceholderListWord(document, existsPlaceholderList);ByteArrayOutputStream fos = new ByteArrayOutputStream();document.write(fos);return fos.toByteArray();}/*** 把 string型的值 替代源模板中的字符*/private static String instanceofStrValue2TemplateStr(String text, String key, String value, XWPFParagraph paragraph) {List<XWPFRun> runs = paragraph.getRuns();String text2 = text.replace(key, value.toString());System.out.println(key + " " + value + "instanceofStr2TemplateStr11  text|" + text + "txt2:" + text2);String keyStr = "";int flag = 0;for (int i = 0; i < runs.size(); i++) {String textTemp = runs.get(i).getText(0);if (textTemp != null && textTemp.contains(key)) {String textStr = textTemp.replace(key, value.toString());runs.get(i).setText(textStr, 0);System.out.println("set key1|"+key+"|"+textStr);runs.get(i).setFontFamily("宋体");break;}// 占位符被截断的方案if (textTemp != null && textTemp.startsWith("$")&& !textTemp.matches("^\\$\\{[a-zA-Z0-9]+\\}$")) {keyStr += textTemp;runs.get(i).setText("", 0);flag = 1;System.out.println("set key2|"+key+"|");} else if (flag == 1) {if (textTemp.contains("}")) {//TODO 此处的contains应该换成startsWith 避免 一个字符为 ”text}“情况keyStr += textTemp;runs.get(i).setText("", 0);System.out.println("set keyStr| "+ keyStr + "|key3 |"+key+"|"+ value.toString());runs.get(i).setText(keyStr.replace(key, value), 0);runs.get(i).setFontFamily("宋体");break;}else{if(textTemp!=null){keyStr += textTemp;runs.get(i).setText("", 0);}}}
//            System.out.println(i+ "runtxt:" + textTemp + " keyStr:"+ keyStr);}return text2;}/*** hainan处理段落** @param dto* @param paragraphList 段落列表* @param map           键值对map* @param doc           doc* @throws InvalidFormatException 异常* @throws FileNotFoundException  异常*/private static void processParagraphs(BaseDto dto, List<XWPFParagraph> paragraphList, Map<String, Object> map,CustomXWPFDocument doc) throws InvalidFormatException, FileNotFoundException {if (paragraphList != null && paragraphList.size() > 0) {// 首选循环段落for (XWPFParagraph paragraph : paragraphList) {// 获取段落的textString text = paragraph.getText();if (StringUtils.isNotBlank(text)) {List<String> ids = new ArrayList<String>();Pattern pattern = Pattern.compile("(?<=\\$\\{)[^}]*(?=\\})");//匹配出${}之间的idMatcher matcher = pattern.matcher(text);while (matcher.find()) {String id = "${" + matcher.group() + "}";ids.add(id);}for (String id : ids) {Object value = map.get(id);System.err.println("test id|" + id + "|value=" + value);String key = id;//字符串值if (value instanceof String) {text = instanceofStrValue2TemplateStr(text, key, value.toString(), paragraph);} else if (value instanceof List) {//1:listinstanceofStrValue2TemplateStr(text, key, "", paragraph);if (OfficeCommonDefine.Report_template_table_name_tag[1].equals(id) || OfficeCommonDefine.Report_template_table_name_tag[2].equals(id)) {//二、    运营监测情况 接入/预接入统计title内容一致String accessTileText = "月(预接入)";if (OfficeCommonDefine.Report_template_table_name_tag[2].equals(id)) {accessTileText = "月(接入)";}System.err.println("--tb1 create--" + id);// 运营监测情况List<ReportOperationalMonitoringDo> list = (List<ReportOperationalMonitoringDo>) value;// 动态创建表头String titleText = dto.getYear() + "年" + dto.getLastMonth() + accessTileText;OfficeBaseDto obd = new OfficeBaseDto(titleText, OfficeCommonDefine.OPERATIONAL_MONITORING_TITLE, 8);XWPFTable table = OfficeUtil.createTableHeader(obd, doc, paragraph);// 动态list行for (int j = 0; j < list.size(); j++) {ReportOperationalMonitoringDo tb1_DO = list.get(j);XWPFTableRow dataRow = table.createRow();dataRow.getCell(0).setText(tb1_DO.getOperatorName());dataRow.getCell(1).setText(tb1_DO.getPowerMonth());String prStr=tb1_DO.getPowerRise();if (StringUtils.isBlank(prStr)) {prStr="";}else if (prStr.indexOf("-") >= 0) {prStr = "↓" + prStr + "%";} else if ("0.00".equals(prStr)||"0".equals(prStr)) {prStr = "0";} else {prStr = "↑" + prStr + "%";}dataRow.getCell(2).setText(prStr);dataRow.getCell(3).setText(tb1_DO.getChargeNumMonth());String crStr = tb1_DO.getChargeNumRise();if (StringUtils.isBlank(crStr)) {crStr="";}else if (crStr.indexOf("-") >= 0) {crStr = "↓" + crStr + "%";
//                                        dataRow.getCell(4).setColor("008000");}else if ("0.00".equals(crStr)||"0".equals(crStr)) {crStr = "0";}else {crStr = "↑" + crStr + "%";
//                                        dataRow.getCell(4).setColor("ff0000");//setColor("ff0000"); //红色}dataRow.getCell(4).setText(crStr);dataRow.getCell(5).setText(tb1_DO.getEquipmentNum());dataRow.getCell(6).setText(tb1_DO.getChargeEquipmentNumMonth());dataRow.getCell(7).setText(tb1_DO.getChargeEquipmentProportion()+"%");}} else if (OfficeCommonDefine.Report_template_table_name_tag[3].equals(id) || OfficeCommonDefine.Report_template_table_name_tag[4].equals(id)|| OfficeCommonDefine.Report_template_table_name_tag[5].equals(id) || OfficeCommonDefine.Report_template_table_name_tag[6].equals(id)) {String firstRowText = "月 充电量排行 前十(预接入)";if (OfficeCommonDefine.Report_template_table_name_tag[4].equals(id)) {firstRowText = "月 充电量排行 前十(接入)";} else if (OfficeCommonDefine.Report_template_table_name_tag[5].equals(id)) {firstRowText = "月 充电次数排行 前十(预接入)";} else if (OfficeCommonDefine.Report_template_table_name_tag[6].equals(id)) {firstRowText = "月 充电次数排行 前十(接入)";}System.err.println("--tb3-6 create--" + id);List<ReportStationTop10Do> list = (List<ReportStationTop10Do>) value;// 动态创建表头String titleText = dto.getYear() + "年" + dto.getLastMonth() + firstRowText;OfficeBaseDto obd = new OfficeBaseDto(titleText, OfficeCommonDefine.STATION_TOP10_TITLE, 4);XWPFTable table = OfficeUtil.createTableHeader(obd, doc, paragraph);//设置标头某列宽度table.getRow(1).getCell(1).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(4000));// 动态行for (int j = 0; j < list.size(); j++) {XWPFTableRow dataRow = table.createRow();String sort = (j + 1) + "";ReportStationTop10Do st_do = list.get(j);dataRow.getCell(0).setText(sort);dataRow.getCell(1).setText(st_do.getStationName());dataRow.getCell(2).setText(st_do.getDistrictName());dataRow.getCell(3).setText(st_do.getOrgName());}} else if (id.indexOf("${layoutTb") >= 0) {//四、接入平台的充电桩市县分布情况 ${tb7}是总计System.err.println("--tb7- create--" + id);List<CityStatisticsVo> list = (List<CityStatisticsVo>) value;System.out.println("layoutTb|" + JSON.toJSONString(list));String titleText = list.get(0).getName();// 动态创建表头OfficeBaseDto obd = new OfficeBaseDto(titleText, OfficeCommonDefine.EQUIPMENT_ACCESS_AREA_TITLE, 5);XWPFTable table = OfficeUtil.createTableHeader(obd, doc, paragraph);// 动态行int size = list.size();int rowCnt=size+1;//加一行为总计int accessStationNumSum=0,preAccessStationNumSum=0;int accessEquipmentNumSum=0,preAccessEquipmentNumSum=0;int accessDCEquipmentNumSum=0,preAccessDCEquipmentNumSum=0;int accessACEquipmentNumSum=0,preAccessACEquipmentNumSum=0;for (int j = 0; j < rowCnt; j++) {XWPFTableRow dataRow = table.createRow();if (j < size) {CityStatisticsVo cs = list.get(j);dataRow.getCell(0).setText(cs.getCity());dataRow.getCell(1).setText(cs.getAccessStationNum() + "/" + cs.getPreAccessStationNum());dataRow.getCell(2).setText(cs.getAccessEquipmentNum() + "/" + cs.getPreAccessEquipmentNum());dataRow.getCell(3).setText(cs.getAccessDCEquipmentNum() + "/" + cs.getPreAccessDCEquipmentNum());dataRow.getCell(4).setText(cs.getAccessACEquipmentNum() + "/" + cs.getPreAccessACEquipmentNum());//算总计rowaccessStationNumSum += cs.getAccessStationNum();preAccessStationNumSum += cs.getPreAccessStationNum();accessEquipmentNumSum += cs.getAccessEquipmentNum();preAccessEquipmentNumSum += cs.getPreAccessEquipmentNum();accessDCEquipmentNumSum += cs.getAccessDCEquipmentNum();preAccessDCEquipmentNumSum += cs.getPreAccessDCEquipmentNum();accessACEquipmentNumSum += cs.getAccessACEquipmentNum();preAccessACEquipmentNumSum += cs.getPreAccessACEquipmentNum();} else {dataRow.getCell(0).setText("总计");dataRow.getCell(1).setText(accessStationNumSum + "/" + preAccessStationNumSum);dataRow.getCell(2).setText(accessEquipmentNumSum + "/" + preAccessEquipmentNumSum);dataRow.getCell(3).setText(accessDCEquipmentNumSum + "/" + preAccessDCEquipmentNumSum);dataRow.getCell(4).setText(accessACEquipmentNumSum + "/" + preAccessACEquipmentNumSum);}}}}}}}}}}

word模板中替换文本中自定义字符串生成月报相关推荐

  1. 将word文件中的文本转成字符串

    将word文件中的文本转成字符串 需要用到apache.poi 下面的一些jar包 下面是pom文件,因为我也是在网上找的,所以可能有多余的jar包: <dependency><gr ...

  2. python如何替换文件部分内容_python 实现批量替换文本中的某部分内容

    一.介绍 在做YOLOv3项目时,会需要将文本文件中的某部分内容进行批量替换和修改,所以编写了python程序批量替换所有文本文件中特定部分的内容. 二.代码实现 import re import o ...

  3. python一键替换_python 实现批量替换文本中的某部分内容

    一.介绍 在做YOLOv3项目时,会需要将文本文件中的某部分内容进行批量替换和修改,所以编写了python程序批量替换所有文本文件中特定部分的内容. 二.代码实现 import re import o ...

  4. Word模板文件,替换内容 文本、图片、表格、列表、区块、嵌套等

    Word模板文件,替换内容 文本.图片.表格.列表.区块.嵌套等 实例:员工信息表Word文件,程序动态替换内容,生成pdf文件 话不多说,先看效果图! 优势: 1.模板只是布局调整,程序无需修改! ...

  5. php依次替换src,如何在php中替换img中src内容

    如何在php中替换img中src内容 发布时间:2020-07-11 16:59:05 来源:亿速云 阅读:101 作者:Leah 本篇文章给大家分享的是有关如何在php中替换img中src内容,小编 ...

  6. php 日期时间 取日期,从PHP中的文本中提取日期,时间和日期范围

    我正在构建一个本地事件日历,它采用RSS提要和网站抓取并从中提取事件日期. 我之前已经问过如何从PHP here中的文本中提取日期,并在MarcDefiant时获得了一个很好的答案: function ...

  7. java 文本编辑器替换特殊字符_linux中批量替换文本中字符串--转载

    (一)通过vi编辑器来替换. vi/vim 中可以使用 :s 命令来替换字符串. :s/well/good/ 替换当前行第一个 well 为 good :s/well/good/g 替换当前行所有 w ...

  8. 批量替换文本中的多组字符串

    [问题] hi friends, I have the following demand and I want to know if you have any suggestions for me: ...

  9. Excel 2010 VBA 入门 048 批量替换文本中的指定字符(replayce函数和方法)

    目录 示例: 实现代码 Replace函数 单元格对象的Replace方法 使用Replace方法实现代码 示例: 如图所示,该表为某公司商品编码.由于商品目录升级,现商品编码中以"GXGY ...

  10. 一个正则替换:一段文本中有若干a img标记,替换文本中的某些词,不包含除了a img标记 中的文字、属性...

    如: abcd</br> cabcdef <a href="">abcdef</a> <img title="cabcdef&q ...

最新文章

  1. i7 7代 linux,【Intel 酷睿i7 7代(移动版)参数】Intel 酷睿i7 7代(移动版)系列CPU参数-ZOL中关村在线...
  2. url rewrite优化url的可读性
  3. 笔记-信息系统开发基础-CMMI组织能力成熟度模型-连续式和阶梯式的分组
  4. centos6.0编译安装mysql5.5脚本
  5. 批量put和单条put
  6. jQuery调用WebService返回JSON数据
  7. android webview webp,iOS WebView中使用webp格式图片的方法
  8. 从html到pug模板,将变量从html-webpack-plugin传递到pug模板
  9. Lock的tryLock()方法
  10. 知识付费小程序源码支持流量主-瀑布流
  11. sqlerror.java.1055,请问大佬,eclipse连接数据库出现这个错误怎么办
  12. java爬虫登录_Java爬虫中怎么爬取需要登录的网站
  13. cad lisp程序大集_AUTO CAD 命令大集
  14. 我的世界java安装_我的世界游戏安装教程 我的世界怎么安装
  15. HTML5实现在线拍照功能(调取摄像头API)
  16. 浙江高职考计算机专业本科,浙江高职自主招生考什么科目
  17. Source Files 与 Resource Files 的区别
  18. 【人脸表情识别】基于视频的人脸表情识别数据集与基本方法
  19. js正则表达式及语法
  20. windows 10企业版windows Defender无法使用

热门文章

  1. loadrunner11 linux服务器,loadrunner11监控linux服务器性能
  2. 【游戏引擎Easy2D】第一个引擎程序
  3. 最全面的PLC学习网站
  4. 【ERP】概念_UFO报表
  5. php排斥ajaxsubmit函数,jQuery中的ajaxSubmit详解
  6. $.ajax.submit,jQuery中的AjaxSubmit使用讲解
  7. 1992-2021合集 全国大学生数学建模竞赛(历年赛题题目+定位分析)
  8. 模拟I2C怎么用--教你使用GPIO口模拟I2C总线协议
  9. 纯php员工管理,php企业员工信息管理系统
  10. 计算机硬件常识知识,计算机硬件基础知识大全