package xiaozhi.modules.sys.service.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.AllArgsConstructor; import xiaozhi.common.constant.Constant; import xiaozhi.common.exception.ErrorCode; import xiaozhi.common.exception.RenException; import xiaozhi.common.page.PageData; import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.JsonUtils; import xiaozhi.common.utils.SM2Utils; import xiaozhi.modules.agent.service.AgentPluginMappingService; import xiaozhi.modules.sys.dao.SysParamsDao; import xiaozhi.modules.sys.dto.SysParamsDTO; import xiaozhi.modules.sys.entity.SysParamsEntity; import xiaozhi.modules.sys.redis.SysParamsRedis; import xiaozhi.modules.sys.service.SysParamsService; /** * 参数管理 */ @AllArgsConstructor @Service public class SysParamsServiceImpl extends BaseServiceImpl implements SysParamsService { private final SysParamsRedis sysParamsRedis; private final AgentPluginMappingService agentPluginMappingService; @Override public PageData page(Map params) { IPage page = baseDao.selectPage( getPage(params, null, false), getWrapper(params)); return getPageData(page, SysParamsDTO.class); } @Override public List list(Map params) { List entityList = baseDao.selectList(getWrapper(params)); return ConvertUtils.sourceToTarget(entityList, SysParamsDTO.class); } private QueryWrapper getWrapper(Map params) { String paramCode = (String) params.get("paramCode"); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("param_type", 1); wrapper.nested(StringUtils.isNotBlank(paramCode), i -> i.like("param_code", paramCode) .or() .like("remark", paramCode)); return wrapper; } @Override public SysParamsDTO get(Long id) { SysParamsEntity entity = baseDao.selectById(id); return ConvertUtils.sourceToTarget(entity, SysParamsDTO.class); } @Override @Transactional(rollbackFor = Exception.class) public void save(SysParamsDTO dto) { validateParamValue(dto); SysParamsEntity entity = ConvertUtils.sourceToTarget(dto, SysParamsEntity.class); insert(entity); sysParamsRedis.set(entity.getParamCode(), entity.getParamValue()); } @Override @Transactional(rollbackFor = Exception.class) public void update(SysParamsDTO dto) { validateParamValue(dto); detectingSMSParameters(dto.getParamCode(), dto.getParamValue()); SysParamsEntity entity = ConvertUtils.sourceToTarget(dto, SysParamsEntity.class); updateById(entity); sysParamsRedis.set(entity.getParamCode(), entity.getParamValue()); } /** * 校验参数值类型 */ private void validateParamValue(SysParamsDTO dto) { if (dto == null) { throw new RenException(ErrorCode.PARAM_VALUE_NULL); } if (StringUtils.isBlank(dto.getParamValue())) { throw new RenException(ErrorCode.PARAM_VALUE_NULL); } if (StringUtils.isBlank(dto.getValueType())) { throw new RenException(ErrorCode.PARAM_TYPE_NULL); } String valueType = dto.getValueType().toLowerCase(); String paramValue = dto.getParamValue(); switch (valueType) { case "string": break; case "array": break; case "number": try { Double.parseDouble(paramValue); } catch (NumberFormatException e) { throw new RenException(ErrorCode.PARAM_NUMBER_INVALID); } break; case "boolean": if (!"true".equalsIgnoreCase(paramValue) && !"false".equalsIgnoreCase(paramValue)) { throw new RenException(ErrorCode.PARAM_BOOLEAN_INVALID); } break; case "json": try { // 首先检查是否以 { 开头,以 } 结尾 String trimmedValue = paramValue.trim(); if (!trimmedValue.startsWith("{") || !trimmedValue.endsWith("}")) { throw new RenException(ErrorCode.PARAM_JSON_INVALID); } // 然后尝试解析JSON JsonUtils.parseObject(paramValue, Object.class); } catch (Exception e) { throw new RenException(ErrorCode.PARAM_JSON_INVALID); } break; default: throw new RenException(ErrorCode.PARAM_TYPE_INVALID); } } @Override @Transactional(rollbackFor = Exception.class) public void delete(String[] ids) { // 删除Redis数据 List paramCodeList = baseDao.getParamCodeList(ids); String[] paramCodes = paramCodeList.toArray(new String[paramCodeList.size()]); if (paramCodes.length > 0) { sysParamsRedis.delete(paramCodes); } // 删除 deleteBatchIds(Arrays.asList(ids)); } @Override public String getValue(String paramCode, Boolean fromCache) { String paramValue = null; if (fromCache) { paramValue = sysParamsRedis.get(paramCode); if (paramValue == null) { paramValue = baseDao.getValueByCode(paramCode); sysParamsRedis.set(paramCode, paramValue); } } else { paramValue = baseDao.getValueByCode(paramCode); } return paramValue; } @Override public T getValueObject(String paramCode, Class clazz) { String paramValue = getValue(paramCode, true); if (StringUtils.isNotBlank(paramValue)) { return JsonUtils.parseObject(paramValue, clazz); } try { return clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RenException(ErrorCode.PARAMS_GET_ERROR); } } @Override @Transactional(rollbackFor = Exception.class) public int updateValueByCode(String paramCode, String paramValue) { int count = baseDao.updateValueByCode(paramCode, paramValue); sysParamsRedis.set(paramCode, paramValue); return count; } @Override public void initServerSecret() { // 获取服务器密钥 String secretParam = getValue(Constant.SERVER_SECRET, false); if (StringUtils.isBlank(secretParam) || "null".equals(secretParam)) { String newSecret = UUID.randomUUID().toString(); updateValueByCode(Constant.SERVER_SECRET, newSecret); } // 初始化SM2密钥对 initSM2KeyPair(); } /** * 初始化SM2密钥对 */ private void initSM2KeyPair() { // 获取SM2公钥 String publicKey = getValue(Constant.SM2_PUBLIC_KEY, false); // 获取SM2私钥 String privateKey = getValue(Constant.SM2_PRIVATE_KEY, false); // 如果公钥或私钥为空,则生成新的密钥对 if (StringUtils.isBlank(publicKey) || StringUtils.isBlank(privateKey) || "null".equals(publicKey) || "null".equals(privateKey)) { Map keyPair = SM2Utils.createKey(); String newPublicKey = keyPair.get(SM2Utils.KEY_PUBLIC_KEY); String newPrivateKey = keyPair.get(SM2Utils.KEY_PRIVATE_KEY); // 更新数据库中的密钥对 updateValueByCode(Constant.SM2_PUBLIC_KEY, newPublicKey); updateValueByCode(Constant.SM2_PRIVATE_KEY, newPrivateKey); } } /** * 检测短信参数是否符合要求 * * @param paramCode 参数编码 * @param paramValue 参数值 * @return 是否通过 */ private boolean detectingSMSParameters(String paramCode, String paramValue) { // 判断是否是开启手机注册的参数编码,如果不是参数编码,着不需要检测其他短信参数,直接返回true if (!Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue().equals(paramCode)) { return true; } // 判断是否为关闭,如果是关闭短信注册,着不需要检测其他短信参数,直接返回true if ("false".equalsIgnoreCase(paramValue)) { return true; } // 检测短信关联参数是否为空 ArrayList list = new ArrayList(); list.add(Constant.SysMSMParam.SERVER_SMS_MAX_SEND_COUNT.getValue()); list.add(Constant.SysMSMParam.ALIYUN_SMS_ACCESS_KEY_ID.getValue()); list.add(Constant.SysMSMParam.ALIYUN_SMS_ACCESS_KEY_SECRET.getValue()); list.add(Constant.SysMSMParam.ALIYUN_SMS_SIGN_NAME.getValue()); list.add(Constant.SysMSMParam.ALIYUN_SMS_SMS_CODE_TEMPLATE_CODE.getValue()); StringBuilder str = new StringBuilder(); list.forEach(item -> { if (!StringUtils.isNoneBlank(item)) { str.append(",").append(item); } }); if (!str.isEmpty()) { String promptStr = "%s这些参数不可以为空"; String substring = str.substring(1, str.length()); throw new RenException(promptStr.formatted(substring)); } return true; } @Override public String getSystemWebMenu(boolean fromCache) { return getValue(Constant.SYSTEM_WEB_MENU, fromCache); } @Override @Transactional(rollbackFor = Exception.class) public void updateSystemWebMenu(String configJson) { // 获取当前配置 String currentConfig = getSystemWebMenu(false); Map currentMap = null; Map newMap = null; try { if (StringUtils.isNotBlank(currentConfig)) { currentMap = JsonUtils.parseMap(currentConfig); } if (StringUtils.isNotBlank(configJson)) { newMap = JsonUtils.parseMap(configJson); } } catch (Exception e) { throw new RenException(ErrorCode.PARAM_JSON_INVALID); } // 检查addressBook功能是否被关闭 if (currentMap != null && newMap != null) { Map currentFeatures = Map.class.cast(currentMap.get("features")); Map newFeatures = Map.class.cast(newMap.get("features")); if (currentFeatures != null && newFeatures != null) { Object currentAddressBookObj = currentFeatures.get("addressBook"); Object newAddressBookObj = newFeatures.get("addressBook"); Boolean currentEnabled = false; Boolean newEnabled = false; if (currentAddressBookObj instanceof Map currentAddressBook) { Object enabled = currentAddressBook.get("enabled"); currentEnabled = enabled != null ? Boolean.class.cast(enabled) : false; } if (newAddressBookObj instanceof Map newAddressBook) { Object enabled = newAddressBook.get("enabled"); newEnabled = enabled != null ? Boolean.class.cast(enabled) : false; } // 如果之前是启用状态,现在被禁用,删除所有call_device插件 if (Boolean.TRUE.equals(currentEnabled) && !Boolean.TRUE.equals(newEnabled)) { agentPluginMappingService.deleteByPluginId("SYSTEM_PLUGIN_CALL_DEVICE"); } } } // 更新配置 updateValueByCode(Constant.SYSTEM_WEB_MENU, configJson); } }