package com.zc.business.controller; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.system.domain.SysLogininfor; import com.zc.business.constant.RedisKeyConstants; import com.zc.business.domain.*; import com.zc.business.enums.UniversalEnum; import com.zc.common.core.httpclient.exception.HttpException; import io.swagger.v3.oas.annotations.Parameter; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.enums.BusinessType; import com.zc.business.service.IDcTrafficSurveyDataService; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.core.page.TableDataInfo; /** * 一类交调数据Controller * * @author liuwenge * @date 2024-10-29 */ @RestController @RequestMapping("/trafficSurveyData/dcTrafficSurveyData") public class DcTrafficSurveyDataController extends BaseController { @Autowired private IDcTrafficSurveyDataService dcTrafficSurveyDataService; @Resource private DcDeviceController dcDeviceController; @Resource private RedisCache redisCache; /** * 每小时执行一次 * 如果请求失败则将当前设备、时间范围放入redis * 下次执行时先处理redis中之前未成功的,最多执行三次 */ @Scheduled(cron = "0 13 * * * ?") public void syncTrafficSectionData() throws HttpException, IOException, ParseException { //先执行之前不成功的 executeFailedData(); HashMap props = new HashMap<>(); // 设置查询条件的键为“timestamp$BTW”,表示时间戳在一定范围内 props.put("terms[0].column", "timestamp$BTW"); ArrayList dateList = new ArrayList<>(); // 添加当前前一小时的开始和结束时间到列表,用于设定时间范围 Date now = new Date(); // 计算上一个小时的时间 Date lastHourStart = DateUtil.beginOfHour(DateUtil.offsetHour(now, -1)); Date lastHourEnd = DateUtil.endOfHour(DateUtil.offsetHour(now, -1)); // 将上一个小时的开始和结束时间添加到列表 String startTime = DateUtil.format(lastHourStart, "yyyy-MM-dd HH:mm:ss"); String endTime = DateUtil.format(lastHourEnd, "yyyy-MM-dd HH:mm:ss"); dateList.add(startTime); dateList.add(endTime); // 将日期列表以逗号分隔并设置为查询条件的值 props.put("terms[0].value", String.join(UniversalEnum.COMMA.getValue(), dateList)); props.put("paging", false); props.put("sorts[0].order", "asc"); props.put("sorts[0].name", "timestamp"); List deviceList = dcTrafficSurveyDataService.selectDeviceList(); String propertyId = "01"; //功能码 List batchData = new ArrayList<>(); for (DcDevice dcDevice : deviceList) { Object data = null; AjaxResult ajaxResult = dcDeviceController.queryDeviceProperties(dcDevice.getIotDeviceId(), propertyId, props); try { if (ajaxResult.get("code").equals(UniversalEnum.TWO_HUNDRED.getNumber()) && ajaxResult.containsKey("data") && ajaxResult.get("data") != null) { data = JSON.parseObject(ajaxResult.get("data").toString()).get("data"); } else { //超时、错误等异常状态,放入缓存下次定时执行时再次请求一遍 Map cacheMap = new HashMap<>(); cacheMap.put("iotDeviceId",dcDevice.getIotDeviceId()); cacheMap.put("stakeMark",dcDevice.getStakeMark()); cacheMap.put("startTime",startTime); cacheMap.put("endTime",endTime); cacheMap.put("count",3); //剩余请求次数 redisCache.setCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,dcDevice.getIotDeviceId()+startTime,cacheMap); break; } } catch (Exception e){ e.printStackTrace(); //超时、错误等异常状态,放入缓存下次定时执行时再次请求一遍 Map cacheMap = new HashMap<>(); cacheMap.put("iotDeviceId",dcDevice.getIotDeviceId()); cacheMap.put("stakeMark",dcDevice.getStakeMark()); cacheMap.put("startTime",startTime); cacheMap.put("endTime",endTime); cacheMap.put("count",3); //剩余请求次数 redisCache.setCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,dcDevice.getIotDeviceId()+startTime,cacheMap); break; } JSONArray dataArray = JSON.parseArray(data.toString()); if (dataArray == null || dataArray.size() < 1){ break; } Integer hezeTotal = 0; Integer jinanTotal = 0; //一小时内所有的车道数据 JSONArray lanesData = new JSONArray(); for (Object o : dataArray) { JSONObject jsonObject = JSON.parseObject(o.toString()); JSONObject formatValue = JSON.parseObject(jsonObject.get("formatValue").toString()); hezeTotal += Integer.parseInt(formatValue.get("1").toString()); jinanTotal += Integer.parseInt(formatValue.get("3").toString()); //车道数据 JSONArray lanes = formatValue.getJSONArray("lanes"); lanesData.addAll(lanes); } // 转换类型 以便使用stream List lanesList = lanesData.toJavaList(JSONObject.class); Map dataList = lanesList.stream() .collect(Collectors.groupingBy( item -> item.getString("laneNumber").substring(0, 1), // 提取 laneNumber 的第一个字符作为 key Collectors.mapping(item -> item, Collectors.collectingAndThen( Collectors.toList(), list -> { // 然后将 List 转换为 JSONArray JSONArray jsonArray = new JSONArray(); jsonArray.addAll(list); return jsonArray; } ) ) )); //菏泽方向数据 DcTrafficSurveyData hezeData = new DcTrafficSurveyData(); hezeData.setIotDeviceId(dcDevice.getIotDeviceId()); hezeData.setStakeMark(dcDevice.getStakeMark()); hezeData.setDirection("1"); hezeData.setTimestamp(lastHourStart); hezeData.setTrafficVolume(Long.valueOf(hezeTotal)); //济南方向数据 DcTrafficSurveyData jinanData = new DcTrafficSurveyData(); jinanData.setIotDeviceId(dcDevice.getIotDeviceId()); jinanData.setStakeMark(dcDevice.getStakeMark()); jinanData.setDirection("3"); jinanData.setTimestamp(lastHourStart); jinanData.setTrafficVolume(Long.valueOf(jinanTotal)); //各方向车道级数据 if (dataList != null && dataList.size() > 0){ JSONArray hezeLanesData = dataList.get("1"); dcTrafficSurveyDataService.formatTrafficSurveyData(hezeData,hezeLanesData); JSONArray jinanLanesData = dataList.get("3"); dcTrafficSurveyDataService.formatTrafficSurveyData(jinanData,jinanLanesData); } batchData.add(hezeData); batchData.add(jinanData); } dcTrafficSurveyDataService.batchInsert(batchData); } /** * @Description 再次执行之前未成功请求的 * * @author liuwenge * @date 2024/12/25 9:36 * @param * @return void */ public void executeFailedData() throws IOException, HttpException, ParseException { Map> cache = redisCache.getCacheMap(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA); if (cache == null || cache.size() == 0) { return; } SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List batchData = new ArrayList<>(); for (Map value : cache.values()) { String iotDeviceId = value.get("iotDeviceId").toString(); String stakeMark = value.get("stakeMark").toString(); String startTime = value.get("startTime").toString(); String endTime = value.get("endTime").toString(); int count = Integer.parseInt(value.get("count").toString()); HashMap props = new HashMap<>(); // 设置查询条件的键为“timestamp$BTW”,表示时间戳在一定范围内 props.put("terms[0].column", "timestamp$BTW"); ArrayList dateList = new ArrayList<>(); dateList.add(startTime); dateList.add(endTime); // 将日期列表以逗号分隔并设置为查询条件的值 props.put("terms[0].value", String.join(UniversalEnum.COMMA.getValue(), dateList)); props.put("paging", false); props.put("sorts[0].order", "asc"); props.put("sorts[0].name", "timestamp"); Object data = null; try { AjaxResult ajaxResult = dcDeviceController.queryDeviceProperties(iotDeviceId, "01", props); if (ajaxResult.get("code").equals(UniversalEnum.TWO_HUNDRED.getNumber()) && ajaxResult.containsKey("data") && ajaxResult.get("data") != null) { data = JSON.parseObject(ajaxResult.get("data").toString()).get("data"); redisCache.delCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,iotDeviceId+startTime); } else { count--; if (count < 1){ redisCache.delCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,iotDeviceId+startTime); } else { value.put("count",count); redisCache.setCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,iotDeviceId+startTime,value); } break; } } catch (Exception e){ e.printStackTrace(); count--; if (count < 1){ redisCache.delCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,iotDeviceId+startTime); } else { value.put("count",count); redisCache.setCacheMapValue(RedisKeyConstants.TRAFFIC_SURVEY_HOURS_DATA,iotDeviceId+startTime,value); } break; } JSONArray dataArray = JSON.parseArray(data.toString()); if (dataArray == null || dataArray.size() < 1){ break; } Integer hezeTotal = 0; Integer jinanTotal = 0; //一小时内所有的车道数据 JSONArray lanesData = new JSONArray(); for (Object o : dataArray) { JSONObject jsonObject = JSON.parseObject(o.toString()); JSONObject formatValue = JSON.parseObject(jsonObject.get("formatValue").toString()); hezeTotal += Integer.parseInt(formatValue.get("1").toString()); jinanTotal += Integer.parseInt(formatValue.get("3").toString()); //车道数据 JSONArray lanes = formatValue.getJSONArray("lanes"); lanesData.addAll(lanes); } // 转换类型 以便使用stream List lanesList = lanesData.toJavaList(JSONObject.class); Map dataList = lanesList.stream() .collect(Collectors.groupingBy( item -> item.getString("laneNumber").substring(0, 1), // 提取 laneNumber 的第一个字符作为 key Collectors.mapping(item -> item, Collectors.collectingAndThen( Collectors.toList(), list -> { // 然后将 List 转换为 JSONArray JSONArray jsonArray = new JSONArray(); jsonArray.addAll(list); return jsonArray; } ) ) )); //菏泽方向数据 DcTrafficSurveyData hezeData = new DcTrafficSurveyData(); hezeData.setIotDeviceId(iotDeviceId); hezeData.setStakeMark(stakeMark); hezeData.setDirection("1"); hezeData.setTimestamp(formatter.parse(startTime)); hezeData.setTrafficVolume(Long.valueOf(hezeTotal)); //济南方向数据 DcTrafficSurveyData jinanData = new DcTrafficSurveyData(); jinanData.setIotDeviceId(iotDeviceId); jinanData.setStakeMark(stakeMark); jinanData.setDirection("3"); jinanData.setTimestamp(formatter.parse(startTime)); jinanData.setTrafficVolume(Long.valueOf(jinanTotal)); //各方向车道级数据 if (dataList != null && dataList.size() > 0){ JSONArray hezeLanesData = dataList.get("1"); dcTrafficSurveyDataService.formatTrafficSurveyData(hezeData,hezeLanesData); JSONArray jinanLanesData = dataList.get("3"); dcTrafficSurveyDataService.formatTrafficSurveyData(jinanData,jinanLanesData); } batchData.add(hezeData); batchData.add(jinanData); } dcTrafficSurveyDataService.batchInsert(batchData); } /** * 查询一类交调数据列表 */ @GetMapping("/list") public AjaxResult list(DcTrafficSurveyData dcTrafficSurveyData) { return dcTrafficSurveyDataService.selectDcTrafficSurveyDataList(dcTrafficSurveyData); } /** * 导出一类交调数据列表 */ @Log(title = "一类交调数据", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, DcTrafficSurveyData dcTrafficSurveyData) throws IOException { AjaxResult ajaxResult = dcTrafficSurveyDataService.selectDcTrafficSurveyDataList(dcTrafficSurveyData); if (ajaxResult.get("code").equals(UniversalEnum.TWO_HUNDRED.getNumber())) { Map data = (Map) ajaxResult.get("data"); List> columnList = (List>) data.get("columnList"); List> rowList = (List>) data.get("rowList"); XSSFWorkbook workbook = new XSSFWorkbook(); // 创建工作簿 Sheet sheet = workbook.createSheet("一类交调站"); // 创建工作表 // 创建数据行样式 CellStyle dataStyle = workbook.createCellStyle(); dataStyle.setAlignment(HorizontalAlignment.CENTER); dataStyle.setVerticalAlignment(VerticalAlignment.CENTER); dataStyle.setBorderRight(BorderStyle.THIN); dataStyle.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); dataStyle.setBorderLeft(BorderStyle.THIN); dataStyle.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); dataStyle.setBorderTop(BorderStyle.THIN); dataStyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); dataStyle.setBorderBottom(BorderStyle.THIN); dataStyle.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); Font dataFont = workbook.createFont(); dataFont.setFontName(UniversalEnum.ARIAL.getValue()); dataFont.setFontHeightInPoints((short) UniversalEnum.TEN.getNumber()); dataStyle.setFont(dataFont); // 创建表头样式 CellStyle headerStyle = workbook.createCellStyle(); headerStyle.cloneStyleFrom(dataStyle); headerStyle.setAlignment(HorizontalAlignment.CENTER); headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); headerStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); Font headerFont = workbook.createFont(); headerFont.setFontName(UniversalEnum.ARIAL.getValue()); headerFont.setFontHeightInPoints((short) UniversalEnum.TEN.getNumber()); headerFont.setBold(true); headerFont.setColor(IndexedColors.WHITE.getIndex()); headerStyle.setFont(headerFont); // 添加表头 Row row = sheet.createRow(UniversalEnum.ZERO.getNumber()); Cell cell = row.createCell(UniversalEnum.ZERO.getNumber()); cell.setCellValue("设备名称"); cell.setCellStyle(headerStyle); cell = row.createCell(UniversalEnum.ONE.getNumber()); cell.setCellValue("方向"); cell.setCellStyle(headerStyle); int i; for (i = 0; i < columnList.size(); i++) { cell = row.createCell(i + 2); cell.setCellValue(columnList.get(i).get("label").toString()); cell.setCellStyle(headerStyle);; } cell = row.createCell(i + 2); cell.setCellValue("合计"); cell.setCellStyle(headerStyle); for (int j = 0; j < rowList.size(); j++) { Row subHeaderRow = sheet.createRow(j+1); cell = subHeaderRow.createCell(UniversalEnum.ZERO.getNumber()); cell.setCellValue("一类交调站"+rowList.get(j).get("stakeMark").toString()); cell.setCellStyle(dataStyle); cell = subHeaderRow.createCell(UniversalEnum.ONE.getNumber()); cell.setCellValue(rowList.get(j).get("direction").toString().equals("1") ? "济南方向" : "菏泽方向"); cell.setCellStyle(dataStyle); int k = 0; for (k = 0; k < columnList.size(); k++) { cell = subHeaderRow.createCell(k + 2); cell.setCellValue(rowList.get(j).get(columnList.get(k).get("key")).toString()); cell.setCellStyle(dataStyle);; } cell = subHeaderRow.createCell(k+2); cell.setCellValue(rowList.get(j).get("total").toString()); cell.setCellStyle(dataStyle); } // 写入文件 try (ServletOutputStream outputStream = response.getOutputStream()){ workbook.write(outputStream); } finally { workbook.close(); } } } /** * 获取一类交调数据详细信息 */ @GetMapping(value = "/{id}") public AjaxResult getInfo(@PathVariable("id") Long id) { return AjaxResult.success(dcTrafficSurveyDataService.selectDcTrafficSurveyDataById(id)); } /** * 新增一类交调数据 */ @Log(title = "一类交调数据", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody DcTrafficSurveyData dcTrafficSurveyData) { return toAjax(dcTrafficSurveyDataService.insertDcTrafficSurveyData(dcTrafficSurveyData)); } /** * 修改一类交调数据 */ @Log(title = "一类交调数据", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@RequestBody DcTrafficSurveyData dcTrafficSurveyData) { return toAjax(dcTrafficSurveyDataService.updateDcTrafficSurveyData(dcTrafficSurveyData)); } /** * 删除一类交调数据 */ @Log(title = "一类交调数据", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { return toAjax(dcTrafficSurveyDataService.deleteDcTrafficSurveyDataByIds(ids)); } /** * 综合查询 */ @PostMapping("/selectComprehensiveData") public AjaxResult selectComprehensiveData(@RequestBody DcTrafficSurveyDataQueryParams dcTrafficSurveyDataQueryParams){ return dcTrafficSurveyDataService.selectComprehensiveData(dcTrafficSurveyDataQueryParams); } /** * 导出综合查询 */ @PostMapping("/exportComprehensiveData") public void exportComprehensiveData(HttpServletResponse response,@RequestBody DcTrafficSurveyDataQueryParams dcTrafficSurveyDataQueryParams) { AjaxResult ajaxResult = dcTrafficSurveyDataService.selectComprehensiveData(dcTrafficSurveyDataQueryParams); if (ajaxResult.get("code").equals(UniversalEnum.TWO_HUNDRED.getNumber())) { if (dcTrafficSurveyDataQueryParams.getDataType().equals("1")){ if (dcTrafficSurveyDataQueryParams.getDirection().equals("2")) { List dcTrafficVolumeData = (List) ajaxResult.get("data"); ExcelUtil util = new ExcelUtil<>(DcTrafficVolumeData.class); util.exportExcel(response, dcTrafficVolumeData, "综合查询"); } else if (dcTrafficSurveyDataQueryParams.getDirection().equals("1")) { List dcTrafficVolumeData = (List) ajaxResult.get("data"); ExcelUtil util = new ExcelUtil<>(DcTrafficVolumeDirectionData.class); util.exportExcel(response, dcTrafficVolumeData, "综合查询"); } } else { if (dcTrafficSurveyDataQueryParams.getDirection().equals("2")) { List dcTrafficSpeedData = (List) ajaxResult.get("data"); ExcelUtil util = new ExcelUtil<>(DcTrafficSpeedData.class); util.exportExcel(response, dcTrafficSpeedData, "综合查询"); } else if (dcTrafficSurveyDataQueryParams.getDirection().equals("1")) { List dcTrafficSpeedData = (List) ajaxResult.get("data"); ExcelUtil util = new ExcelUtil<>(DcTrafficSpeedDirectionData.class); util.exportExcel(response, dcTrafficSpeedData, "综合查询"); } } } } /** * 实时数据 小时数据 */ @PostMapping("/selectRealTimeData") public AjaxResult selectRealTimeData(@RequestBody DcTrafficSurveyDataQueryParams dcTrafficSurveyDataQueryParams) throws IOException, HttpException { return dcTrafficSurveyDataService.selectRealTimeData(dcTrafficSurveyDataQueryParams); } }