diff --git a/common/common-online/src/main/java/apelet/common/online/config/OnlineAsyncConfig.java b/common/common-online/src/main/java/apelet/common/online/config/OnlineAsyncConfig.java new file mode 100644 index 0000000..c9cf094 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/config/OnlineAsyncConfig.java @@ -0,0 +1,36 @@ +package apelet.common.online.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * common-online异步任务线程池配置。 + *

供在线表单发布生成权限字等异步任务使用。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Configuration +@EnableAsync +public class OnlineAsyncConfig { + + /** + * 权限字生成/清理专用线程池。 + */ + @Bean("permCodeTaskExecutor") + public ThreadPoolTaskExecutor permCodeTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(2); + executor.setMaxPoolSize(4); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("perm-code-"); + // 队列满时由调用线程执行,避免丢弃任务。 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } +} diff --git a/common/common-online/src/main/java/apelet/common/online/config/OnlineAutoConfig.java b/common/common-online/src/main/java/apelet/common/online/config/OnlineAutoConfig.java index 45338b2..ba86a99 100644 --- a/common/common-online/src/main/java/apelet/common/online/config/OnlineAutoConfig.java +++ b/common/common-online/src/main/java/apelet/common/online/config/OnlineAutoConfig.java @@ -1,6 +1,7 @@ package apelet.common.online.config; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Import; /** * common-online模块的自动配置引导类。 @@ -9,5 +10,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties * @date 2023-08-04 */ @EnableConfigurationProperties({OnlineProperties.class}) +@Import(OnlineAsyncConfig.class) public class OnlineAutoConfig { } diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java index b39fb7b..6c9787b 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java @@ -1139,9 +1139,11 @@ public class OnlineFormController { if (newSubTableNames.isEmpty()) { return false; } + List subTableNameList = new ArrayList<>(newSubTableNames.size()); for (String subTableName : newSubTableNames) { // 因为是附表,所以要加上 subTableName = "t_" + subTableName + "_entry"; + subTableNameList.add(subTableName); OnlFormHead subHead = onlFormHeadService.createMetaAndSync(subTableName, onlFormHead.getTableTxt() + "附表", CustomUtil.MetaType_Entry, onlFormHead.getTableName()); // 获取子表的 OnlineTable OnlineTable subOnlineTable = onlineTableService.getOne(new LambdaQueryWrapper().eq(OnlineTable::getTableName, subTableName.toLowerCase())); @@ -1161,7 +1163,7 @@ public class OnlineFormController { } //这里要将 所有的附表名称 加到 apelet.common.generator.model.OnlFormHead.childName 后面 - String newSubTableName = String.join(",", newSubTableNames); + String newSubTableName = String.join(",", subTableNameList); if (StringUtils.isNotBlank(onlFormHead.getChildName())) { onlFormHead.setChildName(onlFormHead.getChildName() + "," + newSubTableName); } else { diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java index 8d137a7..a6e37f9 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java @@ -23,6 +23,7 @@ import apelet.common.online.dto.OnlinePageDto; import apelet.common.online.model.*; import apelet.common.online.model.constant.PageStatus; import apelet.common.online.service.*; +import apelet.common.online.upms.service.OnlinePermCodeService; import apelet.common.online.vo.OnlineDatasourceVo; import apelet.common.online.vo.OnlinePageDatasourceVo; import apelet.common.online.vo.OnlinePageVo; @@ -77,6 +78,8 @@ public class OnlinePageController { private OnlineColumnService onlineColumnService; @Autowired private IOnlFormFieldService onlFormFieldService; + @Autowired + private OnlinePermCodeService onlinePermCodeService; //new=新建元数据,exist=现有元数据 private static final String META_SOURCE_NEW = "new"; @@ -494,6 +497,11 @@ public class OnlinePageController { } onlinePageService.updatePublished(pageId, published); } + //异步发布权限字 + if (BooleanUtil.isTrue(published)) { + onlinePermCodeService.genPermCodeByPageId(pageId, TokenData.takeFromRequest().getUserId()); + } + return ResponseResult.success(); } @@ -511,10 +519,13 @@ public class OnlinePageController { if (!verifyResult.isSuccess()) { return ResponseResult.errorFrom(verifyResult); } + OnlinePage originalOnlinePage = verifyResult.getData(); if (!onlinePageService.remove(pageId)) { errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); } + // 异步清理发布时自动生成的权限字。 + onlinePermCodeService.removePermCodeByPageCode(originalOnlinePage.getPageCode()); return ResponseResult.success(); } diff --git a/common/common-online/src/main/java/apelet/common/online/service/OnlinePageService.java b/common/common-online/src/main/java/apelet/common/online/service/OnlinePageService.java index b15c644..0d174d7 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/OnlinePageService.java +++ b/common/common-online/src/main/java/apelet/common/online/service/OnlinePageService.java @@ -14,7 +14,7 @@ import java.util.List; */ public interface OnlinePageService extends IBaseService { - /** + /**z * 保存新增对象。 * * @param onlinePage 新增对象。 diff --git a/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodeMapper.java b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodeMapper.java new file mode 100644 index 0000000..d3225e7 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodeMapper.java @@ -0,0 +1,14 @@ +package apelet.common.online.upms.dao; + +import apelet.common.core.base.dao.BaseDaoMapper; +import apelet.common.online.upms.model.SysPermCode; + +/** + * 权限字数据访问操作接口。 + *

在线表单发布自动生成权限字使用,精简自 tenant-admin 的同名 Mapper。

+ * + * @author guifc + * @date 2023-08-04 + */ +public interface SysPermCodeMapper extends BaseDaoMapper { +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodePermMapper.java b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodePermMapper.java new file mode 100644 index 0000000..d4075b3 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermCodePermMapper.java @@ -0,0 +1,14 @@ +package apelet.common.online.upms.dao; + +import apelet.common.core.base.dao.BaseDaoMapper; +import apelet.common.online.upms.model.SysPermCodePerm; + +/** + * 权限字与权限资源关系数据访问操作接口。 + *

在线表单发布自动生成权限字使用,精简自 tenant-admin 的同名 Mapper。

+ * + * @author guifc + * @date 2023-08-04 + */ +public interface SysPermCodePermMapper extends BaseDaoMapper { +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermMapper.java b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermMapper.java new file mode 100644 index 0000000..d290163 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermMapper.java @@ -0,0 +1,14 @@ +package apelet.common.online.upms.dao; + +import apelet.common.core.base.dao.BaseDaoMapper; +import apelet.common.online.upms.model.SysPerm; + +/** + * 权限资源数据访问操作接口。 + *

在线表单发布自动生成权限字使用,精简自 tenant-admin 的同名 Mapper。

+ * + * @author guifc + * @date 2023-08-04 + */ +public interface SysPermMapper extends BaseDaoMapper { +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermModuleMapper.java b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermModuleMapper.java new file mode 100644 index 0000000..2cb8969 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/dao/SysPermModuleMapper.java @@ -0,0 +1,14 @@ +package apelet.common.online.upms.dao; + +import apelet.common.core.base.dao.BaseDaoMapper; +import apelet.common.online.upms.model.SysPermModule; + +/** + * 权限模块数据访问操作接口。 + *

在线表单发布自动生成权限字使用,精简自 tenant-admin 的同名 Mapper。

+ * + * @author guifc + * @date 2023-08-04 + */ +public interface SysPermModuleMapper extends BaseDaoMapper { +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/model/SysPerm.java b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPerm.java new file mode 100644 index 0000000..c77b5e6 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPerm.java @@ -0,0 +1,55 @@ +package apelet.common.online.upms.model; + +import apelet.common.core.base.model.BaseModel; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 权限资源实体对象。 + *

在线表单发布自动生成权限字使用,仅保留数据库字段,精简自 tenant-admin 的同名实体。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "xy_sys_perm") +public class SysPerm extends BaseModel { + + /** + * 权限Id。 + */ + @TableId(value = "perm_id") + private Long permId; + + /** + * 权限所在的权限模块Id。 + */ + @TableField(value = "module_id") + private Long moduleId; + + /** + * 权限名称。 + */ + @TableField(value = "perm_name") + private String permName; + + /** + * 关联的URL。 + */ + private String url; + + /** + * 权限在当前模块下的顺序,由小到大。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCode.java b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCode.java new file mode 100644 index 0000000..62ebf65 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCode.java @@ -0,0 +1,62 @@ +package apelet.common.online.upms.model; + +import apelet.common.core.base.model.BaseModel; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 权限字实体对象。 + *

在线表单发布自动生成权限字使用,仅保留数据库字段,精简自 tenant-admin 的同名实体。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "xy_sys_perm_code") +public class SysPermCode extends BaseModel { + + /** + * 主键Id。 + */ + @TableId(value = "perm_code_id") + private Long permCodeId; + + /** + * 上级权限字Id。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 权限字标识(一般为有含义的英文字符串)。 + */ + @TableField(value = "perm_code") + private String permCode; + + /** + * 权限类型(0: 表单 1: UI片段 2: 操作)。 + */ + @TableField(value = "perm_code_type") + private Integer permCodeType; + + /** + * 显示名称。 + */ + @TableField(value = "show_name") + private String showName; + + /** + * 显示顺序(数值越小,越靠前)。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCodePerm.java b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCodePerm.java new file mode 100644 index 0000000..b1fe2e4 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermCodePerm.java @@ -0,0 +1,29 @@ +package apelet.common.online.upms.model; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 权限字与权限资源关联实体对象。 + *

在线表单发布自动生成权限字使用,精简自 tenant-admin 的同名实体。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Data +@TableName(value = "xy_sys_perm_code_perm") +public class SysPermCodePerm { + + /** + * 权限字Id。 + */ + @TableField(value = "perm_code_id") + private Long permCodeId; + + /** + * 权限Id。 + */ + @TableField(value = "perm_id") + private Long permId; +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermModule.java b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermModule.java new file mode 100644 index 0000000..b60e159 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/model/SysPermModule.java @@ -0,0 +1,56 @@ +package apelet.common.online.upms.model; + +import apelet.common.core.base.model.BaseModel; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 权限模块实体对象。 + *

在线表单发布自动生成权限字使用,仅保留数据库字段,精简自 tenant-admin 的同名实体。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "xy_sys_perm_module") +public class SysPermModule extends BaseModel { + + /** + * 权限模块Id。 + */ + @TableId(value = "module_id") + private Long moduleId; + + /** + * 上级权限模块Id。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 权限模块名称。 + */ + @TableField(value = "module_name") + private String moduleName; + + /** + * 权限模块类型(0: 普通模块 1: Controller模块)。 + */ + @TableField(value = "module_type") + private Integer moduleType; + + /** + * 权限模块在当前层级下的顺序,由小到大。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/service/OnlinePermCodeService.java b/common/common-online/src/main/java/apelet/common/online/upms/service/OnlinePermCodeService.java new file mode 100644 index 0000000..4003aa6 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/service/OnlinePermCodeService.java @@ -0,0 +1,26 @@ +package apelet.common.online.upms.service; + +/** + * 在线表单权限字生成/清理服务接口。 + *

在线表单发布后自动生成权限字,删除时同步清理。实现类中的方法均为异步执行。

+ * + * @author guifc + * @date 2023-08-04 + */ +public interface OnlinePermCodeService { + + /** + * 在线表单发布后,异步生成权限字相关数据(幂等:先生成前先按 pageCode 清理旧数据再重建)。 + * + * @param pageId 页面主键Id。 + * @param userId 操作者Id。异步线程中没有请求上下文,因此由调用方传入,用于填充创建/更新人。 + */ + void genPermCodeByPageId(Long pageId, Long userId); + + /** + * 删除在线表单时,异步清理自动生成的权限字树及其关联的权限资源、权限模块。 + * + * @param pageCode 页面编码。 + */ + void removePermCodeByPageCode(String pageCode); +} diff --git a/common/common-online/src/main/java/apelet/common/online/upms/service/impl/OnlinePermCodeServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/upms/service/impl/OnlinePermCodeServiceImpl.java new file mode 100644 index 0000000..7266b79 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/upms/service/impl/OnlinePermCodeServiceImpl.java @@ -0,0 +1,305 @@ +package apelet.common.online.upms.service.impl; + +import apelet.common.core.annotation.MyDataSourceResolver; +import apelet.common.core.base.model.BaseModel; +import apelet.common.core.constant.ApplicationConstant; +import apelet.common.core.constant.GlobalDeletedFlag; +import apelet.common.core.util.DefaultDataSourceResolver; +import apelet.common.generator.dao.OnlFormHeadMapper; +import apelet.common.generator.model.OnlFormHead; +import apelet.common.online.dao.OnlinePageMapper; +import apelet.common.online.dao.OnlineTableMapper; +import apelet.common.online.model.OnlinePage; +import apelet.common.online.model.OnlineTable; +import apelet.common.online.upms.dao.SysPermCodeMapper; +import apelet.common.online.upms.dao.SysPermCodePermMapper; +import apelet.common.online.upms.dao.SysPermMapper; +import apelet.common.online.upms.dao.SysPermModuleMapper; +import apelet.common.online.upms.model.SysPerm; +import apelet.common.online.upms.model.SysPermCode; +import apelet.common.online.upms.model.SysPermCodePerm; +import apelet.common.online.upms.model.SysPermModule; +import apelet.common.online.upms.service.OnlinePermCodeService; +import apelet.common.sequence.wrapper.IdGeneratorWrapper; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 在线表单权限字生成/清理服务实现类。 + *

在线表单发布后自动生成权限字,删除时同步清理。生成与清理均为异步执行,内部自行捕获异常并记录日志。

+ * + * @author guifc + * @date 2023-08-04 + */ +@Slf4j +@MyDataSourceResolver( + resolver = DefaultDataSourceResolver.class, + intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) +@Service("onlinePermCodeService") +public class OnlinePermCodeServiceImpl implements OnlinePermCodeService { + + /** 主表字段下载文件接口路径后缀。 */ + private static final String DOWNLOAD_DATASOURCE = "/onlineOperation/downloadDatasource"; + /** 数据源主表字段上传文件接口路径后缀。 */ + private static final String UPLOAD_DATASOURCE = "/onlineOperation/uploadDatasource"; + /** 数据源一对多关联的从表字段下载文件接口路径后缀。 */ + private static final String DOWNLOAD_ONE_TO_MANY = "/onlineOperation/downloadOneToManyRelation"; + /** 数据源一对多关联的从表字段上传文件接口路径后缀。 */ + private static final String UPLOAD_ONE_TO_MANY = "/onlineOperation/uploadOneToManyRelation"; + + @Value("${common-online.urlPrefix:}") + private String urlPrefix; + + @Autowired + private OnlinePageMapper onlinePageMapper; + @Autowired + private OnlFormHeadMapper onlFormHeadMapper; + @Autowired + private OnlineTableMapper onlineTableMapper; + @Autowired + private SysPermModuleMapper sysPermModuleMapper; + @Autowired + private SysPermMapper sysPermMapper; + @Autowired + private SysPermCodeMapper sysPermCodeMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 发布后异步生成权限字,先生成前先清理旧数据保证幂等。 + */ + @Async("permCodeTaskExecutor") + @Transactional(rollbackFor = Exception.class) + @Override + public void genPermCodeByPageId(Long pageId, Long userId) { + try { + this.doGenPermCode(pageId, userId); + } catch (Exception e) { + log.error("在线表单发布生成权限字失败,pageId={}", pageId, e); + } + } + + /** + * 删除表单后异步清理权限字相关数据。 + */ + @Async("permCodeTaskExecutor") + @Transactional(rollbackFor = Exception.class) + @Override + public void removePermCodeByPageCode(String pageCode) { + try { + this.doRemovePermCode(pageCode); + } catch (Exception e) { + log.error("在线表单删除清理权限字失败,pageCode={}", pageCode, e); + } + } + + private void doGenPermCode(Long pageId, Long userId) { + OnlinePage page = onlinePageMapper.selectById(pageId); + if (page == null || StrUtil.isBlank(page.getPageCode())) { + log.warn("生成权限字失败,页面不存在或页面编码为空,pageId={}", pageId); + return; + } + String pageCode = page.getPageCode(); + String pageName = StrUtil.nullToEmpty(page.getPageName()); + // 先清理旧数据,保证幂等。 + this.doRemovePermCode(pageCode); + // 主表。 + OnlFormHead mainHead = onlFormHeadMapper.selectById(page.getMasterTableId()); + if (mainHead == null || StrUtil.isBlank(mainHead.getTableName())) { + log.warn("生成权限字失败,找不到主表对应的 onl_form_head,pageId={}, masterTableId={}", + pageId, page.getMasterTableId()); + return; + } + // 附表:sort 取主表 table_name。 + QueryWrapper slaveWrapper = new QueryWrapper<>(); + slaveWrapper.eq("sort", mainHead.getTableName()); + List headList = new ArrayList<>(); + headList.add(mainHead); + headList.addAll(onlFormHeadMapper.selectList(slaveWrapper)); + // 组装 map:onl_form_head.table_name -> zz_online_table.model_name。 + Map modelNameMap = new HashMap<>(); + for (OnlFormHead head : headList) { + if (StrUtil.isBlank(head.getTableName())) { + continue; + } + OnlineTable onlineTable = this.getOnlineTableByTableName(head.getTableName()); + if (onlineTable != null && StrUtil.isNotBlank(onlineTable.getModelName())) { + modelNameMap.put(head.getTableName(), onlineTable.getModelName()); + } + } + String mainModelName = modelNameMap.get(mainHead.getTableName()); + if (StrUtil.isBlank(mainModelName)) { + log.warn("生成权限字失败,主表 {} 未匹配到 zz_online_table", mainHead.getTableName()); + return; + } + Date now = new Date(); + Long operatorUserId = userId != null ? userId : 0L; + // 权限模块:moduleType=0 根模块 + moduleType=1 子模块,所有权限挂在子模块下。 + SysPermModule rootModule = this.buildModule(0L, 0, pageName, 1, operatorUserId, now); + sysPermModuleMapper.insert(rootModule); + SysPermModule childModule = this.buildModule(rootModule.getModuleId(), 1, pageName, 1, operatorUserId, now); + sysPermModuleMapper.insert(childModule); + // 权限字树:type=0 根 -> type=1 片段 -> type=2 操作。 + SysPermCode code0 = this.buildPermCode(0L, pageCode, 0, pageName, 1, operatorUserId, now); + sysPermCodeMapper.insert(code0); + String code1Str = pageCode + ":" + pageCode; + SysPermCode code1 = this.buildPermCode(code0.getPermCodeId(), code1Str, 1, pageName, 1, operatorUserId, now); + sysPermCodeMapper.insert(code1); + // 每个表(主表+附表)各生成下载/上传两条 perm、两条操作权限字及其关联。 + for (OnlFormHead head : headList) { + if (StrUtil.isBlank(head.getTableName())) { + continue; + } + String modelName = modelNameMap.get(head.getTableName()); + if (StrUtil.isBlank(modelName)) { + continue; + } + boolean isMain = head == mainHead; + // perm_name:主表 = table_txt + 下载/上传;附表 = 主表table_txt + 附表table_txt + 下载/上传。 + String permNameBase = isMain ? StrUtil.nullToEmpty(head.getTableTxt()) + : StrUtil.nullToEmpty(mainHead.getTableTxt()) + StrUtil.nullToEmpty(head.getTableTxt()); + // 上传下载 URL 统一使用主表 model_name,仅路径区分主表/附表。 + String downloadUrl = this.makeUrl(isMain ? DOWNLOAD_DATASOURCE : DOWNLOAD_ONE_TO_MANY, mainModelName); + String uploadUrl = this.makeUrl(isMain ? UPLOAD_DATASOURCE : UPLOAD_ONE_TO_MANY, mainModelName); + String code2Base = code1Str + ":" + modelName; + SysPerm downloadPerm = this.buildPerm(childModule.getModuleId(), permNameBase + "下载文件", downloadUrl, 1, operatorUserId, now); + sysPermMapper.insert(downloadPerm); + SysPerm uploadPerm = this.buildPerm(childModule.getModuleId(), permNameBase + "上传文件", uploadUrl, 2, operatorUserId, now); + sysPermMapper.insert(uploadPerm); + SysPermCode code2Download = this.buildPermCode(code1.getPermCodeId(), code2Base + "download", 2, permNameBase + "下载文件", 1, operatorUserId, now); + sysPermCodeMapper.insert(code2Download); + SysPermCode code2Upload = this.buildPermCode(code1.getPermCodeId(), code2Base + "upload", 2, permNameBase + "上传文件", 2, operatorUserId, now); + sysPermCodeMapper.insert(code2Upload); + this.insertPermCodePerm(code2Download.getPermCodeId(), downloadPerm.getPermId()); + this.insertPermCodePerm(code2Upload.getPermCodeId(), uploadPerm.getPermId()); + } + log.info("在线表单发布生成权限字完成,pageId={}, pageCode={}, 表数={}", pageId, pageCode, headList.size()); + } + + /** + * 按 pageCode 清理权限字树及其关联的权限资源、权限模块。 + */ + private void doRemovePermCode(String pageCode) { + if (StrUtil.isBlank(pageCode)) { + return; + } + SysPermCode root = sysPermCodeMapper.selectOne(new QueryWrapper() + .eq("perm_code", pageCode).eq("perm_code_type", 0)); + if (root == null) { + return; + } + // 收集整棵权限字树(type=0 -> 1 -> 2)。 + List codeIdList = new ArrayList<>(); + codeIdList.add(root.getPermCodeId()); + Set codeIdSet = new HashSet<>(codeIdList); + List parentIdList = new ArrayList<>(codeIdList); + while (CollUtil.isNotEmpty(parentIdList)) { + List childList = sysPermCodeMapper.selectList( + new QueryWrapper().in("parent_id", parentIdList)); + parentIdList = childList.stream().map(SysPermCode::getPermCodeId).collect(Collectors.toList()); + codeIdSet.addAll(parentIdList); + } + // 权限字与权限关联、权限资源及其模块。 + List relationList = sysPermCodePermMapper.selectList( + new QueryWrapper().in("perm_code_id", codeIdSet)); + if (CollUtil.isNotEmpty(relationList)) { + sysPermCodePermMapper.delete(new QueryWrapper().in("perm_code_id", codeIdSet)); + } + Set permIdSet = relationList.stream().map(SysPermCodePerm::getPermId).collect(Collectors.toSet()); + Set moduleIdSet = new HashSet<>(); + if (CollUtil.isNotEmpty(permIdSet)) { + List permList = sysPermMapper.selectList(new QueryWrapper().in("perm_id", permIdSet)); + moduleIdSet = permList.stream().map(SysPerm::getModuleId).collect(Collectors.toSet()); + sysPermMapper.delete(new QueryWrapper().in("perm_id", permIdSet)); + } + sysPermCodeMapper.delete(new QueryWrapper().in("perm_code_id", codeIdSet)); + // 删除权限模块(子模块及其上级根模块)。 + if (CollUtil.isNotEmpty(moduleIdSet)) { + List moduleList = sysPermModuleMapper.selectList( + new QueryWrapper().in("module_id", moduleIdSet)); + moduleIdSet = moduleList.stream().flatMap(m -> Stream.of(m.getModuleId(), m.getParentId())) + .filter(Objects::nonNull).filter(id -> id != 0).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(moduleIdSet)) { + sysPermModuleMapper.delete(new QueryWrapper().in("module_id", moduleIdSet)); + } + } + log.info("在线表单删除清理权限字完成,pageCode={}, 权限字数={}", pageCode, codeIdSet.size()); + } + + private OnlineTable getOnlineTableByTableName(String tableName) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("table_name", tableName); + return onlineTableMapper.selectOne(wrapper); + } + + private String makeUrl(String path, String modelName) { + return urlPrefix + path + "/" + modelName; + } + + private SysPermModule buildModule(Long parentId, Integer moduleType, String moduleName, + Integer showOrder, Long userId, Date now) { + SysPermModule module = new SysPermModule(); + module.setModuleId(idGenerator.nextLongId()); + module.setParentId(parentId); + module.setModuleName(moduleName); + module.setModuleType(moduleType); + module.setShowOrder(showOrder); + module.setDeletedFlag(GlobalDeletedFlag.NORMAL); + this.fillCommonFields(module, userId, now); + return module; + } + + private SysPerm buildPerm(Long moduleId, String permName, String url, + Integer showOrder, Long userId, Date now) { + SysPerm perm = new SysPerm(); + perm.setPermId(idGenerator.nextLongId()); + perm.setModuleId(moduleId); + perm.setPermName(permName); + perm.setUrl(url); + perm.setShowOrder(showOrder); + perm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + this.fillCommonFields(perm, userId, now); + return perm; + } + + private SysPermCode buildPermCode(Long parentId, String permCode, Integer permCodeType, String showName, + Integer showOrder, Long userId, Date now) { + SysPermCode code = new SysPermCode(); + code.setPermCodeId(idGenerator.nextLongId()); + code.setParentId(parentId); + code.setPermCode(permCode); + code.setPermCodeType(permCodeType); + code.setShowName(showName); + code.setShowOrder(showOrder); + code.setDeletedFlag(GlobalDeletedFlag.NORMAL); + this.fillCommonFields(code, userId, now); + return code; + } + + private void fillCommonFields(BaseModel entity, Long userId, Date now) { + entity.setCreateUserId(userId); + entity.setUpdateUserId(userId); + entity.setCreateTime(now); + entity.setUpdateTime(now); + } + + private void insertPermCodePerm(Long permCodeId, Long permId) { + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(permCodeId); + permCodePerm.setPermId(permId); + sysPermCodePermMapper.insert(permCodePerm); + } +}