Forráskód Böngészése

北京中央研究院传输文件

zhangchenglong 2 éve
szülő
commit
f8575ac838

+ 12 - 8
in-cloud/pom.xml

@@ -16,7 +16,6 @@
         <maven.compiler.target>8</maven.compiler.target>
     </properties>
 
-
     <dependencies>
 
         <dependency>
@@ -77,7 +76,6 @@
             <version>${mybatis.plus.version}</version>
         </dependency>
 
-
         <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
         <dependency>
             <groupId>cn.dev33</groupId>
@@ -89,7 +87,6 @@
             <artifactId>sa-token-dao-redis</artifactId>
         </dependency>
 
-
         <!-- 配置使用 redis 启动器 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -108,7 +105,11 @@
             <version>0.9.5.4</version>
         </dependency>
 
-
+        <dependency>
+            <groupId>net.jodah</groupId>
+            <artifactId>expiringmap</artifactId>
+            <version>0.5.8</version>
+        </dependency>
 
         <dependency>
             <groupId>com.jiayue</groupId>
@@ -117,9 +118,7 @@
         </dependency>
 
         <!--<dependency>
-
             <groupId>org.springframework.boot</groupId>
-
             <artifactId>spring-boot-starter-velocity</artifactId>
             <version>1.4.1.RELEASE</version>
         </dependency>-->
@@ -134,6 +133,13 @@
             <version>0.9.0</version>
             <scope>compile</scope>
         </dependency>
+
+        <dependency>
+            <groupId>com.jcraft</groupId>
+            <artifactId>jsch</artifactId>
+            <version>0.1.53</version>
+        </dependency>
+
     </dependencies>
 
     <build>
@@ -153,6 +159,4 @@
         </plugins>
     </build>
 
-
-
 </project>

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

@@ -14,4 +14,9 @@ public interface CompanyConstant {
      */
     String COMPANY_QNHL = "QNHL";
 
+    /**
+     * 北京中烟研究院
+     */
+    String COMPANY_BJZYYJY = "BJZYYJY";
+
 }

+ 3 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/constants/enums/StatusEnum.java

@@ -11,8 +11,11 @@ public enum StatusEnum {
     SUCCESS("success","success","成功"),
     RESPONSE_FAIL("response_fail","response_fail","请求失败,响应错误"),
     DOWNLOAD_FILE_FAIL("response_fail","response_fail","下载文件失败"),
+    CREATE_FILE_FAIL("create_file_fail","create_file_fail","生成文件失败"),
+    PUSH_URL_ERROR("push_url_error","push_url_error","推送sftp地址/端口错误"),
     DOWNLOAD_FILE_ERROR("response_fail","response_fail","下载文件异常"),
     FILE_NULL("file_null","file_null","文件为空"),
+    STATION_CODE_NULL("station_code_null","station_code_null","场站编码为空"),
 
 
     CONNECT_RESPONSE_FORMAT_ERROR("response_format_error","response_format_error","响应格式异常"),

+ 58 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/job/data/pull/PullRealPowerDataJob.java

@@ -0,0 +1,58 @@
+package com.jiayue.insu.incloud.job.data.pull;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+import com.jiayue.insu.incloud.constants.CommonStant;
+import com.jiayue.insu.incloud.constants.enums.StatusEnum;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.pulldata.PullInitData;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.service.StationService;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDateTime;
+
+
+/**
+ * 北京中央研究院 拉取实际功率数据
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+public class PullRealPowerDataJob implements Job {
+
+    @Autowired
+    private PullInitData pullInitData;
+    @Autowired
+    private StationService stationService;
+    @Autowired
+    private RecordService recordService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        String code = jobExecutionContext.getTrigger().getJobKey().getName();
+        String[] split = code.split("-");
+        if (split != null && split.length > 0) {
+            String stationCode = split[0];
+            Station one = stationService.findByStationCode(stationCode);
+            if (one != null) {
+                //查询是否有今天成功记录 (为提高稳定性,该定时任务采取在规定时间段内 重复循环执行的定时策略,故:需要查询是否存在成功记录)
+                Record successRecord = recordService.findTimeAndTypeAndStateAndStation(
+                        LocalDateTimeUtil.beginOfDay(LocalDateTime.now()),
+                        CommonStant.RECORD_TYPE_PULL_INIT,
+                        StatusEnum.SUCCESS.getCode(), stationCode);
+
+                //没有成功记录进行业务
+                if (successRecord == null) {
+                    pullInitData.pullDQAndNWPData(one);
+                }
+
+            }
+        }
+
+    }
+}

+ 55 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/job/data/push/BJZYYJYPushInitDqDataJob.java

@@ -0,0 +1,55 @@
+package com.jiayue.insu.incloud.job.data.push;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+import com.jiayue.insu.incloud.constants.CommonStant;
+import com.jiayue.insu.incloud.constants.enums.QNHLEnum;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.pushdata.PushDataForBJZYYJY;
+import com.jiayue.insu.incloud.pushdata.PushDataForQNHL;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.service.StationService;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDateTime;
+
+/**
+ * 北京中央研究院推送原始短期数据定时任务
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+public class BJZYYJYPushInitDqDataJob implements Job {
+
+    @Autowired
+    private PushDataForBJZYYJY pushDataForBJZYYJY;
+    @Autowired
+    private StationService stationService;
+    @Autowired
+    private RecordService recordService;
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        String code = jobExecutionContext.getTrigger().getJobKey().getName();
+        String[] split = code.split("-");
+        if(split!=null && split.length>0){
+            String stationCode = split[0];
+            Station one = stationService.findByStationCode(stationCode);
+            if (one != null) {
+                //查询是否有今天成功记录 (为提高稳定性,该定时任务采取在规定时间段内 重复循环执行的定时策略,故:需要查询是否存在成功记录)
+                Record successRecord = recordService.findTimeAndTypeAndStateAndStation(
+                        LocalDateTimeUtil.beginOfDay(LocalDateTime.now()),
+                        CommonStant.RECORD_TYPE_PUSH_INIT,
+                        QNHLEnum.REQUEST_SUCCESS.getSign(), stationCode);
+                //没有成功记录进行业务
+                if(successRecord == null) {
+                    pushDataForBJZYYJY.pushDQData(one);
+                }
+            }
+        }
+
+    }
+}

+ 54 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/job/data/push/BJZYYJYPushInitRealDataJob.java

@@ -0,0 +1,54 @@
+package com.jiayue.insu.incloud.job.data.push;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+import com.jiayue.insu.incloud.constants.CommonStant;
+import com.jiayue.insu.incloud.constants.enums.QNHLEnum;
+import com.jiayue.insu.incloud.entity.Record;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.pushdata.PushDataForBJZYYJY;
+import com.jiayue.insu.incloud.service.RecordService;
+import com.jiayue.insu.incloud.service.StationService;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDateTime;
+
+/**
+ * 北京中央研究院推送实际功率数据定时任务
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+public class BJZYYJYPushInitRealDataJob implements Job {
+
+    @Autowired
+    private PushDataForBJZYYJY pushDataForBJZYYJY;
+    @Autowired
+    private StationService stationService;
+    @Autowired
+    private RecordService recordService;
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        String code = jobExecutionContext.getTrigger().getJobKey().getName();
+        String[] split = code.split("-");
+        if(split!=null && split.length>0){
+            String stationCode = split[0];
+            Station one = stationService.findByStationCode(stationCode);
+            if (one != null) {
+                //查询是否有今天成功记录 (为提高稳定性,该定时任务采取在规定时间段内 重复循环执行的定时策略,故:需要查询是否存在成功记录)
+                Record successRecord = recordService.findTimeAndTypeAndStateAndStation(
+                        LocalDateTimeUtil.beginOfDay(LocalDateTime.now()),
+                        CommonStant.RECORD_TYPE_PUSH_REAL,
+                        QNHLEnum.REQUEST_SUCCESS.getSign(), stationCode);
+                //没有成功记录进行业务
+                if(successRecord == null) {
+                    pushDataForBJZYYJY.pushRealPowerData(one);
+                }
+            }
+        }
+
+    }
+}

+ 6 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/pulldata/IPullInitForecastData.java

@@ -27,4 +27,10 @@ public interface IPullInitForecastData {
      * @return 是否成功
      */
     Boolean pullNWPData(Station station);
+
+    /**
+     * 拉取实际功率数据
+     * @return 是否成功
+     */
+    Boolean pullRPData(Station station);
 }

+ 5 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/pulldata/PullInitData.java

