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 20ac04ac..33301bfa 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 @@ -31,7 +31,7 @@ public class GnssDevice { private String parentid; private Integer devicetype; private String tenantname; - private Integer project_id = 0; + private String project_id; private Integer group_id = 1; //组参数,缓存自动下发 private Integer calc_group_id = 1; private Integer fwd_group_id = 0; diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/ForwardGnssTask.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/ForwardGnssTask.java new file mode 100644 index 00000000..3a0e496f --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/ForwardGnssTask.java @@ -0,0 +1,114 @@ +package com.imdroid.sideslope.fwd; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.imdroid.secapi.dto.GnssCalcData; +import com.imdroid.secapi.dto.GnssCalcDataMapper; +import com.imdroid.secapi.dto.GnssDevice; +import com.imdroid.secapi.dto.GnssDeviceMapper; +import com.imdroid.sideslope.util.GsonUtil; +import com.imdroid.sideslope.util.NumberUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Layton + * @date 2020/12/23 17:14 + */ +@Component +@Configuration +@EnableScheduling +public class ForwardGnssTask { + + private final Logger logger = LoggerFactory.getLogger(ForwardGnssTask.class); + + @Autowired + private GnssDeviceMapper deviceMapper; + + @Autowired + private GnssCalcDataMapper gnssDataMapper; + @Autowired + private XFZTcpClient xfzTcpClient; + /** + * 每半小时转发GNSS解算结果 + */ + @Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次 + private void forwardGnss() { + forwardGnssToXFZ(1); + } + + private void forwardGnssToXFZ(int tenantId) { + LocalDateTime nowTime = LocalDateTime.now(); + ConcurrentHashMap> projects = new ConcurrentHashMap<>(); + + // 转发新发展数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("tenantid", tenantId); + List gnssDeviceList = deviceMapper.selectList(queryWrapper); + List records; + for(GnssDevice device:gnssDeviceList){ + String projectId = device.getProject_id(); + if(projectId == null) continue; + + records = projects.get(projectId); + if(records == null){ + records = new ArrayList<>(); + projects.put(projectId,records); + } + QueryWrapper gnssQueryWrapper = new QueryWrapper<>(); + gnssQueryWrapper.eq("deviceid",device.getDeviceid()); + gnssQueryWrapper.orderByDesc("createtime"); + GnssCalcData record = gnssDataMapper.selectOne(gnssQueryWrapper); + if(record != null && record.getEnabled()){ + if(nowTime.isBefore(record.getCreatetime().plusMinutes(40))) { + records.add(record); + } + } + } + + // 按项目打包推送 + String sendTime = nowTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + for (Map.Entry> entry: projects.entrySet()){ + SendToXFZ(entry.getKey(), entry.getValue(), sendTime); + } + + } + + void SendToXFZ(String projectId, List records, String sendTime){ + if(records.size() == 0) return; + + XFZTcpMessage xfzTcpMessage = new XFZTcpMessage(); + xfzTcpMessage.setProjectID(projectId); + xfzTcpMessage.setWorkPointID(projectId); + + List dataList = new ArrayList<>(records.size()); + xfzTcpMessage.setData(dataList); + + for(GnssCalcData locationRecord: records) { + XFZTcpMessage.Data data = new XFZTcpMessage.Data(); + dataList.add(data); + data.setDataTime(sendTime); + data.setDevNum(locationRecord.getDeviceid()); + data.setDevtype("GNSS"); + // 单位由mm转化为m + data.setX(NumberUtils.scale(locationRecord.getRb562e() * 0.001, 5)); + data.setY(NumberUtils.scale(locationRecord.getRb562n() * 0.001, 5)); + data.setZ(NumberUtils.scale(locationRecord.getRb562d() * 0.001, 5)); + } + String json = GsonUtil.toJson(xfzTcpMessage); + xfzTcpClient.writeAndFlush(json); + logger.info("project " + projectId + ": push calculation result to XFZ"); + } + +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpClient.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpClient.java new file mode 100644 index 00000000..86c0c46f --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpClient.java @@ -0,0 +1,116 @@ +package com.imdroid.sideslope.fwd; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * @author Layton + * @date 2023/2/18 20:35 + */ +@Component +public class XFZTcpClient implements ApplicationRunner { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${xfz.server.host}") + private String host; + + @Value("${xfz.server.port}") + private int port; + + @Value("${xfz.server.data.send}") + private boolean send; + + private Bootstrap bootstrap; + private EventLoopGroup group; + private Channel channel; + + public void start() { + new Thread(this::connect, "xfz-tcp-client").start(); + } + + private void init() { + //客户端需要一个事件循环组 + group = new NioEventLoopGroup(); + //创建客户端启动对象 + // bootstrap 可重用, 只需在NettyClient实例化的时候初始化即可. + bootstrap = new Bootstrap(); + bootstrap.group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + //加入处理器 + ch.pipeline().addLast(new XFZTcpMessageHandler(XFZTcpClient.this)); + } + }); + } + + public void connect() { + logger.info("netty client starting"); + //启动客户端去连接服务器端 + try { + ChannelFuture cf = bootstrap.connect(host, port); + cf.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + //重连交给后端线程执行 + future.channel().eventLoop().schedule(() -> { + logger.info("xfz tcp client reconnect"); + try { + connect(); + } catch (Exception e) { + e.printStackTrace(); + } + }, 3000, TimeUnit.MILLISECONDS); + } else { + logger.info("xfz tcp client start success!"); + } + } + }); + //对通道关闭进行监听 + this.channel = cf.channel(); + this.channel.closeFuture().sync(); + } catch (Exception e) { + logger.error("xfz netty client error:", e); + } + } + + + public void writeAndFlush(String json) { + if (!send) { + return; + } + String str = "#" + json + "!"; + ByteBuf buf = Unpooled.buffer(); + buf.writeBytes(str.getBytes(StandardCharsets.UTF_8)); + channel.writeAndFlush(buf).addListener(future -> { + if (future.isSuccess()) { + logger.info("send {} to xfz server succeed.", str); + } else { + logger.info("send {} to xfz server failed.", str); + } + }); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + init(); + start(); + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessage.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessage.java new file mode 100644 index 00000000..c5538817 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessage.java @@ -0,0 +1,158 @@ +package com.imdroid.sideslope.fwd; + +import java.util.List; + +/** + * @author Layton + * @date 2023/2/19 9:16 + */ +public class XFZTcpMessage { + + private String ProjectID; + + private String WorkPointID; + + private String WorkPointLng = "0"; + + private String WorkPointLat = "0"; + + private List data; + + + public static class Data { + private String DevNum; + + private String Devtype; + + private String DevLng = "0"; + + private String DevLat = "0"; + + private double x; + + private double y; + + private double z; + + private String DataTime; + + public Data() { + + } + + public Data(String devNum, String devtype, String devLng, String devLat, double x, double y, double z, String dataTime) { + DevNum = devNum; + Devtype = devtype; + DevLng = devLng; + DevLat = devLat; + this.x = x; + this.y = y; + this.z = z; + DataTime = dataTime; + } + + public String getDevNum() { + return DevNum; + } + + public void setDevNum(String devNum) { + DevNum = devNum; + } + + public String getDevtype() { + return Devtype; + } + + public void setDevtype(String devtype) { + Devtype = devtype; + } + + public String getDevLng() { + return DevLng; + } + + public void setDevLng(String devLng) { + DevLng = devLng; + } + + public String getDevLat() { + return DevLat; + } + + public void setDevLat(String devLat) { + DevLat = devLat; + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return y; + } + + public void setY(double y) { + this.y = y; + } + + public double getZ() { + return z; + } + + public void setZ(double z) { + this.z = z; + } + + public String getDataTime() { + return DataTime; + } + + public void setDataTime(String dataTime) { + DataTime = dataTime; + } + } + + public String getProjectID() { + return ProjectID; + } + + public void setProjectID(String projectID) { + ProjectID = projectID; + } + + public String getWorkPointID() { + return WorkPointID; + } + + public void setWorkPointID(String workPointID) { + WorkPointID = workPointID; + } + + public String getWorkPointLng() { + return WorkPointLng; + } + + public void setWorkPointLng(String workPointLng) { + WorkPointLng = workPointLng; + } + + public String getWorkPointLat() { + return WorkPointLat; + } + + public void setWorkPointLat(String workPointLat) { + WorkPointLat = workPointLat; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessageHandler.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessageHandler.java new file mode 100644 index 00000000..acf9cdc6 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/fwd/XFZTcpMessageHandler.java @@ -0,0 +1,50 @@ +package com.imdroid.sideslope.fwd; + +import com.imdroid.sideslope.util.DataTypeUtil; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Layton + * @date 2023/2/18 20:36 + */ +public class XFZTcpMessageHandler extends SimpleChannelInboundHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final XFZTcpClient tcpClient; + + public XFZTcpMessageHandler(XFZTcpClient tcpClient) { + this.tcpClient = tcpClient; + } + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf buf) throws Exception { + if (logger.isDebugEnabled()) { + byte[] data = new byte[buf.readableBytes()]; + buf.getBytes(0, data); + logger.debug("receive gxxfz server message:" + DataTypeUtil.getHexString(data)); + } + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + logger.info("xfz tcp channel active"); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + logger.info("xfz tcp channel inactive"); + tcpClient.connect(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + logger.error("XFZTcpMessageHandler error: {}", cause.toString()); + ctx.close(); + } + +} diff --git a/sec-beidou-rtcm/src/main/resources/application.properties b/sec-beidou-rtcm/src/main/resources/application.properties index fdb408e9..4734b8d2 100644 --- a/sec-beidou-rtcm/src/main/resources/application.properties +++ b/sec-beidou-rtcm/src/main/resources/application.properties @@ -28,4 +28,8 @@ app.format.date = yyyy-MM-dd app.format.time = HH:mm:ss app.format.datetime = yyyy-MM-dd HH:mm:ss -mybatis-plus.configuration.map-underscore-to-camel-case=false \ No newline at end of file +mybatis-plus.configuration.map-underscore-to-camel-case=false + +xfz.server.host = 171.106.48.63 +xfz.server.port = 52000 +xfz.server.data.send = false \ No newline at end of file diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/LayuiController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/IndexController.java similarity index 63% rename from sec-beidou/src/main/java/com/imdroid/beidou/controller/LayuiController.java rename to sec-beidou/src/main/java/com/imdroid/beidou/controller/IndexController.java index 3d42d737..1ff72f2c 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/controller/LayuiController.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/IndexController.java @@ -4,11 +4,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller -public class LayuiController extends BasicController{ - @RequestMapping("/login") - public String login(){ - return "/login"; - } +public class IndexController extends BasicController{ @RequestMapping("/") public String index0() { @@ -25,9 +21,4 @@ public class LayuiController extends BasicController{ return "/page/device_overview"; } - @RequestMapping("/page/gnss_data_tools") - public String gnssDataTools() { - return "/page/gnss_data_tools"; - } - } diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/LoginController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/LoginController.java index a5f2f7f1..c0852dd3 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/controller/LoginController.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/LoginController.java @@ -13,6 +13,7 @@ import com.imdroid.beidou.entity.UserMapper; import com.imdroid.beidou.utils.BCryptPasswordEncoderUtil; import com.imdroid.beidou.utils.WXUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -25,8 +26,7 @@ import java.io.IOException; * * @author LiGang */ -@RequestMapping -@RestController +@Controller public class LoginController { @Autowired @@ -41,6 +41,11 @@ public class LoginController { @Autowired private BCryptPasswordEncoderUtil bCryptPasswordEncoderUtil; + @RequestMapping("/login") + public String login(){ + return "/login"; + } + @PostMapping(value = "/do_login") @ResponseBody public HttpResult login(UserLoginVO userLoginVO, HttpServletRequest request, HttpServletResponse response) throws Exception { diff --git a/sec-beidou/src/main/resources/db/schema.sql b/sec-beidou/src/main/resources/db/schema.sql index bd252735..ff7ccf39 100644 --- a/sec-beidou/src/main/resources/db/schema.sql +++ b/sec-beidou/src/main/resources/db/schema.sql @@ -45,7 +45,7 @@ CREATE TABLE IF NOT EXISTS `gnssdevices` ( `parentid` varchar(20) DEFAULT NULL, `devicetype` smallint DEFAULT 0, `tenantname` varchar(100) NOT NULL, - `project_id` int NOT NULL DEFAULT 0 COMMENT '项目id', + `project_id` varchar(64) DEFAULT NULL COMMENT '项目id', `group_id` int DEFAULT 1, `calc_group_id` int DEFAULT 1, `fwd_group_id` int DEFAULT 0, diff --git a/sec-beidou/src/main/resources/static/api/init.json b/sec-beidou/src/main/resources/static/api/init.json index 18e8756b..137dfad9 100644 --- a/sec-beidou/src/main/resources/static/api/init.json +++ b/sec-beidou/src/main/resources/static/api/init.json @@ -258,12 +258,6 @@ "href": "page/gnss_data_raw", "icon": "fa fa-database", "target": "_self" - }, - { - "title": "测试工具", - "href": "page/gnss_data_tools", - "icon": "fa fa-wrench", - "target": "_self" } ] }, diff --git a/sec-beidou/src/main/resources/templates/page/gnss_status.html b/sec-beidou/src/main/resources/templates/page/gnss_status.html index f757f3ce..a517c8df 100644 --- a/sec-beidou/src/main/resources/templates/page/gnss_status.html +++ b/sec-beidou/src/main/resources/templates/page/gnss_status.html @@ -45,7 +45,7 @@
@@ -84,17 +84,12 @@ {field: 'devicetime', title: '设备时间'}, {field: 'satelliteinview', title: '可见卫星'}, {field: 'satelliteinuse', title: '使用卫星'}, - {field: 'd3xxbytes', title: 'D3XX字节数'}, - {field: 'b562bytes', title: 'B562字节数'}, {field: 'state', title: '状态',templet: '#stateTrans'}, {field: 'warning', title: '告警',templet: '#warningTrans'}, {field: 'location', title: '位置'}, {field: 'voltage', title: '电压'}, {field: 'temperature', title: '温度'}, {field: 'humidity', title: '湿度'}, - {field: 'roll', title: 'roll'}, - {field: 'pitch', title: 'pitch'}, - {field: 'yaw', title: 'yaw'}, {field: 'rssi', title: '信号'}, {title: '操作', toolbar: '#currentTableBar', align: "center"} ]], 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 e68906d0..8e3f8479 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 @@ -38,9 +38,9 @@
- +
- +