package com.mes.plc.factory;
import com.mes.device.entity.DeviceConfig;
import com.mes.plc.client.PlcClient;
import com.mes.plc.client.impl.ModbusPlcClient;
import com.mes.plc.client.impl.S7PlcClient;
import com.mes.service.PlcDynamicDataService;
import com.mes.s7.enhanced.EnhancedS7Serializer;
import com.mes.s7.provider.S7SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* PLC客户端工厂
*
* 根据设备配置创建不同类型的PLC客户端实例
*
*
* @author huang
* @date 2025/12/19
*/
@Slf4j
@Component
public class PlcClientFactory {
// S7序列化器提供者
@Autowired
private S7SerializerProvider s7SerializerProvider;
// PLC动态数据服务
@Autowired
private PlcDynamicDataService plcDynamicDataService;
// 客户端缓存,提高性能
private final ConcurrentMap clientCache = new ConcurrentHashMap<>();
/**
* 根据设备配置创建或获取PLC客户端
*
* @param device 设备配置
* @return PLC客户端实例
*/
public PlcClient getClient(DeviceConfig device) {
if (device == null) {
log.error("设备配置为空,无法创建PLC客户端");
return null;
}
// 生成缓存键
String cacheKey = generateCacheKey(device);
// 尝试从缓存中获取客户端
PlcClient client = clientCache.get(cacheKey);
if (client != null && client.isConnected()) {
return client;
}
// 缓存中没有或连接已断开,创建新客户端
try {
client = createClient(device);
if (client != null) {
// 连接PLC
if (client.connect()) {
// 将客户端放入缓存
clientCache.put(cacheKey, client);
log.info("PLC客户端创建成功: cacheKey={}, plcType={}", cacheKey, client.getPlcType());
} else {
log.error("PLC客户端连接失败: cacheKey={}, plcType={}", cacheKey, client.getPlcType());
// 连接失败,不放入缓存
client = null;
}
}
} catch (Exception e) {
log.error("创建PLC客户端失败: cacheKey={}", cacheKey, e);
client = null;
}
return client;
}
/**
* 生成缓存键
*
* @param device 设备配置
* @return 缓存键
*/
private String generateCacheKey(DeviceConfig device) {
StringBuilder sb = new StringBuilder();
sb.append("device:")
.append(device.getId())
.append(":")
.append(device.getPlcType())
.append(":")
.append(device.getPlcIp())
.append(":")
.append(device.getPlcPort());
return sb.toString();
}
/**
* 根据设备类型创建不同的PLC客户端
*
* @param device 设备配置
* @return PLC客户端实例
*/
private PlcClient createClient(DeviceConfig device) {
if (device == null) {
return null;
}
String plcType = device.getPlcType();
if (plcType == null || plcType.isEmpty()) {
log.error("PLC类型为空,无法创建客户端: deviceId={}", device.getId());
return null;
}
// 根据PLC类型创建不同的客户端
// 支持 S7_1200, S7_1500 等格式,也支持 S1200, S1500 等格式
String normalizedPlcType = plcType.toUpperCase();
if (normalizedPlcType.startsWith("S7") ||
normalizedPlcType.startsWith("S1200") ||
normalizedPlcType.startsWith("S1500") ||
normalizedPlcType.startsWith("S200") ||
normalizedPlcType.startsWith("S300") ||
normalizedPlcType.startsWith("S400")) {
// S7协议客户端
return createS7Client(device);
} else if (normalizedPlcType.equals("MODBUS")) {
// Modbus协议客户端
return createModbusClient(device);
} else {
log.error("不支持的PLC类型: deviceId={}, plcType={}", device.getId(), plcType);
return null;
}
}
/**
* 创建S7协议客户端
*
* @param device 设备配置
* @return S7客户端实例
*/
private PlcClient createS7Client(DeviceConfig device) {
try {
// 获取S7序列化器
EnhancedS7Serializer s7Serializer = s7SerializerProvider.getSerializer(device);
if (s7Serializer == null) {
log.error("获取S7Serializer失败: deviceId={}", device.getId());
return null;
}
// 创建S7客户端
S7PlcClient client = new S7PlcClient(device, s7Serializer);
// 设置PLC动态数据服务
client.setPlcDynamicDataService(this.plcDynamicDataService);
return client;
} catch (Exception e) {
log.error("创建S7客户端失败: deviceId={}", device.getId(), e);
return null;
}
}
/**
* 创建Modbus协议客户端
*
* @param device 设备配置
* @return Modbus客户端实例
*/
private PlcClient createModbusClient(DeviceConfig device) {
try {
// 创建Modbus客户端
return new ModbusPlcClient(device);
} catch (Exception e) {
log.error("创建Modbus客户端失败: deviceId={}", device.getId(), e);
return null;
}
}
/**
* 关闭并移除指定设备的PLC客户端
*
* @param device 设备配置
*/
public void removeClient(DeviceConfig device) {
if (device == null) {
return;
}
String cacheKey = generateCacheKey(device);
PlcClient client = clientCache.remove(cacheKey);
if (client != null) {
client.disconnect();
log.info("PLC客户端已移除: cacheKey={}", cacheKey);
}
}
/**
* 关闭并清除所有PLC客户端
*/
public void clearAllClients() {
log.info("开始清除所有PLC客户端,当前缓存大小: {}", clientCache.size());
for (PlcClient client : clientCache.values()) {
try {
client.disconnect();
} catch (Exception e) {
log.error("关闭PLC客户端失败", e);
}
}
clientCache.clear();
log.info("所有PLC客户端已清除");
}
/**
* 获取客户端缓存大小
*
* @return 缓存大小
*/
public int getCacheSize() {
return clientCache.size();
}
}