package jnpf.i18n.provider; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.TimedCache; import jnpf.base.UserInfo; import jnpf.config.ConfigValueUtil; import jnpf.constant.GlobalConst; import jnpf.constant.model.MCode; import jnpf.util.TenantHolder; import jnpf.util.UserProvider; import lombok.extern.slf4j.Slf4j; import java.util.Locale; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; /** * 国际化语言翻译 */ @Slf4j public class MyI18nMessageProvider implements I18nMessageProvider { private ConfigValueUtil configValueUtil; private final long CACHE_TIME = 48 * 60 * 60000L; // 未使用的情况下, 默认48小时失效, 使用后重新计算缓存时效 private TimedCache> tenantMessageProperties = CacheUtil.newTimedCache(CACHE_TIME); // 翻译内容提供者 private DynamicMessageProvider dynamicMessageProvider; // 租户语言加载锁 private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); private Properties emptyProperties = new Properties(); public MyI18nMessageProvider(ConfigValueUtil configValueUtil, DynamicMessageProvider dynamicMessageProvider) { this.configValueUtil = configValueUtil; this.dynamicMessageProvider = dynamicMessageProvider; // 执行定时清理 tenantMessageProperties.schedulePrune(CACHE_TIME); } public void removeTenantCache(String tenantId) { tenantMessageProperties.remove(tenantId); } public void loadTenantMessage(String tenantId, Locale locale) { Properties i18nListProperties = dynamicMessageProvider.getI18nListProperties(locale); TimedCache tenantProperties = tenantMessageProperties.get(tenantId); if (tenantProperties == null) { tenantProperties = CacheUtil.newTimedCache(CACHE_TIME); tenantMessageProperties.put(tenantId, tenantProperties); } if (i18nListProperties == null) { // 语言加载失败, 一分钟后重新加载, 避免高频请求 tenantProperties.put(locale.toLanguageTag(), emptyProperties, 60000L); } else { // 无论是否有内容返回都是加载成功, 如果properties为空没有翻译数据, 服务端新增翻译时会清空缓存重新加载 tenantProperties.put(locale.toLanguageTag(), i18nListProperties); } } @Override public MCode getI18nMessage(String code, Locale locale) { UserInfo userInfo = UserProvider.getUser(); // 未登录不获取 if (userInfo.getToken() == null) { return null; } // 默认租户或者当前租户 String tenantId = GlobalConst.DEFAULT_TENANT_VALUE; if (configValueUtil.isMultiTenancy()) { tenantId = TenantHolder.getDatasourceId(); } // 开启租户未获取到租户 不进行翻译获取 if (tenantId != null) { // 租户配置中的语言配置 String languageTag = locale.toLanguageTag(); if (!tenantMessageProperties.containsKey(tenantId) || !tenantMessageProperties.get(tenantId).containsKey(languageTag)) { // 租户其他线程正在加载多语言则直接返回 ReentrantLock lock = lockMap.computeIfAbsent(tenantId, k -> new ReentrantLock()); boolean isLock = false; try { isLock = lock.tryLock(); if (isLock) { loadTenantMessage(tenantId, locale); } else { log.debug("[{}]语言加载中, 直接返回", tenantId); return null; } } finally { if (isLock) { lock.unlock(); } } } Properties languageProperty = tenantMessageProperties.get(tenantId).get(languageTag, false); if (languageProperty != null) { Object message = languageProperty.get(code); if (message != null) { return new MCode("", code, message.toString()); } } } return null; } }