文件上传下载功能

This commit is contained in:
xy
2024-09-11 11:37:58 +08:00
parent 9dab90ab88
commit 72e81b1b6d
45 changed files with 1611 additions and 400 deletions

View File

@@ -0,0 +1,27 @@
package com.njcn.access.api;
import com.njcn.access.api.fallback.AskDeviceDataClientFallbackFactory;
import com.njcn.common.pojo.constant.ServerInfo;
import com.njcn.common.pojo.response.HttpResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author xy
*/
@FeignClient(value = ServerInfo.ACCESS_BOOT, path = "/askDeviceData", fallbackFactory = AskDeviceDataClientFallbackFactory.class,contextId = "askDeviceData")
public interface AskDeviceDataFeignClient {
@PostMapping("/askDeviceRootPath")
HttpResult<String> askDeviceRootPath(@RequestParam("nDid") String nDid);
@PostMapping("/askDeviceFileOrDir")
HttpResult<String> askDeviceFileOrDir(@RequestParam("nDid") String nDid, @RequestParam("name") String name);
@PostMapping("/downloadFile")
HttpResult<Boolean> downloadFile(@RequestParam("nDid") String nDid, @RequestParam("name") String name, @RequestParam("size") Integer size, @RequestParam("fileCheck") String fileCheck);
@PostMapping("/rebootDevice")
HttpResult<String> rebootDevice(@RequestParam("nDid") String nDid);
}

View File

@@ -0,0 +1,20 @@
package com.njcn.access.api;
import com.njcn.access.api.fallback.CsSoftInfoClientFallbackFactory;
import com.njcn.access.pojo.po.CsSoftInfoPO;
import com.njcn.common.pojo.constant.ServerInfo;
import com.njcn.common.pojo.response.HttpResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author xy
*/
@FeignClient(value = ServerInfo.ACCESS_BOOT, path = "/csSoftInfo", fallbackFactory = CsSoftInfoClientFallbackFactory.class,contextId = "csSoftInfo")
public interface CsSoftInfoFeignClient {
@PostMapping("/findSoftInfo")
HttpResult<CsSoftInfoPO> findSoftInfo(@RequestParam("id") String id);
}

View File

@@ -0,0 +1,60 @@
package com.njcn.access.api.fallback;
import com.njcn.access.api.AskDeviceDataFeignClient;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.redis.utils.RedisUtil;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author xy
*/
@Slf4j
@Component
public class AskDeviceDataClientFallbackFactory implements FallbackFactory<AskDeviceDataFeignClient> {
@Resource
private RedisUtil redisUtil;
@Override
public AskDeviceDataFeignClient create(Throwable cause) {
//判断抛出异常是否为解码器抛出的业务异常
Enum<?> exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK;
if (cause.getCause() instanceof BusinessException) {
BusinessException businessException = (BusinessException) cause.getCause();
}
Enum<?> finalExceptionEnum = exceptionEnum;
return new AskDeviceDataFeignClient() {
@Override
public HttpResult<String> askDeviceRootPath(String nDid) {
log.error("{}异常,降级处理,异常为:{}","平台询问装置报文",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
@Override
public HttpResult<String> askDeviceFileOrDir(String nDid, String name) {
log.error("{}异常,降级处理,异常为:{}","设备文件/目录信息询问",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
@Override
public HttpResult<Boolean> downloadFile(String nDid, String name, Integer size, String fileCheck) {
log.error("{}异常,降级处理,异常为:{}","文件下载",cause.toString());
redisUtil.delete("fileDowning");
redisUtil.delete("fileCheck"+name);
throw new BusinessException(finalExceptionEnum);
}
@Override
public HttpResult<String> rebootDevice(String nDid) {
log.error("{}异常,降级处理,异常为:{}","设备重启",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
};
}
}

View File

@@ -0,0 +1,34 @@
package com.njcn.access.api.fallback;
import com.njcn.access.api.CsSoftInfoFeignClient;
import com.njcn.access.pojo.po.CsSoftInfoPO;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author xy
*/
@Slf4j
@Component
public class CsSoftInfoClientFallbackFactory implements FallbackFactory<CsSoftInfoFeignClient> {
@Override
public CsSoftInfoFeignClient create(Throwable cause) {
//判断抛出异常是否为解码器抛出的业务异常
Enum<?> exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK;
if (cause.getCause() instanceof BusinessException) {
BusinessException businessException = (BusinessException) cause.getCause();
}
Enum<?> finalExceptionEnum = exceptionEnum;
return new CsSoftInfoFeignClient() {
@Override
public HttpResult<CsSoftInfoPO> findSoftInfo(String id) {
log.error("{}异常,降级处理,异常为:{}","获取装置软件信息",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
};
}
}

View File

@@ -14,10 +14,10 @@ public enum AccessResponseEnum {
* A0301 ~ A0399 用于用户模块的枚举
* <p>
*/
NDID_NO_FIND("A0301", "设备未录入!"),
NDID_SAME_STEP("A0301", "设备已注册!"),
NDID_NO_FIND("A0301", "装置未录入!"),
NDID_SAME_STEP("A0301", "装置已注册!"),
MISSING_CLIENT("A0302","设备客户端不在线!"),
MISSING_CLIENT("A0302","装置端不在线!"),
MODEL_REPEAT("A0302", "模板存在,请勿重复录入!"),
MODEL_NO_FIND("A0302", "模板不存在,请先录入模板数据!"),
MODEL_ERROR("A0302", "模板未找到,生成监测点失败!"),
@@ -30,7 +30,7 @@ public enum AccessResponseEnum {
DEV_MODEL_NOT_FIND("A0303","装置型号未找到!"),
DEV_IS_NOT_ZL("A0303","注册装置不是直连装置!"),
DEV_IS_NOT_WG("A0303","注册装置不是网关!"),
DEV_IS_NOT_PORTABLE("A0303","注册装置不是便携式设备!"),
DEV_IS_NOT_PORTABLE("A0303","注册装置不是便携式装置!"),
REGISTER_RESPONSE_ERROR("A0304","装置注册,装置侧应答失败!"),
ACCESS_RESPONSE_ERROR("A0304","装置注册,装置侧应答失败!"),
@@ -62,7 +62,7 @@ public enum AccessResponseEnum {
RELOAD_UPLOAD_ERROR("A0308","平台重新上送文件异常"),
CLDID_IS_NULL("A0309","逻辑子设备标识为空"),
MODULE_NUMBER_IS_NULL("A0309","设备子模块个数为空"),
MODULE_NUMBER_IS_NULL("A0309","装置子模块个数为空"),
LDEVINFO_IS_NULL("A0309","逻辑设备信息为空"),
SOFTINFO_IS_NULL("A0309","软件信息为空"),
@@ -71,6 +71,8 @@ public enum AccessResponseEnum {
PROCESS_SAME_ERROR("A0311","当前调试已完成,请勿重复调试"),
PROCESS_MISSING_ERROR("A0311","调试流程缺失,请核查功能调试、出厂调试"),
PROCESS_ERROR("A0311","调试流程异常,请先进行功能调试、出厂调试!"),
FILE_CHECK_ERROR("A0312","文件校验码不一致!"),
;
private final String code;

View File

@@ -44,6 +44,7 @@ public enum TypeEnum {
TYPE_28("4662","设备根目录查询应答"),
TYPE_29("9217","设备心跳请求"),
TYPE_30("4865","设备数据主动上送"),
TYPE_31("8503","设备控制命令"),
/**
* 数据类型
@@ -63,6 +64,7 @@ public enum TypeEnum {
DATA_13("13","内部定值InSet"),
DATA_14("14","控制Ctrl"),
DATA_16("16","波形文件"),
DATA_48("48","工程信息"),
/**
* 数据模型列表

View File

@@ -84,4 +84,83 @@ public class RspDataDto {
private Double capacityA;
}
/**
* 工程信息
*/
@Data
public static class ProjectInfo {
@SerializedName("PrjName")
@ApiModelProperty("项目名称")
private String prjName;
@SerializedName("PrjTimeStart")
@ApiModelProperty("项目起始时间")
private Long prjTimeStart;
@SerializedName("PrjTimeEnd")
@ApiModelProperty("项目结束时间")
private Long prjTimeEnd;
@SerializedName("PrjDataPath")
@ApiModelProperty("文件路径")
private String prjDataPath;
@SerializedName("DevType")
@ApiModelProperty("装置型号")
private String devType;
@SerializedName("DevMac")
@ApiModelProperty("装置mac")
private String devMac;
@SerializedName("AppVersion")
@ApiModelProperty("设备应用程序版本信息")
private String appVersion;
@SerializedName("Cldid")
@ApiModelProperty("逻辑子设备ID0-逻辑设备本身)")
private Integer clDid;
@SerializedName("StatCycle")
@ApiModelProperty("分钟数据统计时间间隔1~10分钟")
private Integer statCycle;
@SerializedName("VolGrade")
@ApiModelProperty("电压等级kV")
private Double volGrade;
@SerializedName("VolConType")
@ApiModelProperty("电压接线方式 0-星型, 1-角型, 2-V型")
private Integer volConType;
@SerializedName("CurConSel")
@ApiModelProperty("电流接线方式 0-正常, 1-合成IB, 2-合成IC")
private Integer curConSel;
@SerializedName("PtRatio")
@ApiModelProperty("PT变比")
private Integer ptRatio;
@SerializedName("CtRatio")
@ApiModelProperty("CT变比")
private Integer ctRatio;
@SerializedName("CapacitySscb")
@ApiModelProperty("基准短路容量MVA")
private Double capacitySscb;
@SerializedName("CapacitySscmin")
@ApiModelProperty("最小短路容量MVA")
private Double capacitySscmin;
@SerializedName("CapacitySt")
@ApiModelProperty("供电设备容量MVA")
private Double capacitySt;
@SerializedName("CapacitySi")
@ApiModelProperty("用户协议容量MVA")
private Double capacitySi;
}
}

View File

@@ -72,6 +72,78 @@ public class AutoDataDto {
@SerializedName("Data")
private String data;
@SerializedName("PrjName")
@ApiModelProperty("工程名称")
private String prjName;
@SerializedName("PrjTimeStart")
@ApiModelProperty("装置启动时间")
private Long prjTimeStart;
@SerializedName("PrjTimeEnd")
@ApiModelProperty("装置结束时间")
private Long prjTimeEnd;
@SerializedName("PrjDataPath")
@ApiModelProperty("装置数据路径")
private String prjDataPath;
@SerializedName("DevType")
@ApiModelProperty("装置型号")
private String devType;
@SerializedName("DevMac")
@ApiModelProperty("装置mac地址")
private String devMac;
@SerializedName("AppVersion")
@ApiModelProperty("装置程序版本")
private String appVersion;
@SerializedName("Cldid")
@ApiModelProperty("逻辑子设备id")
private Integer clDid;
@SerializedName("StatCycle")
@ApiModelProperty("统计间隔")
private Integer statCycle;
@SerializedName("VolGrade")
@ApiModelProperty("电压等级")
private Float volGrade;
@SerializedName("VolConType")
@ApiModelProperty("电压接线方式0-星型, 1-角型, 2-V型")
private Integer volConType;
@SerializedName("CurConSel")
@ApiModelProperty("电流接线方式0-正常, 1-合成IB, 2-合成IC")
private Integer curConSel;
@SerializedName("PtRatio")
@ApiModelProperty("PT变比")
private Integer ptRatio;
@SerializedName("CtRatio")
@ApiModelProperty("ct变比")
private Integer ctRatio;
@SerializedName("CapacitySscb")
@ApiModelProperty("基准短路容量")
private Float capacitySscb;
@SerializedName("CapacitySscmin")
@ApiModelProperty("最小短路容量")
private Float capacitySscmin;
@SerializedName("CapacitySt")
@ApiModelProperty("供电设备容量")
private Float capacitySt;
@SerializedName("CapacitySi")
@ApiModelProperty("用户协议容量")
private Float capacitySi;
}
}

View File

@@ -0,0 +1,22 @@
package com.njcn.access.pojo.dto;
import com.alibaba.nacos.shaded.com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.io.Serializable;
/**
* @author xy
*/
@Data
public class ControlDto implements Serializable {
@SerializedName("Cldid")
private Integer clDid;
@SerializedName("CmdType")
private String cmdType;
@SerializedName("CmdParm")
private String cmdParm;
}

View File

@@ -0,0 +1,52 @@
package com.njcn.access.pojo.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author xy
* 装置缓存信息
*/
@Data
public class DeviceRedisInfoDto {
@ApiModelProperty("装置id")
private String deviceId;
@ApiModelProperty("装置nDid")
private String nDid;
@ApiModelProperty("装置类型")
private String deviceType;
@ApiModelProperty("装置模板id")
private String modelId;
@ApiModelProperty("模板名称")
private String modelName;
@ApiModelProperty("模板版本")
private String modelVersion;
@ApiModelProperty("模板类型 0:治理模板 1:电能质量模板")
private Integer modelType;
@ApiModelProperty("监测点信息")
private List<LineRedisInfo> lineList;
@Data
public static class LineRedisInfo {
@ApiModelProperty("监测点id")
private String lineId;
@ApiModelProperty("监测点位置")
private String location;
@ApiModelProperty("逻辑设备编码")
private Integer clDid;
}
}

View File

@@ -0,0 +1,63 @@
package com.njcn.access.pojo.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* @author xy
* 模板缓存信息
*/
@Data
public class ModelRedisInfoDto {
@ApiModelProperty("模板id")
private String modelId;
@ApiModelProperty("模板名称")
private String modelName;
@ApiModelProperty("模板时间")
private LocalDate versionDate;
@ApiModelProperty("模板版本")
private String version;
@ApiModelProperty("数据集集合")
private List<DataSet> dataSetList;
@Data
public static class DataSet {
@ApiModelProperty("数据集id")
private String dataSetId;
@ApiModelProperty("数据集名称")
private String dataSetName;
@ApiModelProperty("数据指标集合")
private List<DataArray> dataArrayList;
}
@Data
public static class DataArray {
@ApiModelProperty("数据指标id")
private String dataArrayId;
@ApiModelProperty("数据指标名称")
private String dataArrayName;
@ApiModelProperty("数据指标别名")
private String anotherName;
@ApiModelProperty("数据指标统计方式")
private String statMethod;
@ApiModelProperty("数据指标相别")
private String phase;
}
}

View File

@@ -34,4 +34,8 @@ public class UploadFileDto {
@ApiModelProperty("文件校验码")
private String fileCheck;
@SerializedName("StepFileCheck")
@ApiModelProperty("当前帧文件校验码")
private String stepFileCheck;
}

View File

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 类的介绍:
@@ -42,7 +43,10 @@ public class FileDto implements Serializable {
private String type;
@SerializedName("FileInfo")
private FileDto.FileInfo fileInfo;
private FileInfo fileInfo;
@SerializedName("DirInfo")
private List<DirInfo> dirInfo;
@SerializedName("Data")
private String data;
@@ -86,4 +90,22 @@ public class FileDto implements Serializable {
private String fileChkType;
}
@Data
public static class DirInfo{
@SerializedName("Name")
private String name;
@SerializedName("Type")
private String type;
@SerializedName("Size")
@ApiModelProperty("文件大小单位KB")
private Integer size;
@SerializedName("Time")
@ApiModelProperty("时间")
private Long time;
}
}

View File

@@ -1,10 +1,8 @@
package com.njcn.access.pojo.po;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.db.bo.BaseEntity;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
@@ -47,7 +45,7 @@ public class CsSoftInfoPO {
/**
* 应用程序发布日期
*/
private Date appDate;
private LocalDateTime appDate;
/**
* 应用程序校验码

View File

@@ -0,0 +1,55 @@
package com.njcn.access.utils;
import org.springframework.stereotype.Component;
/**
* @author xy
*/
@Component
public class CRC32Utils {
// CRC-32/MPEG-2 多项式, x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
private static final int POLYNOMIAL = 0x04C11DB7;
public static int calculateCRC32(byte[] buf, int len, int seed) {
if (buf == null || len <= 0) {
return seed;
}
int crc = seed;
int count = 0;
// 对长度进行填充以适应32位整数
int rem = len % Integer.BYTES;
if (rem > 0) {
int n = Integer.BYTES - rem;
byte[] newBuf = new byte[len + n];
System.arraycopy(buf, 0, newBuf, 0, len);
// 填充字节用0xFF
for (int i = len; i < len + n; i++) {
newBuf[i] = (byte) 0xFF;
}
buf = newBuf;
len += n;
}
int uiCount = len / Integer.BYTES;
for (int k = 0; k < uiCount; k++) {
int uiTemp = 0;
for (int i = 0; i < Integer.BYTES; i++) {
uiTemp |= (buf[k * Integer.BYTES + i] & 0xFF) << (8 * (3 - i));
}
for (int j = 0; j < 32; j++) {
// 检查最高位是否为1
if ((crc ^ uiTemp) < 0) {
crc = 0x04C11DB7 ^ (crc << 1);
count ++;
} else {
crc <<= 1;
}
uiTemp <<= 1;
}
}
return crc;
}
}

View File

@@ -0,0 +1,45 @@
package com.njcn.access.utils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author xy
*/
@Component
public class ChannelObjectUtil {
/**
* 将list转成对应实体
* @param object
* @param clazz
* @return
* @param <T>
*/
public <T> List<T> objectToList(Object object, Class<T> clazz) {
List<T> resultList = new ArrayList<>();
if (object instanceof List<?>) {
for (Object o : (List<?>) object) {
resultList.add(clazz.cast(o));
}
}
return resultList;
}
/**
* 将object转成对应实体
* @param object
* @param clazz
* @return
* @param <T>
*/
public <T> T objectToSingleObject(Object object, Class<T> clazz) {
if (clazz.isInstance(object)) {
return clazz.cast(object);
}
// 或者抛出异常,根据您的需求
return null;
}
}

View File

@@ -0,0 +1,94 @@
package com.njcn.access.utils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* 类的介绍:
*
* @author xuyang
* @version 1.0.0
* @createTime 2023/4/10 16:03
*/
public class JsonUtil {
/**
* @param jsonString 要保存的JSON串
* @param filePath 保存到的文件路径
* @param fileName 文件名称
* @return
*/
//保存json 文件
public static boolean createJsonFile(String jsonString, String filePath, String fileName) {
// 标记文件生成是否成功
boolean flag = true;
// 拼接文件完整路径
String fullPath = filePath + File.separator + fileName + ".json";
// 生成json格式文件
try {
// 保证创建一个新文件
File file = new File(fullPath);
// 如果父目录不存在,创建父目录
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
// 如果已存在,删除旧文件
if (file.exists()) {
file.delete();
}
file.createNewFile();
// 格式化json字符串
//jsonString = JsonFormatTool.formatJson2(jsonString);
// 将格式化后的字符串写入文件
Writer write = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
write.write(jsonString);
write.flush();
write.close();
} catch (Exception e) {
flag = false;
e.printStackTrace();
}
// 返回是否成功的标记
return flag;
}
/**
* 生成随机文件名:当前年月日时分秒+五位随机数
* @return
*/
public static String getRandomFileName() {
SimpleDateFormat simpleDateFormat;
simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
Date date = new Date();
String str = simpleDateFormat.format(date);
Random random = new Random();
// 获取5位随机数
int ranNum = (int) (random.nextDouble() * (99999 - 10000 + 1)) + 10000;
// 当前时间
return ranNum + str;
}
public static String convertStreamToString(InputStream inputStream){
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,53 @@
package com.njcn.access.utils;
import com.alibaba.nacos.shaded.com.google.common.reflect.TypeToken;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.njcn.access.config.MqttInfo;
import com.njcn.access.pojo.dto.mqtt.MqttClientDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import java.io.IOException;
import java.util.Objects;
/**
* 类的介绍:
*
* @author xuyang
* @version 1.0.0
* @createTime 2023/7/14 14:44
*/
@Data
@Order(100)
@Configuration
@AllArgsConstructor
public class MqttUtil {
private final MqttInfo mqttInfo;
public boolean judgeClientOnline(String id) {
boolean result = false;
try {
Gson gson = new Gson();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(mqttInfo.getUrl() + "/api/v5/clients/" + id)
.header("Content-Type", "application/json")
.header("Authorization", Credentials.basic(mqttInfo.getUserName(), mqttInfo.getPassword()))
.build();
Response response = client.newCall(request).execute();
response.body();
MqttClientDto mqttClientDto = gson.fromJson(Objects.requireNonNull(response.body()).string(), new TypeToken<MqttClientDto>(){}.getType());
result = mqttClientDto.isConnected();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}