| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- import { GenericCrudService } from '@d8d/shared-crud';
- import { DataSource, In } from 'typeorm';
- import { SystemConfigMt } from '../entities/system-config.entity.mt';
- import { redisUtil } from '@d8d/shared-utils';
- export class SystemConfigServiceMt extends GenericCrudService<SystemConfigMt> {
- constructor(dataSource: DataSource) {
- super(dataSource, SystemConfigMt, {
- tenantOptions: {
- enabled: true,
- tenantIdField: 'tenantId',
- autoExtractFromContext: true
- },
- userTracking: {
- createdByField: 'createdBy',
- updatedByField: 'updatedBy'
- }
- });
- }
- /**
- * 根据配置键获取配置值(带缓存)
- */
- async getConfigByKey(configKey: string, tenantId: number): Promise<string | null> {
- // 1. 先尝试从缓存获取
- const cachedValue = await redisUtil.getSystemConfig(tenantId, configKey);
- // 2. 如果缓存命中且不是空值缓存
- if (cachedValue !== null && !redisUtil.isNullValue(cachedValue)) {
- return cachedValue;
- }
- // 3. 如果是空值缓存,直接返回null
- if (cachedValue !== null && redisUtil.isNullValue(cachedValue)) {
- return null;
- }
- // 4. 缓存未命中,查询数据库
- const config = await this.repository.findOne({
- where: { configKey, tenantId }
- });
- const configValue = config?.configValue || null;
- // 5. 将结果写入缓存
- if (configValue !== null) {
- // 正常值,缓存1小时
- await redisUtil.setSystemConfig(tenantId, configKey, configValue, 3600);
- } else {
- // 空值,缓存5分钟防止缓存穿透
- await redisUtil.setNullSystemConfig(tenantId, configKey, 300);
- }
- return configValue;
- }
- /**
- * 根据配置键获取配置值,如果不存在则返回默认值
- */
- async getConfigByKeyWithDefault(configKey: string, defaultValue: string, tenantId: number): Promise<string> {
- const value = await this.getConfigByKey(configKey, tenantId);
- return value || defaultValue;
- }
- /**
- * 批量获取配置(带缓存)
- */
- async getConfigsByKeys(configKeys: string[], tenantId: number): Promise<Record<string, string>> {
- // 1. 先尝试从缓存批量获取
- const cachedValues = await redisUtil.getSystemConfigs(tenantId, configKeys);
- const result: Record<string, string> = {};
- const missingKeys: string[] = [];
- // 2. 处理缓存命中的键
- configKeys.forEach(key => {
- const cachedValue = cachedValues[key];
- if (cachedValue !== null && !redisUtil.isNullValue(cachedValue)) {
- result[key] = cachedValue;
- } else if (cachedValue === null) {
- // 缓存未命中,需要查询数据库
- missingKeys.push(key);
- }
- // 如果是空值缓存,不添加到结果中(保持为undefined)
- });
- // 3. 如果有未命中的键,查询数据库
- if (missingKeys.length > 0) {
- const configs = await this.repository.find({
- where: {
- configKey: In(missingKeys),
- tenantId
- }
- });
- const dbValues: Record<string, string> = {};
- configs.forEach(config => {
- if (config.configValue !== null) {
- dbValues[config.configKey] = config.configValue;
- }
- });
- // 4. 处理数据库查询结果并更新缓存
- const cachePromises: Promise<void>[] = [];
- missingKeys.forEach(key => {
- const dbValue = dbValues[key];
- if (dbValue !== undefined) {
- // 数据库中有值,添加到结果并缓存
- result[key] = dbValue;
- cachePromises.push(redisUtil.setSystemConfig(tenantId, key, dbValue, 3600));
- } else {
- // 数据库中无值,设置空值缓存
- cachePromises.push(redisUtil.setNullSystemConfig(tenantId, key, 300));
- }
- });
- // 等待所有缓存操作完成
- if (cachePromises.length > 0) {
- await Promise.all(cachePromises);
- }
- }
- return result;
- }
- /**
- * 设置配置值,如果配置键不存在则创建,存在则更新
- */
- async setConfig(configKey: string, configValue: string, tenantId: number, description?: string): Promise<SystemConfigMt> {
- const existingConfig = await this.repository.findOne({
- where: { configKey, tenantId }
- });
- if (existingConfig) {
- // 更新现有配置
- const updatedConfig = await this.update(existingConfig.id, {
- configValue,
- description: description || existingConfig.description
- });
- // 清除相关缓存
- await redisUtil.deleteSystemConfig(tenantId, configKey);
- return updatedConfig!;
- } else {
- // 创建新配置
- const newConfig = await this.create({
- configKey,
- configValue,
- description,
- tenantId
- } as SystemConfigMt);
- // 清除相关缓存(如果之前有空值缓存)
- await redisUtil.deleteSystemConfig(tenantId, configKey);
- return newConfig!;
- }
- }
- /**
- * 获取租户的所有配置
- */
- async getAllConfigs(tenantId: number): Promise<SystemConfigMt[]> {
- return await this.repository.find({ where: { tenantId } });
- }
- /**
- * 删除配置
- */
- async deleteConfig(configKey: string, tenantId: number): Promise<boolean> {
- const config = await this.repository.findOne({
- where: { configKey, tenantId }
- });
- if (!config) {
- return false;
- }
- await this.delete(config.id);
- // 清除相关缓存
- await redisUtil.deleteSystemConfig(tenantId, configKey);
- return true;
- }
- /**
- * 重写update方法,在更新时清除缓存
- */
- async update(id: number, data: Partial<SystemConfigMt>): Promise<SystemConfigMt | null> {
- const updatedConfig = await super.update(id, data);
- if (updatedConfig) {
- // 清除相关缓存
- const effectiveTenantId = updatedConfig.tenantId ?? 0;
- await redisUtil.deleteSystemConfig(effectiveTenantId, updatedConfig.configKey);
- }
- return updatedConfig;
- }
- /**
- * 重写delete方法,在删除时清除缓存
- */
- async delete(id: number): Promise<boolean> {
- // 先获取配置信息,以便后续清除缓存
- const config = await this.getById(id);
- const result = await super.delete(id);
- if (result && config) {
- // 清除相关缓存
- const effectiveTenantId = config.tenantId ?? 0;
- await redisUtil.deleteSystemConfig(effectiveTenantId, config.configKey);
- }
- return result;
- }
- /**
- * 缓存预热 - 预加载常用配置到缓存
- */
- async warmUpCache(tenantId: number, configKeys?: string[]): Promise<void> {
- // 如果没有指定配置键,预加载所有配置
- const keysToWarm = configKeys || ['app.login.enabled', 'app.payment.enabled', 'app.notification.enabled'];
- // 批量获取配置并缓存
- await this.getConfigsByKeys(keysToWarm, tenantId);
- }
- }
|