refactor(integration): 重构配置管理功能

- 新增通用 ConfigManager 类,实现配置管理的通用功能
- 新增 DeviceConfigManager 和 ScenicConfigManager 类,分别实现设备和景区的配置管理- 更新相关控制器和服务,使用新的配置管理器类
-调整设备和景区的配置数据结构,以适应新的管理方式
This commit is contained in:
2025-09-02 15:30:54 +08:00
parent 2dee78247e
commit 8e770a5b97
8 changed files with 424 additions and 20 deletions

View File

@@ -11,7 +11,7 @@ import com.ycwl.basic.pricing.service.ICouponService;
import com.ycwl.basic.pricing.service.VoucherPrintService; import com.ycwl.basic.pricing.service.VoucherPrintService;
import com.ycwl.basic.repository.FaceRepository; import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.util.ScenicConfigManager; import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;

View File

@@ -0,0 +1,241 @@
package com.ycwl.basic.integration.common.manager;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 通用配置管理器基类
* 提供配置查找、类型转换等通用功能
*
* @param <T> 配置DTO类型
*/
public abstract class ConfigManager<T> {
protected List<T> configs;
public ConfigManager(List<T> configs) {
this.configs = configs != null ? configs : new ArrayList<>();
}
/**
* 获取配置项的键
* 子类需要实现此方法来提取配置键
*/
protected abstract String getConfigKey(T config);
/**
* 获取配置项的值
* 子类需要实现此方法来提取配置值
*/
protected abstract Object getConfigValue(T config);
/**
* 根据键查找配置项
*/
protected T findConfigByKey(String key) {
if (key == null || configs == null) {
return null;
}
return configs.stream()
.filter(config -> key.equals(getConfigKey(config)))
.findFirst()
.orElse(null);
}
/**
* 获取字符串配置值
*/
public String getString(String key) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
return value != null ? value.toString() : null;
}
/**
* 获取字符串配置值,如果不存在则返回默认值
*/
public String getString(String key, String defaultValue) {
String value = getString(key);
return value != null ? value : defaultValue;
}
/**
* 获取整型配置值
*/
public Integer getInteger(String key) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
if (value == null) return null;
if (value instanceof Integer) return (Integer) value;
if (value instanceof Number) return ((Number) value).intValue();
if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
return null;
}
}
return null;
}
/**
* 获取整型配置值,如果不存在则返回默认值
*/
public Integer getInteger(String key, Integer defaultValue) {
Integer value = getInteger(key);
return value != null ? value : defaultValue;
}
/**
* 获取布尔型配置值
*/
public Boolean getBoolean(String key) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
if (value == null) return null;
if (value instanceof Boolean) return (Boolean) value;
if (value instanceof String) {
String str = ((String) value).toLowerCase().trim();
return "true".equals(str) || "1".equals(str) || "yes".equals(str);
}
if (value instanceof Number) {
return ((Number) value).intValue() != 0;
}
return null;
}
/**
* 获取布尔型配置值,如果不存在则返回默认值
*/
public Boolean getBoolean(String key, Boolean defaultValue) {
Boolean value = getBoolean(key);
return value != null ? value : defaultValue;
}
/**
* 获取浮点型配置值
*/
public Float getFloat(String key) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
if (value == null) return null;
if (value instanceof Float) return (Float) value;
if (value instanceof Number) return ((Number) value).floatValue();
if (value instanceof String) {
try {
return Float.parseFloat((String) value);
} catch (NumberFormatException e) {
return null;
}
}
return null;
}
/**
* 获取浮点型配置值,如果不存在则返回默认值
*/
public Float getFloat(String key, Float defaultValue) {
Float value = getFloat(key);
return value != null ? value : defaultValue;
}
/**
* 获取BigDecimal配置值
*/
public BigDecimal getBigDecimal(String key) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
if (value == null) return null;
if (value instanceof BigDecimal) return (BigDecimal) value;
if (value instanceof Number) return new BigDecimal(value.toString());
if (value instanceof String) {
try {
return new BigDecimal((String) value);
} catch (NumberFormatException e) {
return null;
}
}
return null;
}
/**
* 获取BigDecimal配置值,如果不存在则返回默认值
*/
public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
BigDecimal value = getBigDecimal(key);
return value != null ? value : defaultValue;
}
/**
* 获取枚举配置值
*/
public <E extends Enum<E>> E getEnum(String key, Class<E> enumClass) {
T config = findConfigByKey(key);
if (config == null) {
return null;
}
Object value = getConfigValue(config);
return parseEnum(value, enumClass);
}
/**
* 解析枚举值
*/
private <E extends Enum<E>> E parseEnum(Object value, Class<E> enumClass) {
if (value == null) return null;
try {
if (value instanceof String) {
return Enum.valueOf(enumClass, (String) value);
}
return Enum.valueOf(enumClass, value.toString());
} catch (IllegalArgumentException e) {
return null;
}
}
/**
* 获取枚举配置值,如果不存在则返回默认值
*/
public <E extends Enum<E>> E getEnum(String key, Class<E> enumClass, E defaultValue) {
E value = getEnum(key, enumClass);
return value != null ? value : defaultValue;
}
/**
* 检查指定键的配置是否存在
*/
public boolean hasConfig(String key) {
return findConfigByKey(key) != null;
}
/**
* 获取所有配置项的数量
*/
public int size() {
return configs.size();
}
/**
* 获取所有配置项
*/
public List<T> getAllConfigs() {
return new ArrayList<>(configs);
}
}

