From 5632424f1ac2bfa26d251bfc1d9daa96c6c99eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Sun, 2 Mar 2025 10:46:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/demo.sql | 233 --------------------- sql/init.sql | 233 +++++++++++++++++++++ .../Listener/LiquidTrayStatusChangedListener.java | 35 ---- .../java/com/qyft/gd/device/client/TcpClient.java | 160 -------------- .../com/qyft/gd/device/core/client/TcpClient.java | 160 ++++++++++++++ .../core/event/LiquidTrayStatusChangedEvent.java | 19 ++ .../device/core/handler/DeviceMessageHandler.java | 68 ++++++ .../listener/LiquidTrayStatusChangedListener.java | 35 ++++ .../device/event/LiquidTrayStatusChangedEvent.java | 19 -- .../gd/device/handler/DeviceMessageHandler.java | 68 ------ .../gd/device/service/DeviceStatusService.java | 3 +- .../gd/device/service/DeviceTcpCMDService.java | 2 +- .../com/qyft/gd/system/config/FilterConfig.java | 2 +- .../qyft/gd/system/config/MybatisPlusConfig.java | 2 +- .../qyft/gd/system/core/MyMetaObjectHandler.java | 36 ---- .../core/filter/JwtAuthenticationFilter.java | 52 +++++ .../system/core/handler/MyMetaObjectHandler.java | 36 ++++ .../gd/system/filter/JwtAuthenticationFilter.java | 52 ----- 18 files changed, 607 insertions(+), 608 deletions(-) delete mode 100644 sql/demo.sql create mode 100644 sql/init.sql delete mode 100644 src/main/java/com/qyft/gd/device/Listener/LiquidTrayStatusChangedListener.java delete mode 100644 src/main/java/com/qyft/gd/device/client/TcpClient.java create mode 100644 src/main/java/com/qyft/gd/device/core/client/TcpClient.java create mode 100644 src/main/java/com/qyft/gd/device/core/event/LiquidTrayStatusChangedEvent.java create mode 100644 src/main/java/com/qyft/gd/device/core/handler/DeviceMessageHandler.java create mode 100644 src/main/java/com/qyft/gd/device/core/listener/LiquidTrayStatusChangedListener.java delete mode 100644 src/main/java/com/qyft/gd/device/event/LiquidTrayStatusChangedEvent.java delete mode 100644 src/main/java/com/qyft/gd/device/handler/DeviceMessageHandler.java delete mode 100644 src/main/java/com/qyft/gd/system/core/MyMetaObjectHandler.java create mode 100644 src/main/java/com/qyft/gd/system/core/filter/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/qyft/gd/system/core/handler/MyMetaObjectHandler.java delete mode 100644 src/main/java/com/qyft/gd/system/filter/JwtAuthenticationFilter.java diff --git a/sql/demo.sql b/sql/demo.sql deleted file mode 100644 index 25e0ee8..0000000 --- a/sql/demo.sql +++ /dev/null @@ -1,233 +0,0 @@ --- 创建 sys_user 表 -CREATE TABLE IF NOT EXISTS sys_user -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT NOT NULL, - nickname TEXT, - password TEXT NOT NULL, - avatar TEXT, - role INTEGER, - is_deleted INTEGER DEFAULT 0, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- 插入测试数据 -INSERT INTO sys_user (username, nickname, password, avatar, role, is_deleted) -VALUES ('admin', 'Admin', '12345', 'admin.png', 1, 0), - ('john_doe', 'John Doe', 'password123', 'avatar1.png', 2, 0), - ('test', 'test', 'test123', 'avatar2.png', 3, 0); - - --- 创建 sys_role 表 -CREATE TABLE IF NOT EXISTS sys_role -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - code TEXT NOT NULL, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- 插入角色数据 -INSERT INTO sys_role (name, code) -VALUES ('管理员', 'ADMIN'), - ('普通用户', 'USER'), - ('测试用户', 'TEST'); - --- 创建 系统配置 表 -CREATE TABLE IF NOT EXISTS sys_settings -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - parent_id INTEGER NOT NULL, - name TEXT NOT NULL, - code TEXT, - value1 TEXT, - value2 TEXT, - value3 TEXT, - value4 TEXT -); -INSERT INTO sys_settings (id, parent_id, name, code, value1, value2, value3, value4) -VALUES (1, -1, '加热区域配置', 'heat_area', '坐标', '硬件代号', '温度', '工艺id'), - (2, 1, 'A1', 'heat_area_A1', '1,1,1', 'hardware_1', '1', ''), - (3, 1, 'A2', 'heat_area_A2', '2,2,2', 'hardware_2', '2', ''), - (4, 1, 'A3', 'heat_area_A3', '3,3,3', 'hardware_3', '3', ''), - (5, 1, 'A4', 'heat_area_A4', '4,4,4', 'hardware_4', '4', ''), - (6, 1, 'A5', 'heat_area_A5', '5,5,5', 'hardware_5', '5', ''), - (7, 1, 'A6', 'heat_area_A6', '6,6,6', 'hardware_6', '6', ''), - (8, -1, '加液区域配置', 'solution_area', '坐标', '硬件代号', '', ''), - (9, 8, '加液区', 'solution_area_A7', '7,7,7', '77', '', ''), - (10, -1, '拍子区域配置', 'lid_area', '坐标', '硬件代号', '', ''), - (11, 10, '拍子存放区', 'lid_area_A8', '8,8,8', '88', '', ''), - (12, -1, '其他系统配置', 'sys_setting', '系统配置的值', '', '', ''), - (13, 12, '溶液量低提示', 'sys_setting_volume', '300', '', '', ''), - (14, 12, '异常处理区', 'sys_setting_abnormal_area', '7', '', '', ''), - (15, 12, '设备信息', 'sys_setting_info', '12345', '', '', ''), - (16, -1, '偏移量', 'sys_offset', '毫米', '', '', ''), - (17, 16, '试管半径', 'sys_offset_tube_radius', '100', '', '', ''), - (18, 16, '试管圆心间距', 'sys_offset_tube_distance', '100', '', '', ''), - (19, 16, '试管高度', 'sys_offset_tube_height', '300', '', '', ''), - (20, 16, '试管架高度', 'sys_offset_tube_rack_height', '280', '', '', ''), - (21, 16, '拍子高度', 'sys_offset_lid_height', '350', '', '', ''), - (22, 16, '试管夹取高度', 'sys_offset_tube_take_height', '10', '', '', ''), - (23, 16, '拍子夹取高度', 'sys_offset_lid_take_height', '10', '', '', ''), - (24, 16, '试管架夹取高度', 'sys_offset_tube_rack_take_height', '10', '', '', ''); - - --- 创建 solutions 溶液 表 -CREATE TABLE IF NOT EXISTS solutions -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR NOT NULL, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (1, '硫酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (2, '盐酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (3, '硝酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (4, '氢氟酸', '2025-02-18 02:46:23', '2025-02-18 02:46:23'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (5, '过氧酸', '2025-02-18 02:46:35', '2025-02-18 02:46:35'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (6, '磷酸', '2025-02-18 02:46:43', '2025-02-18 02:46:43'); -INSERT INTO "solutions" ("id", "name", "create_time", "update_time") -VALUES (7, '纯水', '2025-02-18 02:46:50', '2025-02-18 02:46:50'); - - --- 创建 ores 矿石 表 -CREATE TABLE IF NOT EXISTS ores -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR NOT NULL, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - -INSERT INTO "ores" ("id", "name", "create_time", "update_time") -VALUES (1, '金矿石', '2025-02-18 02:47:35', '2025-02-18 02:47:35'); -INSERT INTO "ores" ("id", "name", "create_time", "update_time") -VALUES (2, '银矿石', '2025-02-18 02:47:41', '2025-02-18 02:47:41'); - --- 创建 crafts 工艺 表 -CREATE TABLE IF NOT EXISTS crafts -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR NOT NULL, - steps TEXT, - ores_id INTEGER, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - -INSERT INTO "crafts" ("name", "steps", "ores_id") -VALUES ('测试工艺1', - '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', - 1); -INSERT INTO "crafts" ("name", "steps", "ores_id") -VALUES ('测试工艺2', - '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', - 1); -INSERT INTO "crafts" ("name", "steps", "ores_id") -VALUES ('测试工艺3', - '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', - 1); - --- 创建 tasks 实验 -CREATE TABLE IF NOT EXISTS tasks -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR NOT NULL, - start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - end_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - status INTEGER, - create_user INTEGER, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - is_deleted INTEGER -); --- 创建 container 容器 -CREATE TABLE IF NOT EXISTS container -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - type INTEGER, - solution_id INTEGER, - pump_id TEXT, - capacity_total INTEGER, - capacity_used INTEGER -); -INSERT INTO container (id, type, solution_id, pump_id, capacity_total, capacity_used) -VALUES (1, 0, 1, 'P001', 5000, 0), - (2, 0, 2, 'P002', 5000, 2500), - (3, 0, 3, 'P003', 5000, 2600), - (4, 0, 4, 'P004', 5000, 4000), - (5, 0, 5, 'P005', 5000, 2400), - (6, 0, 6, 'P006', 5000, 4500), - (7, 0, 7, 'P007', 5000, 4900), - (8, 0, 3, 'P008', 5000, 100), - (9, 1, null, 'P009', 5000, 0); --- 创建 logs 日志 -CREATE TABLE IF NOT EXISTS logs -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - text TEXT, - create_user INTEGER, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- 创建 task_steps 步骤记录 -CREATE TABLE IF NOT EXISTS task_steps -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id INTEGER, - step_description TEXT, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- 创建 ctrl_func 设备控制方法记录表 -CREATE TABLE ctrl_func -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - func_cmd TEXT NOT NULL, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -INSERT INTO ctrl_func (name, func_cmd) -VALUES ('开门', 'openDoor'), - ('关门', 'closeDoor'), - ('张开夹爪', 'openClaw'), - ('收合夹爪', 'closeClaw'), - ('移至加热区', 'moveToHeatArea'), - ('移动单个试管', 'moveTube'), - ('移至加液区', 'moveToActionArea'), - ('拍照', 'takePhoto'), - ('开始加热', 'startHeat'), - ('停止加热', 'stopHeat'), - ('开始摇匀', 'startShakeUp'), - ('结束摇匀', 'stopShakeUp'), - ('添加溶液', 'injectFluid'), - ('机械臂移动至指定坐标', 'moveMachineArm'), - ('抬起托盘', 'upTray'), - ('降下托盘', 'downTray'); - - --- 创建 ctrl_func_step 设备控制方法步骤表,params为null的话会从传入参数获取 -CREATE TABLE ctrl_func_step -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - func_cmd TEXT NOT NULL, - device_cmd TEXT NOT NULL, - remarks TEXT, - params TEXT, - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -INSERT INTO ctrl_func_step (func_cmd, device_cmd, remarks, params) -VALUES ('openDoor', 'openDoor', null, null), - ('openDoor', 'openDoor', null, null), - ('openDoor', 'openDoor', null, null); diff --git a/sql/init.sql b/sql/init.sql new file mode 100644 index 0000000..25e0ee8 --- /dev/null +++ b/sql/init.sql @@ -0,0 +1,233 @@ +-- 创建 sys_user 表 +CREATE TABLE IF NOT EXISTS sys_user +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + nickname TEXT, + password TEXT NOT NULL, + avatar TEXT, + role INTEGER, + is_deleted INTEGER DEFAULT 0, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 插入测试数据 +INSERT INTO sys_user (username, nickname, password, avatar, role, is_deleted) +VALUES ('admin', 'Admin', '12345', 'admin.png', 1, 0), + ('john_doe', 'John Doe', 'password123', 'avatar1.png', 2, 0), + ('test', 'test', 'test123', 'avatar2.png', 3, 0); + + +-- 创建 sys_role 表 +CREATE TABLE IF NOT EXISTS sys_role +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + code TEXT NOT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 插入角色数据 +INSERT INTO sys_role (name, code) +VALUES ('管理员', 'ADMIN'), + ('普通用户', 'USER'), + ('测试用户', 'TEST'); + +-- 创建 系统配置 表 +CREATE TABLE IF NOT EXISTS sys_settings +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + parent_id INTEGER NOT NULL, + name TEXT NOT NULL, + code TEXT, + value1 TEXT, + value2 TEXT, + value3 TEXT, + value4 TEXT +); +INSERT INTO sys_settings (id, parent_id, name, code, value1, value2, value3, value4) +VALUES (1, -1, '加热区域配置', 'heat_area', '坐标', '硬件代号', '温度', '工艺id'), + (2, 1, 'A1', 'heat_area_A1', '1,1,1', 'hardware_1', '1', ''), + (3, 1, 'A2', 'heat_area_A2', '2,2,2', 'hardware_2', '2', ''), + (4, 1, 'A3', 'heat_area_A3', '3,3,3', 'hardware_3', '3', ''), + (5, 1, 'A4', 'heat_area_A4', '4,4,4', 'hardware_4', '4', ''), + (6, 1, 'A5', 'heat_area_A5', '5,5,5', 'hardware_5', '5', ''), + (7, 1, 'A6', 'heat_area_A6', '6,6,6', 'hardware_6', '6', ''), + (8, -1, '加液区域配置', 'solution_area', '坐标', '硬件代号', '', ''), + (9, 8, '加液区', 'solution_area_A7', '7,7,7', '77', '', ''), + (10, -1, '拍子区域配置', 'lid_area', '坐标', '硬件代号', '', ''), + (11, 10, '拍子存放区', 'lid_area_A8', '8,8,8', '88', '', ''), + (12, -1, '其他系统配置', 'sys_setting', '系统配置的值', '', '', ''), + (13, 12, '溶液量低提示', 'sys_setting_volume', '300', '', '', ''), + (14, 12, '异常处理区', 'sys_setting_abnormal_area', '7', '', '', ''), + (15, 12, '设备信息', 'sys_setting_info', '12345', '', '', ''), + (16, -1, '偏移量', 'sys_offset', '毫米', '', '', ''), + (17, 16, '试管半径', 'sys_offset_tube_radius', '100', '', '', ''), + (18, 16, '试管圆心间距', 'sys_offset_tube_distance', '100', '', '', ''), + (19, 16, '试管高度', 'sys_offset_tube_height', '300', '', '', ''), + (20, 16, '试管架高度', 'sys_offset_tube_rack_height', '280', '', '', ''), + (21, 16, '拍子高度', 'sys_offset_lid_height', '350', '', '', ''), + (22, 16, '试管夹取高度', 'sys_offset_tube_take_height', '10', '', '', ''), + (23, 16, '拍子夹取高度', 'sys_offset_lid_take_height', '10', '', '', ''), + (24, 16, '试管架夹取高度', 'sys_offset_tube_rack_take_height', '10', '', '', ''); + + +-- 创建 solutions 溶液 表 +CREATE TABLE IF NOT EXISTS solutions +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR NOT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (1, '硫酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (2, '盐酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (3, '硝酸', '2025-02-18 02:44:07', '2025-02-18 02:44:07'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (4, '氢氟酸', '2025-02-18 02:46:23', '2025-02-18 02:46:23'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (5, '过氧酸', '2025-02-18 02:46:35', '2025-02-18 02:46:35'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (6, '磷酸', '2025-02-18 02:46:43', '2025-02-18 02:46:43'); +INSERT INTO "solutions" ("id", "name", "create_time", "update_time") +VALUES (7, '纯水', '2025-02-18 02:46:50', '2025-02-18 02:46:50'); + + +-- 创建 ores 矿石 表 +CREATE TABLE IF NOT EXISTS ores +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR NOT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO "ores" ("id", "name", "create_time", "update_time") +VALUES (1, '金矿石', '2025-02-18 02:47:35', '2025-02-18 02:47:35'); +INSERT INTO "ores" ("id", "name", "create_time", "update_time") +VALUES (2, '银矿石', '2025-02-18 02:47:41', '2025-02-18 02:47:41'); + +-- 创建 crafts 工艺 表 +CREATE TABLE IF NOT EXISTS crafts +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR NOT NULL, + steps TEXT, + ores_id INTEGER, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO "crafts" ("name", "steps", "ores_id") +VALUES ('测试工艺1', + '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', + 1); +INSERT INTO "crafts" ("name", "steps", "ores_id") +VALUES ('测试工艺2', + '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', + 1); +INSERT INTO "crafts" ("name", "steps", "ores_id") +VALUES ('测试工艺3', + '[{"method":"upTray"},{"method":"downTray"},{"method":"addLiquid","params":{"tubeSolList":[{"tubeNum":15,"addLiquidList":[{"solId":15,"volume":20}]}]}},{"method":"moveToSol"},{"method":"moveToHeat"},{"method":"shaking","params":{"second":6}},{"method":"startHeating","params":{"temperature":200}},{"method":"stopHeating"},{"method":"takePhoto"},{"method":"delay","params":{"second":2}}]', + 1); + +-- 创建 tasks 实验 +CREATE TABLE IF NOT EXISTS tasks +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR NOT NULL, + start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + end_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + status INTEGER, + create_user INTEGER, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_deleted INTEGER +); +-- 创建 container 容器 +CREATE TABLE IF NOT EXISTS container +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + solution_id INTEGER, + pump_id TEXT, + capacity_total INTEGER, + capacity_used INTEGER +); +INSERT INTO container (id, type, solution_id, pump_id, capacity_total, capacity_used) +VALUES (1, 0, 1, 'P001', 5000, 0), + (2, 0, 2, 'P002', 5000, 2500), + (3, 0, 3, 'P003', 5000, 2600), + (4, 0, 4, 'P004', 5000, 4000), + (5, 0, 5, 'P005', 5000, 2400), + (6, 0, 6, 'P006', 5000, 4500), + (7, 0, 7, 'P007', 5000, 4900), + (8, 0, 3, 'P008', 5000, 100), + (9, 1, null, 'P009', 5000, 0); +-- 创建 logs 日志 +CREATE TABLE IF NOT EXISTS logs +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + text TEXT, + create_user INTEGER, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 创建 task_steps 步骤记录 +CREATE TABLE IF NOT EXISTS task_steps +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id INTEGER, + step_description TEXT, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 创建 ctrl_func 设备控制方法记录表 +CREATE TABLE ctrl_func +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + func_cmd TEXT NOT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +INSERT INTO ctrl_func (name, func_cmd) +VALUES ('开门', 'openDoor'), + ('关门', 'closeDoor'), + ('张开夹爪', 'openClaw'), + ('收合夹爪', 'closeClaw'), + ('移至加热区', 'moveToHeatArea'), + ('移动单个试管', 'moveTube'), + ('移至加液区', 'moveToActionArea'), + ('拍照', 'takePhoto'), + ('开始加热', 'startHeat'), + ('停止加热', 'stopHeat'), + ('开始摇匀', 'startShakeUp'), + ('结束摇匀', 'stopShakeUp'), + ('添加溶液', 'injectFluid'), + ('机械臂移动至指定坐标', 'moveMachineArm'), + ('抬起托盘', 'upTray'), + ('降下托盘', 'downTray'); + + +-- 创建 ctrl_func_step 设备控制方法步骤表,params为null的话会从传入参数获取 +CREATE TABLE ctrl_func_step +( + id INTEGER PRIMARY KEY AUTOINCREMENT, + func_cmd TEXT NOT NULL, + device_cmd TEXT NOT NULL, + remarks TEXT, + params TEXT, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +INSERT INTO ctrl_func_step (func_cmd, device_cmd, remarks, params) +VALUES ('openDoor', 'openDoor', null, null), + ('openDoor', 'openDoor', null, null), + ('openDoor', 'openDoor', null, null); diff --git a/src/main/java/com/qyft/gd/device/Listener/LiquidTrayStatusChangedListener.java b/src/main/java/com/qyft/gd/device/Listener/LiquidTrayStatusChangedListener.java deleted file mode 100644 index 91386c7..0000000 --- a/src/main/java/com/qyft/gd/device/Listener/LiquidTrayStatusChangedListener.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.qyft.gd.device.Listener; - -import com.qyft.gd.device.event.LiquidTrayStatusChangedEvent; -import com.qyft.gd.device.model.bo.DeviceStatus; -import com.qyft.gd.device.service.DeviceOperationalService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -@RequiredArgsConstructor -public class LiquidTrayStatusChangedListener { - private final DeviceOperationalService deviceOperationalService; - - @EventListener - @Async - public void handleDeviceStatusChanged(LiquidTrayStatusChangedEvent event) { - DeviceStatus deviceStatus = event.getDeviceStatus(); - // 在这里处理设备状态变化的逻辑 - if (deviceStatus.getDoorStatus()) {//开门 - if (deviceStatus.getLiquidArea().getLiquidTray()) { - //放入了托盘 - log.info("用户放入了托盘"); - deviceOperationalService.putTray(); - } else { - //取走了托盘 - log.info("用户取走了托盘"); - deviceOperationalService.removeTray(); - } - } - } -} diff --git a/src/main/java/com/qyft/gd/device/client/TcpClient.java b/src/main/java/com/qyft/gd/device/client/TcpClient.java deleted file mode 100644 index 5ad2cc6..0000000 --- a/src/main/java/com/qyft/gd/device/client/TcpClient.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.qyft.gd.device.client; - -import cn.hutool.json.JSONUtil; -import com.qyft.gd.device.common.jsonrpc.JsonRpcRequest; -import com.qyft.gd.device.config.TcpConfig; -import com.qyft.gd.device.handler.DeviceMessageHandler; -import com.qyft.gd.device.model.bo.DeviceFeedback; -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.Unpooled; -import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.codec.json.JsonObjectDecoder; -import io.netty.util.CharsetUtil; -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -@Slf4j -@Component -@RequiredArgsConstructor -public class TcpClient { - - private final TcpConfig tcpConfig; - - private final DeviceMessageHandler deviceMessageHandler; - - private final EventLoopGroup group = new NioEventLoopGroup(); - private Channel channel; - private Bootstrap bootstrap; - - - @PostConstruct - public void init() { - if (tcpConfig.isEnable()) { - connect(); - } - } - - public void connect() { - try { - if (bootstrap == null) { - bootstrap = new Bootstrap(); - bootstrap.group(group) - .channel(NioSocketChannel.class) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, tcpConfig.getTimeout()) - .handler(new ChannelInitializer<>() { - @Override - protected void initChannel(Channel ch) { - ch.pipeline().addLast(new JsonObjectDecoder()); - ch.pipeline().addLast(deviceMessageHandler); - ch.pipeline().addLast(new TcpConnectionHandler()); - } - }); - } - - log.info("尝试连接到TCP服务 {}:{}", tcpConfig.getHost(), tcpConfig.getPort()); - ChannelFuture future = bootstrap.connect(new InetSocketAddress(tcpConfig.getHost(), tcpConfig.getPort())); - - future.addListener((ChannelFutureListener) f -> { - if (f.isSuccess()) { - channel = f.channel(); - log.info("已链接到TCP服务"); - } else { - log.error("无法连接到TCP服务. {}ms后重试...", tcpConfig.getReconnect()); - f.channel().eventLoop().schedule(this::connect, tcpConfig.getReconnect(), TimeUnit.MILLISECONDS); - } - }); - - } catch (Exception e) { - log.error("尝试连接到TCP服务发生意外错误: {}", e.getMessage(), e); - } - } - - @Scheduled(fixedRateString = "${tcp.reconnect}") - public void checkConnection() { - if (channel == null || !channel.isActive()) { - log.error("TCP服务链接丢失"); - connect(); - } - } - - public boolean send(String request) { - if (channel != null && channel.isActive()) { - channel.writeAndFlush(Unpooled.copiedBuffer(request, CharsetUtil.UTF_8)); - return true; - } else { - log.error("TCP服务未连接,无法发送请求: {}", request); - return false; - } - } - - public DeviceFeedback sendCommand(String method) { - JsonRpcRequest request = new JsonRpcRequest(); - request.setMethod(method); - return this.sendCommand(request); - } - - public DeviceFeedback sendCommand(String method, Map params) { - JsonRpcRequest request = new JsonRpcRequest(); - request.setMethod(method); - request.setParams(params); - return this.sendCommand(request); - } - - public DeviceFeedback sendCommand(JsonRpcRequest request) { - if (request.getId() == null) { - request.setId(UUID.randomUUID().toString()); - } - CompletableFuture future = new CompletableFuture<>(); - deviceMessageHandler.responseMap.put(request.getId(), future); - try { - if (request.getParams() == null) { - request.setParams(new HashMap<>()); - } - request.getParams().put("class", "test"); - String requestJsonStr = JSONUtil.toJsonStr(request); - log.info("发送TCP指令(同步) {}", requestJsonStr); - if (this.send(requestJsonStr)) { - return future.get(tcpConfig.getFeedbackTimeout(), TimeUnit.MILLISECONDS); // 等待 FEEDBACK 响应 - } else { - return null; - } - } catch (Exception e) { - log.error("发送TCP指令错误(同步) {}", JSONUtil.toJsonStr(request), e); - } finally { - deviceMessageHandler.responseMap.remove(request.getId()); //确保完成后移除 - } - return null; - } - - private class TcpConnectionHandler extends ChannelInboundHandlerAdapter { - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - // 连接断开时的处理逻辑 - log.error("TCP连接丢失,准备重新连接..."); - if (channel != null) { - channel.close(); - } - connect(); - super.channelInactive(ctx); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - log.error("TCP连接发生异常: {}", cause.getMessage(), cause); - ctx.close(); - } - } -} diff --git a/src/main/java/com/qyft/gd/device/core/client/TcpClient.java b/src/main/java/com/qyft/gd/device/core/client/TcpClient.java new file mode 100644 index 0000000..b7d733a --- /dev/null +++ b/src/main/java/com/qyft/gd/device/core/client/TcpClient.java @@ -0,0 +1,160 @@ +package com.qyft.gd.device.core.client; + +import cn.hutool.json.JSONUtil; +import com.qyft.gd.device.common.jsonrpc.JsonRpcRequest; +import com.qyft.gd.device.config.TcpConfig; +import com.qyft.gd.device.core.handler.DeviceMessageHandler; +import com.qyft.gd.device.model.bo.DeviceFeedback; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.json.JsonObjectDecoder; +import io.netty.util.CharsetUtil; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TcpClient { + + private final TcpConfig tcpConfig; + + private final DeviceMessageHandler deviceMessageHandler; + + private final EventLoopGroup group = new NioEventLoopGroup(); + private Channel channel; + private Bootstrap bootstrap; + + + @PostConstruct + public void init() { + if (tcpConfig.isEnable()) { + connect(); + } + } + + public void connect() { + try { + if (bootstrap == null) { + bootstrap = new Bootstrap(); + bootstrap.group(group) + .channel(NioSocketChannel.class) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, tcpConfig.getTimeout()) + .handler(new ChannelInitializer<>() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new JsonObjectDecoder()); + ch.pipeline().addLast(deviceMessageHandler); + ch.pipeline().addLast(new TcpConnectionHandler()); + } + }); + } + + log.info("尝试连接到TCP服务 {}:{}", tcpConfig.getHost(), tcpConfig.getPort()); + ChannelFuture future = bootstrap.connect(new InetSocketAddress(tcpConfig.getHost(), tcpConfig.getPort())); + + future.addListener((ChannelFutureListener) f -> { + if (f.isSuccess()) { + channel = f.channel(); + log.info("已链接到TCP服务"); + } else { + log.error("无法连接到TCP服务. {}ms后重试...", tcpConfig.getReconnect()); + f.channel().eventLoop().schedule(this::connect, tcpConfig.getReconnect(), TimeUnit.MILLISECONDS); + } + }); + + } catch (Exception e) { + log.error("尝试连接到TCP服务发生意外错误: {}", e.getMessage(), e); + } + } + + @Scheduled(fixedRateString = "${tcp.reconnect}") + public void checkConnection() { + if (channel == null || !channel.isActive()) { + log.error("TCP服务链接丢失"); + connect(); + } + } + + public boolean send(String request) { + if (channel != null && channel.isActive()) { + channel.writeAndFlush(Unpooled.copiedBuffer(request, CharsetUtil.UTF_8)); + return true; + } else { + log.error("TCP服务未连接,无法发送请求: {}", request); + return false; + } + } + + public DeviceFeedback sendCommand(String method) { + JsonRpcRequest request = new JsonRpcRequest(); + request.setMethod(method); + return this.sendCommand(request); + } + + public DeviceFeedback sendCommand(String method, Map params) { + JsonRpcRequest request = new JsonRpcRequest(); + request.setMethod(method); + request.setParams(params); + return this.sendCommand(request); + } + + public DeviceFeedback sendCommand(JsonRpcRequest request) { + if (request.getId() == null) { + request.setId(UUID.randomUUID().toString()); + } + CompletableFuture future = new CompletableFuture<>(); + deviceMessageHandler.responseMap.put(request.getId(), future); + try { + if (request.getParams() == null) { + request.setParams(new HashMap<>()); + } + request.getParams().put("class", "test"); + String requestJsonStr = JSONUtil.toJsonStr(request); + log.info("发送TCP指令(同步) {}", requestJsonStr); + if (this.send(requestJsonStr)) { + return future.get(tcpConfig.getFeedbackTimeout(), TimeUnit.MILLISECONDS); // 等待 FEEDBACK 响应 + } else { + return null; + } + } catch (Exception e) { + log.error("发送TCP指令错误(同步) {}", JSONUtil.toJsonStr(request), e); + } finally { + deviceMessageHandler.responseMap.remove(request.getId()); //确保完成后移除 + } + return null; + } + + private class TcpConnectionHandler extends ChannelInboundHandlerAdapter { + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + // 连接断开时的处理逻辑 + log.error("TCP连接丢失,准备重新连接..."); + if (channel != null) { + channel.close(); + } + connect(); + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + log.error("TCP连接发生异常: {}", cause.getMessage(), cause); + ctx.close(); + } + } +} diff --git a/src/main/java/com/qyft/gd/device/core/event/LiquidTrayStatusChangedEvent.java b/src/main/java/com/qyft/gd/device/core/event/LiquidTrayStatusChangedEvent.java new file mode 100644 index 0000000..fa3eac3 --- /dev/null +++ b/src/main/java/com/qyft/gd/device/core/event/LiquidTrayStatusChangedEvent.java @@ -0,0 +1,19 @@ +package com.qyft.gd.device.core.event; + +import com.qyft.gd.device.model.bo.DeviceStatus; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +/** + * 加液区托盘状态发生变化事件 + */ +@Getter +public class LiquidTrayStatusChangedEvent extends ApplicationEvent { + private final DeviceStatus deviceStatus; + + public LiquidTrayStatusChangedEvent(Object source, DeviceStatus deviceStatus) { + super(source); + this.deviceStatus = deviceStatus; + } + +} diff --git a/src/main/java/com/qyft/gd/device/core/handler/DeviceMessageHandler.java b/src/main/java/com/qyft/gd/device/core/handler/DeviceMessageHandler.java new file mode 100644 index 0000000..e7870f0 --- /dev/null +++ b/src/main/java/com/qyft/gd/device/core/handler/DeviceMessageHandler.java @@ -0,0 +1,68 @@ +package com.qyft.gd.device.core.handler; + +import cn.hutool.json.JSONUtil; +import com.qyft.gd.app.common.constant.WebSocketMessageType; +import com.qyft.gd.device.common.constant.TcpMessageType; +import com.qyft.gd.device.common.jsonrpc.JsonRpcResponse; +import com.qyft.gd.device.model.bo.DeviceAlarm; +import com.qyft.gd.device.model.bo.DeviceFeedback; +import com.qyft.gd.device.model.bo.DeviceStatus; +import com.qyft.gd.device.service.DeviceStatusService; +import com.qyft.gd.app.service.WebSocketService; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.CharsetUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor +public class DeviceMessageHandler extends ChannelInboundHandlerAdapter { + + public final Map> responseMap = new ConcurrentHashMap<>(); + private final DeviceStatusService deviceStatusService; + private final WebSocketService webSocketService; + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + ByteBuf buf = (ByteBuf) msg; + String serverMsg = buf.toString(CharsetUtil.UTF_8); + try { + JsonRpcResponse jsonRpcResponse = JSONUtil.toBean(serverMsg, JsonRpcResponse.class); + if (TcpMessageType.STATUS.equals(jsonRpcResponse.getType())) {//设备状态 + DeviceStatus deviceStatus = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceStatus.class); + deviceStatusService.updateDeviceStatus(deviceStatus); // 更新设备状态 + } else if (TcpMessageType.ALARM.equals(jsonRpcResponse.getType())) {//设备报警 + log.error("设备报警: {}", serverMsg); + DeviceAlarm deviceAlarm = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceAlarm.class); + webSocketService.pushMsg(WebSocketMessageType.ALARM, deviceAlarm); + } else if (TcpMessageType.FEEDBACK.equals(jsonRpcResponse.getType())) {//设备指令反馈 + DeviceFeedback deviceFeedback = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceFeedback.class); + this.handleTcpResponse(deviceFeedback); + } + } catch (Exception e) { + log.error("TCP服务消息处理错误: {}, error: {}", serverMsg, e.getMessage(), e); + } finally { + buf.release(); + } + } + + private void handleTcpResponse(DeviceFeedback deviceFeedback) { + String requestId = deviceFeedback.getId(); + CompletableFuture future = responseMap.remove(requestId); + if (future != null) { + future.complete(deviceFeedback); + } else { + log.error("未找到 requestId: {} 对应的等待请求", requestId); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/qyft/gd/device/core/listener/LiquidTrayStatusChangedListener.java b/src/main/java/com/qyft/gd/device/core/listener/LiquidTrayStatusChangedListener.java new file mode 100644 index 0000000..8dab4af --- /dev/null +++ b/src/main/java/com/qyft/gd/device/core/listener/LiquidTrayStatusChangedListener.java @@ -0,0 +1,35 @@ +package com.qyft.gd.device.core.listener; + +import com.qyft.gd.device.core.event.LiquidTrayStatusChangedEvent; +import com.qyft.gd.device.model.bo.DeviceStatus; +import com.qyft.gd.device.service.DeviceOperationalService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class LiquidTrayStatusChangedListener { + private final DeviceOperationalService deviceOperationalService; + + @EventListener + @Async + public void handleDeviceStatusChanged(LiquidTrayStatusChangedEvent event) { + DeviceStatus deviceStatus = event.getDeviceStatus(); + // 在这里处理设备状态变化的逻辑 + if (deviceStatus.getDoorStatus()) {//开门 + if (deviceStatus.getLiquidArea().getLiquidTray()) { + //放入了托盘 + log.info("用户放入了托盘"); + deviceOperationalService.putTray(); + } else { + //取走了托盘 + log.info("用户取走了托盘"); + deviceOperationalService.removeTray(); + } + } + } +} diff --git a/src/main/java/com/qyft/gd/device/event/LiquidTrayStatusChangedEvent.java b/src/main/java/com/qyft/gd/device/event/LiquidTrayStatusChangedEvent.java deleted file mode 100644 index 5679532..0000000 --- a/src/main/java/com/qyft/gd/device/event/LiquidTrayStatusChangedEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.qyft.gd.device.event; - -import com.qyft.gd.device.model.bo.DeviceStatus; -import lombok.Getter; -import org.springframework.context.ApplicationEvent; - -/** - * 加液区托盘状态发生变化事件 - */ -@Getter -public class LiquidTrayStatusChangedEvent extends ApplicationEvent { - private final DeviceStatus deviceStatus; - - public LiquidTrayStatusChangedEvent(Object source, DeviceStatus deviceStatus) { - super(source); - this.deviceStatus = deviceStatus; - } - -} diff --git a/src/main/java/com/qyft/gd/device/handler/DeviceMessageHandler.java b/src/main/java/com/qyft/gd/device/handler/DeviceMessageHandler.java deleted file mode 100644 index 3a3cf39..0000000 --- a/src/main/java/com/qyft/gd/device/handler/DeviceMessageHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.qyft.gd.device.handler; - -import cn.hutool.json.JSONUtil; -import com.qyft.gd.app.common.constant.WebSocketMessageType; -import com.qyft.gd.device.common.constant.TcpMessageType; -import com.qyft.gd.device.common.jsonrpc.JsonRpcResponse; -import com.qyft.gd.device.model.bo.DeviceAlarm; -import com.qyft.gd.device.model.bo.DeviceFeedback; -import com.qyft.gd.device.model.bo.DeviceStatus; -import com.qyft.gd.device.service.DeviceStatusService; -import com.qyft.gd.app.service.WebSocketService; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.util.CharsetUtil; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; - -@Slf4j -@Component -@ChannelHandler.Sharable -@RequiredArgsConstructor -public class DeviceMessageHandler extends ChannelInboundHandlerAdapter { - - public final Map> responseMap = new ConcurrentHashMap<>(); - private final DeviceStatusService deviceStatusService; - private final WebSocketService webSocketService; - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - ByteBuf buf = (ByteBuf) msg; - String serverMsg = buf.toString(CharsetUtil.UTF_8); - try { - JsonRpcResponse jsonRpcResponse = JSONUtil.toBean(serverMsg, JsonRpcResponse.class); - if (TcpMessageType.STATUS.equals(jsonRpcResponse.getType())) {//设备状态 - DeviceStatus deviceStatus = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceStatus.class); - deviceStatusService.updateDeviceStatus(deviceStatus); // 更新设备状态 - } else if (TcpMessageType.ALARM.equals(jsonRpcResponse.getType())) {//设备报警 - log.error("设备报警: {}", serverMsg); - DeviceAlarm deviceAlarm = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceAlarm.class); - webSocketService.pushMsg(WebSocketMessageType.ALARM, deviceAlarm); - } else if (TcpMessageType.FEEDBACK.equals(jsonRpcResponse.getType())) {//设备指令反馈 - DeviceFeedback deviceFeedback = JSONUtil.toBean(jsonRpcResponse.getData(), DeviceFeedback.class); - this.handleTcpResponse(deviceFeedback); - } - } catch (Exception e) { - log.error("TCP服务消息处理错误: {}, error: {}", serverMsg, e.getMessage(), e); - } finally { - buf.release(); - } - } - - private void handleTcpResponse(DeviceFeedback deviceFeedback) { - String requestId = deviceFeedback.getId(); - CompletableFuture future = responseMap.remove(requestId); - if (future != null) { - future.complete(deviceFeedback); - } else { - log.error("未找到 requestId: {} 对应的等待请求", requestId); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/qyft/gd/device/service/DeviceStatusService.java b/src/main/java/com/qyft/gd/device/service/DeviceStatusService.java index 2e21f63..e11712c 100644 --- a/src/main/java/com/qyft/gd/device/service/DeviceStatusService.java +++ b/src/main/java/com/qyft/gd/device/service/DeviceStatusService.java @@ -1,12 +1,11 @@ package com.qyft.gd.device.service; import cn.hutool.core.bean.BeanUtil; -import com.qyft.gd.device.event.LiquidTrayStatusChangedEvent; +import com.qyft.gd.device.core.event.LiquidTrayStatusChangedEvent; import com.qyft.gd.device.model.bo.DeviceOperationalStatus; import com.qyft.gd.device.model.bo.DeviceStatus; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/qyft/gd/device/service/DeviceTcpCMDService.java b/src/main/java/com/qyft/gd/device/service/DeviceTcpCMDService.java index 5330c46..35d8bb0 100644 --- a/src/main/java/com/qyft/gd/device/service/DeviceTcpCMDService.java +++ b/src/main/java/com/qyft/gd/device/service/DeviceTcpCMDService.java @@ -1,7 +1,7 @@ package com.qyft.gd.device.service; import cn.hutool.json.JSONUtil; -import com.qyft.gd.device.client.TcpClient; +import com.qyft.gd.device.core.client.TcpClient; import com.qyft.gd.device.common.constant.DeviceCommands; import com.qyft.gd.device.common.jsonrpc.JsonRpcRequest; import com.qyft.gd.device.model.bo.DeviceFeedback; diff --git a/src/main/java/com/qyft/gd/system/config/FilterConfig.java b/src/main/java/com/qyft/gd/system/config/FilterConfig.java index f669a18..d3d6974 100644 --- a/src/main/java/com/qyft/gd/system/config/FilterConfig.java +++ b/src/main/java/com/qyft/gd/system/config/FilterConfig.java @@ -1,6 +1,6 @@ package com.qyft.gd.system.config; -import com.qyft.gd.system.filter.JwtAuthenticationFilter; +import com.qyft.gd.system.core.filter.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/com/qyft/gd/system/config/MybatisPlusConfig.java b/src/main/java/com/qyft/gd/system/config/MybatisPlusConfig.java index 516f4cf..23e964c 100644 --- a/src/main/java/com/qyft/gd/system/config/MybatisPlusConfig.java +++ b/src/main/java/com/qyft/gd/system/config/MybatisPlusConfig.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; -import com.qyft.gd.system.core.MyMetaObjectHandler; +import com.qyft.gd.system.core.handler.MyMetaObjectHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; diff --git a/src/main/java/com/qyft/gd/system/core/MyMetaObjectHandler.java b/src/main/java/com/qyft/gd/system/core/MyMetaObjectHandler.java deleted file mode 100644 index 1895341..0000000 --- a/src/main/java/com/qyft/gd/system/core/MyMetaObjectHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.qyft.gd.system.core; - -import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; -import org.apache.ibatis.reflection.MetaObject; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; - -/** - * mybatis-plus 字段自动填充 - */ -@Component -public class MyMetaObjectHandler implements MetaObjectHandler { - - /** - * 新增填充创建时间 - * - * @param metaObject 元数据 - */ - @Override - public void insertFill(MetaObject metaObject) { - this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class); - this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); - } - - /** - * 更新填充更新时间 - * - * @param metaObject 元数据 - */ - @Override - public void updateFill(MetaObject metaObject) { - this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); - } - -} diff --git a/src/main/java/com/qyft/gd/system/core/filter/JwtAuthenticationFilter.java b/src/main/java/com/qyft/gd/system/core/filter/JwtAuthenticationFilter.java new file mode 100644 index 0000000..58cb243 --- /dev/null +++ b/src/main/java/com/qyft/gd/system/core/filter/JwtAuthenticationFilter.java @@ -0,0 +1,52 @@ +package com.qyft.gd.system.core.filter; + +import com.qyft.gd.system.common.result.ResultCode; +import com.qyft.gd.system.common.utils.JwtUtil; +import com.qyft.gd.system.common.utils.ResponseUtils; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Value("${jwt.enabled:true}") // 从配置文件中读取 jwt.enabled,默认为 true + private boolean jwtEnabled; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String token = getTokenFromRequest(request); + if (shouldBypass(request)) { + filterChain.doFilter(request, response); + return; + } + if (token != null && JwtUtil.parseJWE(token) != null) { + request.setAttribute("token", token); // 可以将 token 存储在 request 属性中,供后续使用 + } else { + if (jwtEnabled) { + ResponseUtils.writeErrMsg(response, ResultCode.ACCESS_TOKEN_INVALID); + return; + } + } + filterChain.doFilter(request, response); + } + + private boolean shouldBypass(HttpServletRequest request) { + String uri = request.getRequestURI(); + return uri.startsWith("/api/auth/login"); + } + + private String getTokenFromRequest(HttpServletRequest request) { + String header = request.getHeader("Authorization"); + if (header != null && header.startsWith("Bearer ")) { + return header.substring(7); // 截取 "Bearer " 后的 token 部分 + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/qyft/gd/system/core/handler/MyMetaObjectHandler.java b/src/main/java/com/qyft/gd/system/core/handler/MyMetaObjectHandler.java new file mode 100644 index 0000000..ed88e39 --- /dev/null +++ b/src/main/java/com/qyft/gd/system/core/handler/MyMetaObjectHandler.java @@ -0,0 +1,36 @@ +package com.qyft.gd.system.core.handler; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * mybatis-plus 字段自动填充 + */ +@Component +public class MyMetaObjectHandler implements MetaObjectHandler { + + /** + * 新增填充创建时间 + * + * @param metaObject 元数据 + */ + @Override + public void insertFill(MetaObject metaObject) { + this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class); + this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); + } + + /** + * 更新填充更新时间 + * + * @param metaObject 元数据 + */ + @Override + public void updateFill(MetaObject metaObject) { + this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); + } + +} diff --git a/src/main/java/com/qyft/gd/system/filter/JwtAuthenticationFilter.java b/src/main/java/com/qyft/gd/system/filter/JwtAuthenticationFilter.java deleted file mode 100644 index 41398ff..0000000 --- a/src/main/java/com/qyft/gd/system/filter/JwtAuthenticationFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.qyft.gd.system.filter; - -import com.qyft.gd.system.common.result.ResultCode; -import com.qyft.gd.system.common.utils.JwtUtil; -import com.qyft.gd.system.common.utils.ResponseUtils; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; - -@Component -public class JwtAuthenticationFilter extends OncePerRequestFilter { - - @Value("${jwt.enabled:true}") // 从配置文件中读取 jwt.enabled,默认为 true - private boolean jwtEnabled; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String token = getTokenFromRequest(request); - if (shouldBypass(request)) { - filterChain.doFilter(request, response); - return; - } - if (token != null && JwtUtil.parseJWE(token) != null) { - request.setAttribute("token", token); // 可以将 token 存储在 request 属性中,供后续使用 - } else { - if (jwtEnabled) { - ResponseUtils.writeErrMsg(response, ResultCode.ACCESS_TOKEN_INVALID); - return; - } - } - filterChain.doFilter(request, response); - } - - private boolean shouldBypass(HttpServletRequest request) { - String uri = request.getRequestURI(); - return uri.startsWith("/api/auth/login"); - } - - private String getTokenFromRequest(HttpServletRequest request) { - String header = request.getHeader("Authorization"); - if (header != null && header.startsWith("Bearer ")) { - return header.substring(7); // 截取 "Bearer " 后的 token 部分 - } - return null; - } -} \ No newline at end of file