Commit 643579e4 authored by ZWT's avatar ZWT

feat(吉林演示): 松原

1.修改风电站运行状态接口,增加模拟实际发电功率处理逻辑,完成接口冒烟测试;
2.修改天气数据处理定时任务,解决晚上十一点半天气预报数据处理异常问题,修改风资源预测数据和光伏资源预测数据时间处理逻辑,完成接口冒烟测试;
3.修改风机预测数据模块相关功能接口,增加判断当前部署环境逻辑,解决查询全量数据问题;
4.修改风机预测数据生成模块第三方风力发电数据生成功能,增加数据拆分逻辑,区分15分数据层级,完成功能冒烟测试;
5.修改风机预测监控页面历史风速统计接口,统计数据不显示问题及小数位过多问题;
6.修改天气预报数据爬取定时任务,解决8:00-11:00期间没有数据问题,完成功能验证;
7,修改风资源预测历史数据处理定时任务,修改查询逻辑,解决未保存历史预测数据问题;

BREAKING CHANGE: 无

Closes 无

[skip ci]
parent 710821ad
......@@ -23,29 +23,6 @@
<artifactId>guava</artifactId>
<version>32.0.0-android</version>
</dependency>
<!--POI start-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls</artifactId>
<version>2.4.6</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.0.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<!--POI end-->
<dependency>
<groupId>com.belerweb</groupId>
......
package pps.core.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import xstartup.base.util.XDateUtils;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.*;
import java.util.logging.Logger;
/**
* Author: lixueyan
* Date: 2021-01-01
* Time: 11:09
* Description: 生成Excel并写入数据
*/
public class ExcelUtils {
private static final String XLS = "xls";
private static final String XLSX = "xlsx";
private static Logger logger = Logger.getLogger(ExcelUtils.class.getName()); // 日志打印类
/**
* 生成Excel并写入数据信息
*
* @param dataList 数据列表
* @return 写入数据后的工作簿对象
*/
public static Workbook exportData(List<Map<String, Object>> dataList, List<String> headerList) {
// 生成xlsx的Excel
Workbook workbook = new SXSSFWorkbook();
CellStyle cs = workbook.createCellStyle();
cs.setWrapText(true); //内容自动换行
cs.setAlignment(HorizontalAlignment.CENTER); //水平居中
cs.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
// 生成Sheet表,写入第一行的列头
Sheet sheet = buildDataSheet(workbook, headerList);
//构建每行的数据内容
int rowNum = 1;
for (Map<String, Object> data : dataList) {
if (CollUtil.isEmpty(data)) {
continue;
}
//输出行数据
Row row = sheet.createRow(rowNum++);
convertDataToRow(data, row, headerList, cs);
}
return workbook;
}
/**
* 生成sheet表,并写入第一行数据(列头)
*
* @param workbook 工作簿对象
* @param headerList
* @return 已经写入列头的Sheet
*/
private static Sheet buildDataSheet(Workbook workbook, List<String> headerList) {
Sheet sheet = workbook.createSheet();
// 设置列头宽度
for (int i = 0; i < headerList.size(); i++) {
sheet.setColumnWidth(i, 4000);
}
// 设置默认行高
sheet.setDefaultRowHeight((short) 400);
// 构建头单元格样式
CellStyle cellStyle = buildHeadCellStyle(sheet.getWorkbook());
// 写入第一行各列的数据
Row head = sheet.createRow(0);
for (int i = 0; i < headerList.size(); i++) {
Cell cell = head.createCell(i);
cell.setCellValue(headerList.get(i));
cell.setCellStyle(cellStyle);
}
return sheet;
}
/**
* 设置第一行列头的样式
*
* @param workbook 工作簿对象
* @return 单元格样式对象
*/
private static CellStyle buildHeadCellStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle();
//对齐方式设置
style.setAlignment(HorizontalAlignment.CENTER);
//边框颜色和宽度设置
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框
//设置背景颜色
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//粗体字设置
Font font = workbook.createFont();
font.setBold(true);
style.setFont(font);
return style;
}
/**
* 将数据转换成行
*
* @param data 源数据
* @param row 行对象
* @param headerList
* @return
*/
private static void convertDataToRow(Map<String, Object> data, Row row, List<String> headerList, CellStyle cs) {
int cellNum = 0;
Cell cell;
for (int i = 0; i < headerList.size(); i++) {
Object val = data.get(headerList.get(i));
cell = row.createCell(cellNum++);
cell.setCellValue(null == val ? "" : val + "");
cell.setCellStyle(cs);
}
}
/**
* 读取Excel文件内容
*
* @param fileName 要读取的Excel文件所在路径
* @param sheetIndex 要读取的指定sheet页,为空时读取全部
* @return 读取结果列表,读取失败时返回null
*/
public static List<Map<String, Object>> readExcel(InputStream inputStream, String fileName, List<String> headerList, Integer sheetIndex) {
Workbook workbook = null;
try {
// 获取Excel后缀名
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
// 获取Excel工作簿
if (CharSequenceUtil.equalsIgnoreCase(fileType, XLS)) {
workbook = new HSSFWorkbook(inputStream);
} else if (CharSequenceUtil.equalsIgnoreCase(fileType, XLSX)) {
workbook = new XSSFWorkbook(inputStream);
}
if (ObjectUtil.isNull(workbook)) {
return Collections.emptyList();
}
// 读取excel中的数据
return parseExcel(workbook, headerList, sheetIndex);
} catch (Exception e) {
logger.warning("解析Excel失败,文件名:" + fileName + " 错误信息:" + e.getMessage());
} finally {
IoUtil.close(inputStream);
}
return Collections.emptyList();
}
/**
* 解析Excel数据
*
* @param workbook Excel工作簿对象
* @param headerList
* @param sheetIndex
* @return 解析结果
*/
public static List<Map<String, Object>> parseExcel(Workbook workbook, List<String> headerList, Integer sheetIndex) {
List<Map<String, Object>> resultDataList = new ArrayList<>();
// 解析sheet
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
if (ObjectUtil.isNotNull(sheetIndex) && !sheetIndex.equals(sheetNum)) {
continue;
}
Sheet sheet = workbook.getSheetAt(sheetNum);
// 校验sheet是否合法
if (ObjectUtil.isNull(sheet)) {
continue;
}
// 获取第一行数据
int firstRowNum = sheet.getFirstRowNum();
Row firstRow = sheet.getRow(firstRowNum);
if (ObjectUtil.isNull(firstRow)) {
logger.warning("解析Excel失败,在第一行没有读取到任何数据!");
}
// 解析每一行的数据,构造数据对象
int rowStart = firstRowNum + 1;
int rowEnd = sheet.getPhysicalNumberOfRows();
for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
Row row = sheet.getRow(rowNum);
if (ObjectUtil.isNull(row)) {
continue;
}
Map<String, Object> resultData = convertRowToData(row, headerList);
if (CollUtil.isEmpty(resultData)) {
logger.warning("第 " + row.getRowNum() + "行数据不合法,已忽略!");
continue;
}
resultDataList.add(resultData);
}
}
return resultDataList;
}
/**
* 将单元格内容转换为字符串
*
* @param cell
* @return
*/
private static String convertCellValueToString(Cell cell) {
if (ObjectUtil.isNull(cell)) {
return null;
}
String returnValue = null;
switch (cell.getCellType()) {
case NUMERIC: //数字
if (DateUtil.isCellDateFormatted(cell)) {
Date d = cell.getDateCellValue();
returnValue = XDateUtils.getDateTimeString(d);
} else {
Double doubleValue = cell.getNumericCellValue();
// 格式化科学计数法,取一位整数
DecimalFormat df = new DecimalFormat("0.00000");
returnValue = df.format(doubleValue);
}
break;
case STRING: //字符串
returnValue = cell.getStringCellValue();
break;
case BOOLEAN: //布尔
boolean booleanValue = cell.getBooleanCellValue();
returnValue = Boolean.toString(booleanValue);
break;
case BLANK: // 空值
break;
case FORMULA: // 公式
returnValue = cell.getCellFormula();
break;
case ERROR: // 故障
break;
default:
break;
}
return returnValue;
}
/**
* 提取每一行中需要的数据,构造成为一个结果数据对象
* <p>
* 当该行中有单元格的数据为空或不合法时,忽略该行的数据
*
* @param row 行数据
* @param headerList
* @return 解析后的行数据对象,行数据错误时返回null
*/
private static Map<String, Object> convertRowToData(Row row, List<String> headerList) {
Map<String, Object> resultData = new HashMap<>();
Cell cell;
int cellNum = 0;
for (String s : headerList) {
cell = row.getCell(cellNum++);
String name = convertCellValueToString(cell);
resultData.put(s, name);
}
return resultData;
}
}
\ No newline at end of file
package pps.core.common.utils;
import cn.hutool.core.collection.CollUtil;
import org.jxls.common.Context;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.transform.Transformer;
import org.jxls.util.JxlsHelper;
import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
/**
* Description:模板导出工具类
* date: 2020/8/20 18:56
*
* @author zjw
*/
public class ExportExcelUtils {
public static void outputFileData(byte[] fileBuff, String filePath) {
File file = new File(filePath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
try (OutputStream out = Files.newOutputStream(file.toPath())) {
out.write(fileBuff);
out.flush();
} catch (IOException ignored) {
}
}
/**
* 根据参数生成excel文件的二进制数据
*
* @param inputStream excel模板路径
* @param params 模板中相关参数的Map
* @return 生成文件的byte数组
*/
public static byte[] genSingleExcelFileData(InputStream inputStream, Map<String, Object> params) {
Context context = new Context();
if (CollUtil.isNotEmpty(params)) {
for (String key : params.keySet()) {
context.putVar(key, params.get(key));
}
}
ByteArrayOutputStream buff = new ByteArrayOutputStream();
try {
JxlsHelper jxlsHelper = JxlsHelper.getInstance();
Transformer transformer = jxlsHelper.createTransformer(inputStream, buff);
JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer.getTransformationConfig().getExpressionEvaluator();
Map<String, Object> funcs = new HashMap<>();
funcs.put("utils", new JxlsUtils()); //添加自定义功能
evaluator.getJexlEngine().setFunctions(funcs);
jxlsHelper.processTemplate(context, transformer);
} catch (IOException ignored) {
}
return buff.toByteArray();
}
}
\ No newline at end of file
package pps.core.common.utils;
import cn.hutool.core.util.RandomUtil;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 验证码
......@@ -36,7 +38,7 @@ public class VerificationCode {
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics gd = buffImg.getGraphics();
// 创建一个随机数生成器类
Random random = new Random();
SecureRandom random = RandomUtil.getSecureRandom();
// 将图像填充为白色
gd.setColor(Color.WHITE);
gd.fillRect(0, 0, width, height);
......
package pps.cloud.base.service;
import pps.cloud.base.service.data.CrawlBaseWatherInput;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.data.XServiceResult;
@XService
public interface BaseWatherCloudService {
@XText("获取电站天气信息")
XServiceResult crawlPlantBaseWatherData(XContext context);
@XText("获取天气信息")
XServiceResult crawlBaseWatherData(XContext context);
@XText("获取天气信息")
XServiceResult crawlBaseWatherDataByCityCode(XContext context, CrawlBaseWatherInput input);
}
package pps.core.base.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import pps.core.base.service.BaseLineService;
import pps.core.base.service.data.third_weather_data.ThirdApiWeatherExcelData;
import xstartup.base.XContext;
import java.util.ArrayList;
import java.util.List;
/**
* 天气数据监听器
*
* @author ZWT
* @date 2024/04/30 11:04
*/
public class ThirdApiWeatherDataListener implements ReadListener<ThirdApiWeatherExcelData> {
private XContext context;
/**
* 缓存的数据
*/
private List<ThirdApiWeatherExcelData> cachedDataList = new ArrayList<>(4096);
public ThirdApiWeatherDataListener(XContext context) {
this.context = context;
}
@Override
public void invoke(ThirdApiWeatherExcelData thirdApiWeatherData, AnalysisContext analysisContext) {
cachedDataList.add(thirdApiWeatherData);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
BaseLineService bean = context.getBean(BaseLineService.class);
bean.saveHistory(context, cachedDataList);
}
}
package pps.core.base.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import pps.core.base.service.BaseLineService;
import pps.core.base.service.data.base_excel.WindPredictionExcelData;
import xstartup.base.XContext;
import java.util.ArrayList;
import java.util.List;
/**
* 风资源数据
*
* @author ZWT
* @date 2024/08/30 15:46
*/
public class WindPredictionDataListener implements ReadListener<WindPredictionExcelData> {
private XContext context;
private String stationId;
/**
* 缓存的数据
*/
private List<WindPredictionExcelData> cachedDataList = new ArrayList<>(4096);
public WindPredictionDataListener(XContext context, String stationId) {
this.context = context;
this.stationId = stationId;
}
@Override
public void invoke(WindPredictionExcelData windPredictionExcelData, AnalysisContext analysisContext) {
cachedDataList.add(windPredictionExcelData);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
BaseLineService bean = context.getBean(BaseLineService.class);
bean.saveWindPredictionHistory(context, cachedDataList, stationId);
}
}
package pps.core.base.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import pps.core.base.entity.BaseDataEnt;
import pps.core.base.entity.BaseDataImportLogEnt;
import pps.core.base.entity.BaseDataView;
import pps.core.base.entity.BaseModelValEnt;
import pps.core.base.enums.ImportFieldDic;
import pps.core.base.mapper.BaseDataImportLogMapper;
import pps.core.base.mapper.BaseDataMapper;
import pps.core.base.mapper.BaseDataViewMapper;
import pps.core.base.mapper.BaseModelValMapper;
import pps.core.base.service.data.base_data.*;
import pps.core.base.service.data.base_line.ImportFileInput;
import pps.core.base.utils.HttpUtils;
import pps.core.common.constant.BusinessConstant;
import pps.core.common.utils.ExcelUtils;
import pps.core.common.utils.ExportExcelUtils;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.base.data.CustomQueryInput;
import xstartup.base.tool.XStorageTool;
import xstartup.base.util.XCopyUtils;
import xstartup.base.util.XJsonUtils;
import xstartup.data.*;
import xstartup.error.XError;
import xstartup.feature.api.annotation.XApiGet;
import xstartup.feature.api.annotation.XApiPost;
import xstartup.feature.api.annotation.XApiUpload;
import xstartup.feature.mybatis.helper.XMapperHelper;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@XService
public class BaseDataService {
@XApiPost
public XServiceResult createBaseData(XContext context, CreateBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
BaseDataEnt entity = new BaseDataEnt();
XCopyUtils.copyObject(input, entity);
mapper.insert(entity);
return XServiceResult.OK;
}
@XApiPost
public XServiceResult updateBaseData(XContext context, UpdateBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
BaseDataEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseDataEnt>()
.eq(BaseDataEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XServiceResult.error(context, XError.NotFound);
}
XCopyUtils.copyObject(input, entity);
mapper.updateById(entity);
return XServiceResult.OK;
}
@XApiPost
public XServiceResult deleteBaseData(XContext context, DeleteBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
BaseDataEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseDataEnt>()
.eq(BaseDataEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XServiceResult.error(context, XError.NotFound);
}
mapper.deleteById(entity);
return XServiceResult.OK;
}
@XApiGet
public XSingleResult<GetBaseDataOutput> getBaseData(XContext context, GetBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
BaseDataEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseDataEnt>()
.eq(BaseDataEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XSingleResult.error(context, XError.NotFound);
}
GetBaseDataOutput output = new GetBaseDataOutput();
XCopyUtils.copyObject(entity, output);
return XSingleResult.success(output);
}
@XApiGet
public XListResult<QueryBaseDataOutput> queryBaseDataCopy(XContext context, GetBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
LambdaQueryWrapper<BaseDataEnt> queryWrapper = new LambdaQueryWrapper<BaseDataEnt>()
.eq(BaseDataEnt::getLineId, input.getLineId())
.orderByAsc(BaseDataEnt::getDataDate);
Date beginTime;
Date endTime;
if (CharSequenceUtil.isBlank(input.getDataDate())) {
DateTime date = DateUtil.date();
beginTime = DateUtil.beginOfDay(date);
endTime = DateUtil.endOfDay(date);
queryWrapper.ge(BaseDataEnt::getDataDate, beginTime)
.le(BaseDataEnt::getDataDate, endTime);
} else {
if (CharSequenceUtil.contains(input.getDataDate(), '@')) {
String[] dataDates = CharSequenceUtil.splitToArray(input.getDataDate(), '@');
beginTime = DateUtil.beginOfDay(DateUtil.parseDateTime(dataDates[0]));
endTime = DateUtil.endOfDay(DateUtil.parseDateTime(dataDates[1]));
queryWrapper.ge(BaseDataEnt::getDataDate, beginTime)
.le(BaseDataEnt::getDataDate, endTime);
} else {
beginTime = DateUtil.beginOfDay(DateUtil.parseDateTime(input.getDataDate()));
endTime = DateUtil.endOfDay(DateUtil.parseDateTime(input.getDataDate()));
queryWrapper.ge(BaseDataEnt::getDataDate, beginTime)
.le(BaseDataEnt::getDataDate, endTime);
}
}
List<BaseDataEnt> list = mapper.selectList(queryWrapper);
CalcBaseDataInput calcBaseDataInput = new CalcBaseDataInput("", input.getKeyName(), input.getLineId(), "train_pre", DateUtil.formatDateTime(beginTime), DateUtil.formatDateTime(endTime));
Map<String, Object> map = getCalcData(context, calcBaseDataInput);
list.forEach(item -> {
String dataDate = DateUtil.formatDateTime(item.getDataDate());
if (map.containsKey(dataDate)) {
item.setPredictedPower(new BigDecimal(map.get(dataDate).toString()));
}
});
return XListResult.success(XCopyUtils.copyNewList(list, QueryBaseDataOutput.class));
}
@XApiGet
public XListResult<QueryBaseDataOutput> queryBaseData(XContext context, GetBaseDataInput input) {
BaseDataImportLogMapper logMapper = context.getBean(BaseDataImportLogMapper.class);
BaseDataImportLogEnt ent = logMapper.selectOne(new LambdaQueryWrapper<BaseDataImportLogEnt>()
.eq(BaseDataImportLogEnt::getLineId, input.getLineId())
.orderByDesc(BaseDataImportLogEnt::getCreateTime)
.last(BusinessConstant.LAST_LIMIT));
List<QueryBaseDataOutput> outputs = new ArrayList<>();
if (ObjectUtil.isNotNull(ent)) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
List<BaseDataEnt> list = mapper.selectList(new LambdaQueryWrapper<BaseDataEnt>()
.ge(BaseDataEnt::getDataDate, ent.getBeginDate())
.le(BaseDataEnt::getDataDate, ent.getEndDate())
.eq(BaseDataEnt::getLineId, input.getLineId())
.orderByAsc(BaseDataEnt::getDataDate));
outputs = XCopyUtils.copyNewList(list, QueryBaseDataOutput.class);
}
return XListResult.success(outputs);
}
@XApiGet
@XText("获取预测数据")
public XListResult<GetBaseDataOutput> queryPreBaseData(XContext context, GetBaseDataInput input) {
BaseDataImportLogMapper logMapper = context.getBean(BaseDataImportLogMapper.class);
BaseDataImportLogEnt ent = logMapper.selectOne(new LambdaQueryWrapper<BaseDataImportLogEnt>()
.eq(BaseDataImportLogEnt::getLineId, input.getLineId())
.orderByDesc(BaseDataImportLogEnt::getCreateTime)
.last(BusinessConstant.LAST_LIMIT));
List<GetBaseDataOutput> outputs = new ArrayList<>();
if (ObjectUtil.isNotNull(ent)) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
List<BaseDataEnt> list = mapper.selectList(new LambdaQueryWrapper<BaseDataEnt>()
.ge(BaseDataEnt::getDataDate, ent.getBeginDate())
.le(BaseDataEnt::getDataDate, ent.getEndDate())
.eq(BaseDataEnt::getLineId, input.getLineId())
.orderByAsc(BaseDataEnt::getDataDate));
Map<String, Object> map = getCalcData(context, new CalcBaseDataInput("", input.getKeyName(), input.getLineId(), "train_pre", DateUtil.formatDateTime(ent.getBeginDate()), DateUtil.formatDateTime(ent.getEndDate())));
list.forEach(item -> {
String dataDate = DateUtil.formatDateTime(item.getDataDate());
if (map.containsKey(dataDate)) {
item.setPredictedPower(new BigDecimal(map.get(dataDate).toString()));
}
});
outputs = XCopyUtils.copyNewList(list, GetBaseDataOutput.class);
}
return XListResult.success(outputs);
}
@XApiGet
public XPageResult<QueryBaseDataOutput> queryBaseDataList(XContext context, QueryBaseDataInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
QueryWrapper<BaseDataEnt> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.eq(BaseDataEnt::getLineId, input.getLineId())
.eq(BaseDataEnt::getDataDate, input.getDataDate());
return XMapperHelper.query(mapper, input, queryWrapper, QueryBaseDataOutput.class);
}
@XApiGet
public XPageResult<QueryBaseDataOutput> dynamicQueryBaseData(XContext context, CustomQueryInput input) {
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
return XMapperHelper.query(mapper, input, BaseDataEnt.class, QueryBaseDataOutput.class);
}
@XText("下载导入模板")
@XApiGet
public XFileResult downloadImportTemplate(XContext context) {
String fileSavePath = XStorageTool.getAbsolutePath("/temp/excel/导入模板_" + DateUtil.formatDate(new Date()) + ".xlsx");
String templateFilePath = "template/import_template.xlsx";
InputStream templateInputStream = this.getClass().getClassLoader().getResourceAsStream(templateFilePath);
byte[] excelContent = ExportExcelUtils.genSingleExcelFileData(templateInputStream, null);
try {
ExportExcelUtils.outputFileData(excelContent, fileSavePath);
} catch (Exception e) {
context.getLogger().error(e);
}
return XFileResult.success(XFileType.APPLICATION_XLSX, fileSavePath);
}
@XText("新增导入")
@XApiUpload
public XServiceResult importFile(XContext context, ImportFileInput input) {
List<String> headerList = getExcelHeaderList();
List<Map<String, Object>> mapList = ExcelUtils.readExcel(input.getFile().getInputStream(), input.getFile().getFileName(), headerList, 0);
try {
List<BaseDataView> dataList = new ArrayList<>(mapList.size());
Date minDate = null;
Date maxDate = null;
for (Map<String, Object> objectMap : mapList) {
BaseDataView dataView = BeanUtil.toBean(objectMap, BaseDataView.class);
dataView.setOuId(input.getWellOuId());
dataView.setLineId(input.getLineId());
if (ObjectUtil.isNotNull(dataView.getDataDate())) {
if (ObjectUtil.isNull(minDate)) {
minDate = dataView.getDataDate();
maxDate = dataView.getDataDate();
}
if (DateUtil.compare(minDate, dataView.getDataDate()) > 0) {
minDate = dataView.getDataDate();
} else if (DateUtil.compare(maxDate, dataView.getDataDate()) < 0) {
maxDate = dataView.getDataDate();
}
}
dataList.add(dataView);
}
if (ObjectUtil.isNull(minDate)) {
return XServiceResult.error(1000, "日期错误");
}
BaseDataMapper mapper = context.getBean(BaseDataMapper.class);
mapper.delete(new LambdaQueryWrapper<BaseDataEnt>()
.eq(BaseDataEnt::getLineId, input.getLineId())
.ge(BaseDataEnt::getDataDate, minDate)
.le(BaseDataEnt::getDataDate, maxDate));
BaseDataViewMapper viewMapper = context.getBean(BaseDataViewMapper.class);
viewMapper.batchInsert(dataList);
BaseDataImportLogMapper logMapper = context.getBean(BaseDataImportLogMapper.class);
BaseDataImportLogEnt ent = new BaseDataImportLogEnt();
ent.setOuId(input.getWellOuId());
ent.setLineId(input.getLineId());
ent.setBeginDate(minDate);
ent.setEndDate(maxDate);
ent.setCreateTime(new Date());
logMapper.insert(ent);
} catch (Exception e) {
return XServiceResult.error(-1, e.getMessage());
}
return XServiceResult.OK;
}
private List<String> getExcelHeaderList() {
List<Map<String, Object>> fieldList = new ArrayList<>();
for (ImportFieldDic value : ImportFieldDic.values()) {
Map<String, Object> map = new HashMap<>();
map.put("col", value.getCol());
map.put("sort", value.getSort());
fieldList.add(map);
}
fieldList.sort(Comparator.comparing(o -> ((Integer) o.get("sort"))));
return fieldList.stream().map(x -> ((String) x.get("col"))).collect(Collectors.toList());
}
@XText("获取预算")
@XApiGet
public XServiceResult calcBaseData(XContext context, CalcBaseDataInput calcBaseDataInput) {
getCalcData(context, calcBaseDataInput);
return XServiceResult.OK;
}
public Map<String, Object> getCalcData(XContext context, CalcBaseDataInput calcBaseDataInput) {
Map<String, Object> returnMap = new HashMap<>();
try {
String jsonString = XJsonUtils.toJson(calcBaseDataInput);
context.getLogger().info(jsonString);
Object ret = HttpUtils.send2("http://121.36.43.217:8098/model/predict", jsonString);
returnMap = XJsonUtils.toMap(ret.toString());
return returnMap;
} catch (Exception e) {
return returnMap;
}
}
public void doTrainData(XContext context, CalcBaseDataInput calcBaseDataInput) {
try {
String jsonString = XJsonUtils.toJson(calcBaseDataInput);
context.getLogger().info(jsonString);
HttpUtils.send2("http://121.36.43.217:8098/model/train",
jsonString);
} catch (Exception e) {
throw new RuntimeException("调用预测接口失败");
}
}
@XApiPost
@XText("预测算法训练")
public XServiceResult trainBaseData(XContext context, TrainBaseModelValInput input) {
BaseDataImportLogMapper logMapper = context.getBean(BaseDataImportLogMapper.class);
BaseDataImportLogEnt ent = logMapper.selectOne(new LambdaQueryWrapper<BaseDataImportLogEnt>()
.eq(BaseDataImportLogEnt::getLineId, input.getLineId())
.orderByDesc(BaseDataImportLogEnt::getCreateTime)
.last(BusinessConstant.LAST_LIMIT));
if (ObjectUtil.isNull(ent))
return XServiceResult.OK;
if (CollUtil.isNotEmpty(input.getKeyNames())) {
for (String keyName : input.getKeyNames()) {
CalcBaseDataInput calcBaseDataInput = new CalcBaseDataInput("", keyName, input.getLineId(), "train_val", DateUtil.formatDateTime(ent.getBeginDate()), DateUtil.formatDateTime(ent.getEndDate()));
doTrainData(context, calcBaseDataInput);
}
} else {
CalcBaseDataInput calcBaseDataInput = new CalcBaseDataInput("", input.getKeyName(), input.getLineId(), "train_val", DateUtil.formatDateTime(ent.getBeginDate()), DateUtil.formatDateTime(ent.getEndDate()));
doTrainData(context, calcBaseDataInput);
}
return XServiceResult.OK;
}
@XApiGet
@XText("获取最新算法训练数据")
public XSingleResult<TrainBaseModelValOutput> getTrainBaseData(XContext context, GetTrainBaseModelValInput input) {
BaseModelValMapper baseModelValMapper = context.getBean(BaseModelValMapper.class);
if (ObjectUtil.isNull(input.getLineId())) {
return XSingleResult.error(500, "请选择线路");
}
if (CharSequenceUtil.isBlank(input.getKeyNames())) {
return XSingleResult.error(500, "请选择模型");
}
BaseModelValEnt baseModelValEnt = baseModelValMapper.selectOne(new LambdaQueryWrapper<BaseModelValEnt>()
.eq(BaseModelValEnt::getLineId, input.getLineId())
.eq(BaseModelValEnt::getKeyname, input.getKeyNames())
.orderByDesc(BaseModelValEnt::getCreatetime).last(BusinessConstant.LAST_LIMIT));
TrainBaseModelValOutput output = XCopyUtils.copyNewObject(baseModelValEnt, TrainBaseModelValOutput.class);
if (ObjectUtil.isNotNull(baseModelValEnt) && CharSequenceUtil.isAllNotBlank(output.getYtrue(), output.getYpred())) {
Map<String, Object> ytrueMap = XJsonUtils.toMap(output.getYtrue().replace("\\", ""));
Map<String, Object> yPreMap = XJsonUtils.toMap(output.getYpred().replace("\\", ""));
List<TrainBaseModelValDetailOutput> list = new ArrayList<>();
for (String key : ytrueMap.keySet()) {
TrainBaseModelValDetailOutput detailOutput = new TrainBaseModelValDetailOutput();
Date date = new Date(Long.parseLong(key));
detailOutput.setKey(DateUtil.formatDateTime(date));
detailOutput.setPower(ytrueMap.get(key).toString());
if (yPreMap.containsKey(key)) {
detailOutput.setPredictedPower(yPreMap.get(key).toString());
}
list.add(detailOutput);
}
output.setList(list);
} else {
output = new TrainBaseModelValOutput();
}
return XSingleResult.success(output);
}
}
\ No newline at end of file
package pps.core.base.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import pps.core.base.entity.*;
import pps.core.base.excel.ThirdApiWeatherDataListener;
import pps.core.base.excel.WindPredictionDataListener;
import pps.core.base.mapper.*;
import pps.core.base.service.data.base_data.GetBaseDataInput;
import pps.core.base.service.data.base_excel.WindPredictionExcelData;
import pps.core.base.service.data.third_weather_data.ThirdApiWeatherExcelData;
import pps.core.base.service.data.third_weather_data.WeatherDeleteCondition;
import pps.core.common.constant.BusinessConstant;
import pps.core.common.utils.BaseUtils;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.data.XServiceResult;
import xstartup.feature.api.annotation.XApiGet;
import java.math.BigDecimal;
import java.util.*;
@XService
public class BaseLineService {
@XText("天气")
@XApiGet(anonymous = true)
public XServiceResult test(XContext context, GetBaseDataInput input) {
BaseWeatherCloudServiceImpl bean = context.getBean(BaseWeatherCloudServiceImpl.class);
bean.weatherDataProcess(context, input.getKeyName());
// WindPredictionHistoryCloudServiceImpl bean = context.getBean(WindPredictionHistoryCloudServiceImpl.class);
// bean.windPredictionHistoryJob(context);
// ThirdWindPowerGenerationCloudServiceImpl bean = context.getBean(ThirdWindPowerGenerationCloudServiceImpl.class);
// bean.thirdWindPowerGenerationJob(context);
return XServiceResult.OK;
}
@XText("风资源历史数据配置导入")
@XApiGet
public XServiceResult importWindPrediction(XContext context) {
String fileName = "D:\\工作\\尚博信\\数据智能事业部\\零碳\\演示\\吉林\\新需求\\20240828\\data\\";
Map<String, String> map = new HashMap<>();
map.put("11.csv", "0191993ac6707650bc41b04b04ce9b62");
map.put("12.csv", "0191993ac6707650bc41b04b04ce9b63");
map.put("13.csv", "0191993ac6707650bc41b04b04ce9b64");
map.put("14.csv", "0191993ac6707650bc41b04b04ce9b65");
map.put("15.csv", "0191993ac6707650bc41b04b04ce9b66");
map.put("16.csv", "11d04d59195746f48e14e149969940e5");
map.put("17.csv", "133dae9b74034bab8c0f96a2878c41aa");
map.put("18.csv", "8aa54645c3e34977ba3d121325881843");
map.put("20.csv", "c0e6e7a0163f4e75a6e5e05627c0731a");
map.forEach((key, value) -> {
EasyExcel.read(fileName + key, WindPredictionExcelData.class, new WindPredictionDataListener(context, value)).sheet().doRead();
});
return XServiceResult.OK;
}
@XText("天气历史数据导入")
@XApiGet
public XServiceResult importHistory(XContext context) {
String fileName = "D:\\home\\result_w.csv";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, ThirdApiWeatherExcelData.class, new ThirdApiWeatherDataListener(context)).sheet().doRead();
return XServiceResult.OK;
}
@XText("重载天气数据")
@XApiGet
public XServiceResult overloadThirdWeather(XContext context) {
ThirdWeatherDataViewMapper mapper = context.getBean(ThirdWeatherDataViewMapper.class);
List<ThirdWeatherDataView> weatherDataViewList = mapper.selectList(null);
//查第二采油厂所有电站
BasePhotovoltaicPlantViewMapper viewMapper = context.getBean(BasePhotovoltaicPlantViewMapper.class);
List<BasePhotovoltaicPlantView> plantList = viewMapper.selectPlantList(BasePhotovoltaicPlantView.builder()
.ouId("2c4c9d1c-ad55-4c14-b889-4dc33e3461e2")
.build());
//todo 老表逻辑(后期删除):后续可能替换
List<PlantPredictedPowerDataEnt> oldDeleteList = new ArrayList<>(32);
List<PlantPredictedPowerDataEnt> oldBatchList = new ArrayList<>(13312);
//获取开始结束时间,添加删除条件
Date beginTime = DateUtil.offsetMinute(weatherDataViewList.get(0).getForecastTime(), -5);
Date endTime = DateUtil.offsetMinute(weatherDataViewList.get(weatherDataViewList.size() - 1).getForecastTime(), 15);
//todo 老表逻辑(后期删除):删除数据逻辑
for (BasePhotovoltaicPlantView plantView : plantList) {
oldDeleteList.add(PlantPredictedPowerDataEnt.builder()
.plantId(plantView.getId())
.createTime(beginTime)
.endTime(endTime)
.build());
}
for (ThirdWeatherDataView thirdWeatherDataView : weatherDataViewList) {
//todo 老表逻辑(后期删除):封装预测数据
for (BasePhotovoltaicPlantView plantView : plantList) {
this.addPlantPredictedPower(oldBatchList, plantView.getId(), thirdWeatherDataView);
}
}
//todo 老表逻辑(后期删除):删除/新增预测数据
this.deletePlantPredictedPowerList(context, oldDeleteList);
this.insertBatchPlantPredictedPowerList(context, oldBatchList);
return XServiceResult.OK;
}
public void saveWindPredictionHistory(XContext context, List<WindPredictionExcelData> cachedDataList, String stationId) {
if (CollUtil.isNotEmpty(cachedDataList)) {
List<WindPredictionFutureView> futureList = new ArrayList<>(cachedDataList.size());
List<WindPredictionHistoryView> historyList = new ArrayList<>(cachedDataList.size());
//按日期顺序排序
cachedDataList.sort(Comparator.comparing(WindPredictionExcelData::getDataTime));
//数据分界线
DateTime futureFlag = DateUtil.offsetDay(DateUtil.beginOfDay(CollUtil.getLast(cachedDataList).getDataTime()), -20);
//数据分片
for (WindPredictionExcelData excelData : cachedDataList) {
if (DateUtil.compare(excelData.getDataTime(), futureFlag) >= 0) {
//未来数据
WindPredictionFutureView build = WindPredictionFutureView.builder()
.stationId(stationId)
.dataTime(excelData.getDataTime())
.windDirection(excelData.getWindDirection())
.windSpeed(excelData.getWindSpeed())
.airTemperature(excelData.getAirTemperature())
.humidity(excelData.getHumidity())
.pressure(excelData.getPressure())
.actualWindSpeed(excelData.getActualWindSpeed())
.actualPower(excelData.getActualPower())
.predictedPower(excelData.getPredictedPower())
.build();
//去重
if (futureList.stream()
.noneMatch(item -> DateUtil.compare(item.getDataTime(), build.getDataTime()) == 0)) {
futureList.add(build);
}
} else {
//历史数据
WindPredictionHistoryView build = WindPredictionHistoryView.builder()
.stationId(stationId)
.dataTime(excelData.getDataTime())
.windDirection(excelData.getWindDirection())
.windSpeed(excelData.getWindSpeed())
.airTemperature(excelData.getAirTemperature())
.humidity(excelData.getHumidity())
.pressure(excelData.getPressure())
.actualWindSpeed(excelData.getActualWindSpeed())
.actualPower(excelData.getActualPower())
.predictedPower(excelData.getPredictedPower())
.build();
//去重
if (historyList.stream()
.noneMatch(item -> DateUtil.compare(item.getDataTime(), build.getDataTime()) == 0)) {
historyList.add(build);
}
}
}
//记录
String futureStart = DateUtil.formatDateTime(CollUtil.getFirst(futureList).getDataTime());
String futureEnd = DateUtil.formatDateTime(CollUtil.getLast(futureList).getDataTime());
String historyStart = DateUtil.formatDateTime(CollUtil.getFirst(historyList).getDataTime());
String historyEnd = DateUtil.formatDateTime(CollUtil.getLast(historyList).getDataTime());
//入库
if (CollUtil.isNotEmpty(futureList)) {
WindPredictionFutureViewMapper futureMapper = context.getBean(WindPredictionFutureViewMapper.class);
if (futureList.size() > BaseUtils.BATCH_SIZE) {
List<List<WindPredictionFutureView>> subList = BaseUtils.getSubList(futureList);
subList.forEach(futureMapper::insertBatch);
} else {
futureMapper.insertBatch(futureList);
}
}
if (CollUtil.isNotEmpty(historyList)) {
WindPredictionHistoryViewMapper historyMapper = context.getBean(WindPredictionHistoryViewMapper.class);
if (historyList.size() > BaseUtils.BATCH_SIZE) {
List<List<WindPredictionHistoryView>> subList = BaseUtils.getSubList(historyList);
subList.forEach(historyMapper::batchInsert);
} else {
historyMapper.batchInsert(historyList);
}
}
}
}
public void saveHistory(XContext context, List<ThirdApiWeatherExcelData> cachedDataList) {
DateTime date = DateUtil.date();
//查第二采油厂所有电站
BasePhotovoltaicPlantViewMapper viewMapper = context.getBean(BasePhotovoltaicPlantViewMapper.class);
List<BasePhotovoltaicPlantView> plantList = viewMapper.selectPlantList(BasePhotovoltaicPlantView.builder()
.ouId("2c4c9d1c-ad55-4c14-b889-4dc33e3461e2")
.build());
//新数据删除接收
List<WeatherDeleteCondition> deleteList = new ArrayList<>(32);
List<ThirdWeatherDataView> weatherDataViewList = new ArrayList<>(2048);
//todo 老表逻辑(后期删除):后续可能替换
List<PlantPredictedPowerDataEnt> oldDeleteList = new ArrayList<>(32);
List<PlantPredictedPowerDataEnt> oldBatchList = new ArrayList<>(13312);
BigDecimal longitude = new BigDecimal("108.321784");
BigDecimal latitude = new BigDecimal("36.485083");
//获取开始结束时间,添加删除条件
Date beginTime = DateUtil.offsetMinute(DateUtil.parseDateTime(cachedDataList.get(0).getTime()), -5);
Date endTime = DateUtil.offsetMinute(DateUtil.parseDateTime(cachedDataList.get(cachedDataList.size() - 1).getTime()), 15);
deleteList.add(
WeatherDeleteCondition.builder()
.longitude(longitude)
.latitude(latitude)
.beginTime(beginTime)
.endTime(endTime)
.build()
);
//todo 老表逻辑(后期删除):删除数据逻辑
for (BasePhotovoltaicPlantView plantView : plantList) {
oldDeleteList.add(PlantPredictedPowerDataEnt.builder()
.plantId(plantView.getId())
.createTime(beginTime)
.endTime(endTime)
.build());
}
//天气数据处理
for (ThirdApiWeatherExcelData excel : cachedDataList) {
DateTime time = DateUtil.parseDateTime(excel.getTime());
ThirdWeatherDataView thirdWeatherDataView = ThirdWeatherDataView.builder()
.dni(excel.getDni())
.ghi(excel.getGhi())
.dhi(excel.getDhi())
.forecastTime(time)
.tem(excel.getTem())
.rhu(excel.getRhu())
.wns(excel.getWns())
.wnd(excel.getWnd())
.wnsGrd(excel.getWnsGrd())
.gust(excel.getGust())
.pre(excel.getPre())
.prsQfe(excel.getPrsQfe())
.vis(excel.getVis())
.clo(excel.getClo())
.uvb(excel.getUvb())
.uvi(0)
.phs(excel.getPhs())
.wep(excel.getWep())
.wnd100m(excel.getWnd100m())
.wns100m(excel.getWns100m())
.wnsGrd100m(excel.getWnsGrd100m())
.longitude(longitude)
.latitude(latitude)
.createTime(date)
.updateTime(date)
.build();
weatherDataViewList.add(
thirdWeatherDataView
);
//todo 老表逻辑(后期删除):封装预测数据
for (BasePhotovoltaicPlantView plantView : plantList) {
this.addPlantPredictedPower(oldBatchList, plantView.getId(), thirdWeatherDataView);
}
}
//todo 老表逻辑(后期删除):删除/新增预测数据
this.deletePlantPredictedPowerList(context, oldDeleteList);
this.insertBatchPlantPredictedPowerList(context, oldBatchList);
if (CollUtil.isNotEmpty(deleteList)) {
ThirdWeatherDataMapper dataMapper = context.getBean(ThirdWeatherDataMapper.class);
if (deleteList.size() > BaseUtils.BATCH_SIZE) {
List<List<WeatherDeleteCondition>> subList = BaseUtils.getSubList(deleteList);
for (List<WeatherDeleteCondition> list : subList) {
LambdaQueryWrapper<ThirdWeatherDataEnt> wrapper = new LambdaQueryWrapper<>();
for (WeatherDeleteCondition dataEnt : list) {
wrapper.or(w -> w.eq(ThirdWeatherDataEnt::getLatitude, dataEnt.getLatitude())
.eq(ThirdWeatherDataEnt::getLongitude, dataEnt.getLongitude())
.between(ThirdWeatherDataEnt::getForecastTime, dataEnt.getBeginTime(), dataEnt.getEndTime())
);
}
dataMapper.delete(wrapper);
}
} else {
LambdaQueryWrapper<ThirdWeatherDataEnt> wrapper = new LambdaQueryWrapper<>();
for (WeatherDeleteCondition dataEnt : deleteList) {
wrapper.or(w -> w.eq(ThirdWeatherDataEnt::getLatitude, dataEnt.getLatitude())
.eq(ThirdWeatherDataEnt::getLongitude, dataEnt.getLongitude())
.between(ThirdWeatherDataEnt::getForecastTime, dataEnt.getBeginTime(), dataEnt.getEndTime())
);
}
dataMapper.delete(wrapper);
}
}
if (CollUtil.isNotEmpty(weatherDataViewList)) {
ThirdWeatherDataViewMapper dataViewMapper = context.getBean(ThirdWeatherDataViewMapper.class);
if (weatherDataViewList.size() > BaseUtils.BATCH_SIZE) {
List<List<ThirdWeatherDataView>> subList = BaseUtils.getSubList(weatherDataViewList);
subList.forEach(dataViewMapper::insertBatch);
} else {
dataViewMapper.insertBatch(weatherDataViewList);
}
}
}
/**
* 添加电厂预测功率
*
* @param batchList 批处理列表
* @param plantId 植物id
* @param thirdWeatherDataView 第三天气数据视图
*/
private void addPlantPredictedPower(List<PlantPredictedPowerDataEnt> batchList, String plantId, ThirdWeatherDataView thirdWeatherDataView) {
DateTime date = DateUtil.date(thirdWeatherDataView.getForecastTime());
batchList.add(PlantPredictedPowerDataEnt.builder()
.plantId(plantId)
.createTime(thirdWeatherDataView.getCreateTime())
.yearTime(String.valueOf(date.year()))
.monthTime(this.zeroFill(date.monthBaseOne()))
.dayTime(this.zeroFill(date.dayOfMonth()))
.hourTime(this.zeroFill(date.hour(true)))
.minTime(this.zeroFill(date.minute()))
.dataDate(date.toString(BusinessConstant.DATE_FORMAT_ALL))
.temperature(thirdWeatherDataView.getTem())
.windSpeed(thirdWeatherDataView.getWns100m())
.windDirection(new BigDecimal(thirdWeatherDataView.getWnd()))
.pressure(thirdWeatherDataView.getPrsQfe())
.humidity(thirdWeatherDataView.getRhu())
.planeIrradiance(thirdWeatherDataView.getDni())
.horizontalIrradiance(thirdWeatherDataView.getGhi())
.power(BigDecimal.ZERO)
.build());
}
/**
* 条件删除预测数据
*
* @param context 上下文
* @param deleteList 删除列表
*/
private void deletePlantPredictedPowerList(XContext context, List<PlantPredictedPowerDataEnt> deleteList) {
if (CollUtil.isNotEmpty(deleteList)) {
PlantPredictedPowerDataMapper mapper = context.getBean(PlantPredictedPowerDataMapper.class);
int size = deleteList.size();
context.getLogger().info("------ deletePlantPredictedPowerList batchDelete delete size: {}", size);
if (size > BaseUtils.BATCH_SIZE) {
List<List<PlantPredictedPowerDataEnt>> subList = BaseUtils.getSubList(deleteList);
for (List<PlantPredictedPowerDataEnt> list : subList) {
LambdaQueryWrapper<PlantPredictedPowerDataEnt> wrapper = new LambdaQueryWrapper<>();
for (PlantPredictedPowerDataEnt dataEnt : list) {
wrapper.or(w -> w.eq(PlantPredictedPowerDataEnt::getPlantId, dataEnt.getPlantId())
.between(PlantPredictedPowerDataEnt::getDataDate, dataEnt.getCreateTime(), dataEnt.getEndTime())
);
}
mapper.delete(wrapper);
}
} else {
LambdaQueryWrapper<PlantPredictedPowerDataEnt> wrapper = new LambdaQueryWrapper<>();
for (PlantPredictedPowerDataEnt dataEnt : deleteList) {
wrapper.or(w -> w.eq(PlantPredictedPowerDataEnt::getPlantId, dataEnt.getPlantId())
.between(PlantPredictedPowerDataEnt::getDataDate, dataEnt.getCreateTime(), dataEnt.getEndTime())
);
}
mapper.delete(wrapper);
}
}
}
/**
* 插入间歇装置预测功率列表
*
* @param context 上下文
* @param batchList 批处理列表
*/
private void insertBatchPlantPredictedPowerList(XContext context, List<PlantPredictedPowerDataEnt> batchList) {
if (CollUtil.isNotEmpty(batchList)) {
PlantPredictedPowerDataViewMapper dataViewMapper = context.getBean(PlantPredictedPowerDataViewMapper.class);
int size = batchList.size();
context.getLogger().info("------ insertBatchPlantPredictedPowerList batchList insert size: {}", size);
if (size > BaseUtils.BATCH_SIZE) {
List<List<PlantPredictedPowerDataEnt>> subList = BaseUtils.getSubList(batchList);
subList.forEach(dataViewMapper::insertBatch);
} else {
dataViewMapper.insertBatch(batchList);
}
}
}
/**
* 零填充
*
* @param number 数字
* @return {@link String}
*/
private String zeroFill(int number) {
if (number < 10) {
return "0" + number;
}
return String.valueOf(number);
}
}
\ No newline at end of file
package pps.core.base.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import pps.core.base.entity.BaseLineAttenuationRateEnt;
import pps.core.base.entity.BaseLineAttenuationRateView;
import pps.core.base.entity.BaseProjectInfoEnt;
import pps.core.base.entity.BaseProjectInfoPredictedDataEnt;
import pps.core.base.mapper.*;
import pps.core.base.service.data.base_line_attenuation_rate.CreateBaseLineAttenuationRateInput;
import pps.core.base.service.data.base_project_info.*;
import pps.core.base.utils.HttpUtils;
import pps.core.common.session.PpsUserSession;
import pps.core.system.entity.SysAreaEnt;
import pps.core.system.mapper.SysAreaMapper;
import xstartup.annotation.XService;
import xstartup.base.XContext;
import xstartup.base.util.XCopyUtils;
import xstartup.base.util.XJsonUtils;
import xstartup.core.base.helper.XThreadHelper;
import xstartup.data.XListResult;
import xstartup.data.XPageResult;
import xstartup.data.XServiceResult;
import xstartup.data.XSingleResult;
import xstartup.error.XError;
import xstartup.feature.api.annotation.XApiGet;
import xstartup.feature.api.annotation.XApiPost;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
@XService
public class BaseProjectInfoService {
@XApiPost
public XServiceResult createProjectInfo(XContext context, CreateBaseProjectInfoInput input) {
BaseProjectInfoMapper mapper = context.getBean(BaseProjectInfoMapper.class);
BaseProjectInfoEnt entity = new BaseProjectInfoEnt();
XCopyUtils.copyObject(input, entity);
Date now = new Date();
PpsUserSession session = context.getSession(PpsUserSession.class);
entity.setCreateById(session.getId());
entity.setCreateByName(session.getUserName());
entity.setCreateTime(now);
entity.setIsDeleted(0);
mapper.insert(entity);
List<BaseLineAttenuationRateView> list = new ArrayList<>();
if (CollUtil.isNotEmpty(input.getList())) {
BaseLineAttenuationRateViewMapper rateMapper = context.getBean(BaseLineAttenuationRateViewMapper.class);
for (CreateBaseLineAttenuationRateInput rateInput : input.getList()) {
BaseLineAttenuationRateView ent = XCopyUtils.copyNewObject(rateInput, BaseLineAttenuationRateView.class);
ent.setType(1);
ent.setCreateTime(now);
ent.setLineId(entity.getId());
ent.setCreateById(session.getId());
ent.setCreateByName(session.getUserName());
list.add(ent);
}
rateMapper.batchInsert(list);
}
//开始预测
XThreadHelper.async(() -> predictedData(context, entity, list));
return XServiceResult.OK;
}
@XApiPost
public XServiceResult updateProjectInfo(XContext context, UpdateBaseProjectInfoInput input) {
BaseProjectInfoMapper mapper = context.getBean(BaseProjectInfoMapper.class);
BaseProjectInfoEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseProjectInfoEnt>()
.eq(BaseProjectInfoEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XServiceResult.error(context, XError.NotFound);
}
XCopyUtils.copyObject(input, entity);
Date now = new Date();
PpsUserSession session = context.getSession(PpsUserSession.class);
entity.setIsDeleted(0);
entity.setModifyTime(now);
entity.setModifyById(session.getId());
entity.setModifyByName(session.getUserName());
mapper.updateById(entity);
BaseLineAttenuationRateMapper rateMapper = context.getBean(BaseLineAttenuationRateMapper.class);
rateMapper.delete(new LambdaQueryWrapper<BaseLineAttenuationRateEnt>()
.eq(BaseLineAttenuationRateEnt::getType, 1)
.eq(BaseLineAttenuationRateEnt::getLineId, entity.getId())
);
List<BaseLineAttenuationRateView> list = new ArrayList<>();
if (CollUtil.isNotEmpty(input.getList())) {
BaseLineAttenuationRateViewMapper rateViewMapper = context.getBean(BaseLineAttenuationRateViewMapper.class);
for (CreateBaseLineAttenuationRateInput rateInput : input.getList()) {
BaseLineAttenuationRateView ent = XCopyUtils.copyNewObject(rateInput, BaseLineAttenuationRateView.class);
ent.setType(1);
ent.setCreateTime(now);
ent.setLineId(entity.getId());
ent.setCreateById(session.getId());
ent.setCreateByName(session.getUserName());
list.add(ent);
}
rateViewMapper.batchInsert(list);
}
//开始预测
XThreadHelper.async(() -> predictedData(context, entity, list));
return XServiceResult.OK;
}
@XApiPost
public XServiceResult deleteProjectInfo(XContext context, DeleteProjectInfoInput input) {
BaseProjectInfoMapper mapper = context.getBean(BaseProjectInfoMapper.class);
BaseProjectInfoEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseProjectInfoEnt>()
.eq(BaseProjectInfoEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XServiceResult.error(context, XError.NotFound);
}
entity.setIsDeleted(1);
mapper.updateById(entity);
return XServiceResult.OK;
}
@XApiGet
public XSingleResult<GetBaseProjectInfoOutput> getProjectInfo(XContext context, GetProjectInfoInput input) {
BaseProjectInfoMapper mapper = context.getBean(BaseProjectInfoMapper.class);
BaseProjectInfoEnt entity = mapper.selectOne(new LambdaQueryWrapper<BaseProjectInfoEnt>()
.eq(BaseProjectInfoEnt::getId, input.getId()));
if (ObjectUtil.isNull(entity)) {
return XSingleResult.error(context, XError.NotFound);
}
GetBaseProjectInfoOutput output = new GetBaseProjectInfoOutput();
XCopyUtils.copyObject(entity, output);
if (CharSequenceUtil.isNotBlank(entity.getProvince())) {
output.setProvince(Integer.valueOf(entity.getProvince()));
}
BaseLineAttenuationRateMapper rateMapper = context.getBean(BaseLineAttenuationRateMapper.class);
List<BaseLineAttenuationRateEnt> list = rateMapper.selectList(new LambdaQueryWrapper<BaseLineAttenuationRateEnt>()
.eq(BaseLineAttenuationRateEnt::getLineId, entity.getId())
.eq(BaseLineAttenuationRateEnt::getType, 1));
if (CollUtil.isNotEmpty(list)) {
List<CreateBaseLineAttenuationRateInput> rateInputs = XCopyUtils.copyNewList(list, CreateBaseLineAttenuationRateInput.class);
output.setList(rateInputs);
}
return XSingleResult.success(output);
}
@XApiGet
public XPageResult<QueryBaseProjectInfoOutput> queryProjectInfoList(XContext context, QueryProjectInfoInput input) {
BaseProjectInfoMapper mapper = context.getBean(BaseProjectInfoMapper.class);
List<BaseProjectInfoEnt> list = mapper.selectList(new LambdaQueryWrapper<BaseProjectInfoEnt>()
.like(CharSequenceUtil.isNotBlank(input.getProjectName()), BaseProjectInfoEnt::getProjectName, input.getProjectName())
.like(CharSequenceUtil.isNotBlank(input.getProductionYear()), BaseProjectInfoEnt::getProductionYear, input.getProductionYear())
);
PageInfo<BaseProjectInfoEnt> pageInfo = new PageInfo<>(list);
List<QueryBaseProjectInfoOutput> outputs = XCopyUtils.copyNewList(pageInfo.getList(), QueryBaseProjectInfoOutput.class);
SysAreaMapper areaMapper = context.getBean(SysAreaMapper.class);
List<SysAreaEnt> areaEntList = areaMapper.selectList(new QueryWrapper<>());
outputs.forEach(item -> {
if (CharSequenceUtil.isNotBlank(item.getProvince())) {
areaEntList.stream()
.filter(area -> CharSequenceUtil.equals(item.getProvince(), area.getId().toString()))
.findFirst()
.ifPresent(areaEnt -> item.setProvince(getParentNameStr(areaEntList, areaEnt)));
}
});
return XPageResult.success(outputs, input, pageInfo.getTotal());
}
@XApiGet
public XListResult<GetProjectInfoPredictedDataOutput> queryProjectInfoPredictedDataList(XContext context, GetProjectInfoPredictedDataInput input) {
BaseProjectInfoPredictedDataMapper mapper = context.getBean(BaseProjectInfoPredictedDataMapper.class);
List<BaseProjectInfoPredictedDataEnt> list = mapper.selectList(new LambdaQueryWrapper<BaseProjectInfoPredictedDataEnt>()
.eq(ObjectUtil.isNotNull(input.getProjectId()), BaseProjectInfoPredictedDataEnt::getProjectId, input.getProjectId())
);
PageInfo<BaseProjectInfoPredictedDataEnt> pageInfo = new PageInfo<>(list);
List<GetProjectInfoPredictedDataOutput> outputs = XCopyUtils.copyNewList(pageInfo.getList(), GetProjectInfoPredictedDataOutput.class);
return XListResult.success(outputs);
}
private void predictedData(XContext context, BaseProjectInfoEnt entity, List<BaseLineAttenuationRateView> list) {
CalcProjectInfoPredictedDataInput input = new CalcProjectInfoPredictedDataInput();
input.setLat(entity.getLatitude());
input.setLon(entity.getLongitude());
input.setAngle(entity.getArrayIncidence());
input.setDirection(entity.getArrayToward());
input.setCapacity(entity.getInstallCapacity());
input.setEfficiency(new BigDecimal("0.35").setScale(2, RoundingMode.HALF_EVEN));
input.setWeather(new BigDecimal("0.7").setScale(2, RoundingMode.HALF_EVEN));
list.sort(Comparator.comparing(BaseLineAttenuationRateView::getSort));
List<BigDecimal> decimals = list.stream().map(BaseLineAttenuationRateView::getAttenuationRate).collect(Collectors.toList());
input.setDecline(decimals);
Map<String, Object> map = getPredictedData(context, input);
//插入数据
BaseProjectInfoPredictedDataMapper mapper = context.getBean(BaseProjectInfoPredictedDataMapper.class);
mapper.delete(new LambdaQueryWrapper<BaseProjectInfoPredictedDataEnt>()
.eq(BaseProjectInfoPredictedDataEnt::getProjectId, entity.getId()));
List<Double> powers = (List<Double>) map.get("power");
Integer particularYear = Integer.valueOf(entity.getProductionYear());
PpsUserSession userSession = context.getSession(PpsUserSession.class);
Date date = new Date();
List<BaseProjectInfoPredictedDataEnt> entList = new ArrayList<>();
for (Double decimal : powers) {
BaseProjectInfoPredictedDataEnt ent = new BaseProjectInfoPredictedDataEnt();
ent.setProjectId(entity.getId());
ent.setParticularYear(particularYear + "");
ent.setPredictedPower(BigDecimal.valueOf(decimal));
ent.setCreateById(userSession.getId());
ent.setCreateByName(userSession.getUserName());
ent.setCreateTime(date);
particularYear++;
entList.add(ent);
}
BaseProjectInfoPredictedDataViewMapper dataViewMapper = context.getBean(BaseProjectInfoPredictedDataViewMapper.class);
dataViewMapper.batchInsert(entList);
}
public Map<String, Object> getPredictedData(XContext context, CalcProjectInfoPredictedDataInput calcProjectInfoPredictedDataInput) {
Map<String, Object> returnMap;
try {
String jsonString = XJsonUtils.toJson(calcProjectInfoPredictedDataInput);
context.getLogger().info(jsonString);
Object ret = HttpUtils.send2("http://121.36.43.217:8098//model/yearmodel",
jsonString);
returnMap = XJsonUtils.toMap(ret.toString());
return returnMap;
} catch (Exception e) {
throw new RuntimeException("调用预测接口失败");
}
}
/**
* 根据子节点获取最上层节点
*
* @return
*/
private String getParentNameStr(List<SysAreaEnt> areaList, SysAreaEnt child) {
String parentNameStr = child.getName();
Integer parentId = child.getParentId();
if (!parentId.equals(120)) {
SysAreaEnt parent = areaList.stream().filter(item -> item.getId().equals(parentId)).findFirst().orElse(null);
String nameStr = getParentNameStr(areaList, parent);
parentNameStr = nameStr + "/" + parentNameStr;
}
return parentNameStr;
}
}
\ No newline at end of file
package pps.core.base.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import pps.cloud.base.service.BaseWatherCloudService;
import pps.cloud.base.service.data.CrawlBaseWatherInput;
import pps.core.base.entity.BasePhotovoltaicPlantView;
import pps.core.base.entity.BaseWatherEnt;
import pps.core.base.entity.PlantPredictedPowerDataEnt;
import pps.core.base.enums.WindDirection;
import pps.core.base.mapper.BasePhotovoltaicPlantViewMapper;
import pps.core.base.mapper.PlantPredictedPowerDataMapper;
import pps.core.base.mapper.PlantPredictedPowerDataViewMapper;
import pps.core.base.mapper.WeatherDataMapper;
import pps.core.base.utils.HttpUtils;
import pps.core.common.constant.BusinessConstant;
import xstartup.annotation.XService;
import xstartup.base.XContext;
import xstartup.base.util.XCopyUtils;
import xstartup.core.base.helper.XThreadHelper;
import xstartup.data.XServiceResult;
import xstartup.feature.api.annotation.XApiGet;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
@XService
public class BaseWatherCloudServiceImpl implements BaseWatherCloudService {
final String provinceUrl = "http://weather.cma.cn/api/dict/province";
final String cityUrl = "http://weather.cma.cn/api/dict/province/";
public static void insertData(XContext context, String plantId, String provinceCode, String cityCode, int runCount) {
String url = "http://weather.cma.cn/web/weather/" + cityCode + ".html";
try {
List<String> timeList = Arrays.asList("15:00", "30:00", "45:00");
PlantPredictedPowerDataMapper mapper = context.getBean(PlantPredictedPowerDataMapper.class);
Document document = Jsoup.parse(new URL(url), 30000);
Elements elements = document.getElementsByClass("mt15"); // 获取class name 是‘mt15’的都有元素对象
Element element;
if (elements.isEmpty()) {
return;
} else {
element = elements.get(1); //根据页面结构获取到需要的元素对象
}
Elements tables = element.getElementsByTag("table");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<String> hourTimeArray;// 时间
List<String> weatherArray; // 天气
List<String> temperatureArray; // 气温
List<String> precipitationArray; // 降水
List<String> windSpeedArray; // 风速
List<String> windDirectionArray; // 风向
List<String> pressureArray; // 气压
List<String> humidityArray;// 湿度
List<String> cloudCoverArray; // 云量
Date date;
Calendar calendar;
String dayTime;
List<PlantPredictedPowerDataEnt> objList = new ArrayList<>();
List<PlantPredictedPowerDataEnt> allList = new ArrayList<>();
if (!tables.isEmpty()) {
for (int i = 0; i < tables.size(); i++) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, i);
date = calendar.getTime();
dayTime = sdf.format(date);
Elements trs = tables.get(i).select("tr");
hourTimeArray = new ArrayList<>();// 时间
weatherArray = new ArrayList<>(); // 天气
temperatureArray = new ArrayList<>(); // 气温
precipitationArray = new ArrayList<>(); // 降水
windSpeedArray = new ArrayList<>(); // 风速
windDirectionArray = new ArrayList<>(); // 风向
pressureArray = new ArrayList<>(); // 气压
humidityArray = new ArrayList<>(); // 湿度
cloudCoverArray = new ArrayList<>(); // 云量
if (!trs.isEmpty()) {
for (int j = 0; j < trs.size(); j++) { // 循环行
Elements tds = trs.get(j).select("td");
for (int k = 1; k < tds.size(); k++) { // 循环列
Element td = tds.get(k);
String td_text;
if ("wicon".equals(td.className()))
td_text = td.getElementsByTag("img").attr("src");
else
td_text = td.text();
if (j == 0)
hourTimeArray.add(td_text);
if (j == 1)
weatherArray.add(td_text);
if (j == 2)
temperatureArray.add(td_text);
if (j == 3)
precipitationArray.add(td_text);
if (j == 4)
windSpeedArray.add(td_text);
if (j == 5)
windDirectionArray.add(td_text);
if (j == 6)
pressureArray.add(td_text);
if (j == 7)
humidityArray.add(td_text);
if (j == 8)
cloudCoverArray.add(td_text);
}
}
}
int Hous = 0;
for (int y = 0; y < 8; y++) {
PlantPredictedPowerDataEnt dao = new PlantPredictedPowerDataEnt();
dao.setCreateTime(new Date());
dao.setPlantId(plantId);
dao.setHourTime(hourTimeArray.get(y));
dao.setTemperature(new BigDecimal(temperatureArray.get(y).replace("℃", "")));
dao.setWindSpeed(new BigDecimal(windSpeedArray.get(y).replace("m/s", "")));
dao.setWindDirection(new BigDecimal(WindDirection.findByValue(windDirectionArray.get(y)).getValue()));
dao.setPressure(new BigDecimal(pressureArray.get(y).replace("hPa", "")));
dao.setHumidity(new BigDecimal(humidityArray.get(y).replace("%", "")));
//判断小时数与查到的小时数,如果查到的小时数小,判断为第二天
if (Hous >= LocalTime.parse(hourTimeArray.get(y)).getHour()) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, (i + 1));
date = calendar.getTime();
dayTime = sdf.format(date);
}
Hous = LocalTime.parse(hourTimeArray.get(y)).getHour();
dao.setYearTime(LocalDate.parse(dayTime).getYear() + "");
dao.setMonthTime(LocalDate.parse(dayTime).getMonthValue() < 10 ? "0" + LocalDate.parse(dayTime).getMonthValue() : LocalDate.parse(dayTime).getMonthValue() + "");
dao.setDayTime(LocalDate.parse(dayTime).getDayOfMonth() < 10 ? "0" + LocalDate.parse(dayTime).getDayOfMonth() : LocalDate.parse(dayTime).getDayOfMonth() + "");
dao.setHourTime(Hous < 10 ? "0" + Hous : Hous + "");
// 5.执行SQL
mapper.delete(new QueryWrapper<PlantPredictedPowerDataEnt>().lambda().eq(PlantPredictedPowerDataEnt::getPlantId, plantId)
.eq(PlantPredictedPowerDataEnt::getYearTime, dao.getYearTime())
.eq(PlantPredictedPowerDataEnt::getMonthTime, dao.getMonthTime())
.eq(PlantPredictedPowerDataEnt::getDayTime, dao.getDayTime())
.eq(PlantPredictedPowerDataEnt::getHourTime, dao.getHourTime()));
dao.setMinTime("00:00");
dao.setDataDate(dao.getYearTime() + "-" + dao.getMonthTime() + "-" + dao.getDayTime() + " " + dao.getHourTime() + ":" + dao.getMinTime());
PlantPredictedPowerDataEnt insertDao = XCopyUtils.copyNewObject(dao, PlantPredictedPowerDataEnt.class);
allList.add(insertDao);
PlantPredictedPowerDataEnt isExit = objList.stream().filter(item -> item.getYearTime().equals(dao.getYearTime()) &&
item.getMonthTime().equals(dao.getMonthTime()) &&
item.getDayTime().equals(dao.getDayTime()) &&
item.getHourTime().equals(dao.getHourTime())).findFirst().orElse(null);
if (isExit == null)
objList.add(dao);
}
}
// 原站点时间结构为:08:00 11:00 14:00 17:00 20:00 23:00 02:00 05:00
// 两条数据中间差了两个小时,使用上下两条数据推算出中间差掉的两个小时
for (int i = 0; i < objList.size() - 1; i++) {
for (int y = 1; y < 3; y++) {
PlantPredictedPowerDataEnt dao = new PlantPredictedPowerDataEnt();
dao.setCreateTime(new Date());
dao.setPlantId(plantId);
int I_i = i + 1;
BigDecimal temperature_1 = objList.get(i).getTemperature();
BigDecimal temperature_2 = objList.get(I_i).getTemperature();
dao.setTemperature(temperature_1.add(temperature_2.subtract(temperature_1).multiply(new BigDecimal(0.3 * y))));
BigDecimal windspeed_1 = objList.get(i).getWindSpeed();
BigDecimal windspeed_2 = objList.get(I_i).getWindSpeed();
dao.setWindSpeed(windspeed_1.add(windspeed_2.subtract(windspeed_1).multiply(new BigDecimal(0.3 * y))));
dao.setWindDirection(objList.get(i).getWindDirection());
BigDecimal pressure_1 = objList.get(i).getPressure();
BigDecimal pressure_2 = objList.get(I_i).getPressure();
dao.setPressure(pressure_1.add(pressure_2.subtract(pressure_1).multiply(new BigDecimal(0.3 * y))));
BigDecimal humidity_1 = objList.get(i).getHumidity();
BigDecimal humidity_2 = objList.get(I_i).getHumidity();
dao.setHumidity(humidity_1.add(humidity_2.subtract(humidity_1).multiply(new BigDecimal(0.3 * y))));
date = sdf.parse(objList.get(i).getYearTime() + "-" + objList.get(i).getMonthTime() + "-" + objList.get(i).getDayTime());
String Hour;
if (23 == Integer.parseInt(objList.get(i).getHourTime())) {
calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, 1);
date = calendar.getTime();
Hour = "0" + (y - 1);
} else {
if ((Integer.parseInt(objList.get(i).getHourTime()) + y) < 10) {
Hour = "0" + (Integer.parseInt(objList.get(i).getHourTime()) + y);
} else {
Hour = (Integer.parseInt(objList.get(i).getHourTime()) + y) + "";
}
}
dayTime = sdf.format(date);
dao.setYearTime(LocalDate.parse(dayTime).getYear() + "");
dao.setMonthTime(LocalDate.parse(dayTime).getMonthValue() < 10 ? "0" + LocalDate.parse(dayTime).getMonthValue() : LocalDate.parse(dayTime).getMonthValue() + "");
dao.setDayTime(LocalDate.parse(dayTime).getDayOfMonth() < 10 ? "0" + LocalDate.parse(dayTime).getDayOfMonth() : LocalDate.parse(dayTime).getDayOfMonth() + "");
dao.setHourTime(Hour);
// 5.执行SQL
mapper.delete(new LambdaQueryWrapper<PlantPredictedPowerDataEnt>()
.eq(PlantPredictedPowerDataEnt::getPlantId, plantId)
.eq(PlantPredictedPowerDataEnt::getYearTime, dao.getYearTime())
.eq(PlantPredictedPowerDataEnt::getMonthTime, dao.getMonthTime())
.eq(PlantPredictedPowerDataEnt::getDayTime, dao.getDayTime())
.eq(PlantPredictedPowerDataEnt::getHourTime, dao.getHourTime()));
dao.setMinTime("00:00");
dao.setDataDate(dao.getYearTime() + "-" + dao.getMonthTime() + "-" + dao.getDayTime() + " " + dao.getHourTime() + ":" + dao.getMinTime());
PlantPredictedPowerDataEnt insertDao = XCopyUtils.copyNewObject(dao, PlantPredictedPowerDataEnt.class);
allList.add(insertDao);
}
}
List<PlantPredictedPowerDataEnt> batchList = new ArrayList<>();
PlantPredictedPowerDataViewMapper dataViewMapper = context.getBean(PlantPredictedPowerDataViewMapper.class);
List<PlantPredictedPowerDataEnt> sortList = allList.stream().sorted(Comparator.comparing(PlantPredictedPowerDataEnt::getDataDate)).collect(Collectors.toList());
for (int i = 0; i < sortList.size(); i++) {
PlantPredictedPowerDataEnt item = sortList.get(i);
batchList.add(item);
if (i < sortList.size() - 1) {
for (int y = 0; y < timeList.size(); y++) {
PlantPredictedPowerDataEnt dao = XCopyUtils.copyNewObject(item);
dao.setMinTime(timeList.get(y));
dao.setDataDate(dao.getYearTime() + "-" + dao.getMonthTime() + "-" + dao.getDayTime() + " " + dao.getHourTime() + ":" + dao.getMinTime());
int I_i = i + 1;
BigDecimal temperature_1 = sortList.get(i).getTemperature() == null ? new BigDecimal(0) : sortList.get(i).getTemperature();
BigDecimal temperature_2 = sortList.get(I_i).getTemperature() == null ? new BigDecimal(0) : sortList.get(I_i).getTemperature();
dao.setTemperature(temperature_1.add(temperature_2.subtract(temperature_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal humidity_1 = sortList.get(i).getHumidity() == null ? new BigDecimal(0) : sortList.get(i).getHumidity();
BigDecimal humidity_2 = sortList.get(I_i).getHumidity() == null ? new BigDecimal(0) : sortList.get(I_i).getHumidity();
dao.setHumidity(humidity_1.add(humidity_2.subtract(humidity_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal windSpeed_1 = sortList.get(i).getWindSpeed() == null ? new BigDecimal(0) : sortList.get(i).getWindSpeed();
BigDecimal windSpeed_2 = sortList.get(I_i).getWindSpeed() == null ? new BigDecimal(0) : sortList.get(I_i).getWindSpeed();
dao.setWindSpeed(windSpeed_1.add(windSpeed_2.subtract(windSpeed_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal pressure_1 = sortList.get(i).getPressure() == null ? new BigDecimal(0) : sortList.get(i).getPressure();
BigDecimal pressure_2 = sortList.get(I_i).getPressure() == null ? new BigDecimal(0) : sortList.get(I_i).getPressure();
dao.setPressure(pressure_1.add(pressure_2.subtract(pressure_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal planeIrradiance_1 = sortList.get(i).getPlaneIrradiance() == null ? new BigDecimal(0) : sortList.get(i).getPlaneIrradiance();
BigDecimal planeIrradiance_2 = sortList.get(I_i).getPlaneIrradiance() == null ? new BigDecimal(0) : sortList.get(I_i).getPlaneIrradiance();
dao.setPlaneIrradiance(planeIrradiance_1.add(planeIrradiance_2.subtract(planeIrradiance_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal horizontalIrradiance_1 = sortList.get(i).getHorizontalIrradiance() == null ? new BigDecimal(0) : sortList.get(i).getHorizontalIrradiance();
BigDecimal horizontalIrradiance_2 = sortList.get(I_i).getHorizontalIrradiance() == null ? new BigDecimal(0) : sortList.get(I_i).getHorizontalIrradiance();
dao.setHorizontalIrradiance(horizontalIrradiance_1.add(horizontalIrradiance_2.subtract(horizontalIrradiance_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
BigDecimal power_1 = sortList.get(i).getPower() == null ? new BigDecimal(0) : sortList.get(i).getPower();
BigDecimal power_2 = sortList.get(I_i).getPower() == null ? new BigDecimal(0) : sortList.get(I_i).getPower();
dao.setPower(power_1.add(power_2.subtract(power_1).multiply(BigDecimal.valueOf(0.3 * (y + 1)))));
batchList.add(dao);
}
}
if (batchList.size() > 500) {
dataViewMapper.insertBatch(batchList);
batchList = new ArrayList<>();
}
}
if (CollUtil.isNotEmpty(batchList)) {
dataViewMapper.insertBatch(batchList);
}
//训练接口http://127.0.0.1:10098/aiprediction/xgbtrain?plantId=018a64635ac47cf58895147b0e1bf7e3
//自动调用预测接口
HttpUtils.send2("http://127.0.0.1:10098/aiprediction/xgbreason?plantId=" + plantId, "");
}
} catch (Exception e) {
context.getLogger().error(e.getMessage());
}
}
public static void insertData(XContext context, String provinceCode, String provinceName, String cityCode, String cityName, int runCount) {
String url = "http://weather.cma.cn/web/weather/" + cityCode + ".html";
try {
WeatherDataMapper mapper = context.getBean(WeatherDataMapper.class);
Document document = Jsoup.parse(new URL(url), 30000);
Elements elements = document.getElementsByClass("mt15"); // 获取class name 是‘mt15’的都有元素对象
Element element;
if (elements.isEmpty()) {
return;
} else {
element = elements.get(1); //根据页面结构获取到需要的元素对象
}
Elements tables = element.getElementsByTag("table");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<String> hourTimeArray;// 时间
List<String> weatherArray; // 天气
List<String> temperatureArray; // 气温
List<String> precipitationArray; // 降水
List<String> windSpeedArray; // 风速
List<String> windDirectionArray; // 风向
List<String> pressureArray; // 气压
List<String> humidityArray;// 湿度
List<String> cloudCoverArray; // 云量
Date date;
Calendar calendar;
String dayTime;
BaseWatherEnt dao;
List<BaseWatherEnt> objList = new ArrayList<>();
if (!tables.isEmpty()) {
for (int i = 0; i < tables.size(); i++) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, i);
date = calendar.getTime();
dayTime = sdf.format(date);
Elements trs = tables.get(i).select("tr");
hourTimeArray = new ArrayList<>(10);// 时间
weatherArray = new ArrayList<>(10); // 天气
temperatureArray = new ArrayList<>(10); // 气温
precipitationArray = new ArrayList<>(10); // 降水
windSpeedArray = new ArrayList<>(10); // 风速
windDirectionArray = new ArrayList<>(10); // 风向
pressureArray = new ArrayList<>(10); // 气压
humidityArray = new ArrayList<>(10); // 湿度
cloudCoverArray = new ArrayList<>(10); // 云量
if (!trs.isEmpty()) {
for (int j = 0; j < trs.size(); j++) { // 循环行
Elements tds = trs.get(j).select("td");
for (int k = 1; k < tds.size(); k++) { // 循环列
Element td = tds.get(k);
String td_text;
if (CharSequenceUtil.equals("wicon", td.className()))
td_text = td.getElementsByTag("img").attr("src");
else
td_text = td.text();
if (j == 0)
hourTimeArray.add(td_text);
if (j == 1)
weatherArray.add(td_text);
if (j == 2)
temperatureArray.add(td_text);
if (j == 3)
precipitationArray.add(td_text);
if (j == 4)
windSpeedArray.add(td_text);
if (j == 5)
windDirectionArray.add(td_text);
if (j == 6)
pressureArray.add(td_text);
if (j == 7)
humidityArray.add(td_text);
if (j == 8)
cloudCoverArray.add(td_text);
}
}
}
int Hous = 0;
for (int y = 0; y < 8; y++) {
dao = new BaseWatherEnt();
dao.setCityCode(cityCode);
dao.setCityName(cityName);
dao.setProvinceCode(provinceCode);
dao.setProvinceName(provinceName);
dao.setHourTime(hourTimeArray.get(y));
dao.setWeather(weatherArray.get(y));
dao.setTemperature(temperatureArray.get(y));
dao.setPrecipitation(precipitationArray.get(y));
dao.setWindSpeed(windSpeedArray.get(y));
dao.setWindDirection(windDirectionArray.get(y));
dao.setPressure(pressureArray.get(y));
dao.setHumidity(humidityArray.get(y));
dao.setCloudCover(cloudCoverArray.get(y));
//由于界面时间为当日8点到第二日5点数据,所以写了下面的判断分支
if (Hous == 0 || Hous <= LocalTime.parse(hourTimeArray.get(y)).getHour()) {
dao.setDayTime(dayTime);
Hous = LocalTime.parse(hourTimeArray.get(y)).getHour();
} else if (2 == LocalTime.parse(hourTimeArray.get(y)).getHour() || 5 == LocalTime.parse(hourTimeArray.get(y)).getHour()) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, (i + 1));
date = calendar.getTime();
dayTime = sdf.format(date);
dao.setDayTime(dayTime);
} else
continue;
// 5.执行SQL
mapper.delete(new LambdaQueryWrapper<BaseWatherEnt>()
.eq(BaseWatherEnt::getProvinceCode, dao.getProvinceCode())
.eq(BaseWatherEnt::getCityCode, dao.getCityCode())
.eq(BaseWatherEnt::getDataDate, dao.getDayTime() + ' ' + dao.getHourTime()));
dao.setDataDate(dao.getDayTime() + ' ' + dao.getHourTime());
mapper.insert(dao);
objList.add(dao);
}
}
// 原站点时间结构为:08:00 11:00 14:00 17:00 20:00 23:00 02:00 05:00
// 两条数据中间差了两个小时,使用上下两条数据推算出中间差掉的两个小时
for (int i = 0; i < objList.size() - 1; i++) {
for (int y = 1; y < 3; y++) {
dao = new BaseWatherEnt();
dao.setCityCode(cityCode);
dao.setCityName(cityName);
dao.setProvinceCode(provinceCode);
dao.setProvinceName(provinceName);
dao.setWeather(objList.get(i).getWeather());
int I_i = i + 1;
double temperature_1 = Double.parseDouble(objList.get(i).getTemperature());
double temperature_2 = Double.parseDouble(objList.get(I_i).getTemperature());
dao.setTemperature((temperature_1 + (temperature_2 - temperature_1) * (0.3 * y)) + "℃");
dao.setPrecipitation(objList.get(i).getPrecipitation());
double windspeed_1 = Double.parseDouble(objList.get(i).getWindSpeed());
double windspeed_2 = Double.parseDouble(objList.get(I_i).getWindSpeed());
dao.setWindSpeed((windspeed_1 + (windspeed_2 - windspeed_1) * (0.3 * y)) + "m/s");
dao.setWindDirection(objList.get(i).getWindDirection());
double pressure_1 = Double.parseDouble(objList.get(i).getPressure());
double pressure_2 = Double.parseDouble(objList.get(I_i).getPressure());
dao.setPressure((pressure_1 + (pressure_2 - pressure_1) * (0.3 * y)) + "hPa");
double humidity_1 = Double.parseDouble(objList.get(i).getHumidity());
double humidity_2 = Double.parseDouble(objList.get(I_i).getHumidity());
dao.setHumidity((humidity_1 + (humidity_2 - humidity_1) * (0.3 * y)) + "%");
double cloudcover_1 = Double.parseDouble(objList.get(i).getCloudCover());
double cloudcover_2 = Double.parseDouble(objList.get(I_i).getCloudCover());
dao.setCloudCover((cloudcover_1 + (cloudcover_2 - cloudcover_1) * (0.3 * y)) + "%");
if (23 == LocalTime.parse(objList.get(i).getHourTime()).getHour()) {
date = sdf.parse(objList.get(i).getDayTime());
calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, 1);
Date tomorrow = calendar.getTime();
dao.setDayTime(sdf.format(tomorrow));
dao.setHourTime("0" + (y - 1) + ":00:00");
} else {
dao.setDayTime(objList.get(i).getDayTime());
String Hour;
if ((LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) < 10) {
Hour = "0" + (LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) + ":00:00";
} else {
Hour = (LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) + ":00:00";
}
dao.setHourTime(Hour);
}
// 5.执行SQL
mapper.delete(new LambdaQueryWrapper<BaseWatherEnt>().eq(BaseWatherEnt::getProvinceCode, dao.getProvinceCode())
.eq(BaseWatherEnt::getCityCode, dao.getCityCode())
.eq(BaseWatherEnt::getDataDate, dao.getDayTime() + ' ' + dao.getHourTime()));
dao.setDataDate(dao.getDayTime() + ' ' + dao.getHourTime());
mapper.insert(dao);
}
}
}
} catch (Exception e) {
context.getLogger().error(e.getMessage());
}
}
@Override
@XApiGet
public XServiceResult crawlPlantBaseWatherData(XContext context) {
try {
//1.获取电站数据,并根据电站数据,获取到电站所在城市,然后获取到天气数据
BasePhotovoltaicPlantViewMapper mapper = context.getBean(BasePhotovoltaicPlantViewMapper.class);
BasePhotovoltaicPlantView view = new BasePhotovoltaicPlantView();
view.setIsDeleted(BusinessConstant.ONE);
List<BasePhotovoltaicPlantView> plantList = mapper.selectPlantDetailList(view);
for (BasePhotovoltaicPlantView item : plantList) {
if (CharSequenceUtil.isAllNotBlank(item.getCityCode(), item.getProvinceCode())) {
insertData(context, item.getId(), item.getProvinceCode(), item.getCityCode(), 1);
}
}
} catch (Exception e) {
context.getLogger().error(e.getMessage());
}
return XServiceResult.OK;
}
@Override
public XServiceResult crawlBaseWatherData(XContext context) {
try {
//请求省份接口。获取省份列表
String provinceStr = HttpUtils.send2(provinceUrl, "");
//解析省份列表字符串,把字符串解析成json对象
JSONObject jsonObject = JSONObject.parseObject(provinceStr);
//处理json对象,变为数组
String[] provinceList = CharSequenceUtil.splitToArray(jsonObject.getString("data"), '|');
for (String proStr : provinceList) {
if (CharSequenceUtil.isNotBlank(proStr)) {
String[] pro = CharSequenceUtil.splitToArray(proStr, ',');
String provinceCode = pro[0];//省编码
String provinceName = pro[1];//省名称
//甘肃 .陕西 (全国周期抓取耗费时间超长,共有2400个城市)
if (CharSequenceUtil.equals(provinceCode, "AJL")) {
//请求省份下的区信息
String cityString = HttpUtils.send2(cityUrl + provinceCode, "");
//解析区json,把字符串解析成json对象
JSONObject cityObj = JSONObject.parseObject(cityString);
//处理json对象,变为数组
String[] cityList = CharSequenceUtil.splitToArray(cityObj.getString("data"), '|');
for (String cityStr : cityList) {
if (CharSequenceUtil.isNotBlank(cityStr)) {
String[] city = CharSequenceUtil.splitToArray(cityStr, ',');
String cityCode = city[0];//区编码
String cityName = city[1];//区名称
XThreadHelper.async(() -> insertData(context, provinceCode, provinceName, cityCode, cityName, 1));
}
}
}
}
}
} catch (Exception e) {
context.getLogger().error(e);
}
return XServiceResult.OK;
}
@Override
public XServiceResult crawlBaseWatherDataByCityCode(XContext context, CrawlBaseWatherInput input) {
insertData(context, input.getProvinceCode(), input.getProvinceName(), input.getCityCode(), input.getCityName(), 1);
return XServiceResult.OK;
}
@XApiGet
public XServiceResult crawlPlantBaseWatherDataTest(XContext context) {
crawlPlantBaseWatherData(context);
return XServiceResult.OK;
}
}
\ No newline at end of file
package pps.core.base.service;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import pps.core.base.entity.BaseWatherEnt;
import pps.core.base.mapper.WeatherDataMapper;
import pps.core.base.service.data.base_wather.GetBaseWatherInput;
import pps.core.base.utils.HttpUtils;
import xstartup.annotation.XService;
import xstartup.base.XContext;
import xstartup.core.base.helper.XThreadHelper;
import xstartup.data.XServiceResult;
import xstartup.feature.api.annotation.XApiGet;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@XService
public class BaseWatherService {
public static void insertData(XContext context, String provinceCode, String provinceName, String cityCode, String cityName, int runCount) {
String url = "http://weather.cma.cn/web/weather/" + cityCode + ".html";
try {
WeatherDataMapper mapper = context.getBean(WeatherDataMapper.class);
Document document = Jsoup.parse(new URL(url), 30000);
Elements elements = document.getElementsByClass("mt15"); // 获取class name 是‘mt15’的都有元素对象
Element element;
if (elements.isEmpty()) {
return;
} else {
element = elements.get(1); //根据页面结构获取到需要的元素对象
}
Elements tables = element.getElementsByTag("table");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<String> hourTimeArray;// 时间
List<String> weatherArray; // 天气
List<String> temperatureArray; // 气温
List<String> precipitationArray; // 降水
List<String> windSpeedArray; // 风速
List<String> windDirectionArray; // 风向
List<String> pressureArray; // 气压
List<String> humidityArray;// 湿度
List<String> cloudCoverArray; // 云量
Date date;
Calendar calendar;
String dayTime;
BaseWatherEnt dao;
List<BaseWatherEnt> objList = new ArrayList<>();
if (!tables.isEmpty()) {
for (int i = 0; i < tables.size(); i++) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, i);
date = calendar.getTime();
dayTime = sdf.format(date);
Elements trs = tables.get(i).select("tr");
hourTimeArray = new ArrayList<>();// 时间
weatherArray = new ArrayList<>(); // 天气
temperatureArray = new ArrayList<>(); // 气温
precipitationArray = new ArrayList<>(); // 降水
windSpeedArray = new ArrayList<>(); // 风速
windDirectionArray = new ArrayList<>(); // 风向
pressureArray = new ArrayList<>(); // 气压
humidityArray = new ArrayList<>(); // 湿度
cloudCoverArray = new ArrayList<>(); // 云量
if (!trs.isEmpty()) {
for (int j = 0; j < trs.size(); j++) { // 循环行
Elements tds = trs.get(j).select("td");
for (int k = 1; k < tds.size(); k++) { // 循环列
Element td = tds.get(k);
String td_text;
if ("wicon".equals(td.className()))
td_text = td.getElementsByTag("img").attr("src");
else
td_text = td.text();
if (j == 0)
hourTimeArray.add(td_text);
if (j == 1)
weatherArray.add(td_text);
if (j == 2)
temperatureArray.add(td_text);
if (j == 3)
precipitationArray.add(td_text);
if (j == 4)
windSpeedArray.add(td_text);
if (j == 5)
windDirectionArray.add(td_text);
if (j == 6)
pressureArray.add(td_text);
if (j == 7)
humidityArray.add(td_text);
if (j == 8)
cloudCoverArray.add(td_text);
}
}
}
int Hous = 0;
for (int y = 0; y < 8; y++) {
dao = new BaseWatherEnt();
dao.setCityCode(cityCode);
dao.setCityName(cityName);
dao.setProvinceCode(provinceCode);
dao.setProvinceName(provinceName);
dao.setHourTime(hourTimeArray.get(y));
dao.setWeather(weatherArray.get(y));
dao.setTemperature(temperatureArray.get(y));
dao.setPrecipitation(precipitationArray.get(y));
dao.setWindSpeed(windSpeedArray.get(y));
dao.setWindDirection(windDirectionArray.get(y));
dao.setPressure(pressureArray.get(y));
dao.setHumidity(humidityArray.get(y));
dao.setCloudCover(cloudCoverArray.get(y));
//由于界面时间为当日8点到第二日5点数据,所以写了下面的判断分支
if (Hous == 0 || Hous <= LocalTime.parse(hourTimeArray.get(y)).getHour()) {
dao.setDayTime(dayTime);
Hous = LocalTime.parse(hourTimeArray.get(y)).getHour();
} else if (2 == LocalTime.parse(hourTimeArray.get(y)).getHour() || 5 == LocalTime.parse(hourTimeArray.get(y)).getHour()) {
calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, (i + 1));
date = calendar.getTime();
dayTime = sdf.format(date);
dao.setDayTime(dayTime);
} else
continue;
// 5.执行SQL
mapper.delete(new LambdaQueryWrapper<BaseWatherEnt>().eq(BaseWatherEnt::getProvinceCode, dao.getProvinceCode())
.eq(BaseWatherEnt::getCityCode, dao.getCityCode())
.eq(BaseWatherEnt::getDataDate, dao.getDayTime() + ' ' + dao.getHourTime()));
dao.setDataDate(dao.getDayTime() + ' ' + dao.getHourTime());
mapper.insert(dao);
objList.add(dao);
}
}
// 原站点时间结构为:08:00 11:00 14:00 17:00 20:00 23:00 02:00 05:00
// 两条数据中间差了两个小时,使用上下两条数据推算出中间差掉的两个小时
for (int i = 0; i < objList.size() - 1; i++) {
for (int y = 1; y < 3; y++) {
dao = new BaseWatherEnt();
dao.setCityCode(cityCode);
dao.setCityName(cityName);
dao.setProvinceCode(provinceCode);
dao.setProvinceName(provinceName);
dao.setWeather(objList.get(i).getWeather());
int I_i = i + 1;
double temperature_1 = Double.parseDouble(objList.get(i).getTemperature());
double temperature_2 = Double.parseDouble(objList.get(I_i).getTemperature());
dao.setTemperature((temperature_1 + (temperature_2 - temperature_1) * (0.3 * y)) + "℃");
dao.setPrecipitation(objList.get(i).getPrecipitation());
double windspeed_1 = Double.parseDouble(objList.get(i).getWindSpeed());
double windspeed_2 = Double.parseDouble(objList.get(I_i).getWindSpeed());
dao.setWindSpeed((windspeed_1 + (windspeed_2 - windspeed_1) * (0.3 * y)) + "m/s");
dao.setWindDirection(objList.get(i).getWindDirection());
double pressure_1 = Double.parseDouble(objList.get(i).getPressure());
double pressure_2 = Double.parseDouble(objList.get(I_i).getPressure());
dao.setPressure((pressure_1 + (pressure_2 - pressure_1) * (0.3 * y)) + "hPa");
double humidity_1 = Double.parseDouble(objList.get(i).getHumidity());
double humidity_2 = Double.parseDouble(objList.get(I_i).getHumidity());
dao.setHumidity((humidity_1 + (humidity_2 - humidity_1) * (0.3 * y)) + "%");
double cloudcover_1 = Double.parseDouble(objList.get(i).getCloudCover());
double cloudcover_2 = Double.parseDouble(objList.get(I_i).getCloudCover());
dao.setCloudCover((cloudcover_1 + (cloudcover_2 - cloudcover_1) * (0.3 * y)) + "%");
if (23 == LocalTime.parse(objList.get(i).getHourTime()).getHour()) {
date = sdf.parse(objList.get(i).getDayTime());
calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, 1);
Date tomorrow = calendar.getTime();
dao.setDayTime(sdf.format(tomorrow));
dao.setHourTime("0" + (y - 1) + ":00:00");
} else {
dao.setDayTime(objList.get(i).getDayTime());
String Hour;
if ((LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) < 10) {
Hour = "0" + (LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) + ":00:00";
} else {
Hour = (LocalTime.parse(objList.get(i).getHourTime()).getHour() + y) + ":00:00";
}
dao.setHourTime(Hour);
}
// 5.执行SQL
mapper.delete(new LambdaQueryWrapper<BaseWatherEnt>()
.eq(BaseWatherEnt::getProvinceCode, dao.getProvinceCode())
.eq(BaseWatherEnt::getCityCode, dao.getCityCode())
.eq(BaseWatherEnt::getDataDate, dao.getDayTime() + ' ' + dao.getHourTime()));
dao.setDataDate(dao.getDayTime() + ' ' + dao.getHourTime());
mapper.insert(dao);
}
}
}
} catch (Exception e) {
context.getLogger().error(e.getMessage());
}
}
@XApiGet
public XServiceResult crawlBaseWeaterData(XContext context, GetBaseWatherInput input) {
try {
String provinceUrl = "http://weather.cma.cn/api/dict/province";
String cityUrl = "http://weather.cma.cn/api/dict/province/";
//请求省份接口。获取省份列表
String provinceStr = HttpUtils.send2(provinceUrl, "");
//解析省份列表字符串,把字符串解析成json对象
JSONObject jsonObject = JSONObject.parseObject(provinceStr);
//处理json对象,变为数组
String[] provinceList = CharSequenceUtil.splitToArray(jsonObject.getString("data"), '|');
for (String proStr : provinceList) {
if (CharSequenceUtil.isNotBlank(proStr)) {
String[] pro = CharSequenceUtil.splitToArray(proStr, ',');
String provinceCode = pro[0];//省编码
String provinceName = pro[1];//省名称
//甘肃 .陕西 (全国周期抓取耗费时间超长,共有2400个城市)
if (CharSequenceUtil.equals(provinceCode, "AJL")) {
//请求省份下的区信息
String cityString = HttpUtils.send2(cityUrl + provinceCode, "");
//解析区json,把字符串解析成json对象
JSONObject cityObj = JSONObject.parseObject(cityString);
//处理json对象,变为数组
String[] cityList = CharSequenceUtil.splitToArray(cityObj.getString("data"), '|');
for (String cityStr : cityList) {
if (CharSequenceUtil.isNotBlank(cityStr)) {
String[] city = CharSequenceUtil.splitToArray(cityStr, ',');
String cityCode = city[0];//区编码
String cityName = city[1];//区名称
XThreadHelper.async(() -> insertData(context, provinceCode, provinceName, cityCode, cityName, 1));
}
}
}
}
}
} catch (Exception e) {
context.getLogger().error(e.getMessage());
}
return XServiceResult.OK;
}
@XApiGet
public XServiceResult crawlBaseWeaterDataByCityCode(XContext context, GetBaseWatherInput input) {
insertData(context, "ASN", "陕西", "57022", "麟游", 1);
return XServiceResult.OK;
}
}
\ No newline at end of file
......@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.NioUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
......@@ -95,9 +94,7 @@ public class BaseWeatherCloudServiceImpl implements IBaseWeatherCloudService {
re.getMailContent(message);
String tempFilePath = this.saveAttachment(message);
logger.info("------ weatherDataProcess load file: {}", tempFilePath);
FileReader fileReader = new FileReader(tempFilePath);
String jsonString = fileReader.readString();
JSONObject jsonObject = JSON.parseObject(jsonString);
JSONObject jsonObject = JSON.parseObject(FileUtil.readUtf8String(tempFilePath));
jsonObjectList.add(jsonObject);
logger.info("------ weatherDataProcess del temp file path: {}", tempFilePath);
FileUtil.del(tempFilePath);
......@@ -180,9 +177,8 @@ public class BaseWeatherCloudServiceImpl implements IBaseWeatherCloudService {
re.getMailContent(message);
String tempFilePath = this.saveAttachment(message);
logger.info("------ weatherApiDataProcess load file: {}", tempFilePath);
FileReader fileReader = new FileReader(tempFilePath);
String jsonString = fileReader.readString();
//处理读取流部分数据丢失精度问题
String jsonString = FileUtil.readUtf8String(tempFilePath);
jsonString = CharSequenceUtil.replace(jsonString, "%", ".");
List<Weather15mData> weather15mDataList = JSON.parseArray(jsonString, Weather15mData.class);
if (CollUtil.isEmpty(weather15mDataList)) {
......
package pps.core.base.utils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
public class HttpUtils {
public static String send2(String url, String param) throws Exception {
URL localURL = new URL(url);
URLConnection connection = localURL.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Accept", "application/json");
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Content-Length", String.valueOf(param.length()));
httpURLConnection.setConnectTimeout(10000);
OutputStream outputStream = null;
OutputStreamWriter outputStreamWriter = null;
InputStream inputStream = null;
String resultBuffer = "";
try {
outputStream = httpURLConnection.getOutputStream();
outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write(param);
outputStreamWriter.flush();
if (httpURLConnection.getResponseCode() >= 300) {
throw new Exception(
"HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode());
}
inputStream = httpURLConnection.getInputStream();
resultBuffer = convertStreamToString(inputStream);
System.out.println(resultBuffer);
} catch (Exception ignored) {
} finally {
if (outputStreamWriter != null) {
outputStreamWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
return resultBuffer;
}
public static String convertStreamToString(InputStream is) {
StringBuilder sb1 = new StringBuilder();
byte[] bytes = new byte[4096];
int size;
try {
while ((size = is.read(bytes)) > 0) {
String str = new String(bytes, 0, size, StandardCharsets.UTF_8);
sb1.append(str);
}
} catch (IOException ignored) {
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
return sb1.toString();
}
}
......@@ -38,10 +38,7 @@ public class ThirdPartyApiConstant {
* 长庆Token
*/
public static final String CQ_TOKEN = "/Smart_Well_Data/api/v1/Auth/GetToken";
/**
* 长庆三叠Token
*/
public static final String CQ_SD_LOGIN = "http://10.59.249.10:8183/admin-api/system/auth/login";
/**
* 获取日耗电日产液等信息
*/
......
package pps.core.prediction.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import pps.core.common.utils.ExcelUtils;
import pps.core.common.utils.ExportExcelUtils;
import pps.core.prediction.entity.PlantPowerDataEnt;
import pps.core.prediction.entity.PlantPowerDataView;
import pps.core.prediction.enums.ImportFieldDic;
import pps.core.prediction.mapper.PlantPowerDataMapper;
import pps.core.prediction.mapper.PlantPowerDataViewMapper;
import pps.core.prediction.service.data.plant_power_data.ImportFileInput;
import pps.core.prediction.service.data.plant_power_data.QueryPlantPowerDataInput;
import pps.core.prediction.service.data.plant_power_data.QueryPlantPowerDataOutput;
import pps.core.prediction.utils.HttpUtils;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.base.tool.XStorageTool;
import xstartup.data.XFileResult;
import xstartup.data.XFileType;
import xstartup.data.XPageResult;
import xstartup.data.XServiceResult;
import xstartup.feature.api.annotation.XApiGet;
import xstartup.feature.api.annotation.XApiUpload;
import xstartup.feature.mybatis.helper.XMapperHelper;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
@XService
@XText("电站实际发电数据")
public class PlantPowerDataService {
......@@ -48,84 +29,4 @@ public class PlantPowerDataService {
queryWrapper.lambda().orderByDesc(PlantPowerDataEnt::getDataDate);
return XMapperHelper.query(mapper, input, queryWrapper, QueryPlantPowerDataOutput.class);
}
@XText("下载电站实际发电数据导入模板")
@XApiGet
public XFileResult downloadImportTemplate(XContext context) {
String fileSavePath = XStorageTool.getAbsolutePath("/temp/excel/导入模板_" + DateUtil.formatDate(DateUtil.date()) + ".xlsx");
String templateFilePath = "template/import_plant_data_template.xlsx";
try (InputStream templateInputStream = this.getClass().getClassLoader().getResourceAsStream(templateFilePath)) {
byte[] excelContent = ExportExcelUtils.genSingleExcelFileData(templateInputStream, null);
ExportExcelUtils.outputFileData(excelContent, fileSavePath);
} catch (Exception e) {
context.getLogger().error(e);
}
return XFileResult.success(XFileType.APPLICATION_XLSX, fileSavePath);
}
@XText("导入电站实际发电数据")
@XApiUpload
public XServiceResult importPlantPowerData(XContext context, ImportFileInput input) {
List<String> headerList = getExcelHeaderList();
List<Map<String, Object>> mapList = ExcelUtils.readExcel(input.getFile().getInputStream(), input.getFile().getFileName(), headerList, 0);
try {
List<PlantPowerDataView> dataList = new ArrayList<>();
Date minDate = null;
Date maxDate = null;
for (Map<String, Object> objectMap : mapList) {
PlantPowerDataView dataView = BeanUtil.toBean(objectMap, PlantPowerDataView.class);
dataView.setPlantId(input.getPlantId());
if (ObjectUtil.isNotNull(dataView.getDataDate())) {
if (ObjectUtil.isNull(minDate)) {
minDate = dataView.getDataDate();
maxDate = dataView.getDataDate();
}
if (minDate.compareTo(dataView.getDataDate()) > 0) {
minDate = dataView.getDataDate();
} else if (maxDate.compareTo(dataView.getDataDate()) < 0) {
maxDate = dataView.getDataDate();
}
dataList.add(dataView);
}
}
if (ObjectUtil.isNull(minDate)) {
return XServiceResult.error(1000, "日期错误");
}
PlantPowerDataMapper mapper = context.getBean(PlantPowerDataMapper.class);
mapper.delete(new QueryWrapper<PlantPowerDataEnt>()
.lambda()
.eq(PlantPowerDataEnt::getPlantId, input.getPlantId())
.ge(PlantPowerDataEnt::getDataDate, minDate)
.le(PlantPowerDataEnt::getDataDate, maxDate));
PlantPowerDataViewMapper viewMapper = context.getBean(PlantPowerDataViewMapper.class);
viewMapper.insertBatch(dataList);
//进行训练
doTrainData(context, input.getPlantId());
} catch (Exception e) {
return XServiceResult.error(-1, e.getMessage());
}
return XServiceResult.OK;
}
private List<String> getExcelHeaderList() {
List<Map<String, Object>> fieldList = new ArrayList<>();
for (ImportFieldDic value : ImportFieldDic.values()) {
Map<String, Object> map = new HashMap<>();
map.put("col", value.getCol());
map.put("sort", value.getSort());
fieldList.add(map);
}
fieldList.sort(Comparator.comparing(o -> ((Integer) o.get("sort"))));
return fieldList.stream().map(x -> ((String) x.get("col"))).collect(Collectors.toList());
}
public void doTrainData(XContext context, String plantId) {
try {
Object ret = HttpUtils.send2("http://127.0.0.1:10098/aiprediction/xgbtrain?plantId=" + plantId,
"");
context.getLogger().info(ret.toString());
} catch (Exception e) {
throw new RuntimeException("调用训练接口失败");
}
}
}
\ No newline at end of file
......@@ -13,7 +13,6 @@ import pps.core.prediction.mapper.PlantPredictedPowerLongTermDataMapper;
import pps.core.prediction.service.data.plant_predicted_power_data.DoPlantPredictedPowerDataInput;
import pps.core.prediction.service.data.plant_predicted_power_data.GetPlantPredictedPowerDataInput;
import pps.core.prediction.service.data.plant_predicted_power_data.GetPlantPredictedPowerDataOutput;
import pps.core.prediction.utils.HttpUtils;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
......@@ -137,17 +136,6 @@ public class PlantPredictedPowerDataService {
@XText("预测电站发电数据")
@XApiPost
public XServiceResult doPredictedPowerData(XContext context, DoPlantPredictedPowerDataInput input) {
doPredictedData(context, input.getPlantId());
return XServiceResult.OK;
}
public void doPredictedData(XContext context, String plantId) {
try {
Object ret = HttpUtils.send2("http://127.0.0.1:10098/aiprediction/xgbreason?plantId=" + plantId,
"");
context.getLogger().info(ret.toString());
} catch (Exception e) {
throw new RuntimeException("调用训练接口失败");
}
}
}
\ No newline at end of file
package pps.core.prediction.service;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import pps.core.common.cache.ThirdPartyConfigCache;
import pps.core.prediction.constant.ThirdPartyApiConstant;
import pps.core.prediction.entity.ThirdActivePowerView;
import pps.core.prediction.enums.BusinessError;
import pps.core.prediction.mapper.ThirdActivePowerViewMapper;
import pps.core.prediction.service.data.third_active_power.GetThirdActivePowerOutput;
import pps.core.prediction.service.data.third_active_power.GetThirdSanDieLoginInfoOutput;
import pps.core.prediction.service.data.third_active_power_daily_update.GetThirdActivePowerDailyUpdateInput;
import xstartup.annotation.XService;
import xstartup.annotation.XText;
import xstartup.base.XContext;
import xstartup.base.exception.XServiceException;
import xstartup.base.util.XCopyUtils;
import xstartup.base.util.XHttpUtils;
import xstartup.data.XListResult;
import xstartup.data.XSingleResult;
import xstartup.feature.api.annotation.XApiPost;
import java.util.List;
......@@ -56,56 +44,7 @@ public class ThirdActivePowerService {
return XListResult.success(XCopyUtils.copyNewList(list, GetThirdActivePowerOutput.class));
}
/**
* 获取三叠登录信息
*
* @param context 上下文
* @return {@link XSingleResult}<{@link GetThirdSanDieLoginInfoOutput}>
*/
@XText("第三方--获取三叠登录信息")
@XApiPost
public XSingleResult<GetThirdSanDieLoginInfoOutput> getThirdSanDieLoginInfo(XContext context) {
String loginInfo;
ThirdPartyConfigCache exist = ThirdPartyConfigCache.exist(context, ThirdPartyApiConstant.CQ_TOKEN_SAN_DIE_CACHE_KEY);
if (ObjectUtil.isNull(exist)) {
loginInfo = this.getSanDieToken(context);
} else {
long duration = (long) exist.getDuration();
if (duration - DateUtil.between(exist.getCurrentDate(), DateUtil.date(), DateUnit.SECOND) < ThirdPartyApiConstant.MAX_SECOND) {
loginInfo = this.getSanDieToken(context);
} else {
loginInfo = exist.getCode();
}
}
return XSingleResult.success(JSON.parseObject(loginInfo, GetThirdSanDieLoginInfoOutput.class));
}
/*---------------------------------- 私有方法 ----------------------------------*/
/**
* 获取三叠令牌
*
* @param context 上下文
* @return {@link String}
*/
private String getSanDieToken(XContext context) {
JSONObject param = new JSONObject();
param.put("username", "31b5604627e345ebb48175de8f2ee0bdem55ajAwMQ==kj");
param.put("password", "sdSktfem55ajAwMSFAIzEw8ef354f215d44c0eafd403ab7a1ce74a");
String result = XHttpUtils.postAsJson(ThirdPartyApiConstant.CQ_SD_LOGIN, param.toJSONString(), 10000);
context.getLogger().info("**** getThirdSanDieLoginInfo result: {}", result);
param = JSON.parseObject(result);
param = param.getJSONObject("data");
if (ObjectUtil.isEmpty(param)) {
throw new XServiceException(context, BusinessError.GetSanDieLoginInfoError);
}
String data = param.toJSONString();
ThirdPartyConfigCache cache = new ThirdPartyConfigCache();
cache.setCodeKey(ThirdPartyApiConstant.CQ_TOKEN_SAN_DIE_CACHE_KEY);
cache.setCode(data);
cache.setValidity(15);
cache.setCurrentDate(DateUtil.date());
ThirdPartyConfigCache.set(context, cache);
return data;
}
}
package pps.core.prediction.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class HttpUtils {
public static String send2(String url, String param) throws Exception {
URL localURL = new URL(url);
URLConnection connection = localURL.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Accept", "application/json");
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Content-Length", String.valueOf(param.length()));
httpURLConnection.setConnectTimeout(10000);
OutputStream outputStream = null;
OutputStreamWriter outputStreamWriter = null;
InputStream inputStream = null;
String resultBuffer = "";
try {
outputStream = httpURLConnection.getOutputStream();
outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write(param);
outputStreamWriter.flush();
if (httpURLConnection.getResponseCode() >= 300) {
throw new Exception(
"HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode());
}
inputStream = httpURLConnection.getInputStream();
resultBuffer = convertStreamToString(inputStream);
} finally {
if (outputStreamWriter != null) {
outputStreamWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
return resultBuffer;
}
public static String convertStreamToString(InputStream is) {
StringBuilder sb1 = new StringBuilder();
byte[] bytes = new byte[4096];
int size;
try {
while ((size = is.read(bytes)) > 0) {
String str = new String(bytes, 0, size, "UTF-8");
sb1.append(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb1.toString();
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment