diff --git a/db/upgrade1128.sql b/db/upgrade1128.sql new file mode 100644 index 0000000..07180b1 --- /dev/null +++ b/db/upgrade1128.sql @@ -0,0 +1,37 @@ +DROP TABLE IF EXISTS `admin`; +CREATE TABLE `admin` ( + `id` mediumint(9) NOT NULL AUTO_INCREMENT COMMENT '管理员id', + `name` varchar(45) NOT NULL COMMENT '管理员名称', + `password` varchar(45) NOT NULL COMMENT '管理员密码', + `menus` varchar(45) DEFAULT NULL COMMENT '菜单配置1:显示 0:隐藏', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; + +LOCK TABLES `admin` WRITE; +INSERT INTO `admin` VALUES (1,'admin','e10adc3949ba59abbe56e057f20f883e','1,1,1,1,1,1,1'); +INSERT INTO `admin` VALUES (2,'user','e10adc3949ba59abbe56e057f20f883e','1,1,1,1,0,0,0'); +UNLOCK TABLES; + +DROP TABLE IF EXISTS `ied_dl_record`; +CREATE TABLE `ied_dl_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `config_id` int(11) DEFAULT NULL, + `remote_path` varchar(200) DEFAULT NULL COMMENT '源路径', + `filename` varchar(45) DEFAULT NULL COMMENT '文件名', + `path` varchar(200) DEFAULT NULL COMMENT '本地路径', + `create_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `ied_dl_config`; +CREATE TABLE `ied_dl_config` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ied_id` int(11) DEFAULT NULL, + `dev_id` int(11) DEFAULT NULL COMMENT '装置ID', + `path` varchar(2000) DEFAULT NULL COMMENT '目录', + `contain` varchar(45) DEFAULT NULL COMMENT '包含文字', + `suffix` varchar(45) DEFAULT NULL COMMENT '后缀名', + `todel` int(11) DEFAULT NULL COMMENT '下载后删除', + `active` int(11) DEFAULT NULL COMMENT '0:停用; 1:启用;', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/src/main/java/com/beanit/iec61850bean/ServerAssociation.java b/src/main/java/com/beanit/iec61850bean/ServerAssociation.java index 1ddbb95..9c3d23b 100644 --- a/src/main/java/com/beanit/iec61850bean/ServerAssociation.java +++ b/src/main/java/com/beanit/iec61850bean/ServerAssociation.java @@ -21,48 +21,13 @@ import com.beanit.asn1bean.ber.types.BerNull; import com.beanit.asn1bean.ber.types.string.BerVisibleString; import com.beanit.iec61850bean.internal.BerBoolean; import com.beanit.iec61850bean.internal.NamedThreadFactory; -import com.beanit.iec61850bean.internal.mms.asn1.AccessResult; -import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedErrorPDU; -import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedRequestPDU; -import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedResponsePDU; -import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceRequest; -import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceResponse; -import com.beanit.iec61850bean.internal.mms.asn1.Data; -import com.beanit.iec61850bean.internal.mms.asn1.DataAccessError; -import com.beanit.iec61850bean.internal.mms.asn1.DefineNamedVariableListRequest; -import com.beanit.iec61850bean.internal.mms.asn1.DefineNamedVariableListResponse; -import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListRequest; -import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListResponse; -import com.beanit.iec61850bean.internal.mms.asn1.GetNameListRequest; -import com.beanit.iec61850bean.internal.mms.asn1.GetNameListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.*; import com.beanit.iec61850bean.internal.mms.asn1.GetNameListResponse.ListOfIdentifier; -import com.beanit.iec61850bean.internal.mms.asn1.GetNamedVariableListAttributesResponse; -import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesRequest; -import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesResponse; -import com.beanit.iec61850bean.internal.mms.asn1.Identifier; -import com.beanit.iec61850bean.internal.mms.asn1.InitiateRequestPDU; -import com.beanit.iec61850bean.internal.mms.asn1.InitiateResponsePDU; -import com.beanit.iec61850bean.internal.mms.asn1.Integer16; -import com.beanit.iec61850bean.internal.mms.asn1.Integer32; -import com.beanit.iec61850bean.internal.mms.asn1.Integer8; -import com.beanit.iec61850bean.internal.mms.asn1.MMSpdu; -import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific; -import com.beanit.iec61850bean.internal.mms.asn1.ParameterSupportOptions; -import com.beanit.iec61850bean.internal.mms.asn1.ReadRequest; -import com.beanit.iec61850bean.internal.mms.asn1.ReadResponse; import com.beanit.iec61850bean.internal.mms.asn1.ReadResponse.ListOfAccessResult; import com.beanit.iec61850bean.internal.mms.asn1.ServiceError.ErrorClass; -import com.beanit.iec61850bean.internal.mms.asn1.ServiceSupportOptions; -import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure; import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components; -import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification; -import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32; -import com.beanit.iec61850bean.internal.mms.asn1.VariableAccessSpecification; -import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; -import com.beanit.iec61850bean.internal.mms.asn1.WriteRequest; -import com.beanit.iec61850bean.internal.mms.asn1.WriteResponse; import com.beanit.josistack.AcseAssociation; import com.beanit.josistack.ByteBufferInputStream; import com.beanit.josistack.DecodingException; @@ -353,6 +318,12 @@ final class ServerAssociation { handleDeleteDataSetRequest(confirmedServiceRequest.getDeleteNamedVariableList()); confirmedServiceResponse.setDeleteNamedVariableList(response); + } else if (confirmedServiceRequest.getFileDirectory() != null) { + logger.debug("Got a FileDirectory request"); + FileDirectoryResponse response = + handleFileDirectoryRequest(confirmedServiceRequest.getFileDirectory()); + + confirmedServiceResponse.setFileDirectory(response); } else { throw new ServiceError( ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, @@ -618,6 +589,16 @@ final class ServerAssociation { return getNameListResponse; } + private FileDirectoryResponse handleFileDirectoryRequest(FileDirectoryRequest request) { + FileName fileSpecification = request.getFileSpecification(); + String path = fileSpecification.getBerGraphicString().get(0).toString(); + FileDirectoryResponse response = new FileDirectoryResponse(); + FileDirectoryResponse.ListOfDirectoryEntry list = new FileDirectoryResponse.ListOfDirectoryEntry(); + list.getDirectoryEntry(); + response.setListOfDirectoryEntry(list); + return response; + } + /** * GetVariableAccessAttributes (GetDataDefinition/GetDataDirectory) can be called with different * kinds of references. Examples: 1. DGEN1 2. DGEN1$CF 3. DGEN1$CF$GnBlk diff --git a/src/main/java/com/xydl/cac/controller/TestController.java b/src/main/java/com/xydl/cac/controller/TestController.java index 3cc51e8..d0c881d 100644 --- a/src/main/java/com/xydl/cac/controller/TestController.java +++ b/src/main/java/com/xydl/cac/controller/TestController.java @@ -1,6 +1,5 @@ package com.xydl.cac.controller; -import com.xydl.cac.iec.IecClient; import com.xydl.cac.model.Response; import com.xydl.cac.model.StaticVariable; import com.xydl.cac.service.IcdFileConfigService; @@ -40,9 +39,28 @@ public class TestController extends BasicController { webSocketServer.sendMessage(msg, warningId); } - @GetMapping("realTimeMap") - @ApiOperation("实时订阅Map") - public Response> realTimeMap() { + @GetMapping("realTimeClientMap") + @ApiOperation("realTimeClientMap") + public Response realTimeClientMap() { return Response.success(StaticVariable.realTimeClientMap); } + + @GetMapping("paramRelationMap") + @ApiOperation("paramRelationMap") + public Response paramRelationMap() { + return Response.success(StaticVariable.paramRelationMap); + } + + @GetMapping("sensorLastDataMap") + @ApiOperation("sensorLastDataMap") + public Response sensorLastDataMap() { + return Response.success(StaticVariable.sensorLastDataMap); + } + + @GetMapping("clearMap") + @ApiOperation("clearMap") + public void clearMap() { + StaticVariable.sensorLastDataMap.clear(); + StaticVariable.paramRelationMap.clear(); + } } diff --git a/src/main/java/com/xydl/cac/entity/Admin.java b/src/main/java/com/xydl/cac/entity/Admin.java index 46d6e52..0bf7273 100644 --- a/src/main/java/com/xydl/cac/entity/Admin.java +++ b/src/main/java/com/xydl/cac/entity/Admin.java @@ -35,4 +35,8 @@ public class Admin { @Column(name = "password") private String password; + @ApiModelProperty("菜单配置 1:显示 0:隐藏") + @Column(name = "menus") + private String menus; + } \ No newline at end of file diff --git a/src/main/java/com/xydl/cac/entity/IedDlConfig.java b/src/main/java/com/xydl/cac/entity/IedDlConfig.java index a783753..0c468e3 100644 --- a/src/main/java/com/xydl/cac/entity/IedDlConfig.java +++ b/src/main/java/com/xydl/cac/entity/IedDlConfig.java @@ -40,6 +40,10 @@ public class IedDlConfig { @Column(name = "path") private String path; + @ApiModelProperty("包含名字") + @Column(name = "contain") + private String contain; + @ApiModelProperty("后缀名") @Column(name = "suffix") private String suffix; diff --git a/src/main/java/com/xydl/cac/entity/IedDlRecord.java b/src/main/java/com/xydl/cac/entity/IedDlRecord.java index d2f3fe3..7e52967 100644 --- a/src/main/java/com/xydl/cac/entity/IedDlRecord.java +++ b/src/main/java/com/xydl/cac/entity/IedDlRecord.java @@ -30,7 +30,11 @@ public class IedDlRecord { @Column(name = "config_id") private Integer configId; - @ApiModelProperty("路径") + @ApiModelProperty("源路径") + @Column(name = "remote_path") + private String remotePath; + + @ApiModelProperty("本地路径") @Column(name = "path") private String path; diff --git a/src/main/java/com/xydl/cac/entity/RemoteDownload.java b/src/main/java/com/xydl/cac/entity/RemoteDownload.java index 42c04d4..11fbf44 100644 --- a/src/main/java/com/xydl/cac/entity/RemoteDownload.java +++ b/src/main/java/com/xydl/cac/entity/RemoteDownload.java @@ -30,11 +30,11 @@ public class RemoteDownload { @Column(name = "config_id") private Integer configId; - @ApiModelProperty("路径") + @ApiModelProperty("源路径") @Column(name = "remote_path") private String remotePath; - @ApiModelProperty("路径") + @ApiModelProperty("本地路径") @Column(name = "path") private String path; diff --git a/src/main/java/com/xydl/cac/iec/IEDCollectService.java b/src/main/java/com/xydl/cac/iec/IEDCollectService.java index 1a2120f..5d81d77 100644 --- a/src/main/java/com/xydl/cac/iec/IEDCollectService.java +++ b/src/main/java/com/xydl/cac/iec/IEDCollectService.java @@ -10,6 +10,7 @@ import com.xydl.cac.repository.*; import com.xydl.cac.service.DataService; import com.xydl.cac.service.IedDlRecordService; import com.xydl.cac.socket.WebSocketServer; +import com.xydl.cac.util.DateUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; @@ -33,6 +34,7 @@ public class IEDCollectService { BizConfig _bizConfig; String folder = "/record"; + HashMap eqmidTimeMap = new HashMap<>(); public IEDCollectService(IcdConfigTypeRepository configRepository, IcdConfigTypeAttRepository attRepository, IcdConfigTypeInstRepository instRepository, RptparamindexRepository rptparamindexRepository, @@ -69,6 +71,7 @@ public class IEDCollectService { try { log.info("61850开始采集数据, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()); this.connect(); + eqmidTimeMap.clear(); if (!CollectionUtils.isEmpty(rptList)) { this.doCollectAndSave(configTypeList, rptList); } @@ -116,7 +119,8 @@ public class IEDCollectService { String value = iecClient.getValue(paramindexNew, fc); String time = iecClient.getValue(paramindexT, fc); log.info("采集到" + fc + " " + paramindexNew + "=" + value + ", t=" + time); - time = time.replace("T", " ").replace("Z", "").replace("z", ""); + time = DateUtil.fromZoneUTCToLocal(time); + time = this.makeSameTime(rpt.getEqmid(), time); _dataService.insertData(rpt.getTablename(), rpt.getEqmid(), time, rpt.getColname(), value); // 更新最新数据缓存 @@ -131,6 +135,15 @@ public class IEDCollectService { StaticVariable.paramRelationMap.put(key, value); } + private String makeSameTime(Integer eqmid, String time) { + String sameTime = eqmidTimeMap.get(eqmid); + if (StringUtils.isBlank(sameTime)) { + sameTime = time; + eqmidTimeMap.put(eqmid, sameTime); + } + return sameTime; + } + private Rptparamindex findRpt(List rptList, String paramindex) { for (Rptparamindex rpt : rptList) { if (rpt.getParamindex().equals(paramindex)) { @@ -153,6 +166,9 @@ public class IEDCollectService { if (StringUtils.isBlank(config.getPath())) { return; } + if (!config.getPath().endsWith("/")) { + config.setPath(config.getPath() + "/"); + } if (config.getDevId() == null) { return; } @@ -162,18 +178,20 @@ public class IEDCollectService { for (FileInformation file : fileList) { String filename = file.getFilename(); if (!filename.endsWith("/")) { - if (StringUtils.isBlank(config.getSuffix()) || - filename.toLowerCase().endsWith(config.getSuffix().toLowerCase())) { + if (matchSuffix(filename, config.getSuffix()) + && matchContain(filename, config.getContain())) { IedDlRecord record = new IedDlRecord(); record.setConfigId(config.getId()); record.setFilename(filename); + record.setRemotePath(config.getPath() + filename); boolean exist = _dlRecordService.exist(record); if (!exist) { String localFilePath = localPath + "/" + filename; - iecClient.getFile(config.getPath(), filename, _bizConfig.getDatapath() + localFilePath, config.getTodel()); + iecClient.getFile(record.getRemotePath(), _bizConfig.getDatapath() + localFilePath, config.getTodel()); record.setPath(_bizConfig.getDataNginxPath() + localFilePath); record.setCreateTime(new Date()); _dlRecordService.add(record); + log.info("采集到" + record.getRemotePath()); } } } @@ -189,6 +207,28 @@ public class IEDCollectService { } } + private boolean matchSuffix(String filename, String suffix) { + if (StringUtils.isBlank(suffix)) { + return true; + } else { + if (filename.toLowerCase().endsWith(suffix.toLowerCase())) { + return true; + } + return false; + } + } + + private boolean matchContain(String filename, String contain) { + if (StringUtils.isBlank(contain)) { + return true; + } else { + if (filename.toLowerCase().contains(contain.toLowerCase())) { + return true; + } + return false; + } + } + public static void updateLastData(Integer eqmid, String colname, String value, String time) { HashMap map = StaticVariable.sensorLastDataMap.get(eqmid); if (map == null) { @@ -212,7 +252,7 @@ public class IEDCollectService { String colname = str[1]; value = bda.getValueString(); if ("acquisitionTime".equals(colname)) { - value = value.replace("T", " ").replace("Z", "").replace("z", ""); + value = DateUtil.fromZoneUTCToLocal(value); } updateLastData(eqmid, colname, value, null); } diff --git a/src/main/java/com/xydl/cac/iec/IecClient.java b/src/main/java/com/xydl/cac/iec/IecClient.java index 04cc63b..025aeca 100644 --- a/src/main/java/com/xydl/cac/iec/IecClient.java +++ b/src/main/java/com/xydl/cac/iec/IecClient.java @@ -3,6 +3,7 @@ package com.xydl.cac.iec; import com.beanit.iec61850bean.*; import com.xydl.cac.entity.IcdIed; import com.xydl.cac.entity.constants.Constants; +import com.xydl.cac.exception.BusinessException; import com.xydl.cac.model.StaticVariable; import com.xydl.cac.socket.WebSocketServer; import lombok.extern.slf4j.Slf4j; @@ -95,6 +96,9 @@ public class IecClient implements ClientEventListener { public String getValue(String paramindex, String fc) throws Exception { FcModelNode node = (FcModelNode) serverModel.findModelNode(paramindex, Fc.valueOf(fc)); + if (node == null) { + throw new BusinessException("icd文件里未找到该节点, " + fc + " " + paramindex); + } clientAssociation.getDataValues(node); if (node instanceof BasicDataAttribute) { String value = ((BasicDataAttribute) node).getValueString(); @@ -148,11 +152,11 @@ public class IecClient implements ClientEventListener { return list; } - public void getFile(String remotePath, String filename, String localPath, Integer todel) throws Exception { + public void getFile(String remotePath, String localPath, Integer todel) throws Exception { GetFileAction gfa = new GetFileAction(localPath); - clientAssociation.getFile(remotePath + filename, gfa); + clientAssociation.getFile(remotePath, gfa); if (todel != null && todel == Constants.TRUE) { - clientAssociation.deleteFile(remotePath + filename); + clientAssociation.deleteFile(remotePath); } } @@ -213,7 +217,7 @@ public class IecClient implements ClientEventListener { str = iecClient.getValue("OMDLMONT/SPDC1.MaxDsch.t", "MX"); System.out.println(str); List list = iecClient.listFile("/fdata"); - iecClient.getFile("/fdata/web/comtrade/1/18/6/", "20241021_113736_703_0_0.dat", "/eqmid/20241021_113736_703_0_0.dat", 1); + iecClient.getFile("/fdata/web/comtrade/1/18/6/20241021_113736_703_0_0.dat", "/eqmid/20241021_113736_703_0_0.dat", 1); } catch (Exception ex) { ex.printStackTrace(); diff --git a/src/main/java/com/xydl/cac/task/CacheTask.java b/src/main/java/com/xydl/cac/task/CacheTask.java index 68b1784..cbca1ca 100644 --- a/src/main/java/com/xydl/cac/task/CacheTask.java +++ b/src/main/java/com/xydl/cac/task/CacheTask.java @@ -17,17 +17,20 @@ public class CacheTask { @Resource WarnRuleService ruleService; - - @Scheduled(cron = "0 0 9 * * ?") - private void clearCache() { + @Scheduled(cron = "0 0 1 * * ?") + private void clearCache1() { StaticVariable.unit_Cache.clear(); StaticVariable.modevType_Cache = null; StaticVariable.jg_Cache = null; StaticVariable.zsb_Cache = null; StaticVariable.rule_Cache.clear(); - StaticVariable.doneWarnMap.clear(); + StaticVariable.paramRelationMap.clear(); } + @Scheduled(cron = "0 30 9 * * ?") + private void clearCache9() { + StaticVariable.doneWarnMap.clear(); + } @Scheduled(initialDelay = 30 * 1000, fixedDelay = 60 * 1000) private void refreshRule() { diff --git a/src/main/java/com/xydl/cac/util/DateUtil.java b/src/main/java/com/xydl/cac/util/DateUtil.java index d9f5b1d..d033d15 100644 --- a/src/main/java/com/xydl/cac/util/DateUtil.java +++ b/src/main/java/com/xydl/cac/util/DateUtil.java @@ -2,14 +2,15 @@ package com.xydl.cac.util; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.time.ZoneId; +import java.time.*; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Date; public class DateUtil { public final static String defaultDatePattern = "yyyy-MM-dd HH:mm:ss"; + public static DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern(defaultDatePattern); /** * 获得默认的 date pattern @@ -89,10 +90,47 @@ public class DateUtil { return cal.getTime(); } + public static Date addHour(Date date, int n) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.HOUR, n); + return cal.getTime(); + } + public static long getDifferenceInDays(Date startDate, Date endDate) { LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); return ChronoUnit.DAYS.between(startLocalDate, endLocalDate); } + public static String fromZoneUTCToLocal(String str) throws ParseException { + String time = str.replace("T", " ") + .replace("Z", "").replace("z", ""); + Date date = parse(time); + time = format(date); + LocalDateTime localtime = LocalDateTime.parse(time, defaultFormatter); + ZonedDateTime zonedDateTime = localtime.atZone(ZoneOffset.UTC); + ZonedDateTime convertedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault()); + String result = convertedDateTime.format(defaultFormatter); + return result; + } + + public static long secondDiff(String str1, String str2) { + try { + Date date1 = parse(str1); + Date date2 = parse(str2); + long sec1 = date1.getTime(); + long sec2 = date2.getTime(); + if (sec1 >= sec2) { + long sec = sec1 - sec2; + return sec / 1000; + } else { + long sec = sec2 - sec1; + return sec / 1000; + } + } catch (Exception e) { + return -1; + } + } + } diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index b905bd9..33cd6df 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -10,9 +10,9 @@ spring: time-zone: GMT+8 datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/iec104?charset=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&connectTimeout=60000&socketTimeout=60000 - username: iec - password: Iec@1043 + url: jdbc:mysql://127.0.0.1:3306/cacdb?charset=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&connectTimeout=60000&socketTimeout=60000 + username: root + password: 123456 data: jdbc: repositories: