mqttTemplate;
+
+ /** 默认配置 */
+ private DefaultConfig defaults = new DefaultConfig();
+
+ /** 配置 RestTemplate Bean */
+ @Bean
+ public RestTemplate restTemplate() {
+ SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+ factory.setConnectTimeout(5000); // 连接超时5秒
+ factory.setReadTimeout(10000); // 读取超时10秒
+ return new RestTemplate(factory);
+ }
+
+ @Data
+ public static class DefaultConfig {
+
+ /** 默认端口 */
+ private int defaultPort = 8080;
+
+ /** 默认超时时间 */
+ private int defaultTimeout = 30;
+
+ /** 默认心跳间隔 */
+ private int defaultKeepAlive = 60;
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/doc/NetworkApiDoc.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/doc/NetworkApiDoc.java
new file mode 100644
index 0000000..8066702
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/doc/NetworkApiDoc.java
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.doc;
+
+/**
+ * 网络组件API文档
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+public class NetworkApiDoc {
+
+ /**
+ * 网络组件管理API文档
+ *
+ * 基础路径: /admin/network
+ *
+ *
1. 查询网络组件列表 GET /admin/network/list 参数: - page: 页码 (可选,默认1) - size: 每页大小 (可选,默认10) - type:
+ * 网络类型 (可选,单个类型,如 TCP_CLIENT) - types: 网络类型列表 (可选,多个类型,如 ["MQTT_CLIENT", "MQTT_SERVER"]) - name:
+ * 网络组件名称 (可选,模糊查询) - productKey: 产品Key (可选) - state: 状态 (可选,true/false) - unionId: 唯一标识 (可选)
+ *
+ *
2. 查询网络组件列表(支持多个类型) GET /admin/network/list/multi-type 参数: - page: 页码 (可选,默认1) - size: 每页大小
+ * (可选,默认10) - type: 网络类型 (可选,支持逗号分隔多个类型,如 "MQTT_CLIENT,MQTT_SERVER") - name: 网络组件名称 (可选,模糊查询) -
+ * productKey: 产品Key (可选) - state: 状态 (可选,true/false) - unionId: 唯一标识 (可选)
+ *
+ *
3. 根据ID查询网络组件 GET /admin/network/{id} 参数: - id: 网络组件ID (路径参数)
+ *
+ *
4. 新增网络组件 POST /admin/network 请求体: { "type": "TCP_SERVER", "unionId": "unique_id",
+ * "productKey": "product_key", "name": "网络组件名称", "description": "详细描述", "state": false,
+ * "configuration": "{\"host\":\"0.0.0.0\",\"port\":6372,\"ssl\":false}", "createUser": "admin" }
+ *
+ *
5. 修改网络组件 PUT /admin/network 请求体: { "id": 1, "type": "TCP_SERVER", "unionId": "unique_id",
+ * "productKey": "product_key", "name": "网络组件名称", "description": "详细描述", "state": false,
+ * "configuration": "{\"host\":\"0.0.0.0\",\"port\":6372,\"ssl\":false}" }
+ *
+ *
6. 删除网络组件 DELETE /admin/network/{id} 参数: - id: 网络组件ID (路径参数)
+ *
+ *
7. 批量删除网络组件 DELETE /admin/network/batch/{ids} 参数: - ids: 网络组件ID数组 (路径参数,逗号分隔)
+ *
+ *
8. 启动网络组件 POST /admin/network/start/{id} 参数: - id: 网络组件ID (路径参数)
+ *
+ *
9. 停止网络组件 POST /admin/network/stop/{id} 参数: - id: 网络组件ID (路径参数)
+ *
+ *
10. 重启网络组件 POST /admin/network/restart/{id} 参数: - id: 网络组件ID (路径参数)
+ *
+ *
11. 获取网络类型列表 GET /admin/network/types
+ *
+ *
12. 验证网络组件配置 POST /admin/network/validate 请求体: { "type": "TCP_SERVER", "unionId":
+ * "unique_id", "name": "网络组件名称", "configuration":
+ * "{\"host\":\"0.0.0.0\",\"port\":6372,\"ssl\":false}" }
+ *
+ *
响应格式: { "code": 200, "msg": "操作成功", "data": { // 具体数据 } }
+ *
+ *
网络类型说明: - TCP_CLIENT: TCP客户端 - TCP_SERVER: TCP服务端 - MQTT_CLIENT: MQTT客户端 - MQTT_SERVER:
+ * MQTT服务端
+ *
+ *
配置示例:
+ *
+ *
TCP_SERVER配置: { "allIdleTime": 0, "allowInsert": false, "alwaysPreDecode": false,
+ * "decoderType": "STRING", "host": "0.0.0.0", "idleInterval": 0, "onlyCache": false,
+ * "parserConfiguration": { "byteOrderLittle": true, "delimited": "]", "delimitedMaxlength": 1024,
+ * "failFast": true }, "parserType": "DELIMITED", "port": 6372, "productKey":
+ * "630477f1cd68445d90b04653", "readerIdleTime": 360, "readTimeout": 0, "sendTimeout": 0, "ssl":
+ * false, "writerIdleTime": 0 }
+ *
+ *
MQTT_SERVER配置: { "autoReconnect": true, "cleanSession": true, "clientIdPrefix": "univ_cli_",
+ * "defaultQos": 1, "enabled": true, "host": "tcp://125.210.48.96:1883", "id":
+ * "6863896d75386b5c1e7e908c", "keepAliveInterval": 60, "password": "univiot@2025!", "productKey":
+ * "local", "ssl": false, "subscribeTopics": "$univ_cli/up/property/+/+", "username": "univ_cli",
+ * "connectTimeout": 30 }
+ */
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/enums/NetworkTypeEnum.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/enums/NetworkTypeEnum.java
new file mode 100644
index 0000000..72ba20e
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/enums/NetworkTypeEnum.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 网络类型枚举
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+@Getter
+@AllArgsConstructor
+public enum NetworkTypeEnum {
+
+ /** TCP客户端 */
+ TCP_CLIENT("TCP_CLIENT", "TCP客户端", "tcp_parser_type"),
+
+ /** TCP服务端 */
+ TCP_SERVER("TCP_SERVER", "TCP服务端", "tcp_parser_type"),
+
+ /** MQTT客户端 */
+ MQTT_CLIENT("MQTT_CLIENT", "MQTT客户端", "mqtt_parser_type"),
+
+ /** MQTT服务端 */
+ MQTT_SERVER("MQTT_SERVER", "MQTT服务端", "mqtt_parser_type");
+
+ /** 类型代码 */
+ private final String code;
+
+ /** 类型名称 */
+ private final String name;
+
+ /** 字典类型 */
+ private final String dictType;
+
+ /**
+ * 根据代码获取枚举
+ *
+ * @param code 类型代码
+ * @return 枚举
+ */
+ public static NetworkTypeEnum getByCode(String code) {
+ for (NetworkTypeEnum type : values()) {
+ if (type.getCode().equals(code)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 根据代码获取名称
+ *
+ * @param code 类型代码
+ * @return 类型名称
+ */
+ public static String getNameByCode(String code) {
+ NetworkTypeEnum type = getByCode(code);
+ return type != null ? type.getName() : code;
+ }
+
+ /**
+ * 根据代码获取字典类型
+ *
+ * @param code 类型代码
+ * @return 字典类型
+ */
+ public static String getDictTypeByCode(String code) {
+ NetworkTypeEnum type = getByCode(code);
+ return type != null ? type.getDictType() : null;
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/service/INetworkService.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/service/INetworkService.java
new file mode 100644
index 0000000..08dbe55
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/service/INetworkService.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.service;
+
+import cn.universal.common.domain.R;
+import cn.universal.persistence.entity.IoTDevice;
+import cn.universal.persistence.entity.Network;
+import cn.universal.persistence.entity.bo.IoTDeviceBO;
+import cn.universal.persistence.entity.bo.NetworkBO;
+import cn.universal.persistence.entity.vo.NetworkVO;
+import cn.universal.persistence.query.NetworkQuery;
+import java.util.List;
+
+/**
+ * 网络组件Service接口
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+public interface INetworkService {
+
+ boolean start(String productKey);
+
+ boolean stop(String productKey);
+
+ Object get(String productKey);
+
+ boolean del(String productKey);
+
+ List selectNetworkList(NetworkBO bo);
+
+ NetworkVO getDetail(Long id);
+
+ List queryMileSightList(NetworkBO bo);
+
+ R insertDevInstance(IoTDeviceBO devInstancebo);
+
+ R deleteDevInstanceByIds(String[] ids);
+
+ void reloadTcpClient(String applicationId);
+
+ /**
+ * 查询网络组件列表
+ *
+ * @param query 查询条件
+ * @return 分页结果
+ */
+ List selectNetworkList(NetworkQuery query);
+
+ /**
+ * 根据ID查询网络组件
+ *
+ * @param id 网络组件ID
+ * @return 网络组件
+ */
+ NetworkVO selectNetworkById(Integer id);
+
+ /**
+ * 新增网络组件
+ *
+ * @param network 网络组件
+ * @return 结果
+ */
+ int insertNetwork(Network network);
+
+ /**
+ * 修改网络组件
+ *
+ * @param network 网络组件
+ * @return 结果
+ */
+ int updateNetwork(Network network);
+
+ /**
+ * 删除网络组件
+ *
+ * @param id 网络组件ID
+ * @return 结果
+ */
+ int deleteNetworkById(Integer id);
+
+ /**
+ * 批量删除网络组件
+ *
+ * @param ids 网络组件ID数组
+ * @return 结果
+ */
+ int deleteNetworkByIds(Integer[] ids);
+
+ /**
+ * 启动网络组件
+ *
+ * @param id 网络组件ID
+ * @return 结果
+ */
+ int startNetwork(Integer id);
+
+ /**
+ * 停止网络组件
+ *
+ * @param id 网络组件ID
+ * @return 结果
+ */
+ int stopNetwork(Integer id);
+
+ /**
+ * 重启网络组件
+ *
+ * @param id 网络组件ID
+ * @return 结果
+ */
+ int restartNetwork(Integer id);
+
+ /**
+ * 获取网络类型列表
+ *
+ * @return 网络类型列表
+ */
+ List getNetworkTypes();
+
+ /**
+ * 验证网络组件配置
+ *
+ * @param network 网络组件
+ * @return 验证结果
+ */
+ boolean validateNetworkConfig(Network network);
+
+ /**
+ * 根据ID查询设备
+ *
+ * @param id 设备ID
+ * @return 设备
+ */
+ IoTDevice getDeviceById(String id);
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/service/impl/NetworkServiceImpl.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/service/impl/NetworkServiceImpl.java
new file mode 100644
index 0000000..5f4038c
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/service/impl/NetworkServiceImpl.java
@@ -0,0 +1,884 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.universal.admin.common.utils.SecurityUtils;
+import cn.universal.admin.network.service.INetworkService;
+import cn.universal.admin.network.utils.NetworkTypeUtil;
+import cn.universal.common.constant.IoTConstant.DownCmd;
+import cn.universal.common.constant.NetworkTypeConstants;
+import cn.universal.common.domain.R;
+import cn.universal.common.enums.NetworkType;
+import cn.universal.common.exception.IoTException;
+import cn.universal.core.service.IoTDownlFactory;
+import cn.universal.mqtt.protocol.third.ThirdMQTTServerManager;
+import cn.universal.persistence.entity.IoTDevice;
+import cn.universal.persistence.entity.IoTProduct;
+import cn.universal.persistence.entity.IoTUser;
+import cn.universal.persistence.entity.Network;
+import cn.universal.persistence.entity.bo.IoTDeviceBO;
+import cn.universal.persistence.entity.bo.NetworkBO;
+import cn.universal.persistence.entity.vo.IoTProductVO;
+import cn.universal.persistence.entity.vo.NetworkVO;
+import cn.universal.persistence.mapper.IoTDeviceFenceRelMapper;
+import cn.universal.persistence.mapper.IoTDeviceMapper;
+import cn.universal.persistence.mapper.IoTProductMapper;
+import cn.universal.persistence.mapper.NetworkMapper;
+import cn.universal.persistence.query.NetworkQuery;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import jakarta.annotation.Resource;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import tk.mybatis.mapper.entity.Example;
+
+/**
+ * 网络组件Service实现类
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+@Slf4j
+@Service
+public class NetworkServiceImpl implements INetworkService {
+
+ @Autowired
+ private NetworkMapper networkMapper;
+
+ @Resource
+ private NetworkMapper netWorkMapper;
+ @Resource
+ private IoTDeviceMapper ioTDeviceMapper;
+ @Resource
+ private IoTProductMapper ioTProductMapper;
+ @Resource
+ private IoTDeviceFenceRelMapper ioTDeviceFenceRelMapper;
+
+
+ @Autowired(required = false)
+ private ThirdMQTTServerManager mqttServerManager;
+
+ @Override
+ public boolean start(String productKey) {
+
+ return true;
+ }
+
+ @Override
+ public boolean stop(String productKey) {
+
+ return true;
+ }
+
+ @Override
+ public Object get(String productKey) {
+ return null;
+ }
+
+ @Override
+ public boolean del(String productKey) {
+ Example ex = new Example(Network.class);
+ ex.createCriteria().andEqualTo("productKey", productKey);
+ return netWorkMapper.deleteByExample(ex) > 0;
+ }
+
+ @Override
+ public List selectNetworkList(NetworkBO bo) {
+ return netWorkMapper.selectNetworkListV1(bo);
+ }
+
+ @Override
+ public NetworkVO getDetail(Long id) {
+ return netWorkMapper.selectById(id);
+ }
+
+ @Override
+ public List queryMileSightList(NetworkBO bo) {
+ return ioTDeviceMapper.queryMileSightList(bo);
+ }
+
+ @Override
+ public R insertDevInstance(IoTDeviceBO devInstancebo) {
+ JSONObject downObj = new JSONObject();
+ // 预添加归属为空
+ downObj.set("appUnionId", "");
+ // 产品编号
+ downObj.set("productKey", devInstancebo.getProductKey());
+ // 设备序列号
+ downObj.set("deviceId", devInstancebo.getDeviceId());
+ // Lora密匙
+ downObj.set("deviceKey", devInstancebo.getSecretKey());
+ // 添加
+ downObj.set("cmd", DownCmd.DEV_ADD.name());
+ // 说明
+ downObj.set("detail", devInstancebo.getDetail());
+ JSONObject ob = new JSONObject();
+ // 设备实例名称
+ ob.set("deviceName", devInstancebo.getDeviceName());
+ // 设备序列号
+ ob.set("imei", devInstancebo.getDeviceId());
+ // 维度
+ ob.set("latitude", devInstancebo.getLatitude());
+ // 经度
+ ob.set("longitude", devInstancebo.getLongitude());
+ // 添加额外参数
+ for (Map.Entry entry : devInstancebo.getOtherParams().entrySet()) {
+ ob.set(entry.getKey(), entry.getValue());
+ }
+ downObj.set("data", ob);
+ IoTProduct ioTProduct = ioTProductMapper.getProductByProductKey(devInstancebo.getProductKey());
+ return IoTDownlFactory.getIDown(ioTProduct.getThirdPlatform()).doAction(downObj);
+ }
+
+ @Override
+ public R deleteDevInstanceByIds(String[] ids) {
+ R result = new R();
+ // 获取网关eui
+ String id1 = ids[0];
+ IoTDevice ioTDevice1 = ioTDeviceMapper.selectDevInstanceById(id1);
+ String gatewayEUI = JSONUtil.parseObj(ioTDevice1.getConfiguration()).getStr("gatewayEUI");
+ if (StrUtil.isBlank(gatewayEUI)) {
+ return R.error("删除失败,缺少网关EUI");
+ }
+ for (String id : ids) {
+ IoTDevice ioTDevice = ioTDeviceMapper.selectDevInstanceById(id);
+ JSONObject downRequest = new JSONObject();
+ downRequest.set("appUnionId", "");
+ downRequest.set("productKey", ioTDevice.getProductKey());
+ downRequest.set("deviceId", ioTDevice.getDeviceId());
+ downRequest.set("cmd", DownCmd.DEV_DEL.name());
+ JSONObject ob = new JSONObject();
+ ob.set("gatewayEUI", gatewayEUI);
+ downRequest.set("data", ob);
+ IoTProduct ioTProduct = ioTProductMapper.getProductByProductKey(ioTDevice.getProductKey());
+ result = IoTDownlFactory.getIDown(ioTProduct.getThirdPlatform()).doAction(downRequest);
+ if (!result.getCode().equals(0)) {
+ return R.error(
+ "设备名称: " + ioTDevice.getDeviceName() + " 删除失败,原因: " + result.getMsg());
+ }
+ ioTDeviceFenceRelMapper.deleteFenceInstance(ioTDevice.getIotId());
+ }
+ return R.ok("删除成功");
+ }
+
+ @Override
+ public void reloadTcpClient(String applicationId) {
+ }
+
+ @Override
+ public List selectNetworkList(NetworkQuery query) {
+ // 验证类型参数
+ // 如果type参数不为空,将其转换为types列表
+ if (StrUtil.isNotBlank(query.getType())) {
+ List types = NetworkTypeUtil.parseTypes(query.getType());
+
+ // 验证所有类型是否有效
+ if (!NetworkTypeUtil.isValidTypes(types)) {
+ List invalidTypes = NetworkTypeUtil.getInvalidTypes(types);
+ throw new IoTException("无效的网络类型: " + String.join(", ", invalidTypes));
+ }
+ // 设置types列表,清空type字段
+ query.setTypes(types);
+ query.setType(null);
+ }
+ // 计算分页参数
+ Page page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
+ List list = networkMapper.selectNetworkList(query);
+ for (NetworkBO bo : list) {
+ // 启用/停用状态
+ bo.setEnableName(Boolean.TRUE.equals(bo.getState()) ? "已启用" : "已停用");
+ // 实际运行状态
+ String type = bo.getType();
+ String productKey = bo.getProductKey();
+ String unionId = bo.getUnionId();
+ if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
+ .equals(type)) {
+
+ } else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
+ .equals(type)) {
+ if (mqttServerManager != null && mqttServerManager.isConnected(unionId)) {
+ bo.setStateName("已启动");
+ bo.setRunning(Boolean.TRUE);
+ } else {
+ bo.setStateName("未启动");
+ bo.setRunning(Boolean.FALSE);
+ }
+ } else {
+ bo.setStateName("未知");
+ bo.setRunning(Boolean.FALSE);
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public NetworkVO selectNetworkById(Integer id) {
+ Network network = networkMapper.selectNetworkById(id);
+ if (network == null) {
+ return null;
+ }
+ NetworkVO vo = new NetworkVO();
+ // 复制基本属性
+ vo.setId(network.getId());
+ vo.setType(network.getType());
+ vo.setUnionId(network.getUnionId());
+ vo.setProductKey(network.getProductKey());
+ vo.setName(network.getName());
+ vo.setDescription(network.getDescription());
+ vo.setCreateDate(network.getCreateDate());
+ vo.setCreateUser(network.getCreateUser());
+ vo.setState(network.getState());
+ vo.setConfiguration(network.getConfiguration());
+ // 类型名称
+ switch (network.getType()) {
+ case NetworkTypeConstants.TCP_CLIENT:
+ vo.setTypeName(NetworkType.TCP_CLIENT.getDescription());
+ break;
+ case NetworkTypeConstants.TCP_SERVER:
+ vo.setTypeName(NetworkType.TCP_SERVER.getDescription());
+ break;
+ case NetworkTypeConstants.MQTT_CLIENT:
+ vo.setTypeName(NetworkType.MQTT_CLIENT.getDescription());
+ break;
+ case NetworkTypeConstants.MQTT_SERVER:
+ vo.setTypeName(NetworkType.MQTT_SERVER.getDescription());
+ break;
+ default:
+ vo.setTypeName(network.getType());
+ }
+ // 启用/停用状态
+ vo.setEnableName(Boolean.TRUE.equals(network.getState()) ? "已启用" : "已停用");
+ // 实际运行状态
+ String type = network.getType();
+ String productKey = network.getProductKey();
+ String unionId = network.getUnionId();
+ if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
+ .equals(type)) {
+ //TODO 开源版本无
+
+ } else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
+ .equals(type)) {
+ if (mqttServerManager != null && mqttServerManager.isConnected(unionId)) {
+ vo.setStateName("已启动");
+ vo.setRunning(Boolean.TRUE);
+ } else {
+ vo.setStateName("未启动");
+ vo.setRunning(Boolean.FALSE);
+ }
+ } else {
+ vo.setStateName("未知");
+ vo.setRunning(Boolean.FALSE);
+ }
+ return vo;
+ }
+
+ /**
+ * 检查端口是否被占用或为常用端口
+ */
+ private void checkPortAvailable(Network network, boolean isUpdate) {
+ if (StrUtil.isBlank(network.getConfiguration())) {
+ return;
+ }
+ JSONObject config = JSONUtil.parseObj(network.getConfiguration());
+ Integer port = config.getInt("port");
+ if (port == null) {
+ return;
+ }
+ // 常用端口
+ Set commonPorts = new HashSet<>();
+ int[] arr = {80, 443, 3306, 6379, 8080, 22, 21, 25, 53, 123, 1521, 5432, 8888, 9000, 5000, 7001,
+ 27017};
+ for (int p : arr) {
+ commonPorts.add(p);
+ }
+ if (commonPorts.contains(port)) {
+ throw new RuntimeException("端口 " + port + " 为常用端口,禁止使用");
+ }
+ // 检查数据库是否被占用
+ Integer excludeId = isUpdate ? network.getId() : null;
+ int count = networkMapper.selectTcpNetworkByPortCount(port, excludeId);
+ if (count > 0) {
+ throw new RuntimeException("端口 " + port + " 已被其他网络组件占用");
+ }
+ }
+
+ @Override
+ @Transactional
+ public int insertNetwork(Network network) {
+ // 验证配置
+ if (!validateNetworkConfig(network)) {
+ throw new RuntimeException("网络组件配置验证失败");
+ }
+
+ // 检查配置唯一性
+ checkConfigurationUniqueness(network, null);
+
+ // 设置默认值
+ if (network.getState() == null) {
+ network.setState(false);
+ }
+
+ // 设置创建用户(如果未设置)
+ if (StrUtil.isBlank(network.getCreateUser())) {
+ // 从当前登录用户获取 unionId
+ network.setCreateUser(SecurityUtils.getUnionId());
+ }
+ network.setUnionId(IdUtil.objectId());
+ network.setState(false);
+
+ // 新增TCP_SERVER时,必须指定productKey,并且不能重复绑定
+ if (NetworkType.TCP_SERVER.getId().equals(network.getType()) || NetworkType.TCP_CLIENT.getId()
+ .equals(network.getType())) {
+ if (StrUtil.isBlank(network.getProductKey())) {
+ throw new RuntimeException("TCP服务组件必须选择产品");
+ }
+ network.setUnionId(network.getProductKey());
+ // 检查是否已被绑定
+ int refCount = ioTProductMapper.countByNetworkUnionId(network.getProductKey());
+ if (refCount > 0) {
+ throw new RuntimeException("该产品已绑定其他TCP服务组件,不能重复绑定");
+ }
+ }
+ checkPortAvailable(network, false);
+ int result = networkMapper.insertNetwork(network);
+ // 新增成功后,若为TCP_SERVER,更新iot_product表
+ if (result > 0 && NetworkType.TCP_SERVER.getId().equals(network.getType())) {
+ ioTProductMapper.updateNetworkUnionIdByProductKey(network.getProductKey(),
+ network.getProductKey());
+ }
+ return result;
+ }
+
+ @Override
+ @Transactional
+ public int updateNetwork(Network network) {
+ if (network == null || network.getId() == null) {
+ throw new RuntimeException("网络组件配置验证失败");
+ }
+ // 验证配置
+ if (!validateNetworkConfig(network)) {
+ throw new RuntimeException("网络组件配置验证失败");
+ }
+ // 检查权限(只能操作自己创建的网络组件,除非是管理员)
+ Network existNetwork = networkMapper.selectNetworkById(network.getId());
+ if (existNetwork == null) {
+ throw new RuntimeException("网络组件不存在");
+ }
+ IoTUser currentUser = SecurityUtils.getIoTUnionUser();
+ if (!existNetwork.getCreateUser().equals(currentUser.getUnionId()) && !currentUser.isAdmin()) {
+ throw new RuntimeException("不能操作不是自己的网络组件");
+ }
+
+ String type = existNetwork.getType();
+ if ((NetworkType.TCP_SERVER.getId().equals(type) || NetworkType.TCP_CLIENT.getId()
+ .equals(type))) {
+ // 只有当unionId发生变化时,才做"已被产品关联且产品下有设备时禁止修改"的校验
+ String oldProductKey = existNetwork.getProductKey();
+ String networkProductKey = network.getProductKey();
+ String current = ioTProductMapper.findProductKeyByNetworkUnionId(oldProductKey);
+ if (current != null && !oldProductKey.equals(networkProductKey)) {
+ int deviceCount = ioTDeviceMapper.countByProductKey(oldProductKey);
+ if (deviceCount > 0) {
+ throw new RuntimeException("原关联产品有设备,无法变更");
+ }
+ }
+ }
+ // 检查配置唯一性(排除自己)
+ checkConfigurationUniqueness(network, network.getId());
+ checkPortAvailable(network, true);
+ int count = networkMapper.updateNetwork(network);
+ if (count > 0 && NetworkType.TCP_SERVER.getId().equals(network.getType())) {
+ ioTProductMapper.updateNetworkUnionIdByProductKey(network.getProductKey(),
+ network.getProductKey());
+ }
+ return count;
+ }
+
+ @Override
+ @Transactional
+ public int deleteNetworkById(Integer id) {
+ Network network = networkMapper.selectNetworkById(id);
+ if (network == null) {
+ throw new RuntimeException("网络组件不存在");
+ }
+ String type = network.getType();
+ // 只对TCP_SERVER和TCP_CLIENT做判断
+ if (NetworkType.TCP_SERVER.getId().equals(type) || NetworkType.TCP_CLIENT.getId()
+ .equals(type)) {
+ // 查找是否有关联产品
+ String productKey = ioTProductMapper.findProductKeyByNetworkUnionId(network.getUnionId());
+ if (productKey != null) {
+ // 查找该产品下是否有设备
+ int deviceCount = ioTDeviceMapper.countByProductKey(productKey);
+ if (deviceCount > 0) {
+ throw new RuntimeException("该网络组件已被产品关联且产品下存在设备,无法删除");
+ }
+ }
+ }
+ return networkMapper.deleteNetworkById(id);
+ }
+
+ @Override
+ @Transactional
+ public int deleteNetworkByIds(Integer[] ids) {
+ return networkMapper.deleteNetworkByIds(ids);
+ }
+
+ @Override
+ @Transactional
+ public int startNetwork(Integer id) {
+ Network network = networkMapper.selectNetworkById(id);
+ if (network == null) {
+ throw new RuntimeException("网络组件不存在");
+ }
+ String type = network.getType();
+ JSONObject config = JSONUtil.parseObj(network.getConfiguration());
+ if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
+ .equals(type)) {
+ Integer port = config.getInt("port");
+ if (port == null) {
+ throw new RuntimeException("TCP网络组件启动/重启时端口不能为空");
+ }
+ } else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
+ .equals(type)) {
+ String host = config.getStr("host");
+ if (StrUtil.isBlank(host)) {
+ throw new RuntimeException("MQTT网络组件启动/重启时host不能为空");
+ }
+ }
+ try {
+ // 根据网络类型调用相应的启动逻辑
+ boolean success = startNetworkByType(network);
+
+ if (success) {
+ log.info("启动网络组件成功: {}", network.getName());
+ return 1;
+ } else {
+ throw new RuntimeException("启动失败: " + network.getName());
+ }
+ } catch (Exception e) {
+ log.error("启动网络组件失败: {}", network.getName(), e);
+ throw new RuntimeException("启动网络组件失败: " + e.getMessage());
+ }
+ }
+
+ @Override
+ @Transactional
+ public int stopNetwork(Integer id) {
+ Network network = networkMapper.selectNetworkById(id);
+ if (network == null) {
+ throw new RuntimeException("网络组件不存在");
+ }
+
+ try {
+ // 根据网络类型调用相应的停止逻辑
+ boolean success = stopNetworkByType(network);
+ if (success) {
+ log.info("停止网络组件成功: {}", network.getName());
+ return 1;
+ } else {
+ throw new RuntimeException("停止网络组件失败: " + network.getName());
+ }
+ } catch (Exception e) {
+ log.error("停止网络组件失败: {}", network.getName(), e);
+ throw new RuntimeException("停止网络组件失败: " + e.getMessage());
+ }
+ }
+
+ @Override
+ @Transactional
+ public int restartNetwork(Integer id) {
+ Network network = networkMapper.selectNetworkById(id);
+ if (network == null) {
+ throw new RuntimeException("网络组件不存在");
+ }
+ String type = network.getType();
+ JSONObject config = JSONUtil.parseObj(network.getConfiguration());
+ if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
+ .equals(type)) {
+ Integer port = config.getInt("port");
+ if (port == null) {
+ throw new RuntimeException("TCP网络组件启动/重启时端口不能为空");
+ }
+ } else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
+ .equals(type)) {
+ String host = config.getStr("host");
+ if (StrUtil.isBlank(host)) {
+ throw new RuntimeException("MQTT网络组件启动/重启时host不能为空");
+ }
+ }
+ try {
+ // 根据网络类型调用相应的重启逻辑
+ boolean success = restartNetworkByType(network);
+
+ if (success) {
+ log.info("重启网络组件成功: {}", network.getName());
+ // 重启后状态应该是启动的
+ return 1;
+ } else {
+ throw new RuntimeException("重启网络组件失败: " + network.getName());
+ }
+ } catch (Exception e) {
+ log.error("重启网络组件失败: {}", network.getName(), e);
+ throw new RuntimeException("重启网络组件失败: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public List getNetworkTypes() {
+ return Arrays.asList(NetworkType.TCP_CLIENT.getId(), NetworkType.TCP_SERVER.getId(),
+ NetworkType.MQTT_CLIENT.getId(), NetworkType.MQTT_SERVER.getId());
+ }
+
+ /**
+ * 验证网络类型是否有效
+ *
+ * @param type 网络类型
+ * @return 是否有效
+ */
+ private boolean isValidNetworkType(String type) {
+ return getNetworkTypes().contains(type);
+ }
+
+ /**
+ * 验证多个网络类型是否都有效
+ *
+ * @param types 网络类型列表
+ * @return 是否都有效
+ */
+ private boolean isValidNetworkTypes(List types) {
+ return types.stream().allMatch(this::isValidNetworkType);
+ }
+
+ @Override
+ public boolean validateNetworkConfig(Network network) {
+ if (network == null) {
+ return false;
+ }
+
+ // 验证必填字段
+ if (StrUtil.isBlank(network.getType()) || StrUtil.isBlank(network.getName())) {
+ return false;
+ }
+
+ // 验证配置JSON格式
+ if (StrUtil.isNotBlank(network.getConfiguration())) {
+ try {
+ JSONUtil.parseObj(network.getConfiguration());
+ } catch (Exception e) {
+ log.warn("网络组件配置JSON格式错误: {}", e.getMessage());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 检查网络组件配置的唯一性
+ *
+ * @param network 网络组件
+ * @param excludeId 排除的网络组件ID(用于更新时排除自己)
+ */
+ private void checkConfigurationUniqueness(Network network, Integer excludeId) {
+ if (StrUtil.isBlank(network.getConfiguration())) {
+ return;
+ }
+
+ try {
+ JSONObject config = JSONUtil.parseObj(network.getConfiguration());
+ String type = network.getType();
+ // TCP类型检查端口唯一性
+ if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
+ .equals(type)) {
+ Integer port = config.getInt("port");
+ if (port != null) {
+ List existingNetworks = networkMapper.selectTcpNetworkByPort(port, excludeId);
+ if (!existingNetworks.isEmpty()) {
+ Network existingNetwork = existingNetworks.get(0);
+ throw new RuntimeException(
+ "端口 " + port + " 已被 " + existingNetwork.getName() + " 网络组件使用");
+ }
+ }
+ }
+
+ // MQTT类型检查主机和用户名组合唯一性
+ if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
+ .equals(type)) {
+ String host = config.getStr("host");
+ String username = config.getStr("username");
+
+ if (StrUtil.isNotBlank(host) && StrUtil.isNotBlank(username)) {
+ List existingNetworks = networkMapper.selectMqttNetworkByHostAndUsername(host,
+ username, excludeId);
+ if (!existingNetworks.isEmpty()) {
+ Network existingNetwork = existingNetworks.get(0);
+ throw new RuntimeException("主机 " + host + " 和用户名 " + username + " 的组合已被 "
+ + existingNetwork.getName() + " 网络组件使用");
+ }
+ }
+ }
+ } catch (Exception e) {
+ if (e instanceof RuntimeException) {
+ throw e;
+ }
+ log.warn("检查网络组件配置唯一性时发生错误: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * 根据网络类型启动网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean startNetworkByType(Network network) {
+ String type = network.getType();
+
+ try {
+ switch (type) {
+ case NetworkTypeConstants.TCP_CLIENT:
+ case NetworkTypeConstants.TCP_SERVER:
+ return startTcpNetwork(network);
+ case NetworkTypeConstants.MQTT_CLIENT:
+ case NetworkTypeConstants.MQTT_SERVER:
+ return startMqttNetwork(network);
+ default:
+ log.warn("不支持的网络类型: {}", type);
+ return false;
+ }
+ } catch (Exception e) {
+ log.error("启动网络组件失败: type={}, name={}", type, network.getName(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 根据网络类型停止网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean stopNetworkByType(Network network) {
+ String type = network.getType();
+
+ try {
+ switch (type) {
+ case NetworkTypeConstants.TCP_CLIENT:
+ case NetworkTypeConstants.TCP_SERVER:
+ return stopTcpNetwork(network);
+ case NetworkTypeConstants.MQTT_CLIENT:
+ case NetworkTypeConstants.MQTT_SERVER:
+ return stopMqttNetwork(network);
+ default:
+ log.warn("不支持的网络类型: {}", type);
+ return false;
+ }
+ } catch (Exception e) {
+ log.error("停止网络组件失败: type={}, name={}", type, network.getName(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 根据网络类型重启网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean restartNetworkByType(Network network) {
+ String type = network.getType();
+
+ try {
+ switch (type) {
+ case NetworkTypeConstants.TCP_CLIENT:
+ case NetworkTypeConstants.TCP_SERVER:
+ return restartTcpNetwork(network);
+ case NetworkTypeConstants.MQTT_CLIENT:
+ case NetworkTypeConstants.MQTT_SERVER:
+ return restartMqttNetwork(network);
+ default:
+ log.warn("不支持的网络类型: {}", type);
+ return false;
+ }
+ } catch (Exception e) {
+ log.error("重启网络组件失败: type={}, name={}", type, network.getName(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 启动TCP网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean startTcpNetwork(Network network) {
+ try {
+ //TODO 开源版本无
+ return true;
+ } catch (Exception e) {
+ log.error("启动TCP网络组件失败: productKey={}", "", e);
+ return false;
+ }
+ }
+
+ /**
+ * 停止TCP网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean stopTcpNetwork(Network network) {
+
+ String productKey = network.getProductKey();
+ if (StrUtil.isBlank(productKey)) {
+ log.error("TCP网络组件缺少productKey: {}", network.getName());
+ return false;
+ }
+ try {
+
+ return true;
+ } catch (Exception e) {
+ log.error("停止TCP网络组件失败: productKey={}", "", e);
+ return false;
+ }
+ }
+
+ /**
+ * 重启TCP网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean restartTcpNetwork(Network network) {
+
+ try {
+ return true;
+ } catch (Exception e) {
+ log.error("重启TCP网络组件失败: productKey={}", "", e);
+ return false;
+ }
+ }
+
+ /**
+ * 启动MQTT网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean startMqttNetwork(Network network) {
+ if (mqttServerManager == null) {
+ log.error("MQTT服务管理器未注入,无法启动MQTT网络组件: {}", network.getName());
+ return false;
+ }
+
+ String unionId = network.getUnionId();
+ if (StrUtil.isBlank(unionId)) {
+ log.error("MQTT网络组件缺少unionId: {}", network.getName());
+ return false;
+ }
+
+ try {
+ boolean success = mqttServerManager.startMqttClient(unionId);
+ if (success) {
+ log.info("MQTT网络组件启动成功: unionId={}", unionId);
+ } else {
+ log.error("MQTT网络组件启动失败: unionId={}", unionId);
+ }
+ return success;
+ } catch (Exception e) {
+ log.error("启动MQTT网络组件失败: unionId={}", unionId, e);
+ return false;
+ }
+ }
+
+ /**
+ * 停止MQTT网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean stopMqttNetwork(Network network) {
+ if (mqttServerManager == null) {
+ log.error("MQTT服务管理器未注入,无法停止MQTT网络组件: {}", network.getName());
+ return false;
+ }
+
+ String unionId = network.getUnionId();
+ if (StrUtil.isBlank(unionId)) {
+ log.error("MQTT网络组件缺少unionId: {}", network.getName());
+ return false;
+ }
+
+ try {
+ boolean success = mqttServerManager.stopMqttClient(unionId);
+ if (success) {
+ log.info("MQTT网络组件停止成功: unionId={}", unionId);
+ } else {
+ log.error("MQTT网络组件停止失败: unionId={}", unionId);
+ }
+ return success;
+ } catch (Exception e) {
+ log.error("停止MQTT网络组件失败: unionId={}", unionId, e);
+ return false;
+ }
+ }
+
+ /**
+ * 重启MQTT网络组件
+ *
+ * @param network 网络组件
+ * @return 是否成功
+ */
+ private boolean restartMqttNetwork(Network network) {
+ if (mqttServerManager == null) {
+ log.error("MQTT服务管理器未注入,无法重启MQTT网络组件: {}", network.getName());
+ return false;
+ }
+
+ String unionId = network.getUnionId();
+ if (StrUtil.isBlank(unionId)) {
+ log.error("MQTT网络组件缺少unionId: {}", network.getName());
+ return false;
+ }
+
+ try {
+ boolean success = mqttServerManager.restartMqttClient(unionId);
+ if (success) {
+ log.info("MQTT网络组件重启成功: unionId={}", unionId);
+ } else {
+ log.error("MQTT网络组件重启失败: unionId={}", unionId);
+ }
+ return success;
+ } catch (Exception e) {
+ log.error("重启MQTT网络组件失败: unionId={}", unionId, e);
+ return false;
+ }
+ }
+
+ @Override
+ public IoTDevice getDeviceById(String id) {
+ return ioTDeviceMapper.selectDevInstanceById(id);
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkConfigUtil.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkConfigUtil.java
new file mode 100644
index 0000000..d1b5fb4
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkConfigUtil.java
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.utils;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.universal.persistence.entity.Network;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 网络组件配置工具类
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+@Slf4j
+public class NetworkConfigUtil {
+
+ /**
+ * 验证网络组件配置
+ *
+ * @param network 网络组件
+ * @return 验证结果
+ */
+ public static boolean validateConfig(Network network) {
+ if (network == null) {
+ return false;
+ }
+
+ // 验证必填字段
+ if (StrUtil.isBlank(network.getType())
+ || StrUtil.isBlank(network.getUnionId())
+ || StrUtil.isBlank(network.getName())) {
+ return false;
+ }
+
+ // 验证配置JSON格式
+ if (StrUtil.isNotBlank(network.getConfiguration())) {
+ try {
+ JSONUtil.parseObj(network.getConfiguration());
+ } catch (Exception e) {
+ log.warn("网络组件配置JSON格式错误: {}", e.getMessage());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 验证TCP配置
+ *
+ * @param config 配置JSON字符串
+ * @return 验证结果
+ */
+ public static boolean validateTcpConfig(String config) {
+ if (StrUtil.isBlank(config)) {
+ return false;
+ }
+
+ try {
+ JSONObject jsonConfig = JSONUtil.parseObj(config);
+
+ // 验证必填字段
+ if (!jsonConfig.containsKey("host") || !jsonConfig.containsKey("port")) {
+ return false;
+ }
+
+ // 验证端口范围
+ int port = jsonConfig.getInt("port", 0);
+ if (port <= 0 || port > 65535) {
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ log.warn("TCP配置验证失败: {}", e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 验证MQTT配置
+ *
+ * @param config 配置JSON字符串
+ * @return 验证结果
+ */
+ public static boolean validateMqttConfig(String config) {
+ if (StrUtil.isBlank(config)) {
+ return false;
+ }
+
+ try {
+ JSONObject jsonConfig = JSONUtil.parseObj(config);
+
+ // 验证必填字段
+ if (!jsonConfig.containsKey("host")) {
+ return false;
+ }
+
+ // 验证QoS范围
+ if (jsonConfig.containsKey("defaultQos")) {
+ int qos = jsonConfig.getInt("defaultQos", -1);
+ if (qos < 0 || qos > 2) {
+ return false;
+ }
+ }
+
+ // 验证心跳间隔
+ if (jsonConfig.containsKey("keepAliveInterval")) {
+ int keepAlive = jsonConfig.getInt("keepAliveInterval", 0);
+ if (keepAlive < 0) {
+ return false;
+ }
+ }
+
+ return true;
+ } catch (Exception e) {
+ log.warn("MQTT配置验证失败: {}", e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 根据网络类型验证配置
+ *
+ * @param network 网络组件
+ * @return 验证结果
+ */
+ public static boolean validateConfigByType(Network network) {
+ if (network == null
+ || StrUtil.isBlank(network.getType())
+ || StrUtil.isBlank(network.getConfiguration())) {
+ return false;
+ }
+
+ switch (network.getType()) {
+ case "TCP_CLIENT":
+ case "TCP_SERVER":
+ return validateTcpConfig(network.getConfiguration());
+ case "MQTT_CLIENT":
+ case "MQTT_SERVER":
+ return validateMqttConfig(network.getConfiguration());
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * 获取默认TCP配置
+ *
+ * @return 默认TCP配置
+ */
+ public static String getDefaultTcpConfig() {
+ JSONObject config = new JSONObject();
+ config.set("host", "0.0.0.0");
+ config.set("port", 8080);
+ config.set("ssl", false);
+ config.set("allIdleTime", 0);
+ config.set("readerIdleTime", 360);
+ config.set("writerIdleTime", 0);
+ config.set("decoderType", "STRING");
+ config.set("parserType", "DELIMITED");
+ config.set(
+ "parserConfiguration",
+ new JSONObject()
+ .set("byteOrderLittle", true)
+ .set("delimited", "]")
+ .set("delimitedMaxlength", 1024)
+ .set("failFast", true));
+ return config.toString();
+ }
+
+ /**
+ * 获取默认MQTT配置
+ *
+ * @return 默认MQTT配置
+ */
+ public static String getDefaultMqttConfig() {
+ JSONObject config = new JSONObject();
+ config.set("host", "tcp://localhost:1883");
+ config.set("username", "");
+ config.set("password", "");
+ config.set("clientIdPrefix", "univ_cli_");
+ config.set("defaultQos", 1);
+ config.set("keepAliveInterval", 60);
+ config.set("connectTimeout", 30);
+ config.set("autoReconnect", true);
+ config.set("cleanSession", true);
+ config.set("ssl", false);
+ config.set("enabled", true);
+ return config.toString();
+ }
+
+ /**
+ * 根据网络类型获取默认配置
+ *
+ * @param type 网络类型
+ * @return 默认配置
+ */
+ public static String getDefaultConfigByType(String type) {
+ switch (type) {
+ case "TCP_CLIENT":
+ case "TCP_SERVER":
+ return getDefaultTcpConfig();
+ case "MQTT_CLIENT":
+ case "MQTT_SERVER":
+ return getDefaultMqttConfig();
+ default:
+ return "{}";
+ }
+ }
+
+ /**
+ * 格式化配置显示
+ *
+ * @param config 配置JSON字符串
+ * @return 格式化后的配置
+ */
+ public static String formatConfig(String config) {
+ if (StrUtil.isBlank(config)) {
+ return "{}";
+ }
+
+ try {
+ return JSONUtil.parseObj(config).toStringPretty();
+ } catch (Exception e) {
+ log.warn("格式化配置失败: {}", e.getMessage());
+ return config;
+ }
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkTypeUtil.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkTypeUtil.java
new file mode 100644
index 0000000..dbeb0d0
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/NetworkTypeUtil.java
@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.utils;
+
+import cn.hutool.core.util.StrUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 网络类型工具类
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+@Slf4j
+public class NetworkTypeUtil {
+
+ /** 支持的网络类型列表 */
+ public static final List SUPPORTED_TYPES =
+ Arrays.asList("TCP_CLIENT", "TCP_SERVER", "MQTT_CLIENT", "MQTT_SERVER");
+
+ /**
+ * 解析网络类型字符串,支持逗号分隔的多个类型
+ *
+ * @param typeStr 类型字符串,如 "MQTT_CLIENT,MQTT_SERVER"
+ * @return 类型列表
+ */
+ public static List parseTypes(String typeStr) {
+ if (StrUtil.isBlank(typeStr)) {
+ return List.of();
+ }
+
+ // 分割并清理空白字符
+ return Arrays.stream(typeStr.split(","))
+ .map(String::trim)
+ .filter(StrUtil::isNotBlank)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 验证网络类型是否有效
+ *
+ * @param type 网络类型
+ * @return 是否有效
+ */
+ public static boolean isValidType(String type) {
+ return SUPPORTED_TYPES.contains(type);
+ }
+
+ /**
+ * 验证多个网络类型是否都有效
+ *
+ * @param types 网络类型列表
+ * @return 是否都有效
+ */
+ public static boolean isValidTypes(List types) {
+ return types.stream().allMatch(NetworkTypeUtil::isValidType);
+ }
+
+ /**
+ * 获取无效的类型列表
+ *
+ * @param types 网络类型列表
+ * @return 无效的类型列表
+ */
+ public static List getInvalidTypes(List types) {
+ return types.stream().filter(type -> !isValidType(type)).collect(Collectors.toList());
+ }
+
+ /**
+ * 格式化类型字符串(去重、排序)
+ *
+ * @param typeStr 原始类型字符串
+ * @return 格式化后的类型字符串
+ */
+ public static String formatTypes(String typeStr) {
+ List types = parseTypes(typeStr);
+ return types.stream().distinct().sorted().collect(Collectors.joining(","));
+ }
+
+ /**
+ * 检查是否包含指定类型
+ *
+ * @param typeStr 类型字符串
+ * @param targetType 目标类型
+ * @return 是否包含
+ */
+ public static boolean containsType(String typeStr, String targetType) {
+ List types = parseTypes(typeStr);
+ return types.contains(targetType);
+ }
+
+ /**
+ * 获取类型的中文名称
+ *
+ * @param type 类型代码
+ * @return 中文名称
+ */
+ public static String getTypeName(String type) {
+ return switch (type) {
+ case "TCP_CLIENT" -> "TCP客户端";
+ case "TCP_SERVER" -> "TCP服务端";
+ case "MQTT_CLIENT" -> "MQTT客户端";
+ case "MQTT_SERVER" -> "MQTT服务端";
+ default -> type;
+ };
+ }
+
+ /**
+ * 获取多个类型的中文名称
+ *
+ * @param types 类型列表
+ * @return 中文名称列表
+ */
+ public static List getTypeNames(List types) {
+ return types.stream().map(NetworkTypeUtil::getTypeName).collect(Collectors.toList());
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/UserContextUtil.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/UserContextUtil.java
new file mode 100644
index 0000000..cf03da6
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/utils/UserContextUtil.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.utils;
+
+import cn.universal.admin.common.utils.SecurityUtils;
+import cn.universal.persistence.entity.IoTUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** 用户上下文工具类 用于获取当前登录用户信息 @Author Aleo */
+public class UserContextUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(UserContextUtil.class);
+
+ /**
+ * 获取当前登录用户的 unionId 如果无法获取用户信息,返回默认值 "system"
+ *
+ * @return 当前用户的 unionId,如果获取失败则返回 "system"
+ */
+ public static String getCurrentUserUnionId() {
+ try {
+ IoTUser currentUser = SecurityUtils.getIoTUnionUser();
+ if (currentUser != null && currentUser.getUnionId() != null) {
+ return currentUser.getUnionId();
+ }
+ } catch (Exception e) {
+ log.warn("获取当前用户信息失败,使用默认用户: {}", e.getMessage());
+ }
+ return "system";
+ }
+
+ /**
+ * 获取当前登录用户信息 如果无法获取用户信息,返回 null
+ *
+ * @return 当前用户信息,如果获取失败则返回 null
+ */
+ public static IoTUser getCurrentUser() {
+ try {
+ return SecurityUtils.getIoTUnionUser();
+ } catch (Exception e) {
+ log.warn("获取当前用户信息失败: {}", e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/cn-universal-admin/src/main/java/cn/universal/admin/network/web/NetworkController.java b/cn-universal-admin/src/main/java/cn/universal/admin/network/web/NetworkController.java
new file mode 100644
index 0000000..c6e2bab
--- /dev/null
+++ b/cn-universal-admin/src/main/java/cn/universal/admin/network/web/NetworkController.java
@@ -0,0 +1,461 @@
+/*
+ *
+ * Copyright (c) 2025, IoT-Universal. All Rights Reserved.
+ *
+ * @Description: 本文件由 Aleo 开发并拥有版权,未经授权严禁擅自商用、复制或传播。
+ * @Author: Aleo
+ * @Email: wo8335224@gmail.com
+ * @Wechat: outlookFil
+ *
+ *
+ */
+
+package cn.universal.admin.network.web;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.universal.admin.common.annotation.Log;
+import cn.universal.admin.common.enums.BusinessType;
+import cn.universal.admin.common.utils.SecurityUtils;
+import cn.universal.admin.network.service.INetworkService;
+import cn.universal.admin.system.web.BaseController;
+import cn.universal.common.domain.R;
+import cn.universal.common.exception.IoTException;
+import cn.universal.persistence.entity.IoTDevice;
+import cn.universal.persistence.entity.IoTUser;
+import cn.universal.persistence.entity.Network;
+import cn.universal.persistence.entity.bo.IoTDeviceBO;
+import cn.universal.persistence.entity.bo.NetworkBO;
+import cn.universal.persistence.entity.vo.NetworkVO;
+import cn.universal.persistence.page.TableDataInfo;
+import cn.universal.persistence.query.AjaxResult;
+import cn.universal.persistence.query.NetworkQuery;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Controller
+ *
+ * @version 1.0 @Author Aleo
+ * @since 2025/1/20
+ */
+@Slf4j
+@RestController
+@Tag(name = "网络管理", description = "网络管理")
+@RequestMapping("/admin/network")
+public class NetworkController extends BaseController {
+
+ @Autowired private INetworkService networkService;
+
+ /** 查询列表 */
+ @GetMapping("/list")
+ public TableDataInfo list(NetworkQuery query) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+ if (iotUser != null && !iotUser.isAdmin()) {
+ query.setCreateUser(iotUser.getUnionId());
+ }
+ List list = networkService.selectNetworkList(query);
+ return getDataTable(list);
+ } catch (Exception e) {
+ log.error("查询列表失败", e);
+ throw new IoTException("查询列表失败: " + e.getMessage());
+ }
+ }
+
+ /** 根据ID查询 */
+ @GetMapping("/{id}")
+ public AjaxResult getInfo(@PathVariable Integer id) {
+ try {
+ String createUser = SecurityUtils.getUnionId();
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+ // 校验用户权限
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限访问该");
+ }
+ return AjaxResult.success(network);
+ } catch (Exception e) {
+ log.error("查询失败", e);
+ return AjaxResult.error("查询失败: " + e.getMessage());
+ }
+ }
+
+ /** 新增 */
+ @PostMapping
+ public AjaxResult add(@RequestBody Network network) {
+ try {
+ // 设置创建用户
+ network.setCreateUser(SecurityUtils.getUnionId());
+ int result = networkService.insertNetwork(network);
+ if (result > 0) {
+ return AjaxResult.success("新增成功");
+ } else {
+ return AjaxResult.error("新增失败");
+ }
+ } catch (Exception e) {
+ log.error("新增失败", e);
+ return AjaxResult.error("新增失败: " + e.getMessage());
+ }
+ }
+
+ /** 修改 */
+ @PutMapping
+ public AjaxResult edit(@RequestBody Network network) {
+ try {
+ // 校验用户权限
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ NetworkVO existingNetwork = networkService.selectNetworkById(network.getId());
+ if (existingNetwork == null) {
+ return AjaxResult.error("不存在");
+ }
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(existingNetwork.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限修改该");
+ }
+
+ int result = networkService.updateNetwork(network);
+ if (result > 0) {
+ return AjaxResult.success("修改成功");
+ } else {
+ return AjaxResult.error("修改失败");
+ }
+ } catch (Exception e) {
+ log.error("修改失败", e);
+ return AjaxResult.error("操作失败" + e.getMessage());
+ }
+ }
+
+ /** 删除 */
+ @DeleteMapping("/{id}")
+ public AjaxResult remove(@PathVariable Integer id) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ // 校验用户权限
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限删除该");
+ }
+
+ int result = networkService.deleteNetworkById(id);
+ if (result > 0) {
+ return AjaxResult.success("删除成功");
+ } else {
+ return AjaxResult.error("删除失败");
+ }
+ } catch (Exception e) {
+ log.error("删除失败", e);
+ return AjaxResult.error("删除失败: " + e.getMessage());
+ }
+ }
+
+ /** 批量删除 */
+ @DeleteMapping("/batch/{ids}")
+ public AjaxResult removeBatch(@PathVariable Integer[] ids) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ // 校验用户权限
+ String createUser = SecurityUtils.getUnionId();
+ for (Integer id : ids) {
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在: " + id);
+ }
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限删除: " + id);
+ }
+ }
+
+ int result = networkService.deleteNetworkByIds(ids);
+ if (result > 0) {
+ return AjaxResult.success("批量删除成功");
+ } else {
+ return AjaxResult.error("批量删除失败");
+ }
+ } catch (Exception e) {
+ log.error("批量删除失败", e);
+ return AjaxResult.error("批量删除失败: " + e.getMessage());
+ }
+ }
+
+ /** 启动 */
+ @PostMapping("/start/{id}")
+ public AjaxResult start(@PathVariable Integer id) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ // 校验用户权限
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限操作该");
+ }
+
+ int result = networkService.startNetwork(id);
+ if (result > 0) {
+ return AjaxResult.success("启动成功");
+ } else {
+ return AjaxResult.error("启动失败");
+ }
+ } catch (Exception e) {
+ log.error("启动失败", e);
+ return AjaxResult.error("启动失败: " + e.getMessage());
+ }
+ }
+
+ /** 停止 */
+ @PostMapping("/stop/{id}")
+ public AjaxResult stop(@PathVariable Integer id) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ // 校验用户权限
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限操作该");
+ }
+
+ int result = networkService.stopNetwork(id);
+ if (result > 0) {
+ return AjaxResult.success("操作成功");
+ } else {
+ return AjaxResult.error("操作失败");
+ }
+ } catch (Exception e) {
+ log.error("操作失败", e);
+ return AjaxResult.error("操作失败: " + e.getMessage());
+ }
+ }
+
+ /** 重启 */
+ @PostMapping("/restart/{id}")
+ public AjaxResult restart(@PathVariable Integer id) {
+ try {
+ IoTUser iotUser = loginIoTUnionUser(SecurityUtils.getUnionId());
+
+ // 校验用户权限
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(network.getCreateUser()) && !iotUser.isAdmin()) {
+ return AjaxResult.error("无权限操作该");
+ }
+
+ int result = networkService.restartNetwork(id);
+ if (result > 0) {
+ return AjaxResult.success("重启成功");
+ } else {
+ return AjaxResult.error("重启失败");
+ }
+ } catch (Exception e) {
+ log.error("重启失败", e);
+ return AjaxResult.error("重启失败: " + e.getMessage());
+ }
+ }
+
+ /** 获取网络类型列表 */
+ @GetMapping("/types")
+ public AjaxResult getNetworkTypes() {
+ try {
+ List types = networkService.getNetworkTypes();
+ return AjaxResult.success(types);
+ } catch (Exception e) {
+ log.error("获取网络类型列表失败", e);
+ return AjaxResult.error("获取网络类型列表失败: " + e.getMessage());
+ }
+ }
+
+ /** 验证配置 */
+ @PostMapping("/validate")
+ public AjaxResult validateConfig(@RequestBody Network network) {
+ try {
+ // 设置创建用户
+ network.setCreateUser(SecurityUtils.getUnionId());
+ boolean isValid = networkService.validateNetworkConfig(network);
+ if (isValid) {
+ return AjaxResult.success("配置验证通过");
+ } else {
+ return AjaxResult.error("配置验证失败");
+ }
+ } catch (Exception e) {
+ log.error("验证配置失败", e);
+ return AjaxResult.error("验证配置失败: " + e.getMessage());
+ }
+ }
+
+ @Resource private INetworkService iNetworkService;
+
+ /** 查询网络列表 */
+ @GetMapping("/v1/list")
+ public TableDataInfo list(NetworkBO bo) {
+ startPage();
+ // 设置用户权限过滤
+ bo.setCreateUser(SecurityUtils.getUnionId());
+ List list = iNetworkService.selectNetworkList(bo);
+ return getDataTable(list);
+ }
+
+ /** 查询绑定指定星纵网关的设备 */
+ @GetMapping("/milesight/list")
+ public TableDataInfo queryMileSightList(NetworkBO bo) {
+ startPage();
+ // 设置用户权限过滤
+ bo.setCreateUser(SecurityUtils.getUnionId());
+ List list = iNetworkService.queryMileSightList(bo);
+ return getDataTable(list);
+ }
+
+ /** 新增设备 */
+ @PostMapping("/milesight/add")
+ @Log(title = "新增设备", businessType = BusinessType.INSERT)
+ public R add(@RequestBody IoTDeviceBO devInstancebo) {
+ // 设置创建用户
+ devInstancebo.setCreatorId(SecurityUtils.getUnionId());
+ R result = iNetworkService.insertDevInstance(devInstancebo);
+ JSONObject jsonObject = JSONUtil.parseObj(result);
+ String code = jsonObject.getStr("code");
+ String msg = jsonObject.getStr("msg");
+ if ("0".equals(code)) {
+ return R.ok();
+ } else {
+ return R.error(msg);
+ }
+ }
+
+ /** 删除设备 */
+ @DeleteMapping("/milesight/{ids}")
+ @Log(title = "删除设备", businessType = BusinessType.DELETE)
+ public R remove(@PathVariable String[] ids) {
+ // 校验用户权限
+ String currentUser = SecurityUtils.getUnionId();
+ for (String id : ids) {
+ IoTDevice device = iNetworkService.getDeviceById(id);
+ if (device == null) {
+ return R.error("设备不存在: " + id);
+ }
+ if (!currentUser.equals(device.getCreatorId())) {
+ return R.error("无权限删除设备: " + id);
+ }
+ }
+ R result = iNetworkService.deleteDevInstanceByIds(ids);
+ JSONObject jsonObject = JSONUtil.parseObj(result);
+ String code = jsonObject.getStr("code");
+ String msg = jsonObject.getStr("msg");
+ if ("0".equals(code)) {
+ return R.ok();
+ } else {
+ return R.error(msg);
+ }
+ }
+
+ @GetMapping("/reload/tcpclient/{applicationId}")
+ public R reloadTcpClient(@PathVariable("applicationId") String applicationId) {
+ // 校验用户权限 - 需要根据applicationId获取相关的信息进行权限校验
+ // 这里可能需要额外的业务逻辑来实现权限校验
+ iNetworkService.reloadTcpClient(applicationId);
+ return R.ok();
+ }
+
+ /** 获取状态 */
+ @GetMapping("/status/{id}")
+ public AjaxResult getStatus(@PathVariable Integer id) {
+ try {
+ NetworkVO network = networkService.selectNetworkById(id);
+ if (network == null) {
+ return AjaxResult.error("不存在");
+ }
+
+ // 校验用户权限
+ String createUser = SecurityUtils.getUnionId();
+ if (!createUser.equals(network.getCreateUser())) {
+ return AjaxResult.error("无权限查看该状态");
+ }
+
+ // 构建状态信息
+ Map status = new HashMap<>();
+ status.put("id", network.getId());
+ status.put("name", network.getName());
+ status.put("type", network.getType());
+ status.put("typeName", network.getTypeName());
+ status.put("state", network.getState());
+ status.put("stateName", network.getStateName());
+ status.put("productKey", network.getProductKey());
+ status.put("unionId", network.getUnionId());
+ status.put("createDate", network.getCreateDate());
+ status.put("createUser", network.getCreateUser());
+
+ return AjaxResult.success(status);
+ } catch (Exception e) {
+ log.error("获取状态失败", e);
+ return AjaxResult.error("获取状态失败: " + e.getMessage());
+ }
+ }
+
+ /** 获取所有状态 */
+ @GetMapping("/status")
+ public AjaxResult getAllStatus() {
+ try {
+ NetworkQuery query = new NetworkQuery();
+ query.setPageNum(1);
+ query.setPageSize(1000); // 获取所有
+ // 设置用户权限过滤
+ query.setCreateUser(SecurityUtils.getUnionId());
+
+ List networks = networkService.selectNetworkList(query);
+
+ List