package com.gkhy.fourierSpecialGasMonitor.schedule; import com.gkhy.fourierSpecialGasMonitor.Application; import com.gkhy.fourierSpecialGasMonitor.commons.enums.ResultCode; import com.gkhy.fourierSpecialGasMonitor.commons.enums.SystemCacheKeyEnum; import com.gkhy.fourierSpecialGasMonitor.commons.exception.BusinessException; import com.gkhy.fourierSpecialGasMonitor.config.file.ReportFilePathConfig; import com.gkhy.fourierSpecialGasMonitor.entity.*; import com.gkhy.fourierSpecialGasMonitor.service.*; import org.apache.commons.compress.utils.IOUtils; import org.apache.poi.ooxml.POIXMLDocument; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xddf.usermodel.chart.*; import org.apache.poi.xddf.usermodel.text.XDDFTextBody; import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; import org.redisson.api.RBucket; import org.redisson.api.RedissonClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.w3c.dom.Element; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.lang.reflect.Field; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; /** * @author Mr.huang * @decription * @date 2023/8/11 13:25 */ @Component public class DailyReportSchedule { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); private static final DateTimeFormatter reportNameFormatter = DateTimeFormatter.ofPattern("yyyy_MM_dd"); private static final DateTimeFormatter execformatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter lineChartXDataDisplay = DateTimeFormatter.ofPattern("HH:mm"); private final Logger logger = LoggerFactory.getLogger(this.getClass()); private static int serialNumber = 4; @Autowired private GasWarnLogService gasWarnLogService; @Autowired private GasConcentrationService gasConcentrationService; @Autowired private RedissonClient redissonClient; @Autowired private RegionService regionService; @Autowired private ReportFilePathConfig reportFilePathConfig; @Autowired private GasFluxService gasFluxService; @Autowired private MonitorDailyReportService monitorDailyReportService; @Autowired private GasCategoryService gasCategoryService; @Scheduled(cron = "0 0 2 * * ?") //每天两点执行一次 // @Scheduled(cron = "0 0/1 * * * ? ") // 分钟 @Async(value = "SocketTaskExecutor") public void generateDailyReport() { LocalDateTime now = LocalDateTime.now(); String startTime = now.format(execformatter); RBucket> bucket = redissonClient.getBucket(SystemCacheKeyEnum.KEY_GAS_CATEGORY.getKey()); List gasCategories = bucket.get(); serialNumber = 4; logger.info("【##】开始生成日报 ,时间:"+startTime); OPCPackage opcPackage = null; //加载文档 logger.info("【##】获取模版并创建相关文件"); XWPFDocument doc = null; try { ClassLoader classLoader = Application.class.getClassLoader(); InputStream originalFileInputStream = classLoader.getResourceAsStream("template/dailyReportTemplate.docx"); String copyFileUrl = reportFilePathConfig.getDcPath()+"temp/dailyReportTemplate.docx"; File file = new File(copyFileUrl); if (!file.exists()){ try { // 获取文件所在的文件夹路径 String folderPath = file.getParent(); // 创建文件夹(包括父目录) File folder = new File(folderPath); if (!folder.exists()){ folder.mkdirs(); } file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileOutputStream copyFileOutputStream = new FileOutputStream(copyFileUrl); IOUtils.copy(originalFileInputStream, copyFileOutputStream); opcPackage = POIXMLDocument.openPackage(copyFileUrl); //FileInputStream originalFileInputStream = new FileInputStream("src/main/resources/template/dailyReportTemplate.docx"); //FileOutputStream copyFileOutputStream = new FileOutputStream("src/main/resources/temp/dailyReportTemplate.docx"); //// 创建副本文件 //IOUtils.copy(originalFileInputStream, copyFileOutputStream); //opcPackage = POIXMLDocument.openPackage("src/main/resources/temp/dailyReportTemplate.docx"); doc = new XWPFDocument(opcPackage); } catch (IOException e) { e.printStackTrace(); } logger.info("【##】获取相关数据,并填充数据"); Map map = dataMap(gasCategories); List paragraphList = doc.getParagraphs(); for (XWPFParagraph par : paragraphList) { //获取段落的文本对象 List runs = par.getRuns(); for (XWPFRun run : runs) { //获取文本的值 String text = run.getText(0); //遍历map for (Map.Entry entry : map.entrySet()) { //获取map的key String key = entry.getKey(); //判断文本的值和map的key,文本中是否有和key一样的占位符 if (text != null && text.indexOf(key) != -1) { //获取对应key的value Object value = entry.getValue(); //把文本的内容,key替换为value text = text.replace(key, value.toString()); //把替换好的文本内容,保存到当前这个文本对象 run.setText(text, 0); } } } } logger.info("【##】生成相关文件信息,保存相关文件"); String format = now.format(reportNameFormatter); String fileName = "富城能源气体监测日报"+format+".docx"; String fileurl = reportFilePathConfig.getDcPath()+fileName; File file = new File(fileurl); if (!file.exists()){ try { // 获取文件所在的文件夹路径 String folderPath = file.getParent(); // 创建文件夹(包括父目录) File folder = new File(folderPath); if (!folder.exists()){ folder.mkdirs(); } file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } try { doc.write(fileOutputStream); fileOutputStream.close(); opcPackage.close(); } catch (IOException e) { e.printStackTrace(); } List gasConcentrations = gasConcentrationService.listDatabyTimeSlot(LocalDateTime.of(now.minusDays(1).toLocalDate(), LocalTime.MIN) , LocalDateTime.of(now.minusDays(1).toLocalDate(), LocalTime.MAX)); // 绘制折线图 logger.info("【##】 开始绘制折线图 "); if (!CollectionUtils.isEmpty(gasConcentrations)) { List gasCategoryForReport = gasCategoryService.findGasCategoryForReport(); for (int i = 0; i < gasCategoryForReport.size(); i++) { String series = gasCategories.get(i).getMolecularFormula() + "浓度观测结果"; String title = gasCategories.get(i).getMolecularFormula(); drawLineChart(gasConcentrations, fileurl, series, title, gasCategories.get(i).getMolecularFormula(), i); } } //List gasFluxes = gasFluxService.listYesterday(); List gasFluxes = gasFluxService.listYesterdayTenAmToSixPm(); List areaNum = gasFluxes.stream().map(GasFlux::getAreaId).distinct().sorted().collect(Collectors.toList()); List allRegion = regionService.findAll(); if (CollectionUtils.isEmpty(allRegion)) throw new BusinessException(this.getClass(), ResultCode.SYSTEM_ERROR_DATABASE_FAIL.getCode(),"区域信息为空"); Map regionMap = allRegion.stream() .collect(Collectors.toMap(Region::getId, Region::getName)); // 绘制柱状图 if (!CollectionUtils.isEmpty(gasFluxes)) { // for (int j = 0; j < gasCategories.size(); j++) { // for (int i = 1; i <= areaNum.size(); i++) { // //for (int j = 0; j < 20; j++) { // int finalI = i; // List gasFluxesByArea = gasFluxes.stream().filter(gasFlux -> gasFlux.getAreaId() == finalI) // .collect(Collectors.toList()); // drawBarChart(gasFluxesByArea, fileurl, regionMap.get(i), gasCategories.get(j).getMolecularFormula(), i, j + 1); // } // } logger.info("【##】 开始绘制柱状图"); for (int i = 0; i < areaNum.size(); i++) { //for (int j = 0; j < 20; j++) { int finalI = areaNum.get(i); List gasFluxesByArea = gasFluxes.stream().filter(gasFlux -> gasFlux.getAreaId() == finalI) .collect(Collectors.toList()); drawBarChart(gasFluxesByArea, fileurl, regionMap.get(areaNum.get(i)), gasCategories.get(0).getMolecularFormula(), areaNum.get(i), 1); } } logger.info("保存相关信息到数据库"); String endTime = LocalDateTime.now().format(execformatter); long execTime = ChronoUnit.SECONDS.between(now, LocalDateTime.now()); MonitorDailyReport report = new MonitorDailyReport(); report.setName(fileName); report.setGmtCreate(now); report.setEndTime(LocalDateTime.now()); report.setFileUrl(reportFilePathConfig.getUrlRootPath()+fileName); MonitorDailyReport save = monitorDailyReportService.save(report); if (save == null) throw new BusinessException(this.getClass(), ResultCode.SYSTEM_ERROR_DATABASE_FAIL,"日常报表保存失败"); logger.info("【##】日报生成成功!!! ,时间:"+endTime+",所耗时间: "+execTime+"s"); } /** * @decription 画柱形图 * @author Mr.huang */ public void drawBarChart(List gasFluxes,String fileurl,String series,String molecularFormula,Integer i,Integer j) { List collect = gasFluxes.stream() .map(gasFlux -> gasFlux.getTime().format(lineChartXDataDisplay)) .collect(Collectors.toList()); String[] x2 = collect.toArray(new String[collect.size()]); String fieldName = "gasValue"; if (j<10){ fieldName = fieldName + "0" + j; }else { fieldName = fieldName + j; } final String fieldTempName = fieldName; Double[] n = gasFluxes.stream().map(obj -> { try { Field field = obj.getClass().getDeclaredField(fieldTempName); field.setAccessible(true); return field.get(obj); } catch (NoSuchFieldException | IllegalAccessException e) { logger.info("柱状图反射获取字段值异常"); return null; } }).collect(Collectors.toList()).toArray(new Double[gasFluxes.size()]); String templatePath = fileurl; XWPFDocument doc=null; InputStream is = null; try{ is = new FileInputStream(new File(templatePath)); doc = new XWPFDocument(is); } catch (Exception e){ System.out.println(e); } //区域名称 String[] series2 = {series};// //y轴 List value2 = new ArrayList<>();//每一条折现图,第二个表1条 value2.add(n); List charts = doc.getCharts(); serialNumber++; for (int k = 0; k < charts.size(); k++) { XWPFChart xwpfChart = charts.get(k); XDDFTitle xddfTitletitle = xwpfChart.getTitle(); if (xddfTitletitle != null) { XDDFTextBody body = xddfTitletitle.getBody(); CTTextBody xmlObject = body.getXmlObject(); String tt = xmlObject.toString(); //图表的标题 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); // 解析 XML 字符串 org.w3c.dom.Document document = builder.parse(new ByteArrayInputStream(tt.getBytes())); // 获取根元素 Element root = document.getDocumentElement(); // 获取包含文本的 元素 Element aT = (Element) root.getElementsByTagName("a:t").item(0); // 获取 元素的文本内容 获取标题具体内容 String value = aT.getTextContent(); String chartTitle = "图"+serialNumber+" "+i+"号厂区排放"+molecularFormula+"通量反演结果"; if ((j+"-"+i).equals(value)) { drawBarChartExec(charts.get(k), series2, x2, value2, chartTitle,molecularFormula); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } } try (FileOutputStream fos = new FileOutputStream(templatePath)) { doc.write(fos); doc.close(); is.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void drawLineChart(List gasConcentrations,String fileurl,String series,String title,String molecularFormula,Integer i) { List collect = gasConcentrations.stream() .map(gasConcentration -> gasConcentration.getTime().format(lineChartXDataDisplay)) .collect(Collectors.toList()); String[] x2 = collect.toArray(new String[collect.size()]); String fieldName = "gasValue"; i = i+1; if (i<10){ fieldName = fieldName + "0" + i; }else { fieldName = fieldName + i; } final String fieldTempName = fieldName; Double[] n = gasConcentrations.stream().map(obj -> { try { Field field = obj.getClass().getDeclaredField(fieldTempName); field.setAccessible(true); return field.get(obj); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); return null; } }).collect(Collectors.toList()).toArray(new Double[gasConcentrations.size()]); String templatePath = fileurl; XWPFDocument doc=null; InputStream is = null; try{ is = new FileInputStream(new File(templatePath)); doc = new XWPFDocument(is); } catch (Exception e){ System.out.println(e); } String[] series2 = {"图" + (i)+" "+series};// String title2=title; //y轴 List value2 = new ArrayList<>(); value2.add(n); // List charts = doc.getCharts(); for (int j = 0; j < charts.size(); j++) { XWPFChart xwpfChart = charts.get(j); XDDFTitle xddfTitletitle = xwpfChart.getTitle(); if (xddfTitletitle != null) { XDDFTextBody body = xddfTitletitle.getBody(); CTTextBody xmlObject = body.getXmlObject(); String tt = xmlObject.toString(); //图表的标题 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); // 解析 XML 字符串 org.w3c.dom.Document document = builder.parse(new ByteArrayInputStream(tt.getBytes())); // 获取根元素 Element root = document.getDocumentElement(); // 获取包含文本的 元素 Element aT = (Element) root.getElementsByTagName("a:t").item(0); // 获取 元素的文本内容 获取标题具体内容 String value = aT.getTextContent(); if (molecularFormula.equals(value)) { drawLineChartExec(charts.get(j), series2, x2, value2, title2); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } } try (FileOutputStream fos = new FileOutputStream(templatePath)) { doc.write(fos); doc.close(); is.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // public void drawBarChartExec(XWPFChart chart, String[] series, String[] categories, // List values, String chartTitle,String molecularFormula) { // final List data = chart.getChartSeries(); // // final XDDFBarChartData line = (XDDFBarChartData) data.get(0);//这里一般获取第一个,我们这里是折线图就是XDDFLineChartData // line.getCategoryAxis().setTitle(chartTitle); // line.getValueAxes().get(0).setTitle(molecularFormula+" Emission Rate (ug/m^2/s)"); // final int numOfPoints = categories.length; // // final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); // // final XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0); // for (int i = 0; i < values.size(); i++) { // final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, i + 1, i + 1)); // Number[] value = values.get(i); // final XDDFNumericalDataSource valuesData = XDDFDataSourcesFactory.fromArray(value, valuesDataRange, i + 1); // XDDFChartData.Series ser;//图表中的系列 // ser = line.getSeries().get(i); // ser.replaceData(categoriesData, valuesData); // CellReference cellReference = chart.setSheetTitle(series[i], 1);//修改系列标题 // ser.setTitle(series[i], cellReference); // } // chart.plot(line); // chart.setTitleText("");//折线图标题 // chart.setTitleOverlay(false); // } public void drawBarChartExec(XWPFChart chart, String[] series, String[] categories, List values, String chartTitle, String molecularFormula) { // 1. 基础参数非空校验 if (chart == null) { logger.error("绘制柱状图失败:图表对象(chart)为null"); return; } if (series == null || series.length == 0) { logger.error("绘制柱状图失败:系列名称(series)为空或长度为0"); return; } if (categories == null || categories.length == 0) { logger.error("绘制柱状图失败:分类轴数据(categories)为空或长度为0"); return; } if (values == null || values.isEmpty()) { logger.error("绘制柱状图失败:数值数据(values)为空或长度为0"); return; } // 校验系列数与数值列表长度一致 if (series.length != values.size()) { logger.error("绘制柱状图失败:系列数({})与数值列表长度({})不匹配", series.length, values.size()); return; } try { // 2. 获取图表数据系列(防御性处理) List data = chart.getChartSeries(); if (data == null || data.isEmpty()) { logger.error("绘制柱状图失败:图表中未找到数据系列(data is empty)"); return; } // 强制转换为柱状图数据(若类型不匹配会抛出ClassCastException,后续捕获) XDDFBarChartData barChartData = (XDDFBarChartData) data.get(0); // 3. 设置坐标轴标题(处理空字符串) barChartData.getCategoryAxis().setTitle(Objects.toString(chartTitle, "分类轴")); // 空标题时用默认值 String valueAxisTitle = (molecularFormula != null ? molecularFormula : "气体") + " Emission Rate (ug/m^2/s)"; barChartData.getValueAxes().get(0).setTitle(valueAxisTitle); // 4. 校验分类轴数据长度(numOfPoints必须≥1,否则范围无效) int numOfPoints = categories.length; if (numOfPoints < 1) { logger.error("绘制柱状图失败:分类轴数据长度(numOfPoints={})小于1,无法生成有效范围", numOfPoints); return; } // 5. 生成分类轴数据范围(避免起止行颠倒) int startRow = 1; int endRow = numOfPoints; if (startRow > endRow) { logger.warn("分类轴数据范围起止行颠倒({} > {}),自动修正", startRow, endRow); // 交换起止行(避免CellRangeAddress抛出异常) int temp = startRow; startRow = endRow; endRow = temp; } CellRangeAddress categoryRange = new CellRangeAddress(startRow, endRow, 0, 0); String categoryDataRange; try { categoryDataRange = chart.formatRange(categoryRange); } catch (Exception e) { logger.error("格式化分类轴数据范围失败:startRow={}, endRow={}, columns=[0,0]", startRow, endRow, e); return; } // 6. 处理分类轴数据源 XDDFDataSource categoriesData; try { categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0); } catch (Exception e) { logger.error("创建分类轴数据源失败", e); return; } // 7. 循环处理每个系列的数值数据 for (int i = 0; i < values.size(); i++) { // 校验当前系列的数值数组非空 Number[] valueArray = values.get(i); if (valueArray == null) { logger.warn("第{}个系列的数值数组为null,跳过处理", i); continue; } // 校验数值数组长度与分类轴长度一致(否则图表可能显示异常) if (valueArray.length != numOfPoints) { logger.warn("第{}个系列的数值长度({})与分类轴长度({})不匹配,可能导致图表异常", i, valueArray.length, numOfPoints); } // 生成当前系列的数值范围 CellRangeAddress valueRange = new CellRangeAddress(startRow, endRow, i + 1, i + 1); String valuesDataRange; try { valuesDataRange = chart.formatRange(valueRange); } catch (Exception e) { logger.error("格式化第{}个系列的数值范围失败:startRow={}, endRow={}, columns=[{},{}]", i, startRow, endRow, i + 1, i + 1, e); continue; // 跳过当前系列,处理下一个 } // 创建数值数据源 XDDFNumericalDataSource valuesData; try { valuesData = XDDFDataSourcesFactory.fromArray(valueArray, valuesDataRange, i + 1); } catch (Exception e) { logger.error("创建第{}个系列的数值数据源失败", i, e); continue; } // 更新系列数据(确保系列存在) List chartSeries = barChartData.getSeries(); if (i >= chartSeries.size()) { logger.error("第{}个系列不存在(图表仅包含{}个系列),跳过处理", i, chartSeries.size()); continue; } XDDFChartData.Series ser = chartSeries.get(i); ser.replaceData(categoriesData, valuesData); // 设置系列标题 String seriesName = series[i] != null ? series[i] : "系列" + i; // 处理空标题 try { CellReference cellReference = chart.setSheetTitle(seriesName, 1); ser.setTitle(seriesName, cellReference); } catch (Exception e) { logger.error("设置第{}个系列标题({})失败", i, seriesName, e); // 标题设置失败不影响数据,继续执行 } } // 8. 绘制图表并清除标题 chart.plot(barChartData); chart.setTitleText(""); // 清除图表标题 chart.setTitleOverlay(false); logger.debug("柱状图绘制完成:标题={}, 系列数={}, 数据点数量={}", chartTitle, series.length, numOfPoints); } catch (ClassCastException e) { // 图表数据类型不匹配(如预期是柱状图,实际是折线图) logger.error("绘制柱状图失败:图表数据类型不匹配(预期XDDFBarChartData)", e); } catch (IndexOutOfBoundsException e) { // 坐标轴或系列索引越界(如getValueAxes()为空) logger.error("绘制柱状图失败:索引越界(可能坐标轴未初始化)", e); } catch (Exception e) { // 捕获其他未预期异常 logger.error("绘制柱状图时发生未知异常", e); } } public void drawLineChartExec(XWPFChart chart, String[] series, String[] categories, List values, String chartTitle) { final List data = chart.getChartSeries(); final XDDFLineChartData line = (XDDFLineChartData) data.get(0);//这里一般获取第一个,我们这里是折线图就是XDDFLineChartData final int numOfPoints = categories.length; //List lineChartXDataDisplayDefault = Arrays.asList("00:00","01:00","02:00","03:00","04:00","05:00","06:00" // ,"07:00","08:00","09:00", // "10:00","11:00","12:00","13:00","19:00"); //for (int i = 0; i < numOfPoints; i++) { // if (!lineChartXDataDisplayDefault.contains(categories[i])) { // categories[i] = ""; // 设置为空字符串,隐藏原有的标签 // } //} final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); final XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0); for (int i = 0; i < values.size(); i++) { final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, i + 1, i + 1)); Number[] value = values.get(i); final XDDFNumericalDataSource valuesData = XDDFDataSourcesFactory.fromArray(value, valuesDataRange, i + 1); XDDFChartData.Series ser;//图表中的系列 ser = line.getSeries().get(i); ser.replaceData(categoriesData, valuesData); CellReference cellReference = chart.setSheetTitle(series[i], 1);//修改系列标题 ser.setTitle(series[i], cellReference); } chart.plot(line); chart.setTitleText(chartTitle);//折线图标题 chart.setTitleOverlay(false); } private Map dataMap(List gasCategories){ logger.info("【##】 生成相关数据"); LocalDateTime now = LocalDateTime.now(); String today = now.format(formatter); String yesterday = LocalDateTime.now().minusDays(1).format(formatter); //要替换的map,key为占位符,value为要被替换的值 Map map = new HashMap<>(); map.put("${today}", today); map.put("${yesterday}", yesterday); map.put("${generalradius}","1km"); map.put("${generalradiu}","300m"); List gasWarnLogs = gasWarnLogService.listYesterday(); if (!CollectionUtils.isEmpty(gasWarnLogs)){ String warnInfo = "根据以上气体浓度变化曲线,各物种的浓度有如下特征:"; for (int i = 0; i < gasWarnLogs.size(); i++) { LocalDateTime warnTime = gasWarnLogs.get(i).getWarnTime(); String time = warnTime.format(execformatter); warnInfo = warnInfo + gasWarnLogs.get(i).getGasMolecularFormula() +"("+gasWarnLogs.get(i).getGasName()+")浓度在"+time+" 出现"+gasWarnLogs.get(i).getGasThresholdName() + "浓度达到:"+gasWarnLogs.get(i).getGasConcentration()+gasWarnLogs.get(i).getGasUnit() + "; "; } map.put("${warn}",warnInfo); }else { map.put("${warn}",""); } String fiveGas = ""; String sixGas = ""; for (int i = 0; i < 3; i++) { String name = gasCategories.get(i).getMolecularFormula()+"("+gasCategories.get(i).getName()+")"; name = name + "、"; if (i < 3){ fiveGas = fiveGas + name; if (i == 2){ int index = fiveGas.lastIndexOf("、"); fiveGas = fiveGas.substring(0, index)+"共三种"; } } if (i < 3){ sixGas = sixGas + name; if (i == 2){ int index = sixGas.lastIndexOf("、"); sixGas = sixGas.substring(0, index)+"共三种"; } } } map.put("${fiveGas}",fiveGas); map.put("${sixGas}",sixGas); return map; } }