@@ -179,6 +179,11 @@ public class PullInitData implements IPullInitForecastData{
         return null;
     }
 
+    @Override
+    public Boolean pullRPData(Station station) {
+        return null;
+    }
+
 
     public List<ForecastData> fileAnalysis(File dqFile, File nwpFile, Station station, LocalDateTime localDateTime) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

+ 326 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/pushdata/PushDataForBJZYYJY.java

@@ -0,0 +1,326 @@
+package com.jiayue.insu.incloud.pushdata;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.file.FileReader;
+import cn.hutool.crypto.digest.HMac;
+import cn.hutool.crypto.digest.HmacAlgorithm;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import com.jcraft.jsch.SftpException;
+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.RecordService;
+import com.jiayue.insu.incloud.utils.FileUtils;
+import com.jiayue.insu.incloud.utils.HttpUtils;
+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.io.FileNotFoundException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 北京中央研究院推送数据
+ *
+ * @author yh
+ * @version 1.0
+ * @since 2022/5/22 11:29
+ */
+@Component
+@Slf4j
+public class PushDataForBJZYYJY implements IPushInitForecastData {
+    @Autowired
+    private RecordService recordService;
+    @Autowired
+    private IntegrationCompanyService integrationCompanyService;
+    @Autowired
+    private FileUtils fileUtils;
+    @Autowired
+    private HttpUtils httpUtils;
+    @Autowired
+    private SFTPUtil sftpUtil;
+    @Value("${localFilePath.initFilePath}")
+    String initFilePath;
+    @Value("${localFilePath.bjFilePath}")
+    String bjFilePath;
+
+    /**
+     * 推送原始预测数据
+     *
+     * @param station 场站信息
+     * @return 是否成功
+     */
+    @Override
+    public Boolean pushDQAndNWPData(Station station) {
+        return null;
+    }
+
+    /**
+     * 将下载好的原始短期文件通过sftp推送
+     *
+     * @param station
+     * @return
+     */
+    @Override
+    public Boolean pushDQData(Station station) {
+        // 获取场站编号
+        String stationCode = station.getStationCode();
+        Record record = new Record(CommonStant.RECORD_TYPE_PUSH_INIT_TO_SFTP, CompanyConstant.COMPANY_BJZYYJY, 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	帽子山光伏电站	2023-06-22 00:00:00	0.0
+            if (originalContent.contains("#")) {
+                // 刨除当天的数据
+                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);
+            }
+        }
+
+        // 文件存放路径 /jiayue/insu/file/bjInit/J00269/
+        String newFilePath = bjFilePath + stationCode + File.separatorChar;
+        String templateName = File.separatorChar + "vms" + File.separatorChar + "BJZYYJYDQ.vm";
+        String newFileName = "modeloutput-" + stationCode + "J001-" + todayStr + "_SUBSHORT.RB";
+        String fileType = "dq";
+        // 文件数据开始时间
+        String fileDateStr = DateUtil.format(DateUtil.beginOfDay(DateUtil.tomorrow()), "yyyyMMdd_HH:mm:ss");
+        this.pushFileToSftp(record, vList, newFilePath, newFileName, templateName, station, fileType, todayStr, fileDateStr);
+        return true;
+    }
+
+    @Override
+    public Boolean pushNWPData(Station station) {
+        return false;
+    }
+
+    /**
+     * 通过sftp推送实际功率
+     *
+     * @param station
+     * @return
+     */
+    public Boolean pushRealPowerData(Station station) {
+        Record record = new Record(CommonStant.RECORD_TYPE_PUSH_REAL_POWER_TO_SFTP, CompanyConstant.COMPANY_BJZYYJY, station.getStationCode(), null, LocalDateTime.now(), LocalDateTime.now(), null, null);
+        // 获取公司信息
+        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(CompanyConstant.COMPANY_BJZYYJY);
+        // 获取云上实际功率接口url
+        String url = integrationCompany.getPullUrl();
+        // 获取当天日期
+        LocalDateTime today = LocalDateTime.now();
+        LocalDateTime yesterday = today.plusDays(-1);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+        String yesterdayStr = yesterday.format(formatter);
+        String todayStr = today.format(formatter);
+        String stationCode = station.getStationCode();
+        // 获取Signature
+        String sign = getSignature("123456&", stationCode, yesterdayStr, todayStr);
+        // post请求参数
+        HashMap<String, String> paramMap = new HashMap<>();
+        paramMap.put("stationCode", station.getStationCode());
+        paramMap.put("startTime", yesterdayStr);
+        paramMap.put("endTime", todayStr);
+        paramMap.put("sign", sign);
+        // 发送post请求并获取结果
+        JSONObject responseJson = httpUtils.httpPost(url, paramMap);
+        JSONArray dataArr = new JSONArray();
+        if (responseJson != null && responseJson.getInt("code") == 0) {
+            dataArr = responseJson.getJSONArray("data");
+        }
+        List<Map<String, Object>> vList = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
+        long time;
+        String realValue;
+        // 循环将请求的数据解析
+        for (int i = 0; i < dataArr.size(); i++) {
+            Map<String, Object> map = new HashMap<>();
+            time = dataArr.getJSONObject(i).getLong("dataTimeStamp");
+            realValue = dataArr.getJSONObject(i).getStr("realPower");
+            map.put("forecastTime", sdf.format(time));
+            map.put("realPower", realValue);
+            vList.add(map);
+        }
+
+        // 文件存放路径 /jiayue/insu/file/bjInit/J00269/
+        String newFilePath = bjFilePath + stationCode + File.separatorChar;
+        DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+        String todayTimeStr = today.format(formatterTime);
+        String newFileName = "realpowerdata-" + stationCode + "J001-" + todayTimeStr + ".RB";
+        String templateName = File.separatorChar + "vms" + File.separatorChar + "BJZYYJYRP.vm";
+        // sftp具体路径
+        String sftpFilePath = "real";
+        // 文件数据开始时间
+        String fileDateStr = DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyyMMdd_HH:mm:ss");
+        this.pushFileToSftp(record, vList, newFilePath, newFileName, templateName, station, sftpFilePath, todayStr, fileDateStr);
+        return false;
+    }
+
+    /**
+     * @param record
+     * @param vList
+     * @param newFilePath
+     * @param newFileName
+     * @param templateName
+     * @param station
+     * @param fileType
+     * @param todayStr
+     * @return
+     */
+    public boolean pushFileToSftp(Record record, List<Map<String, Object>> vList, String newFilePath, String newFileName, String templateName, Station station, String fileType, 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 + todayStr + File.separatorChar + fileType;
+
+//        SFTPUtil sftp = new SFTPUtil(station.getUsername(), station.getPassword(), sftpUrl, sftpPort);
+        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());
+        // 多级目录创建并上传
+        try {
+            sftpUtil.uploadByFileAndPath(userName, passWord, sftpUrl, sftpPort, newFile, sftpFilePath, newFile.getName());
+        } catch (SftpException e) {
+            e.printStackTrace();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        // 保存日志
+        recordService.save(record);
+        return true;
+    }
+
+    /**
+     * @param keyStr
+     * @param paramsStr
+     * @return
+     */
+    public String getSignature(String keyStr, String... paramsStr) {
+        byte[] key = keyStr.getBytes();
+        HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);
+        //拼接签名元数据
+        String signOrg = Convert.toStr(paramsStr);
+        String macHexSign = mac.digestHex(signOrg);
+        return macHexSign;
+    }
+}

