From 86776c2405379d7de77ba648ec6ba9e82018284a Mon Sep 17 00:00:00 2001 From: weidong Date: Sat, 2 Nov 2024 20:54:04 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=91=A8=E6=9C=9F?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E8=A7=A6=E5=8F=91=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calc/SingleLineGNSSCalcService.java | 20 +++++++++---------- .../D3F2StopIndicationMessageExecutor.java | 5 +++++ .../templates/page/table/frequent_cmd.html | 4 +++- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java index 04ee65b1..3e474af7 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java @@ -153,15 +153,15 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService { @Override public void calSingleDone(Device device, GnssGroupCalc groupCalc, LocalDateTime resultTime) { - // executor已经在线程处理了 - /* ThreadManager.getScheduledThreadPool().schedule(() -> { - try { - calCycleResult(device, groupCalc, resultTime); - } catch (Exception e) { - logger.error(e.toString()); - } - },50, TimeUnit.MILLISECONDS); -*/ + ScheduledFuture future = timerMap.get(device.getDeviceId()); + if (future != null && !future.isDone()) { + future.cancel(true); + future = null; + } + if(null == groupCalc){ + groupCalc = getGroupCalc(device.getCalcGroupId()); + if(groupCalc == null) return; + } calCycleResult(device, groupCalc, resultTime); } @@ -181,7 +181,7 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService { } catch (Exception e) { logger.error(e.toString()); } - },30, TimeUnit.SECONDS); + },90, TimeUnit.SECONDS); timerMap.put(device.getDeviceId(), future); } diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java index b6be25d7..8a6d425a 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D3F2StopIndicationMessageExecutor.java @@ -3,6 +3,7 @@ package com.imdroid.sideslope.executor; import com.imdroid.common.util.ThreadManager; import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.dto.GnssTrxMsg; +import com.imdroid.sideslope.calc.GNSSDataCalcService; import com.imdroid.sideslope.calc.MultiLineGNSSCalcService; import com.imdroid.sideslope.message.D3F2StopIndicationMessage; import com.imdroid.sideslope.sal.Device; @@ -34,6 +35,8 @@ public class D3F2StopIndicationMessageExecutor implements Executor From 7c9a5b0d26569d9c44651481d25127d5afe6d169 Mon Sep 17 00:00:00 2001 From: weidong Date: Tue, 5 Nov 2024 17:17:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96log=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/imdroid/secapi/dto/GnssDevice.java | 6 + .../imdroid/secapi/dto/GnssSingleData.java | 44 ++++ .../secapi/dto/GnssSingleDataMapper.java | 13 + .../resources/mapper/GnssSingleDataMapper.xml | 18 ++ .../calc/SingleLineGNSSCalcService.java | 35 ++- .../executor/D331RtcmMessageExecutor.java | 9 +- .../executor/D341LocationMessageExecutor.java | 18 +- .../D3F0SelfCheckMessageExecutor.java | 5 +- .../D3F2StopIndicationMessageExecutor.java | 15 +- .../message/D341LocationMessage.java | 2 + .../message/D3F0SelfCheckMessage.java | 5 + .../message/D3F2StopIndicationMessage.java | 5 + .../sideslope/sal/DbDeviceServiceImpl.java | 2 + .../com/imdroid/sideslope/sal/Device.java | 4 + .../sideslope/server/tcp/RtcmTcpHandler.java | 5 +- .../service/GnssSingleBufferService.java | 10 + .../service/GnssSingleBufferServiceImpl.java | 81 ++++++ .../sideslope/service/WarningServiceImpl.java | 16 ++ .../controller/GnssSingleDataController.java | 93 +++++++ .../beidou/task/DeviceStatusChecker.java | 12 + .../static/api/init_super_admin.json | 6 + .../templates/page/gnss_single_data.html | 249 ++++++++++++++++++ .../templates/page/table/gnss_add_dev.html | 11 + .../common/util/WarningLogExecutor.java | 89 +++++++ 24 files changed, 736 insertions(+), 17 deletions(-) create mode 100644 sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleData.java create mode 100644 sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleDataMapper.java create mode 100644 sec-api/src/main/resources/mapper/GnssSingleDataMapper.xml create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferService.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferServiceImpl.java create mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssSingleDataController.java create mode 100644 sec-beidou/src/main/resources/templates/page/gnss_single_data.html create mode 100644 sec-common/src/main/java/com/imdroid/common/util/WarningLogExecutor.java diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssDevice.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssDevice.java index 3ecb7ed2..c72bbdf4 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssDevice.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssDevice.java @@ -25,6 +25,9 @@ public class GnssDevice { public static final short MODEL_G505 = 0; //F9P public static final short MODEL_G510 = 1; //博通 + public static final short LOGGING_MODE_SIMPLE = 0; // 精简模式( 仅D3F0和D3F2 ) + public static final short LOGGING_MODE_FULL = 1; // 完整模式 + @TableId(value = "id", type = IdType.AUTO) private Long id; private Integer tenantid; @@ -60,4 +63,7 @@ public class GnssDevice { private String imei; private Short model; + // 日志记录控制 + private Short loggingmode; + } diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleData.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleData.java new file mode 100644 index 00000000..b79891f6 --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleData.java @@ -0,0 +1,44 @@ +package com.imdroid.secapi.dto; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.time.LocalDateTime; +import lombok.Data; + +@Data +@TableName(value = "gnssdevicesinglerecords") +public class GnssSingleData { + public static final short MODEL_G505 = 0; //F9P + public static final short MODEL_G510 = 1; //博通 + + + @TableId(value = "id", type = IdType.AUTO) + @ExcelIgnore + Long id; + @ExcelProperty("设备编号") + String deviceid; + + @ExcelProperty("记录时间") + LocalDateTime createtime; + + // 博通的 GGA 经纬度数据 + // F9P 的私有格式 B562 的 ECEF 数据 + @ExcelProperty("型号") + Short model; + + @ExcelProperty("东") + double x; // GGA时是 latitude, ECEF时是 x + @ExcelProperty("北") + double y; // GGA时是 longitude, ECEF时是 y + @ExcelProperty("天") + double z; // GGA时是 altitude, ECEF时是 z + + // GGA 时 GPS状态,0初始化,1单点定位,2码差分,3无效PPS,4固定解,5浮点解,6正在估算7,人工输入固定值,8模拟模式,9WAAS差分 + // ECEF 时 0无B562,1 浮点解,2 固定解 + @ExcelProperty("状态") + int status; +} diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleDataMapper.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleDataMapper.java new file mode 100644 index 00000000..7b9b2ed6 --- /dev/null +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssSingleDataMapper.java @@ -0,0 +1,13 @@ +package com.imdroid.secapi.dto; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface GnssSingleDataMapper extends MPJBaseMapper { + Page queryByDeviceId(@Param("page") IPage page, @Param("deviceId") String deviceId, + @Param("beginTime") String beginTime, @Param("endTime") String endTime, @Param("count") Integer count); +} diff --git a/sec-api/src/main/resources/mapper/GnssSingleDataMapper.xml b/sec-api/src/main/resources/mapper/GnssSingleDataMapper.xml new file mode 100644 index 00000000..d80fbdaf --- /dev/null +++ b/sec-api/src/main/resources/mapper/GnssSingleDataMapper.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java index 3e474af7..49e81bcf 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/calc/SingleLineGNSSCalcService.java @@ -3,16 +3,14 @@ package com.imdroid.sideslope.calc; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.imdroid.common.util.DataTypeUtil; import com.imdroid.common.util.ThreadManager; -import com.imdroid.secapi.dto.GnssCalcData; -import com.imdroid.secapi.dto.GnssCalcDataMapper; -import com.imdroid.secapi.dto.GnssGroupCalc; -import com.imdroid.secapi.dto.GnssGroupCalcMapper; +import com.imdroid.secapi.dto.*; import com.imdroid.sideslope.bd.*; import com.imdroid.sideslope.message.D341LocationMessage; import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.DeviceService; import com.imdroid.sideslope.server.DeviceChannel; import com.imdroid.sideslope.server.OnlineChannels; +import com.imdroid.sideslope.service.GnssSingleBufferService; import com.imdroid.sideslope.service.WarningService; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -56,6 +54,9 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService { @Autowired GnssCalcDataMapper dataMapper; + @Autowired + private GnssSingleBufferService gnssSingleDataService; + // 非线程安全,需加同步保护 List groupCalcList; @@ -149,6 +150,32 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService { hardResetDevice(deviceId); } } + + // 若是该设备开启了日志记录,则保存单次解析的数据 + if(device.getLoggingmode() == GnssDevice.LOGGING_MODE_FULL){ + // 保存单次解析的原始数据,受 loggingmode 字段控制 + GnssSingleData gnssSingleData = new GnssSingleData(); + gnssSingleData.setDeviceid(device.getDeviceId()); + gnssSingleData.setCreatetime(LocalDateTime.now()); + gnssSingleData.setModel(device.getModel()); + if((device.getModel() == GnssDevice.MODEL_G505) && (doubles !=null)){ + gnssSingleData.setX(doubles[0]); + gnssSingleData.setY(doubles[1]); + gnssSingleData.setZ(doubles[2]); + gnssSingleData.setStatus((int) doubles[3]); + gnssSingleDataService.addData(gnssSingleData); + } + else if((device.getModel() == GnssDevice.MODEL_G510) && (gga !=null)){ + gnssSingleData.setX(gga.getLatitude()); + gnssSingleData.setY(gga.getLongitude()); + gnssSingleData.setZ(gga.getAltitude()); + gnssSingleData.setStatus(gga.getQuality()); + gnssSingleDataService.addData(gnssSingleData); + } + } + + + } @Override diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java index 0d37fdb8..af6bcb5f 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java @@ -1,5 +1,6 @@ package com.imdroid.sideslope.executor; +import com.imdroid.common.util.DataTypeUtil; import com.imdroid.common.util.ThreadManager; import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.dto.GnssDevice; @@ -41,7 +42,13 @@ public class D331RtcmMessageExecutor implements Executor // 补齐tenantId Device device1 = deviceService.findByDeviceId(id); if(device1 == null || device1.getOpMode() == GnssDevice.OP_MODE_UNUSE) return null; - logger.debug("receive d331 rtcm message of device: "+message.getId()+", seq:"+message.getSeq()+", len:"+message.getLen()); + + // 原始码流输出到日志文件 -- INFO 级别 + // 只有测站开了日志记录,或者消息来自基站,才将原码记录到日志文件 + if(device1.getLoggingmode() == GnssDevice.LOGGING_MODE_FULL || device1.getDeviceType() == GnssDevice.TYPE_REFERENCE_STATION){ + logger.info("receive {} d331 message: {}", message.getId(), DataTypeUtil.getHexString(message.getSrcData())); + logger.info("receive d331 rtcm message of device: {}, seq:{}, len:{}", message.getId(), message.getSeq(), message.getLen()); + } // 推送基站数据 if(device1.getOpMode() == GnssDevice.OP_MODE_USE) { diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D341LocationMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D341LocationMessageExecutor.java index 4388e65d..e60c0488 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D341LocationMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D341LocationMessageExecutor.java @@ -1,7 +1,9 @@ package com.imdroid.sideslope.executor; +import com.imdroid.common.util.DataTypeUtil; import com.imdroid.common.util.ThreadManager; import com.imdroid.secapi.client.BeidouClient; +import com.imdroid.secapi.dto.GnssDevice; import com.imdroid.sideslope.bd.Gga; import com.imdroid.sideslope.calc.GNSSDataCalcService; import com.imdroid.sideslope.message.D341LocationMessage; @@ -35,14 +37,17 @@ public class D341LocationMessageExecutor implements Executor { private final Logger logger = LoggerFactory.getLogger(RtcmTcpServer.class); @Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf src) throws Exception{ - if (logger.isDebugEnabled()) { + /*if (logger.isDebugEnabled()) { byte[] data = new byte[src.readableBytes()]; src.getBytes(0, data); logger.debug("receive message:" + DataTypeUtil.getHexString(data)); - } + }*/ try { BaseMessage message = MessageParser.instance.parse(src); OnlineChannels.INSTANCE.updateConfigChannel(message.getId(), ctx.channel(), null); diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferService.java new file mode 100644 index 00000000..a46c643b --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferService.java @@ -0,0 +1,10 @@ +package com.imdroid.sideslope.service; + +import com.imdroid.secapi.dto.GnssSingleData; + +public interface GnssSingleBufferService { + void addData(GnssSingleData data); + void flush(); + void clear(); + int getBufferSize(); +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferServiceImpl.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferServiceImpl.java new file mode 100644 index 00000000..e49b92d8 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/GnssSingleBufferServiceImpl.java @@ -0,0 +1,81 @@ +package com.imdroid.sideslope.service; + +import com.imdroid.secapi.dto.GnssSingleData; +import com.imdroid.secapi.dto.GnssSingleDataMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class GnssSingleBufferServiceImpl implements GnssSingleBufferService { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final List buffer = new ArrayList<>(); + + // BUFFER_SIZE 暂定此大小 + private static final int BUFFER_SIZE = 1024; + // 资源锁 + private final Object lock = new Object(); + + @Autowired + private GnssSingleDataMapper gnssSingleDataMapper; + + @Override + public void addData(GnssSingleData data) { + if (data == null) { + return; + } + synchronized (lock) { + buffer.add(data); + if (buffer.size() >= BUFFER_SIZE) { + // 溢出时直接保存 + // 此处暂定,但很有必要引入一个线程来保存,避免阻塞主线程 + flush(); + } + } + } + + @Override + public void flush() { + synchronized (lock) { + if (buffer.isEmpty()) { + return; + } + + try { + List batchList = new ArrayList<>(buffer); + buffer.clear(); + // 由于每秒写数据库操作频繁,这里采用批量保存的方式 + saveBatch(batchList); + + logger.debug("批量插入{}条数据成功", batchList.size()); + } catch (Exception e) { + logger.error("批量插入数据失败", e); + throw e; + } + } + } + + private void saveBatch(List dataList) { + for (GnssSingleData data : dataList) { + gnssSingleDataMapper.insert(data); + } + } + + @Override + public void clear() { + synchronized (lock) { + buffer.clear(); + } + } + + @Override + public int getBufferSize() { + synchronized(lock) { + return buffer.size(); + } + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java index 555b48c7..5c4b706e 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java @@ -2,9 +2,11 @@ package com.imdroid.sideslope.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.imdroid.common.util.NumberUtils; +import com.imdroid.common.util.WarningLogExecutor; import com.imdroid.secapi.dto.*; import com.imdroid.sideslope.sal.Device; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; @@ -22,6 +24,9 @@ public class WarningServiceImpl implements WarningService { @Autowired GnssStatusMapper gnssStatusMapper; + @Value("${warning.log.directory}") + private String logDirectory; + // warning type <-> level & value Map cfgMap = new ConcurrentHashMap<>(); int warningLevel2Code = 0; @@ -174,6 +179,9 @@ public class WarningServiceImpl implements WarningService { warningMsgMapper.insert(warningMsg); //告警级别 curStatus.setWarningcode(curStatus.getWarningcode() | warningType); + + // 新告警出现后,生成对应设备的 warning 日志文件 + generate_warning_logs(curStatus.getDeviceid(),warningType,auxInfo); } isUpdated = true; } @@ -219,4 +227,12 @@ public class WarningServiceImpl implements WarningService { } } } + + public void generate_warning_logs(String device_id,int warning_type,String warning_type_name){ + if (warning_type == WarningCfg.TYPE_LOW_VOLTAGE) { + WarningLogExecutor warningLogExecutor = new WarningLogExecutor(logDirectory); + warningLogExecutor.generateWarningLogs(device_id, warning_type_name); + } + + } } diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssSingleDataController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssSingleDataController.java new file mode 100644 index 00000000..4c4f2cd5 --- /dev/null +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssSingleDataController.java @@ -0,0 +1,93 @@ +package com.imdroid.beidou.controller; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.imdroid.beidou.service.CommonExcelService; +import com.imdroid.secapi.dto.GnssSingleData; +import com.imdroid.secapi.dto.GnssSingleDataMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpSession; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Controller +public class GnssSingleDataController extends BasicController implements CommonExcelService { + + @Autowired + GnssSingleDataMapper gnssSingleDataMapper; + + final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + + @RequestMapping("/page/gnss_single_data") + public String gnssSingleData(Model m, HttpSession session){ + initModel(m, session); + + return "/page/gnss_single_data"; + } + + + @RequestMapping("/gnss/data/list_single_data") + @ResponseBody + public JSONObject listData(HttpSession session, Integer page, Integer limit, String searchParams) { + // 检查查询条件 + JSONObject search = null; + if (searchParams != null) { + search = (JSONObject) JSONObject.parse(searchParams); + System.out.println(search); + String deviceId = search.getString("deviceid"); + Integer freqency = search.getInteger("freqency"); + String begin = search.getString("dgt_.createtime"); + String end = search.getString("dlt_.createtime"); + + if(deviceId != null && !deviceId.isEmpty() && freqency!=0){ + Page pageable = new Page<>(page == null ? 1 : page, limit == null ? 10 : limit); + + // 缺省按1小时采样,如果时间跨度较大,则按最多300条记录的采样率采样 + int sample = 6; + + if(freqency == 2){ + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime beginTime = endTime.minusDays(30); + if(begin!=null && !begin.isEmpty()){ + beginTime = LocalDateTime.parse(begin,df); + } + if(end!=null && !end.isEmpty()){ + endTime = LocalDateTime.parse(end,df); + } + Duration duration = Duration.between(beginTime, endTime); + int hours = (int)duration.toHours(); + if(hours > 300) sample = hours*6/300; + } + Page calcDataList = gnssSingleDataMapper.queryByDeviceId(pageable, deviceId,begin,end,sample); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("code", 0); + jsonObject.put("msg", ""); + jsonObject.put("count", calcDataList.getTotal()); + jsonObject.put("data", calcDataList.getRecords()); + return jsonObject; + } + } + + return this.pageList(session, page, limit, searchParams); + } + + + @Override + public Class getEntityClass() { + return GnssSingleData.class; + } + + @Override + public BaseMapper getMapper() { + return gnssSingleDataMapper; + } +} diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java b/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java index 773f15ee..eec06a93 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java @@ -3,9 +3,11 @@ package com.imdroid.beidou.task; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.query.MPJQueryWrapper; import com.imdroid.beidou.service.NotificationService; +import com.imdroid.common.util.WarningLogExecutor; import com.imdroid.secapi.dto.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; @@ -44,6 +46,10 @@ public class DeviceStatusChecker { GnssCalcDataMapper dataMapper; @Autowired GnssDeviceMapper deviceMapper; + + @Value("${warning.log.directory}") + private String logDirectory; + static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次 @@ -153,6 +159,12 @@ public class DeviceStatusChecker { status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_NO_FIXED_RESULT); status.setWarning(WarningCfg.LEVEL_2); deviceIds.add(status.getDeviceid()); + + // 生成 Warning 日志 + WarningLogExecutor warningLogExecutor = new WarningLogExecutor(logDirectory); + warningLogExecutor.generateWarningLogs(status.getDeviceid(),WarningCfg.TYPE_NAME_NO_FIXED_RESULT); + + } gnssStatusMapper.updateById(status); } diff --git a/sec-beidou/src/main/resources/static/api/init_super_admin.json b/sec-beidou/src/main/resources/static/api/init_super_admin.json index 5229f44c..9835dffc 100644 --- a/sec-beidou/src/main/resources/static/api/init_super_admin.json +++ b/sec-beidou/src/main/resources/static/api/init_super_admin.json @@ -53,6 +53,12 @@ "icon": "fa fa-calculator", "target": "_self" }, + { + "title": "Log", + "href": "page/gnss_single_data", + "icon": "fa fa-clipboard", + "target": "_self" + }, { "title": "配置管理", "href": "", diff --git a/sec-beidou/src/main/resources/templates/page/gnss_single_data.html b/sec-beidou/src/main/resources/templates/page/gnss_single_data.html new file mode 100644 index 00000000..3555a637 --- /dev/null +++ b/sec-beidou/src/main/resources/templates/page/gnss_single_data.html @@ -0,0 +1,249 @@ + + + + + 单次解算记录 + + + + + + + +
+
+
+ 搜索信息 +
+
+
+
+ +
+ + +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+ + +
+
+
+
+
+
+
    +
  • 数据表格
  • +
  • 单个设备曲线
  • +
+
+
+
+
+
+
+
+
+
+ + +
+
+ + + + + + \ No newline at end of file diff --git a/sec-beidou/src/main/resources/templates/page/table/gnss_add_dev.html b/sec-beidou/src/main/resources/templates/page/table/gnss_add_dev.html index e59c96c7..a1b37c1e 100644 --- a/sec-beidou/src/main/resources/templates/page/table/gnss_add_dev.html +++ b/sec-beidou/src/main/resources/templates/page/table/gnss_add_dev.html @@ -34,6 +34,16 @@ + +
+ +
+ +
+
@@ -292,6 +302,7 @@ $('#fwd_group_id').val(data.fwd_group_id); $('#fwd_group_id2').val(data.fwd_group_id2); $('#opmode').val(data.opmode); + $('#loggingmode').val(data.loggingmode); $('#fwddeviceid').val(data.fwddeviceid); $('#ipose').val(data.ipose); $('#iposn').val(data.iposn); diff --git a/sec-common/src/main/java/com/imdroid/common/util/WarningLogExecutor.java b/sec-common/src/main/java/com/imdroid/common/util/WarningLogExecutor.java new file mode 100644 index 00000000..feaf22bc --- /dev/null +++ b/sec-common/src/main/java/com/imdroid/common/util/WarningLogExecutor.java @@ -0,0 +1,89 @@ +package com.imdroid.common.util; + +import java.io.*; +import java.nio.file.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class WarningLogExecutor { + + private final String logDirectory; + private final ExecutorService executor; + // 记录已初始化的文件 + private final ConcurrentHashMap initializedFiles = new ConcurrentHashMap<>(); + + public WarningLogExecutor(String logDirectory) { + this.logDirectory = logDirectory; + this.executor = ThreadManager.getSingleThreadPool("warning_log_thread"); + } + + public void generateWarningLogs(String keyword, String warningTypeName) { + try { + String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); + String warningFileName = "Warning-" + keyword + "-" + date + ".log"; + Path warningFile = Paths.get(logDirectory, warningFileName); + + // 如果是新文件,先写入初始化信息 + if (initializedFiles.putIfAbsent(warningFileName, true) == null) { + initializeWarningFile(warningFile, keyword, warningTypeName); + } + + // 找到日志文件 + List logFiles = Files.list(Paths.get(logDirectory)) + .filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().matches("sideslopertcm(\\.\\d{4}-\\d{2}-\\d{2}\\.\\d+)?\\.log")) + .collect(Collectors.toList()); + + for (Path logFile : logFiles) { + executor.submit(() -> processFile(logFile, keyword, warningTypeName, warningFile)); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + executor.shutdown(); + } + } + + private void initializeWarningFile(Path warningFile, String keyword, String warningTypeName) { + try (BufferedWriter writer = Files.newBufferedWriter(warningFile, + StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { + writer.write("=== Warning Log File ==="); + writer.newLine(); + writer.write("Created Time: " + LocalDateTime.now()); + writer.newLine(); + writer.write("Warning Type Name: " + warningTypeName); + writer.newLine(); + writer.write("Keyword: " + keyword); + writer.newLine(); + writer.write("=============================="); + writer.newLine(); + writer.newLine(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void processFile(Path logFile, String keyword, String warningTypeName, Path warningFile) { + try (BufferedReader reader = Files.newBufferedReader(logFile); + BufferedWriter writer = Files.newBufferedWriter(warningFile, + StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { + + writer.write("Processing source file: " + logFile.getFileName()); + writer.newLine(); + + String line; + while ((line = reader.readLine()) != null) { + if (line.contains(keyword)) { + writer.write(line); + writer.newLine(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file