Bläddra i källkod

内蒙东润sftp传输dq和nwp

zhangchenglong 3 veckor sedan
förälder
incheckning
ce6da90e32

+ 1 - 1
in-cloud/src/main/java/com/jiayue/insu/incloud/config/SaTokenConfigure.java

@@ -27,7 +27,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
         registry.addInterceptor(new SaRouteInterceptor())
                 .addPathPatterns("/**")
                 .excludePathPatterns("/login/doLogin","/file/**","/stati/**","/index.html")
-                .excludePathPatterns("/login/doLogin","/file/**","/stati/**","/index.html","/pfserver/**","/pfserverTest/**");// 外网接口拦截取消
+                .excludePathPatterns("/login/doLogin","/file/**","/stati/**","/index.html","/pfserver/**","/pfserverTest/**","/postTest/**");// 外网接口拦截取消
     }
 
 

+ 5 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/constants/CompanyConstant.java

@@ -31,6 +31,11 @@ public interface CompanyConstant {
 
     String COMPANY_LX = "LX";
 
+    /**
+     * 帽子山光伏电站CODE
+     */
+    String STATION_MZS_CODE = "J00269";
+
 
 
 }

+ 46 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/controller/PostTest.java

@@ -0,0 +1,46 @@
+package com.jiayue.insu.incloud.controller;
+
+import cn.hutool.json.JSONObject;
+import com.jiayue.insu.incloud.constants.CommonStant;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.pushdata.PushDataToSftp;
+import com.jiayue.insu.incloud.service.StationService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * StationController
+ *
+ * @author yh
+ * @date 2022-03-18 15:48:48
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/postTest")
+public class PostTest {
+
+    @Autowired
+    public PushDataToSftp pushDataToSftp;
+    @Autowired
+    public StationService stationService;
+
+    /**
+     * @param
+     * @return
+     */
+    @PostMapping("/test")
+    public JSONObject test(String stationCode) {
+        //校验授权信息并返回用户名及密码
+        JSONObject result = new JSONObject();
+        result.set("result", "success");
+        Station station = stationService.checkAndFindStation(stationCode, CommonStant.RECORD_TYPE_PUSH_INIT);
+        pushDataToSftp.pushDQAndNWPData(station);
+        return result;
+    }
+}

+ 312 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/pushdata/PushCommon.java

