diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java index ffc7f55..1045814 100644 --- a/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java +++ b/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java @@ -5,7 +5,9 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.gxwebsoft.common.system.entity.Setting; import com.gxwebsoft.common.system.param.SettingParam; +import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -37,4 +39,20 @@ public interface SettingMapper extends BaseMapper { @InterceptorIgnore(tenantLine = "true") Setting getBySettingKeyIgnore(@Param("param") SettingParam param); + + /** + * 统计指定租户下某 setting_key 的记录数(绕过多租户插件,自行按 tenant_id 过滤)。 + * 用于初始化时幂等判断,避免被上下文租户覆盖。 + */ + @InterceptorIgnore(tenantLine = "true") + @Select("SELECT COUNT(1) FROM sys_setting WHERE setting_key = #{settingKey} AND tenant_id = #{tenantId} AND deleted = 0") + int countByKeyAndTenant(@Param("settingKey") String settingKey, @Param("tenantId") Integer tenantId); + + /** + * 显式插入系统设置(绕过多租户插件,tenant_id 由实体携带,确保写入目标租户)。 + */ + @InterceptorIgnore(tenantLine = "true") + @Insert("INSERT INTO sys_setting (setting_key, content, sort_number, comments, tenant_id, create_time, update_time, deleted) " + + "VALUES (#{settingKey}, #{content}, #{sortNumber}, #{comments}, #{tenantId}, #{createTime}, #{updateTime}, 0)") + int insertSetting(Setting setting); } diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java index efe09ae..8eefa20 100644 --- a/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java @@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.gxwebsoft.common.core.Constants; import com.gxwebsoft.common.core.utils.CommonUtil; import com.gxwebsoft.common.core.utils.DomainUtil; +import com.gxwebsoft.common.core.utils.MinioUtil; import com.gxwebsoft.common.core.utils.RedisUtil; import com.gxwebsoft.common.system.entity.*; import com.gxwebsoft.common.system.mapper.MenuMapper; import com.gxwebsoft.common.system.mapper.RoleMapper; import com.gxwebsoft.common.system.mapper.RoleMenuMapper; +import com.gxwebsoft.common.system.mapper.SettingMapper; import com.gxwebsoft.common.system.mapper.UserRoleMapper; import com.gxwebsoft.common.system.mapper.TenantMapper; import com.gxwebsoft.common.system.param.MenuParam; @@ -21,6 +23,7 @@ import com.gxwebsoft.common.system.param.TenantParam; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageResult; +import com.alibaba.fastjson.JSONObject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -28,6 +31,7 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -73,6 +77,8 @@ import java.util.stream.Collectors; private UserService userService; @Resource private RedisUtil redisUtil; + @Resource + private SettingMapper settingMapper; @Override public PageResult pageRel(TenantParam param) { @@ -616,6 +622,12 @@ import java.util.stream.Collectors; // 添加菜单ID到超级管理员所属角色ID if (resultMenu) { saveRedis(company); + // 初始化默认 MinIO 云存储配置(oss-{tenantId} 桶 + 自动建桶/策略),失败不阻断开通 + try { + initDefaultUploadSetting(company.getTid()); + } catch (Exception e) { + System.out.println("[Tenant] 初始化默认上传配置失败(不影响开通): " + e.getMessage()); + } } } @@ -667,6 +679,52 @@ import java.util.stream.Collectors; redisUtil.set(key, tenant); } + /** + * 为新开通的租户写入默认 MinIO 上传配置,并自动建桶 + 匿名只读策略。 + * 幂等:若已存在 upload 配置则跳过。 + */ + private void initDefaultUploadSetting(Integer tenantId) { + // 绕过多租户插件,按目标租户精确计数,避免被上下文租户覆盖 + int exists = settingMapper.countByKeyAndTenant("upload", tenantId); + if (exists > 0) { + return; + } + final String bucketName = "oss-" + tenantId; + final String endpoint = "https://minio.sitelnk.cn"; + final String accessKeyId = "ZB1RK0ARI4XPF0CWA2FF"; + final String accessKeySecret = "QPnFBGLmXxto1lBEiaTyXgf4E4H46e8TOR4sYyiY"; + + JSONObject content = new JSONObject(); + content.put("settingKey", "upload"); + content.put("uploadMethod", "minio"); + content.put("bucketName", bucketName); + content.put("bucketEndpoint", endpoint); + content.put("accessKeyId", accessKeyId); + content.put("accessKeySecret", accessKeySecret); + content.put("bucketDomain", endpoint + "/" + bucketName); + + Setting setting = new Setting(); + setting.setSettingKey("upload"); + setting.setContent(content.toJSONString()); + setting.setSortNumber(0); + setting.setComments("默认MinIO存储"); + setting.setTenantId(tenantId); + setting.setDeleted(0); + setting.setCreateTime(new Date()); + setting.setUpdateTime(new Date()); + settingMapper.insertSetting(setting); + + // 预热上传配置缓存,避免新租户首次读取命中空缓存 + redisUtil.set("Upload:" + tenantId, content); + + // 自动建桶 + 匿名只读策略(失败不阻断开通) + try { + MinioUtil.ensureBucketReady(MinioUtil.buildClient(endpoint, accessKeyId, accessKeySecret), endpoint, bucketName); + } catch (Exception e) { + System.out.println("[Tenant] 初始化时自动建桶失败(忽略): " + e.getMessage()); + } + } + @Override public boolean destructionAll(Integer tenantId){ if (baseMapper.destructionAll(tenantId)) {