+ 93 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/utils/FileUtils.java

@@ -0,0 +1,93 @@
+package com.jiayue.insu.incloud.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+
+/**
+ * @description:
+ * @author: zhangchenglong
+ * @createDate: 2023/6/28
+ * @version: 1.0
+ */
+@Slf4j
+@Component
+public class FileUtils {
+
+    @Autowired
+    private VelocityEngine velocityEngine;
+
+    /**
+     * 功能描述: 创建文件
+     *
+     * @param:
+     * @return:
+     * @auther: bizy
+     * @date: 2018/7/18 15:47 下午
+     */
+    public void creatFile(File file, StringWriter writer) {
+        FileOutputStream os = null;
+        try {
+            boolean res = file.createNewFile();
+            if (res) {
+                os = new FileOutputStream(file);
+                // 采用UTF-8字符集
+                os.write(writer.toString().getBytes("UTF-8"));
+                os.flush();
+            } else {
+                log.warn(file.getName() + ":文件生成失败");
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            log.warn(file.getName() + ":文件创建失败");
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    log.error("文件生成关闭流失败", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * 根据文件模板,创建文件
+     *
+     * @param filePath        文件路径
+     * @param fileName        文件名
+     * @param templateName    模板名称
+     * @param velocityContext 模板数据内容
+     * @return
+     */
+    public File createFileByVelocityTemplate(String filePath, String fileName, String templateName, VelocityContext velocityContext) {
+        // 获取模板
+        String vmsPath = SystermUtils.getResourceBasePath() + templateName;
+        File file = null;
+        // 创建模板
+        Template template = this.velocityEngine.getTemplate(vmsPath);
+        // 如果模板不为空
+        if (template != null) {
+            StringWriter writer;
+            writer = new StringWriter();
+            // 写入文件内容
+            template.merge(velocityContext, writer);
+            log.info(filePath);
+            // 创建文件
+            File fileUrl = new File(filePath);
+            // 判断目录是否存在,如果不存在则创建路径
+            if (!fileUrl.exists()) {
+                fileUrl.mkdirs();
+            }
+            file = new File(filePath + File.separatorChar + fileName);
+            // 创建文件
+            this.creatFile(file, writer);
+        }
+        return file;
+    }
+}

+ 51 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/utils/HttpUtils.java

@@ -0,0 +1,51 @@
+package com.jiayue.insu.incloud.utils;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @description:
+ * @author: zhangchenglong
+ * @createDate: 2023/6/28
+ * @version: 1.0
+ */
+@Slf4j
+@Component
+public class HttpUtils {
+
+    /**
+     * @param url
+     * @param param
+     * @return
+     */
+    public JSONObject httpPost(String url, HashMap<String, String> param) {
+        JSONObject result = new JSONObject();
+        String response = "";
+        String paramStr = "?";
+        if (param != null) {
+            for (Map.Entry<String, String> entry : param.entrySet()) {
+                paramStr = paramStr + entry.getKey() + "=" + entry.getValue() + "&";
+            }
+            paramStr = paramStr.substring(0, paramStr.length() - 1);
+        }
+        url = url + paramStr;
+        try {
+            HttpRequest httpRequest = HttpRequest.post(url)
+                    .header("Content-Type", "application/json");
+            httpRequest.setGlobalTimeout(20000);
+            response = httpRequest.execute().body();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        // 将返回结果转为json
+        result = JSONUtil.parseObj(response);
+        return result;
+    }
+
+}

+ 319 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/utils/SFTPUtil.java

@@ -0,0 +1,319 @@
+package com.jiayue.insu.incloud.utils;
+
+import com.jcraft.jsch.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * @description:
+ * @author: 张成龙
+ * @createDate: 2021/9/27
+ * @version: 1.0
+ */
+@Component
+@Slf4j
+public class SFTPUtil {
+
+    private ChannelSftp sftp;
+
+    private Session session;
+
+    // FTP 登录用户名
+    private String userName;
+    // FTP 登录密码
+    private String password;
+    // FTP 服务器地址IP地址
+    private String host;
+    // FTP 端口
+    private int port;
+
+    /**
+     * 构造基于密码认证的sftp对象
+     *
+     * @param userName
+     * @param password
+     * @param host
+     * @param port
+     */
+    public SFTPUtil(String userName, String password, String host, int port) {
+        this.userName = userName;
+        this.password = password;
+        this.host = host;
+        this.port = port;
+    }
+
+    public SFTPUtil() {
+    }
+
+    /**
+     * 连接sftp服务器
+     *
+     * @throws Exception
+     */
+    public void login() {
+        try {
+            JSch jsch = new JSch();
+            log.info("sftp connect by host:{} username:{}", host, userName);
+
+            session = jsch.getSession(userName, host, port);
+            log.info("Session is build");
+            if (password != null) {
+                session.setPassword(password);
+            }
+            Properties config = new Properties();
+            config.put("StrictHostKeyChecking", "no");
+
+            session.setConfig(config);
+            session.connect();
+            log.info("Session is connected");
+
+            Channel channel = session.openChannel("sftp");
+            channel.connect();
+            log.info("channel is connected");
+
+            sftp = (ChannelSftp) channel;
+            log.info(String.format("sftp server host:[%s] port:[%s] is connect successfull", host, port));
+        } catch (JSchException e) {
+            log.error("Cannot connect to specified sftp server : {}:{} \n Exception message is: {}", new Object[]{host, port, e.getMessage()});
+        }
+    }
+
+    /**
+     * 关闭连接 server
+     */
+    public void logout() {
+        if (sftp != null) {
+            if (sftp.isConnected()) {
+                sftp.disconnect();
+                log.info("sftp is closed already");
+            }
+        }
+        if (session != null) {
+            if (session.isConnected()) {
+                session.disconnect();
+                log.info("sshSession is closed already");
+            }
+        }
+    }
+
+    /**
+     * 递归根据路径创建文件夹
+     *
+     * @param dirs     根据 / 分隔后的数组文件夹名称
+     * @param tempPath 拼接路径
+     * @param length   文件夹的格式
+     * @param index    数组下标
+     * @return
+     */
+    public void mkdirDir(String[] dirs, String tempPath, int length, int index) {
+        // 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
+        index++;
+        if (index < length) {
+            // 目录不存在,则创建文件夹
+            tempPath += "/" + dirs[index];
+        }
+        try {
+            log.info("检测目录[" + tempPath + "]");
+            sftp.cd(tempPath);
+            if (index < length) {
+                mkdirDir(dirs, tempPath, length, index);
+            }
+        } catch (SftpException ex) {
+            log.warn("创建目录[" + tempPath + "]");
+            try {
+                sftp.mkdir(tempPath);
+                sftp.cd(tempPath);
+            } catch (SftpException e) {
+                e.printStackTrace();
+                log.error("创建目录[" + tempPath + "]失败,异常信息[" + e.getMessage() + "]");
+
+            }
+            log.info("进入目录[" + tempPath + "]");
+            mkdirDir(dirs, tempPath, length, index);
+        }
+    }
+
+    /**
+     * 将输入流的数据上传到sftp作为文件(多层目录)
+     *
+     * @param directory    上传到该目录(多层目录)
+     * @param sftpFileName sftp端文件名
+     * @param input        输入流
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void uploadMore(String directory, String sftpFileName, InputStream input) throws SftpException {
+        try {
+            sftp.cd(directory);
+        } catch (SftpException e) {
+            // 目录不存在,则创建文件夹
+            String[] dirs = directory.split("/");
+            String tempPath = "";
+            int index = 0;
+            mkdirDir(dirs, tempPath, dirs.length, index);
+        }
+        sftp.put(input, sftpFileName);// 上传文件
+    }
+
+    /**
+     * 将输入流的数据上传到sftp作为文件
+     *
+     * @param directory    上传到该目录(单层目录)
+     * @param sftpFileName sftp端文件名
+     * @param input        输入流
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void upload(String directory, String sftpFileName, InputStream input) throws SftpException {
+        try {
+            sftp.cd(directory);
+        } catch (SftpException e) {
+            log.warn("directory is not exist");
+            sftp.mkdir(directory);
+            sftp.cd(directory);
+        }
+        sftp.put(input, sftpFileName);
+        log.info("file:{} is upload successful", sftpFileName);
+    }
+
+    /**
+     * 上传单个文件
+     *
+     * @param directory  上传到sftp目录
+     * @param uploadFile 要上传的文件,包括路径
+     * @throws FileNotFoundException
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void upload(String directory, String uploadFile) throws FileNotFoundException, SftpException {
+        File file = new File(uploadFile);
+        upload(directory, file.getName(), new FileInputStream(file));
+    }
+
+    /**
+     * 将byte[]上传到sftp,作为文件。注意:从String生成byte[]是,要指定字符集。
+     *
+     * @param directory    上传到sftp目录
+     * @param sftpFileName 文件在sftp端的命名
+     * @param byteArr      要上传的字节数组
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void upload(String directory, String sftpFileName, byte[] byteArr) throws SftpException {
+        upload(directory, sftpFileName, new ByteArrayInputStream(byteArr));
+    }
+
+    /**
+     * 将字符串按照指定的字符编码上传到sftp
+     *
+     * @param directory    上传到sftp目录
+     * @param sftpFileName 文件在sftp端的命名
+     * @param dataStr      待上传的数据
+     * @param charsetName  sftp上的文件,按该字符编码保存
+     * @throws UnsupportedEncodingException
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void upload(String directory, String sftpFileName, String dataStr, String charsetName) throws UnsupportedEncodingException, SftpException {
+        upload(directory, sftpFileName, new ByteArrayInputStream(dataStr.getBytes(charsetName)));
+    }
+
+    /**
+     * 下载文件
+     *
+     * @param directory    下载目录
+     * @param downloadFile 下载的文件
+     * @param saveFile     存在本地的路径
+     * @throws SftpException
+     * @throws FileNotFoundException
+     * @throws Exception
+     */
+    public void download(String directory, String downloadFile, String saveFile) throws SftpException, FileNotFoundException {
+        if (directory != null && !"".equals(directory)) {
+            sftp.cd(directory);
+        }
+        File file = new File(saveFile);
+        sftp.get(downloadFile, new FileOutputStream(file));
+        log.info("file:{} is download successful", downloadFile);
+    }
+
+    /**
+     * 下载文件
+     *
+     * @param directory    下载目录
+     * @param downloadFile 下载的文件名
+     * @return 字节数组
+     * @throws SftpException
+     * @throws IOException
+     * @throws Exception
+     */
+    public byte[] download(String directory, String downloadFile) throws SftpException, IOException {
+        if (directory != null && !"".equals(directory)) {
+            sftp.cd(directory);
+        }
+        InputStream is = sftp.get(downloadFile);
+        byte[] fileData = IOUtils.toByteArray(is);
+        log.info("file:{} is download successful", downloadFile);
+        return fileData;
+    }
+
+    /**
+     * 删除文件
+     *
+     * @param directory  要删除文件所在目录
+     * @param deleteFile 要删除的文件
+     * @throws SftpException
+     * @throws Exception
+     */
+    public void delete(String directory, String deleteFile) throws SftpException {
+        sftp.cd(directory);
+        sftp.rm(deleteFile);
+    }
+
+    /**
+     * 列出目录下的文件
+     *
+     * @param directory 要列出的目录
+     * @return
+     * @throws SftpException
+     */
+    public Vector<?> listFiles(String directory) throws SftpException {
+        return sftp.ls(directory);
+    }
+
+//    public static void main(String[] args) throws SftpException, IOException {
+//        SFTPUtil sftp = new SFTPUtil("jyzx2023", "hH6*7E$h", "114.115.165.178", 22);
+//        sftp.login();
+//        File file = new File("..\\sftp测试.txt");
+//        System.out.println(System.getProperty("user.dir"));
+//        InputStream is = new FileInputStream(file);
+//        // 多级目录创建并上传
+//        sftp.upload("/subdata/20230620/real", "sftp测试.txt", is);
+//        sftp.logout();
+//    }
+
+    /**
+     *
+     * @param userName
+     * @param password
+     * @param host
+     * @param port
+     * @param file
+     * @throws SftpException
+     * @throws FileNotFoundException
+     */
+    public void uploadByFileAndPath(String userName ,String password ,String host ,int port ,File file,String sftpFilePath, String fileName) throws SftpException, FileNotFoundException {
+        SFTPUtil sftp = new SFTPUtil(userName, password, host, port);
+        sftp.login();
+        System.out.println(System.getProperty("user.dir"));
+        InputStream is = new FileInputStream(file);
+        // 多级目录创建并上传
+        sftp.upload(sftpFilePath, fileName, is);
+        sftp.logout();
+    }
+
+}

+ 8 - 0
in-cloud/src/main/resources/vms/BJZYYJYDQ.vm

@@ -0,0 +1,8 @@
+//${createTime}
+<! Entity=modeloutput time='${date}' !>
+<modeloutput::${stationCode}J001>
+@id	times	prepower	upper	lower
+#foreach( $dq in $vList )
+#${velocityCount}	${dq.forecastTime}	${dq.fpValue}
+#end
+</modeloutput::${stationCode}J001>

+ 8 - 0
in-cloud/src/main/resources/vms/BJZYYJYRP.vm

@@ -0,0 +1,8 @@
+//${createTime}
+<! Entity=realpowerdata time='${date}' !>
+<realpowerdata::${stationCode}J001>
+@id	times	realPower	reactivePower	fan_speed_avg	fan_direction_avg
+#foreach( $dq in $vList )
+#${velocityCount}	${dq.forecastTime}	${dq.realPower}	NULL	NULL	NULL
+#end
+</realpowerdata::${stationCode}J001>