@@ -0,0 +1,312 @@
+package com.jiayue.insu.incloud.pushdata;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.file.FileReader;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import com.jiayue.insu.incloud.constants.CommonStant;
+import com.jiayue.insu.incloud.constants.CompanyConstant;
+import com.jiayue.insu.incloud.constants.enums.StatusEnum;
+import com.jiayue.insu.incloud.entity.IntegrationCompany;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.service.IntegrationCompanyService;
+import com.jiayue.insu.incloud.service.MinIoService;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.utils.FileUtils;
+import com.jiayue.insu.incloud.utils.SFTPUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.velocity.VelocityContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 将数据推送至sftp
+ *
+ * @author changchenglong
+ * @version 1.0
+ * @since 2025/5/27 14:29
+ */
+@Component
+@Slf4j
+public class PushCommon {
+    @Autowired
+    private RecordService recordService;
+    @Autowired
+    private IntegrationCompanyService integrationCompanyService;
+    @Autowired
+    private MinIoService minIoService;
+    @Autowired
+    private FileUtils fileUtils;
+    @Autowired
+    private SFTPUtil sftpUtil;
+    @Value("${localFilePath.initFilePath}")
+    String initFilePath;
+    @Value("${localFilePath.bjFilePath}")
+    String bjFilePath;
+
+    /**
+     * 推送短期数据导sftp
+     *
+     * @param station
+     * @param companyCode
+     * @param newFilePath
+     * @param newFileName
+     * @param templateName
+     * @param newFilePath
+     * @param newFilePath
+     * @return
+     */
+    public Boolean pushDQData(Station station, String companyCode, String newFilePath, String newFileName, String templateName) {
+        // 获取场站编号
+        String stationCode = station.getStationCode();
+        Record record = new Record(CommonStant.RECORD_TYPE_PUSH_INIT_TO_SFTP, companyCode, stationCode, null, LocalDateTime.now(), LocalDateTime.now(), null, null);
+        record.setState(StatusEnum.SUCCESS.getSign());
+        // 如果场站编号为空,则返回
+        if (stationCode == null || "".equals(stationCode)) {
+            record.setState(StatusEnum.STATION_CODE_NULL.getSign());
+            record.setStateContent(StatusEnum.STATION_CODE_NULL.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        // 获取指定目录下的短期原始数据(/jiayue/insu/file/init/J00269/)
+        String filePath = initFilePath + stationCode + File.separatorChar;
+        File files = new File(filePath);
+        String[] fileNames = files.list();
+        // 如果文件名列表为空
+        if (fileNames == null || fileNames.length == 0) {
+            log.info("指定目录下无文件");
+            record.setState(StatusEnum.FILE_NULL.getSign());
+            record.setStateContent(StatusEnum.FILE_NULL.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        // 获取当天日期
+        LocalDateTime today = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+        DateTimeFormatter formatterSeparator = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String todaySeparatorStr = today.format(formatterSeparator);
+        String todayStr = today.format(formatter);
+        // 转为list并根据日期筛选排序
+        List<String> fileList = Arrays.stream(fileNames).collect(Collectors.toList());
+        List<String> filterFileList = fileList.stream().filter(s -> s.contains(todayStr)).filter(s -> s.contains("DQ")).collect(Collectors.toList());
+        // 如果筛选后无文件
+        if (filterFileList.size() == 0) {
+            log.info("无当日文件");
+            record.setState(StatusEnum.FILE_NULL.getSign());
+            record.setStateContent(StatusEnum.FILE_NULL.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        filterFileList.sort(Collections.reverseOrder());
+        // 获取原始文件
+        File originalFile = new File(filterFileList.get(0));
+        // 读取文件
+        FileReader fileReader = new FileReader(filePath + originalFile);
+        List<String> originalContents = fileReader.readLines();
+
+        List<Map<String, Object>> vList = new ArrayList<>();
+        String dataTime[];
+        // 循环解析原始短期文件
+        for (String originalContent : originalContents) {
+            // 从有#的数据开始获取 数据示例:#1	XXX光伏电站	2023-06-22 00:00:00	0.0
+            if (originalContent.contains("#")) {
+                // 如果是帽子山光伏电站,刨除掉当天数据
+                if (CompanyConstant.STATION_MZS_CODE.equals(stationCode)) {
+                    // 刨除当天的数据
+                    if (originalContent.contains(todaySeparatorStr)) {
+                        continue;
+                    }
+                }
+
+                // 根据分隔符分割,取时间和功率
+                String[] originalContentArr = originalContent.split("\t");
+                Map<String, Object> map = new HashMap<>();
+                // 如果分割后的数组长度小于4,则数据格式不正确
+                if (originalContentArr.length < 4) {
+                    continue;
+                }
+                // 将时间2023-06-22 00:00:00根据分隔分割并组成2023-06-22_00:00:00格式
+                dataTime = originalContentArr[2].split(" ");
+                // 如果分割后的数组长度小于2,则数据格式不正确
+                if (dataTime.length < 2) {
+                    continue;
+                }
+                // 将预测时间和预测功率放入list中
+                map.put("forecastTime", dataTime[0] + "_" + dataTime[1]);
+                map.put("fpValue", originalContentArr[3]);
+                vList.add(map);
+            }
+        }
+
+        String fileType = todayStr + File.separatorChar + "dq";
+        // 文件数据开始时间
+        String fileDateStr = DateUtil.format(DateUtil.beginOfDay(DateUtil.tomorrow()), "yyyyMMdd_HH:mm:ss");
+        // 推送数据至sftp
+        this.pushFileToSftp(record, vList, newFilePath, newFileName, templateName, station, fileType, companyCode, fileDateStr);
+        return true;
+    }
+
+    /**
+     * 推送nwp数据导sftp
+     *
+     * @param station
+     * @param companyCode
+     * @param newFilePath
+     * @param newFileName
+     * @param templateName
+     * @return
+     */
+    public Boolean pushNWPData(Station station, String companyCode, String newFilePath, String newFileName, String templateName) {
+
+        JSONObject errMsg = new JSONObject();
+
+        // 获取场站编号
+        String stationCode = station.getStationCode();
+        Record record = new Record(CommonStant.RECORD_TYPE_PUSH_INIT_TO_SFTP, companyCode, stationCode, null, LocalDateTime.now(), LocalDateTime.now(), null, null);
+        record.setState(StatusEnum.SUCCESS.getSign());
+
+        String beginDate = DateUtil.today();
+        String endDate = DateUtil.format(DateUtil.tomorrow(), "yyyy-MM-dd");
+
+        // 从minIo获取文件
+        File originalFile = minIoService.downLoadFileFromMinIo(station, "nwp", beginDate, endDate, errMsg);
+
+        if(originalFile==null){
+            return false;
+        }
+        String filePath = initFilePath + stationCode + File.separatorChar;
+
+        String path11 = originalFile.getAbsolutePath();
+        // 读取文件
+        FileReader fileReader = new FileReader(originalFile.getAbsolutePath());
+        List<String> originalContents = fileReader.readLines();
+
+        List<Map<String, Object>> vList = new ArrayList<>();
+        for (String originalContent : originalContents) {
+            if (originalContent.startsWith("#")) {
+                String[] string_arr = originalContent.split("\t");
+                if (StrUtil.isNotEmpty(string_arr[2])) {
+                    // 每一条数据的json,放入预测数据和预测时间
+                    Map<String, Object> oneJson = new HashMap<>();
+                    oneJson.put("farmId", string_arr[1]);
+                    oneJson.put("scDate", string_arr[2]);
+                    oneJson.put("scTime", string_arr[3]);
+                    oneJson.put("preDate", string_arr[4]);
+                    oneJson.put("preTime", string_arr[5]);
+                    oneJson.put("t", new BigDecimal(string_arr[6]).subtract(new BigDecimal("273.15")));
+                    oneJson.put("rh", new BigDecimal(string_arr[7]));
+                    oneJson.put("pressure", new BigDecimal(string_arr[8]));
+                    oneJson.put("swr", new BigDecimal(string_arr[9]));
+                    oneJson.put("lwr", new BigDecimal(string_arr[10]));
+                    oneJson.put("senf", new BigDecimal(string_arr[11]));
+                    oneJson.put("ws10", new BigDecimal(string_arr[12]));
+                    oneJson.put("ws30", new BigDecimal(string_arr[13]));
+                    oneJson.put("ws50", new BigDecimal(string_arr[14]));
+                    oneJson.put("ws70", new BigDecimal(string_arr[15]));
+                    oneJson.put("ws80", new BigDecimal(string_arr[16]));
+                    oneJson.put("ws90", new BigDecimal(string_arr[17]));
+                    oneJson.put("ws100", new BigDecimal(string_arr[18]));
+                    oneJson.put("ws170", new BigDecimal(string_arr[19]));
+                    oneJson.put("wd10", new BigDecimal(string_arr[20]));
+                    oneJson.put("wd30", new BigDecimal(string_arr[21]));
+                    oneJson.put("wd50", new BigDecimal(string_arr[22]));
+                    oneJson.put("wd70", new BigDecimal(string_arr[23]));
+                    oneJson.put("wd80", new BigDecimal(string_arr[24]));
+                    oneJson.put("wd90", new BigDecimal(string_arr[25]));
+                    oneJson.put("wd100", new BigDecimal(string_arr[26]));
+                    oneJson.put("wd170", new BigDecimal(string_arr[27]));
+                    // 将一每条数据放入datas(一天的json)中
+                    vList.add(oneJson);
+                }
+            }
+        }
+
+        DateTime today = DateUtil.date();
+        String todayStr = today.toString("yyyyMMdd");
+        String fileDateStr = DateUtil.format(DateUtil.beginOfDay(DateUtil.tomorrow()), "yyyyMMdd_HH:mm:ss");
+        String fileType = todayStr + File.separatorChar + "nwp";
+        this.pushFileToSftp(record, vList, newFilePath, newFileName, templateName, station, fileType, companyCode, fileDateStr);
+        return true;
+    }
+
+    /**
+     * @param record
+     * @param vList
+     * @param newFilePath
+     * @param newFileName
+     * @param templateName
+     * @param station
+     * @param dateAndFileType
+     * @param companyCode
+     * @return
+     */
+    public boolean pushFileToSftp(Record record, List<Map<String, Object>> vList, String newFilePath, String newFileName, String templateName, Station station, String dateAndFileType, String companyCode, String fileDateStr) {
+
+        VelocityContext velocityContext = new VelocityContext();
+        velocityContext.put("vList", vList);
+        velocityContext.put("createTime", DateUtil.format(new Date(), "yyyyMMdd_HH:mm:ss"));
+        velocityContext.put("date", fileDateStr);
+        velocityContext.put("stationCode", station.getStationCode());
+        velocityContext.put("stationName", station.getName());
+
+        File newFile;
+        // 生成新文件
+        try {
+            newFile = fileUtils.createFileByVelocityTemplate(newFilePath, newFileName, templateName, velocityContext);
+        } catch (Exception e) {
+            e.printStackTrace();
+            record.setState(StatusEnum.CREATE_FILE_FAIL.getSign());
+            record.setStateContent(StatusEnum.CREATE_FILE_FAIL.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        // 获取公司信息
+        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(companyCode);
+        String sftpInfo = integrationCompany.getPushUrl();
+        String[] sftpInfoArr = sftpInfo.split(":");
+        // 如果sftp的url配置不对,正确为   用户名:密码:ip:端口号:路径
+        if (sftpInfoArr.length < 5) {
+            record.setState(StatusEnum.PUSH_URL_ERROR.getSign());
+            record.setStateContent(StatusEnum.PUSH_URL_ERROR.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        String userName = sftpInfoArr[0];
+        String passWord = sftpInfoArr[1];
+        String sftpUrl = sftpInfoArr[2];
+        // 如果端口为空
+        if (sftpInfoArr[3] == null || "".equals(sftpInfoArr[3])) {
+            record.setState(StatusEnum.PUSH_URL_ERROR.getSign());
+            record.setStateContent(StatusEnum.PUSH_URL_ERROR.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        int sftpPort = Integer.valueOf(sftpInfoArr[3]);
+        String sftpFilePath = sftpInfoArr[4];
+        sftpFilePath = sftpFilePath + File.separatorChar + dateAndFileType;
+
+        log.info("getUsername:" + userName);
+        log.info("getPassword:" + passWord);
+        log.info("sftpUrl:" + sftpUrl);
+        log.info("sftpPort:" + sftpPort);
+        log.info("sftpFilePath:" + sftpFilePath);
+        log.info("newFileName:" + newFile.getName());
+        // 多级目录创建并上传
+//        sftpFilePath = "/home/20250528/dq";
+        sftpUtil.uploadByFileAndPath(userName, passWord, sftpUrl, sftpPort, newFile, sftpFilePath, newFile.getName());
+        // 保存日志
+        recordService.save(record);
+        return true;
+    }
+
+}

+ 159 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/pushdata/PushDataToSftp.java

@@ -0,0 +1,159 @@
+package com.jiayue.insu.incloud.pushdata;
+
+import cn.hutool.core.date.DateUtil;
+import com.jiayue.insu.incloud.constants.CompanyConstant;
+import com.jiayue.insu.incloud.constants.enums.StatusEnum;
+import com.jiayue.insu.incloud.entity.IntegrationCompany;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.service.IntegrationCompanyService;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.utils.FileUtils;
+import com.jiayue.insu.incloud.utils.SFTPUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.velocity.VelocityContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 将数据推送至sftp
+ *
+ * @author changchenglong
+ * @version 1.0
+ * @since 2025/5/27 14:29
+ */
+@Component
+@Slf4j
+public class PushDataToSftp implements IPushInitForecastData {
+    @Autowired
+    private RecordService recordService;
+    @Autowired
+    private PushCommon pushCommon;
+    @Autowired
+    private IntegrationCompanyService integrationCompanyService;
+    @Autowired
+    private FileUtils fileUtils;
+    @Autowired
+    private SFTPUtil sftpUtil;
+    @Value("${localFilePath.drFilePath}")
+    String drFilePath;
+
+    /**
+     * 推送原始预测数据
+     *
+     * @param station 场站信息
+     * @return 是否成功
+     */
+    @Override
+    public Boolean pushDQAndNWPData(Station station) {
+        this.pushDQData(station);
+        this.pushNWPData(station);
+        return null;
+    }
+
+    /**
+     * 将下载好的原始短期文件通过sftp推送
+     *
+     * @param station
+     * @return
+     */
+    @Override
+    public Boolean pushDQData(Station station) {
+        String stationCode = station.getStationCode();
+        String newFilePath = drFilePath + stationCode + File.separatorChar;
+        String tomorrowStr = DateUtil.format(DateUtil.tomorrow(), "yyyyMMdd");
+        String newFileName = "modeloutput-" + stationCode + "J001-" + tomorrowStr + "AM.txt";
+        String templateName = File.separatorChar + "vms" + File.separatorChar + "DR_DQ.vm";
+        pushCommon.pushDQData(station, station.getInCode(), newFilePath, newFileName, templateName);
+        return true;
+    }
+
+    @Override
+    public Boolean pushNWPData(Station station) {
+        Boolean result = false;
+        String stationCode = station.getStationCode();
+        String newFilePath = drFilePath + stationCode + File.separatorChar;
+        String tomorrowStr = DateUtil.format(DateUtil.tomorrow(), "yyyyMMdd");
+        String newFileName = "modeloutput-" + stationCode + "J001-" + tomorrowStr + "NWP.RB";
+        String templateName = File.separatorChar + "vms" + File.separatorChar + "DR_NWP.vm";
+        result = pushCommon.pushNWPData(station, station.getInCode(), newFilePath, newFileName, templateName);
+        return result;
+    }
+
+    /**
+     * @param record
+     * @param vList
+     * @param newFilePath
+     * @param newFileName
+     * @param templateName
+     * @param station
+     * @param dateAndFileType
+     * @param todayStr
+     * @return
+     */
+    public boolean pushFileToSftp(Record record, List<Map<String, Object>> vList, String newFilePath, String newFileName, String templateName, Station station, String dateAndFileType, String todayStr, String fileDateStr) {
+
+        VelocityContext velocityContext = new VelocityContext();
+        velocityContext.put("vList", vList);
+        velocityContext.put("createTime", DateUtil.format(new Date(), "yyyyMMdd_HH:mm:ss"));
+        velocityContext.put("date", fileDateStr);
+        velocityContext.put("stationCode", station.getStationCode());
+        velocityContext.put("stationName", station.getName());
+
+        File newFile;
+        // 生成新文件
+        try {
+            newFile = fileUtils.createFileByVelocityTemplate(newFilePath, newFileName, templateName, velocityContext);
+        } catch (Exception e) {
+            e.printStackTrace();
+            record.setState(StatusEnum.CREATE_FILE_FAIL.getSign());
+            record.setStateContent(StatusEnum.CREATE_FILE_FAIL.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        // 获取公司信息
+        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(CompanyConstant.COMPANY_BJZYYJY);
+        String sftpInfo = integrationCompany.getPushUrl();
+        String[] sftpInfoArr = sftpInfo.split(":");
+        // 如果sftp的url配置不对,正确为   用户名:米面:ip:端口号:路径
+        if (sftpInfoArr.length < 5) {
+            record.setState(StatusEnum.PUSH_URL_ERROR.getSign());
+            record.setStateContent(StatusEnum.PUSH_URL_ERROR.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        String userName = sftpInfoArr[0];
+        String passWord = sftpInfoArr[1];
+        String sftpUrl = sftpInfoArr[2];
+        // 如果端口为空
+        if (sftpInfoArr[3] == null || "".equals(sftpInfoArr[3])) {
+            record.setState(StatusEnum.PUSH_URL_ERROR.getSign());
+            record.setStateContent(StatusEnum.PUSH_URL_ERROR.getMsg());
+            recordService.save(record);
+            return false;
+        }
+        int sftpPort = Integer.valueOf(sftpInfoArr[3]);
+        String sftpFilePath = sftpInfoArr[4];
+        sftpFilePath = sftpFilePath + File.separatorChar + dateAndFileType;
+
+        log.info("getUsername:" + userName);
+        log.info("getPassword:" + passWord);
+        log.info("sftpUrl:" + sftpUrl);
+        log.info("sftpPort:" + sftpPort);
+        log.info("sftpFilePath:" + sftpFilePath);
+        log.info("newFileName:" + newFile.getName());
+        // 多级目录创建并上传
+        sftpUtil.uploadByFileAndPath(userName, passWord, sftpUrl, sftpPort, newFile, sftpFilePath, newFile.getName());
+        // 保存日志
+        recordService.save(record);
+        return true;
+    }
+
+
+}

+ 38 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/service/MinIoService.java

@@ -0,0 +1,38 @@
+package com.jiayue.insu.incloud.service;
+
+import cn.hutool.json.JSONObject;
+import com.jiayue.insu.incloud.entity.Station;
+
+import java.io.File;
+
+/**
+ * 预测数据业务接口
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+public interface MinIoService {
+
+    /**
+     * 从minIo下载文件
+     *
+     * @param station
+     * @param type
+     * @param startTime
+     * @param endTime
+     * @param errMsg
+     * @return
+     */
+    File downLoadFileFromMinIo(Station station, String type, String startTime, String endTime, JSONObject errMsg);
+
+    /**
+     * 从minIo下载文件后,回传状态
+     *
+     * @param stationCode
+     * @param fileName
+     * @param type
+     * @param status
+     */
+    void postBackMinIoState(String stationCode, String fileName, String type, String status);
+}

+ 329 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/service/impl/MinIoServiceImpl.java

@@ -0,0 +1,329 @@
+package com.jiayue.insu.incloud.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.jiayue.insu.incloud.constants.enums.StatusEnum;
+import com.jiayue.insu.incloud.constants.vo.FileCreateLog;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.service.MinIoService;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.utils.JsonResultUtil;
+import com.jiayue.insu.incloud.utils.SystermUtils;
+import com.jiayue.insu.minio.util.MinioUtilService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * 预测数据业务实现
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+@Slf4j
+@Service
+public class MinIoServiceImpl implements MinIoService {
+
+    @Value("${minio.pull.url}")
+    String url;
+    @Value("${minio.pull.fileurl}")
+    String fileurl;
+    @Value("${minio.fileurl}")
+    String fileDir;
+    @Value("${minio.bucketname}")
+    private String bucketName;
+    @Value("${minio.pull.cloudFileCreateLog}")
+    private String cloudFileCreateLog;
+    @Value("${minio.postBackUrl}")
+    private String postBackUrl;
+    @Value("${minio.pushCorrFileUrl}")
+    private String pushCorrFileUrl;
+
+    @Autowired
+    RedisTemplate redisTemplate;
+    @Autowired
+    private MinioUtilService minioUtilService;
+    @Autowired
+    public RecordService recordService;
+
+
+    /**
+     * 向minIo中放入文件
+     *
+     * @param file
+     * @param stationCode
+     * @return
+     */
+    public JSONObject pushFileToMinIo(File file, String stationCode) {
+        // 存放完文件后返回的文件路径
+        String minIoFileUrl;
+        InputStream in = null;
+        InputStream inB = null;
+        try {
+            // 查看桶名称是否存在
+            boolean flag = minioUtilService.bucketExists(bucketName);
+            if (!flag) {
+                return JsonResultUtil.failure("MinIo桶不存在");
+            }
+            // 向minIo中放入文件
+            in = new FileInputStream(file);
+            String fileName = "/" + stationCode + "/" + file.getName();
+            minIoFileUrl = minioUtilService.putObject(bucketName, fileName, in);
+            // 如果是AB机,向B中也放入文件
+            if (stationCode.indexOf("-A") > 0) {
+                // InputStream 在被读取后,指针已经移动到了流的末尾,第二次上传B时就已经没有数据了,故新建一个输入流
+                inB = new FileInputStream(file);
+                String fileNameB = "/" + stationCode.replace("-A", "-B") + "/" + file.getName();
+                minIoFileUrl = minIoFileUrl + ";" + minioUtilService.putObject(bucketName, fileNameB, inB);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return JsonResultUtil.failure("推送MinIo失败");
+        } finally {
+            close(in);
+            close(inB);
+        }
+        return JsonResultUtil.success(minIoFileUrl);
+    }
+
+    /**
+     * 请求V3云平台返回上传minIo文件信息
+     *
+     * @param stationCode
+     * @param fileName
+     * @param fileDownloadUrl
+     */
+    public void postFileCreateInfoToCloud(String stationCode, String fileName, String fileDownloadUrl) {
+        fileDownloadUrl = fileDownloadUrl.split("\\?")[0];
+        Map<String, Object> urlMap = new HashMap<>();
+        urlMap.put("stationCode", stationCode);
+        urlMap.put("stationName", stationCode);
+        urlMap.put("fileName", fileName);
+        urlMap.put("fileDownloadUrl", fileDownloadUrl);
+        urlMap.put("sign", SystermUtils.caluMd5Sign(stationCode + DateUtil.today()));
+        try {
+            String body = HttpUtil.post(cloudFileCreateLog, urlMap, 10000);
+            JSONObject result = JSONUtil.parseObj(body);
+            if (!"0".equals(result.getStr(JsonResultUtil.CODE_TAG))) {
+                log.info("请求V3云平台失败");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.info("请求V3云平台失败");
+        }
+    }
+
+    /**
+     * 从minIo下载文件
+     *
+     * @param station
+     * @param type
+     * @return
+     */
+    public File downLoadFileFromMinIo(Station station, String type, String startTime, String endTime, JSONObject errMsg) {
+        // 如果场站信息为空
+        if (station == null) {
+            log.info("场站信息为空");
+            errMsg.set("msg", "场站信息为空");
+            return null;
+        }
+
+        if (startTime == null || "".equals(startTime)) {
+            log.info("文件获取失败,开始时间为空");
+            errMsg.set("msg", "文件获取失败,开始时间为空");
+            return null;
+        }
+
+        // 校验日期格式
+        if (startTime.indexOf("-") == -1) {
+            log.info("文件获取失败,开始时间格式不正确,正确格式为yyyy-MM-dd");
+            errMsg.set("msg", "文件获取失败,开始时间格式不正确,正确格式为yyyy-MM-dd");
+            return null;
+        }
+
+        Record record = new Record();
+        log.info("下载minIo原始RB文件 --> {}" + station.getStationCode());
+        try {
+            // 从云上获取minIo中指定日期的文件信息 格式https://117.78.19.70:9010/client/getFileLogsForAio/J00260/2023-08-11
+            String getUrl = url + station.getStationCode() + "/" + startTime;
+            HttpRequest httpRequest = HttpRequest.get(getUrl);
+            httpRequest.setGlobalTimeout(20000);
+            String body = httpRequest.execute().body();
+            JSONObject json = JSONUtil.parseObj(body);
+            String data = json.get("data").toString();
+            String code = json.get("code").toString();
+            if (!code.equals("0") || data.length() <= 0) {
+                record.setState(StatusEnum.RESPONSE_FAIL.getCode());
+                log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.RESPONSE_FAIL.getMsg());
+                errMsg.set("msg", "下载原始文件失败");
+                return null;
+            }
+            // 获取文件信息列表
+            JSONArray array = JSONUtil.parseArray(data);
+            // 文件列表
+            List<FileCreateLog> list = array.toList(FileCreateLog.class);
+            // 如果文件列表为空,则未获取到文件
+            if (CollectionUtil.isEmpty(list)) {
+                record.setState(StatusEnum.FILE_NULL.getCode());
+                log.info("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
+                errMsg.set("msg", "下载原始文件失败");
+                return null;
+            }
+
+            // 保存文件路径
+            String fileSaveUrl = fileDir + File.separatorChar + "init" + File.separatorChar + station.getStationCode();
+            log.info("文件保存路径" + fileSaveUrl);
+            File dir = new File(fileSaveUrl);
+            if (!dir.exists()) {// 判断目录是否存在
+                dir.mkdirs();
+                log.info("创建目录:" + fileSaveUrl);
+            }
+            // 筛选指定日期短期文件
+            List<FileCreateLog> listFile = new ArrayList<>();
+            String nowUrl = "";
+            String downloadFileName = "";
+            // 如果是短期
+            if ("dq".equals(type)) {
+                listFile = list.stream().filter(f -> f.getFileName().contains("DQ_" + startTime.replace("-", ""))).collect(Collectors.toList());
+                //  如果文件为空,
+                if (CollectionUtil.isEmpty(listFile)) {
+                    record.setState(StatusEnum.FILE_NULL.getCode());
+                    log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode() + " DQ文件", StatusEnum.FILE_NULL.getMsg());
+                    errMsg.set("msg", "下载原始文件失败");
+                    return null;
+                }
+                // 将短期文件倒序,获取最新的文件
+                listFile.sort(Comparator.comparing(FileCreateLog::getFileName).reversed());
+                // 拼接下载文件url=fileUrl(下载文件请求地址)+从minIo获取的最新一条的文件id
+                nowUrl = fileurl + listFile.get(0).getId();
+                downloadFileName = listFile.get(0).getFileName();
+                // 如果是超短期
+            } else if ("cdq".equals(type)) {
+                // 格式化开始时间 将时间2019-10-10 01:15 转为=》201910100115
+                String formatStartTime = startTime.replace("-", "").replace(" ", "").replace(":", "");
+                // 根据CDQ_201910100115 筛选超短期文件
+                listFile = list.stream().filter(f -> f.getFileName().contains("CDQ_" + formatStartTime)).collect(Collectors.toList());
+            } else if ("nwp".equals(type)) {
+                listFile = list.stream().filter(f -> f.getFileName().contains("NWP_" + startTime.replace("-", ""))).collect(Collectors.toList());
+                // 将短期文件倒序,获取最新的文件
+//                listFile.sort(Comparator.comparing(FileCreateLog::getFileName).reversed());
+                listFile.sort(Comparator.comparing(FileCreateLog::getFileName));
+                // 拼接下载文件url=fileUrl(下载文件请求地址)+从minIo获取的最新一条的文件id
+                nowUrl = fileurl + listFile.get(0).getId();
+                downloadFileName = listFile.get(0).getFileName();
+            }
+            //  如果文件为空,
+            if (CollectionUtil.isEmpty(listFile)) {
+                log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
+                record.setState(StatusEnum.FILE_NULL.getCode());
+                errMsg.set("msg", "下载原始文件失败");
+                return null;
+            }
+
+            try {
+                // 通过url下载文件
+                File nowFile = HttpUtil.downloadFileFromUrl(nowUrl, fileSaveUrl + File.separatorChar + downloadFileName);
+                if (nowFile == null) {
+                    record.setState(StatusEnum.DOWNLOAD_FILE_ERROR.getCode());
+                    log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
+                    errMsg.set("msg", "下载原始文件失败");
+                    return null;
+                }
+
+                // 回传dq和nwp文件状态
+                this.postBackMinIoState(station.getStationCode(), nowFile.getName(), "down", "是");
+                // 返回文件
+                return nowFile;
+            } catch (Exception e) {
+                record.setState(StatusEnum.DOWNLOAD_FILE_FAIL.getCode());
+                log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.DOWNLOAD_FILE_FAIL.getMsg());
+                e.printStackTrace();
+                errMsg.set("msg", "下载原始文件失败");
+                return null;
+            }
+        } catch (Exception e) {
+            record.setState(StatusEnum.RESPONSE_FAIL.getCode());
+            log.error("下载minIo原始RB文件 --> {} 失败,失败原因:{}", station.getStationCode(), StatusEnum.RESPONSE_FAIL.getMsg());
+            e.printStackTrace();
+            errMsg.set("msg", "下载原始文件失败");
+            return null;
+        }
+    }
+
+
+    /**
+     * 从minIo下载文件后,回传状态
+     *
+     * @param stationCode
+     * @param fileName
+     * @param type
+     * @param status
+     */
+    @Override
+    public void postBackMinIoState(String stationCode, String fileName, String type, String status) {
+        Map urlParams = new HashMap(4);
+        urlParams.put("stationCode", stationCode);
+        urlParams.put("forecastFileName", fileName);
+        urlParams.put("type", type);
+        urlParams.put("status", status);
+        log.debug("回传文件状态给新平台,请求参数", JSONUtil.toJsonStr(urlParams));
+        String repose = HttpUtil.post(postBackUrl, urlParams, 10000);
+        log.info("回传文件状态给新平台,请求相应 {}", repose);
+    }
+
+
+    /**
+     * 判断是否是NULL 和是否是数值
+     *
+     * @param data
+     * @return
+     */
+    public BigDecimal isNumberOrNull(String data) {
+        BigDecimal bigDecimal = new BigDecimal("-99");
+        if (!data.contains("null") && !data.contains("NULL")) {
+
+            Pattern pattern = Pattern.compile("-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?");
+            Matcher isNum = pattern.matcher(data);
+            try {
+                if (isNum.matches()) {
+                    bigDecimal = new BigDecimal(data).setScale(2, BigDecimal.ROUND_DOWN);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+
+        return bigDecimal;
+    }
+
+    // 封装一个安全的关闭方法
+    private static void close(InputStream inputStream) {
+        if (inputStream != null) {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace(); // 可选:日志记录
+            }
+        }
+    }
+}

+ 11 - 4
in-cloud/src/main/java/com/jiayue/insu/incloud/utils/SFTPUtil.java

@@ -176,7 +176,7 @@ public class SFTPUtil {
             log.warn(directory + ":directory is not exist");
             try {
                 // 循环创建路径
-                this.createParentDirectories(sftp, directory);
+                directory = this.createParentDirectories(sftp, directory);
                 // 切换路径
                 sftp.cd(directory);
             } catch (SftpException e1) {
@@ -339,13 +339,19 @@ public class SFTPUtil {
      * @param sftpChannel
      * @param directory
      */
-    private static void createParentDirectories(ChannelSftp sftpChannel, String directory) {
-        String[] directories = directory.split("/");
+    private static String createParentDirectories(ChannelSftp sftpChannel, String directory) {
+        String[] directories  = {};
+        String separatorChar = "/";
+        if(directory.contains("/")){
+            directories = directory.split("/");
+        }else if(directory.contains("\\")){
+            directories = directory.split("\\\\");
+        }
         String parentDirectory = "";
 
         for (String dir : directories) {
             if (!dir.isEmpty()) {
-                parentDirectory += "/" + dir;
+                parentDirectory += separatorChar + dir;
                 try {
                     sftpChannel.mkdir(parentDirectory);
                 } catch (Exception e) {
@@ -354,6 +360,7 @@ public class SFTPUtil {
             }
         }
         log.info("创建路径:" + parentDirectory);
+        return parentDirectory;
     }
 
 }

+ 7 - 0
in-cloud/src/main/resources/vms/DR_DQ.vm

@@ -0,0 +1,7 @@
+<! Entity=modeloutput time='${date}'!>
+<modeloutput::${stationCode}J001>
+farmId  scDate	scTime	preDate	preTime	t	rh	pressure	swr	lwr	senf	latf	momf	mslp	clc	prt	prl	prc	ws10	ws30	ws50	ws70	ws80	ws90	ws100	ws170	wd10	wd30	wd50	wd70	wd80	wd90	wd100	wd170
+#foreach( $nwp in $vList )
+${nwp.farmId} ${nwp.scDate} ${nwp.scTime} ${nwp.preDate} ${nwp.preTime} ${nwp.t} ${nwp.rh} ${nwp.pressure} ${nwp.swr} ${nwp.lwr} ${nwp.senf} ${nwp.latf} ${nwp.momf} ${nwp.mslp} ${nwp.clc} ${nwp.prt} ${nwp.prl} ${nwp.prc} ${nwp.ws10} ${nwp.ws30} ${nwp.ws50} ${nwp.ws70} ${nwp.ws80} ${nwp.ws90} ${nwp.ws100} ${nwp.ws170} ${nwp.wd10} ${nwp.wd30} ${nwp.wd50} ${nwp.wd70} ${nwp.wd80} ${nwp.wd90} ${nwp.wd100} ${nwp.wd170}
+#end
+</modeloutput::${stationCode}J001>

+ 7 - 0
in-cloud/src/main/resources/vms/DR_NWP.vm

@@ -0,0 +1,7 @@
+<! Entity=modeloutput time='${date}'!>
+<气象预测::${stationName} date='${date}'>
+farmId	scDate	scTime	preDate	preTime	t	rh	pressure	swr	lwr	senf	ws10	ws30	ws50	ws70	ws80	ws90	ws100	ws170	wd10	wd30	wd50	wd70	wd80	wd90	wd100	wd170
+#foreach( $nwp in $vList )
+${nwp.farmId} ${nwp.scDate} ${nwp.scTime} ${nwp.preDate} ${nwp.preTime} ${nwp.t} ${nwp.rh} ${nwp.pressure} ${nwp.swr} ${nwp.lwr} ${nwp.senf} ${nwp.ws10} ${nwp.ws30} ${nwp.ws50} ${nwp.ws70} ${nwp.ws80} ${nwp.ws90} ${nwp.ws100} ${nwp.ws170} ${nwp.wd10} ${nwp.wd30} ${nwp.wd50} ${nwp.wd70} ${nwp.wd80} ${nwp.wd90} ${nwp.wd100} ${nwp.wd170}
+#end
+</气象预测::${stationName}>