View File

@@ -0,0 +1,122 @@
package com.ycwl.basic.integration.common.manager;
import com.ycwl.basic.integration.device.dto.config.DeviceConfigV2DTO;
import java.util.List;
/**
* 设备配置管理器
* 基于通用ConfigManager实现设备配置的管理功能
*/
public class DeviceConfigManager extends ConfigManager<DeviceConfigV2DTO> {
public DeviceConfigManager(List<DeviceConfigV2DTO> configs) {
super(configs);
}
@Override
protected String getConfigKey(DeviceConfigV2DTO config) {
return config != null ? config.getConfigKey() : null;
}
@Override
protected Object getConfigValue(DeviceConfigV2DTO config) {
return config != null ? config.getConfigValue() : null;
}
/**
* 获取设备配置类型
*/
public String getConfigType(String key) {
DeviceConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getConfigType() : null;
}
/**
* 获取设备配置描述
*/
public String getConfigDescription(String key) {
DeviceConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getDescription() : null;
}
/**
* 获取设备配置ID
*/
public Long getConfigId(String key) {
DeviceConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getId() : null;
}
// 设备配置的常用快捷方法
/**
* 获取设备IP地址
*/
public String getIpAddress() {
return getString("ip_address");
}
/**
* 获取设备分辨率
*/
public String getResolution() {
return getString("resolution");
}
/**
* 获取设备帧率
*/
public Integer getFramerate() {
return getInteger("framerate");
}
/**
* 获取设备协议
*/
public String getProtocol() {
return getString("protocol");
}
/**
* 获取设备用户名
*/
public String getUsername() {
return getString("username");
}
/**
* 获取设备密码
*/
public String getPassword() {
return getString("password");
}
/**
* 获取设备亮度
*/
public Integer getBrightness() {
return getInteger("brightness");
}
/**
* 获取设备对比度
*/
public Integer getContrast() {
return getInteger("contrast");
}
/**
* 获取设备质量
*/
public String getQuality() {
return getString("quality");
}
/**
* 检查设备是否启用录制
*/
public Boolean isRecordingEnabled() {
return getBoolean("recording_enabled");
}
}

View File

@@ -1,4 +1,4 @@
package com.ycwl.basic.util; package com.ycwl.basic.integration.common.manager;
import com.ycwl.basic.integration.common.util.ConfigValueUtil; import com.ycwl.basic.integration.common.util.ConfigValueUtil;
import com.ycwl.basic.integration.scenic.dto.config.ScenicConfigV2DTO; import com.ycwl.basic.integration.scenic.dto.config.ScenicConfigV2DTO;
@@ -9,11 +9,12 @@ import java.util.stream.Collectors;
/** /**
* 景区配置管理器 * 景区配置管理器
* 基于通用ConfigManager实现景区配置的管理功能
* *
* 提供类型安全的配置值获取功能支持多种数据类型的自动转换 * 提供类型安全的配置值获取功能支持多种数据类型的自动转换
* 当类型不兼容时返回null而不是抛出异常 * 当类型不兼容时返回null而不是抛出异常
*/ */
public class ScenicConfigManager { public class ScenicConfigManager extends ConfigManager<ScenicConfigV2DTO> {
private final Map<String, Object> configMap; private final Map<String, Object> configMap;
@@ -23,6 +24,7 @@ public class ScenicConfigManager {
* @param configList 配置项列表 * @param configList 配置项列表
*/ */
public ScenicConfigManager(List<ScenicConfigV2DTO> configList) { public ScenicConfigManager(List<ScenicConfigV2DTO> configList) {
super(configList);
this.configMap = new HashMap<>(); this.configMap = new HashMap<>();
if (configList != null) { if (configList != null) {
for (ScenicConfigV2DTO config : configList) { for (ScenicConfigV2DTO config : configList) {
@@ -39,9 +41,20 @@ public class ScenicConfigManager {
* @param configMap 配置Map * @param configMap 配置Map
*/ */
public ScenicConfigManager(Map<String, Object> configMap) { public ScenicConfigManager(Map<String, Object> configMap) {
super(null); // 使用Map构造时父类configs为null
this.configMap = configMap != null ? new HashMap<>(configMap) : new HashMap<>(); this.configMap = configMap != null ? new HashMap<>(configMap) : new HashMap<>();
} }
@Override
protected String getConfigKey(ScenicConfigV2DTO config) {
return config != null ? config.getConfigKey() : null;
}
@Override
protected Object getConfigValue(ScenicConfigV2DTO config) {
return config != null ? config.getConfigValue() : null;
}
/** /**
* 获取字符串值 * 获取字符串值
* *
@@ -325,7 +338,7 @@ public class ScenicConfigManager {
* *
* @return 配置Map的拷贝 * @return 配置Map的拷贝
*/ */
public Map<String, Object> getAllConfigs() { public Map<String, Object> getAllConfigsAsMap() {
return new HashMap<>(configMap); return new HashMap<>(configMap);
} }

View File

@@ -16,7 +16,7 @@ import com.ycwl.basic.pricing.service.VoucherPrintService;
import com.ycwl.basic.printer.ticket.FeiETicketPrinter; import com.ycwl.basic.printer.ticket.FeiETicketPrinter;
import com.ycwl.basic.repository.FaceRepository; import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.util.ScenicConfigManager; import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.utils.WxMpUtil; import com.ycwl.basic.utils.WxMpUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.Strings;

View File

@@ -1,5 +1,7 @@
package com.ycwl.basic.repository; package com.ycwl.basic.repository;
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
import com.ycwl.basic.integration.device.dto.config.DeviceConfigV2DTO;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.mapper.DeviceMapper; import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity; import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
@@ -7,6 +9,7 @@ import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.utils.SnowFlakeUtil; import com.ycwl.basic.utils.SnowFlakeUtil;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService; import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO; import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -31,6 +34,9 @@ public class DeviceRepository {
public static final String DEVICE_ONLINE_CACHE_KEY = "device:online_status:%s"; public static final String DEVICE_ONLINE_CACHE_KEY = "device:online_status:%s";
public static final String DEVICE_CACHE_KEY = "device:%s"; public static final String DEVICE_CACHE_KEY = "device:%s";
public static final String DEVICE_CONFIG_CACHE_KEY = "device:%s:config"; public static final String DEVICE_CONFIG_CACHE_KEY = "device:%s:config";
public static final String DEVICE_CONFIG_MANAGER_CACHE_KEY = "device:%s:config:manager";
@Autowired
private DeviceConfigIntegrationService deviceConfigIntegrationService;
/** /**
* 将DeviceV2DTO转换为DeviceEntity * 将DeviceV2DTO转换为DeviceEntity
@@ -71,18 +77,41 @@ public class DeviceRepository {
} }
public DeviceConfigEntity getDeviceConfig(Long deviceId) { public DeviceConfigEntity getDeviceConfig(Long deviceId) {
if (redisTemplate.hasKey(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId))) { List<DeviceConfigV2DTO> configList = deviceConfigIntegrationService.getDeviceConfigs(deviceId);
return JacksonUtil.parseObject(redisTemplate.opsForValue().get(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId)), DeviceConfigEntity.class); if (configList != null && !configList.isEmpty()) {
return convertToDeviceConfigEntity(configList, deviceId);
} }
DeviceConfigEntity deviceConfig = deviceMapper.getConfigByDeviceId(deviceId); return null;
if (null == deviceConfig) {
deviceConfig = new DeviceConfigEntity();
deviceConfig.setId(SnowFlakeUtil.getLongId());
deviceConfig.setDeviceId(deviceId);
deviceMapper.addConfig(deviceConfig);
} }
redisTemplate.opsForValue().set(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId), JacksonUtil.toJSONString(deviceConfig), 3, TimeUnit.DAYS);
return deviceConfig; /**
* 获取设备配置管理器
*
* @param deviceId 设备ID
* @return DeviceConfigManager实例,如果获取失败返回null
*/
public DeviceConfigManager getDeviceConfigManager(Long deviceId) {
try {
List<DeviceConfigV2DTO> configList = deviceConfigIntegrationService.getDeviceConfigs(deviceId);
return new DeviceConfigManager(configList);
} catch (Exception e) {
log.warn("获取设备配置管理器失败, deviceId: {}", deviceId, e);
return null;
}
}
/**
* 将DeviceConfigV2DTO列表转换为DeviceConfigEntity(为了兼容性)
*/
private DeviceConfigEntity convertToDeviceConfigEntity(List<DeviceConfigV2DTO> configList, Long deviceId) {
DeviceConfigEntity entity = new DeviceConfigEntity();
entity.setId(SnowFlakeUtil.getLongId());
entity.setDeviceId(deviceId);
// 由于DeviceConfigEntity没有通用的configJson字段,这里只设置基本信息
// 具体的配置项需要通过DeviceConfigManager来访问
return entity;
} }
public boolean clearDeviceCache(String deviceNo) { public boolean clearDeviceCache(String deviceNo) {
@@ -106,9 +135,11 @@ public class DeviceRepository {
DeviceEntity device = getDevice(deviceId); DeviceEntity device = getDevice(deviceId);
redisTemplate.delete(String.format(DEVICE_CACHE_KEY, device.getNo())); redisTemplate.delete(String.format(DEVICE_CACHE_KEY, device.getNo()));
redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, device.getNo())); redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, device.getNo()));
redisTemplate.delete(String.format(DEVICE_CONFIG_MANAGER_CACHE_KEY, device.getNo()));
} }
redisTemplate.delete(String.format(DEVICE_CACHE_KEY, deviceId)); redisTemplate.delete(String.format(DEVICE_CACHE_KEY, deviceId));
redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId)); redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId));
redisTemplate.delete(String.format(DEVICE_CONFIG_MANAGER_CACHE_KEY, deviceId));
return true; return true;
} }

View File

@@ -19,13 +19,12 @@ import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.pay.enums.PayAdapterType; import com.ycwl.basic.pay.enums.PayAdapterType;
import com.ycwl.basic.storage.enums.StorageType; import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.util.ScenicConfigManager; import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Map;
@Component @Component
public class ScenicRepository { public class ScenicRepository {

View File

@@ -3,7 +3,6 @@ package com.ycwl.basic.service.pc.impl;
import com.ycwl.basic.facebody.FaceBodyFactory; import com.ycwl.basic.facebody.FaceBodyFactory;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter; import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.pay.PayFactory; import com.ycwl.basic.pay.PayFactory;
import com.ycwl.basic.pay.adapter.IPayAdapter; import com.ycwl.basic.pay.adapter.IPayAdapter;
@@ -12,10 +11,9 @@ import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.storage.StorageFactory; import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException; import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
import com.ycwl.basic.util.ScenicConfigManager; import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.util.TtlCacheMap; import com.ycwl.basic.util.TtlCacheMap;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;