对比新文件 |
| | |
| | | package com.iailab.module.system.api.app; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import com.iailab.framework.common.pojo.CommonResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.module.system.api.app.dto.AppMenuRespDTO; |
| | | import com.iailab.module.system.api.app.dto.AppRespDTO; |
| | | import com.iailab.module.system.convert.app.AppConvert; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.service.app.AppMenuService; |
| | | import com.iailab.module.system.service.app.AppService; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.*; |
| | | |
| | | import static com.iailab.framework.common.pojo.CommonResult.success; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; |
| | | |
| | | @RestController // 提供 RESTful API 接口,给 Feign 调用 |
| | | @Validated |
| | | public class AppApiImpl implements AppApi { |
| | | |
| | | @Resource |
| | | private AppService appService; |
| | | |
| | | // @Override |
| | | // public CommonResult<List<AppMenuRespDTO>> getAppMenuList(Long id) { |
| | | // List<AppMenuDO> children = new LinkedList<>(); |
| | | // // 遍历每一层 |
| | | // Collection<Long> parentIds = Collections.singleton(id); |
| | | // for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 |
| | | // // 查询当前层,所有的子应用菜单 |
| | | // List<AppMenuDO> menus = appMenuService.selectListByParentId(parentIds); |
| | | // // 1. 如果没有子菜单,则结束遍历 |
| | | // if (CollUtil.isEmpty(menus)) { |
| | | // break; |
| | | // } |
| | | // // 2. 如果有子应用菜单,继续遍历 |
| | | // children.addAll(menus); |
| | | // parentIds = convertSet(menus, AppMenuDO::getId); |
| | | // } |
| | | //// children = appMenuService.filterDisableMenus(children); |
| | | // return success(AppConvert.INSTANCE.buildMenuTree(id, children)); |
| | | // } |
| | | |
| | | @Override |
| | | public CommonResult<List<AppRespDTO>> getAppList() { |
| | | List<AppDO> list = appService.getList(); |
| | | list.sort(Comparator.comparing(AppDO::getOrderNum)); |
| | | return success(BeanUtils.toBean(list, AppRespDTO.class)); |
| | | } |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.api.app; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import com.iailab.framework.common.pojo.CommonResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.module.system.api.app.dto.AppMenuRespDTO; |
| | | import com.iailab.module.system.api.app.dto.AppRespDTO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppRespVO; |
| | | import com.iailab.module.system.convert.app.AppConvert; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.service.app.AppMenuService; |
| | | import com.iailab.module.system.service.app.AppService; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.*; |
| | | |
| | | import static com.iailab.framework.common.pojo.CommonResult.success; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; |
| | | |
| | | @RestController // 提供 RESTful API 接口,给 Feign 调用 |
| | | @Validated |
| | | public class AppMenuApiImpl implements AppMenuApi { |
| | | |
| | | @Resource |
| | | private AppMenuService appMenuService; |
| | | |
| | | @Resource |
| | | private AppService appService; |
| | | |
| | | @Override |
| | | public CommonResult<List<AppMenuRespDTO>> getAppMenuList(Long id) { |
| | | List<AppMenuDO> children = new LinkedList<>(); |
| | | // 遍历每一层 |
| | | Collection<Long> parentIds = Collections.singleton(id); |
| | | for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 |
| | | // 查询当前层,所有的子应用菜单 |
| | | List<AppMenuDO> menus = appMenuService.selectListByParentId(parentIds); |
| | | // 1. 如果没有子菜单,则结束遍历 |
| | | if (CollUtil.isEmpty(menus)) { |
| | | break; |
| | | } |
| | | // 2. 如果有子应用菜单,继续遍历 |
| | | children.addAll(menus); |
| | | parentIds = convertSet(menus, AppMenuDO::getId); |
| | | } |
| | | // children = appMenuService.filterDisableMenus(children); |
| | | return success(AppConvert.INSTANCE.buildMenuTree(id, children)); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<List<AppRespDTO>> getAppList() { |
| | | List<AppDO> list = appService.getList(); |
| | | list.sort(Comparator.comparing(AppDO::getOrderNum)); |
| | | return success(BeanUtils.toBean(list, AppRespDTO.class)); |
| | | } |
| | | } |
| | |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.framework.excel.core.util.ExcelUtils; |
| | | import com.iailab.module.system.api.app.dto.AppMenuRespDTO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppRespVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; |
| | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "获得分页") |
| | | @PreAuthorize("@ss.hasPermission('system:app:query')") |
| | | public CommonResult<PageResult<AppRespVO>> getTenantPage(@Valid AppPageReqVO pageVO) { |
| | | public CommonResult<PageResult<AppRespVO>> getAppPage(@Valid AppPageReqVO pageVO) { |
| | | PageResult<AppDO> pageResult = appService.getPage(pageVO); |
| | | return success(BeanUtils.toBean(pageResult, AppRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/getAppList") |
| | | @Operation(summary = "获得应用列表") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | public CommonResult<List<AppRespVO>> getAppList() { |
| | | List<AppDO> appDOS = appService.getList(); |
| | | return success(BeanUtils.toBean(appDOS, AppRespVO.class)); |
| | | } |
| | | |
| | | // @GetMapping("/getAppMenu") |
| | | // @Operation(summary = "获得应用菜单列表") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | // @Parameter(name = "id", description = "ID", required = true, example = "1024") |
| | | // public CommonResult<List<AppRespVO>> getAppMenu(@RequestParam("id") Long id) { |
| | | // List<AppMenuRespDTO> appDOS = appService.getAppMenu(id); |
| | | // return success(BeanUtils.toBean(appDOS, AppRespVO.class)); |
| | | // } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "导出租户 Excel") |
| | | @PreAuthorize("@ss.hasPermission('system:tenant:export')") |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app; |
| | | |
| | | import com.iailab.framework.common.pojo.CommonResult; |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.module.system.controller.admin.app.vo.*; |
| | | import com.iailab.module.system.dal.dataobject.app.AppGroupDO; |
| | | import com.iailab.module.system.service.app.AppGroupService; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.validation.Valid; |
| | | |
| | | import java.util.List; |
| | | |
| | | import static com.iailab.framework.common.pojo.CommonResult.success; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | @Tag(name = "管理后台 - 应用分组") |
| | | @RestController |
| | | @RequestMapping("/system/app-group") |
| | | public class AppGroupController { |
| | | |
| | | @Resource |
| | | private AppGroupService appGroupService; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "创建应用分组") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:create')") |
| | | public CommonResult<Long> createApp(@Valid @RequestBody AppGroupSaveReqVO createReqVO) { |
| | | return success(appGroupService.create(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "更新应用分组") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:update')") |
| | | public CommonResult<Boolean> updateApp(@Valid @RequestBody AppGroupSaveReqVO updateReqVO) { |
| | | appGroupService.update(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "删除应用分组") |
| | | @Parameter(name = "id", description = "ID", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:delete')") |
| | | public CommonResult<Boolean> deleteAppGroup(@RequestParam("id") Long id) { |
| | | appGroupService.delete(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "获得应用分组") |
| | | @Parameter(name = "id", description = "ID", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:query')") |
| | | public CommonResult<AppGroupRespVO> getInfo(@RequestParam("id") Long id) { |
| | | AppGroupDO data = appGroupService.getInfo(id); |
| | | return success(BeanUtils.toBean(data, AppGroupRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "获得分页") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:query')") |
| | | public CommonResult<PageResult<AppGroupRespVO>> getAppGroupPage(@Valid AppGroupPageReqVO pageVO) { |
| | | PageResult<AppGroupDO> pageResult = appGroupService.getPage(pageVO); |
| | | return success(BeanUtils.toBean(pageResult, AppGroupRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/getAppGroupList") |
| | | @Operation(summary = "获得应用分组列表") |
| | | @PreAuthorize("@ss.hasPermission('system:app-group:query')") |
| | | public CommonResult<List<AppGroupRespVO>> getAppList() { |
| | | List<AppGroupDO> appGroupDOS = appGroupService.getList(); |
| | | return success(BeanUtils.toBean(appGroupDOS, AppGroupRespVO.class)); |
| | | } |
| | | } |
对比新文件 |
| | |
| | | //package com.iailab.module.system.controller.admin.app; |
| | | // |
| | | //import com.iailab.framework.common.enums.CommonStatusEnum; |
| | | //import com.iailab.framework.common.pojo.CommonResult; |
| | | //import com.iailab.framework.common.util.object.BeanUtils; |
| | | //import com.iailab.module.system.controller.admin.app.vo.AppMenuRespVO; |
| | | //import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | //import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; |
| | | //import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSimpleRespVO; |
| | | //import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | //import com.iailab.module.system.service.app.AppMenuService; |
| | | //import io.swagger.v3.oas.annotations.Operation; |
| | | //import io.swagger.v3.oas.annotations.Parameter; |
| | | //import io.swagger.v3.oas.annotations.tags.Tag; |
| | | //import org.springframework.security.access.prepost.PreAuthorize; |
| | | //import org.springframework.validation.annotation.Validated; |
| | | //import org.springframework.web.bind.annotation.*; |
| | | // |
| | | //import javax.annotation.Resource; |
| | | //import javax.validation.Valid; |
| | | //import java.util.Comparator; |
| | | //import java.util.List; |
| | | // |
| | | //import static com.iailab.framework.common.pojo.CommonResult.success; |
| | | // |
| | | //@Tag(name = "应用菜单") |
| | | //@RestController |
| | | //@RequestMapping("/system/app-menu") |
| | | //@Validated |
| | | //public class AppMenuController { |
| | | // |
| | | // @Resource |
| | | // private AppMenuService appMenuService; |
| | | // |
| | | // @PostMapping("/create") |
| | | // @Operation(summary = "创建菜单") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:create')") |
| | | // public CommonResult<Long> createMenu(@Valid @RequestBody MenuSaveVO createReqVO) { |
| | | // Long menuId = appMenuService.createMenu(createReqVO); |
| | | // return success(menuId); |
| | | // } |
| | | // |
| | | // @PutMapping("/update") |
| | | // @Operation(summary = "修改菜单") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:update')") |
| | | // public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { |
| | | // appMenuService.updateMenu(updateReqVO); |
| | | // return success(true); |
| | | // } |
| | | // |
| | | // @DeleteMapping("/delete") |
| | | // @Operation(summary = "删除菜单") |
| | | // @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:delete')") |
| | | // public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) { |
| | | // appMenuService.deleteMenu(id); |
| | | // return success(true); |
| | | // } |
| | | // |
| | | // @GetMapping("/list") |
| | | // @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | // public CommonResult<List<AppMenuRespVO>> getMenuList(MenuListReqVO reqVO) { |
| | | // List<AppMenuDO> list = appMenuService.getMenuList(reqVO); |
| | | // list.sort(Comparator.comparing(AppMenuDO::getSort)); |
| | | // return success(BeanUtils.toBean(list, AppMenuRespVO.class)); |
| | | // } |
| | | // |
| | | // @GetMapping({"/list-all-simple", "simple-list"}) |
| | | // @Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + |
| | | // "在多租户的场景下,会只返回租户所在套餐有的菜单") |
| | | // public CommonResult<List<MenuSimpleRespVO>> getSimpleMenuList() { |
| | | // List<AppMenuDO> list = appMenuService.getMenuListByTenant( |
| | | // new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| | | // list.sort(Comparator.comparing(AppMenuDO::getSort)); |
| | | // return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); |
| | | // } |
| | | // |
| | | // @GetMapping("/get") |
| | | // @Operation(summary = "获取菜单信息") |
| | | // @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | // public CommonResult<AppMenuRespVO> getMenu(Long id) { |
| | | // AppMenuDO menu = appMenuService.getMenu(id); |
| | | // return success(BeanUtils.toBean(menu, AppMenuRespVO.class)); |
| | | // } |
| | | // |
| | | //} |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import com.iailab.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.ToString; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | @Schema(description = "管理后台 - 应用分组分页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | public class AppGroupPageReqVO extends PageParam { |
| | | |
| | | private String code; |
| | | |
| | | private String name; |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | @Schema(description = "管理后台 - 应用分组 Response VO") |
| | | @Data |
| | | @ExcelIgnoreUnannotated |
| | | public class AppGroupRespVO { |
| | | |
| | | @Schema(description = "应用分组id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @ExcelProperty("应用分组id") |
| | | private Long id; |
| | | |
| | | @Schema(description = "应用分组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组编号") |
| | | @ExcelProperty("应用分组编号") |
| | | private String code; |
| | | |
| | | @Schema(description = "应用分组名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组名称") |
| | | @ExcelProperty("应用分组名称") |
| | | private String name; |
| | | |
| | | @Schema(description = "应用分组图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组图标") |
| | | @ExcelProperty("应用分组图标") |
| | | private String icon; |
| | | |
| | | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "排序") |
| | | @ExcelProperty("排序") |
| | | private Integer sort; |
| | | |
| | | @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "备注") |
| | | @ExcelProperty("备注") |
| | | private String remark; |
| | | |
| | | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @ExcelProperty("创建时间") |
| | | private LocalDateTime createTime; |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author PanZhibao |
| | | * @Description |
| | | * @createTime 2024年08月17日 |
| | | */ |
| | | @Schema(description = "管理后台 - 应用创建/修改 Request VO") |
| | | @Data |
| | | public class AppGroupSaveReqVO { |
| | | |
| | | @Schema(description = "ID") |
| | | private Long id; |
| | | |
| | | @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "应用编号不能为空") |
| | | private String code; |
| | | |
| | | @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "应用名称不能为空") |
| | | private String name; |
| | | |
| | | @Schema(description = "应用图标", example = "") |
| | | private String icon; |
| | | |
| | | @Schema(description = "排序", example = "") |
| | | private Integer sort; |
| | | |
| | | @Schema(description = "备注", example = "") |
| | | private String remark; |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | @Schema(description = "应用菜单列表 Request VO") |
| | | @Data |
| | | public class AppMenuListReqVO { |
| | | |
| | | @Schema(description = "菜单名称,模糊匹配", example = "平台") |
| | | private String name; |
| | | |
| | | @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") |
| | | private Integer status; |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | import javax.validation.constraints.Size; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "应用菜单信息 Response VO") |
| | | @Data |
| | | public class AppMenuRespVO { |
| | | |
| | | @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") |
| | | @NotBlank(message = "菜单名称不能为空") |
| | | @Size(max = 50, message = "菜单名称长度不能超过50个字符") |
| | | private String name; |
| | | |
| | | @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") |
| | | @Size(max = 100) |
| | | private String permission; |
| | | |
| | | @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "菜单类型不能为空") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @NotNull(message = "显示顺序不能为空") |
| | | private Integer sort; |
| | | |
| | | @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @NotNull(message = "父菜单 ID 不能为空") |
| | | private Long parentId; |
| | | |
| | | @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") |
| | | @Size(max = 200, message = "路由地址不能超过200个字符") |
| | | private String path; |
| | | |
| | | @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") |
| | | private String icon; |
| | | |
| | | @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") |
| | | @Size(max = 200, message = "组件路径不能超过255个字符") |
| | | private String component; |
| | | |
| | | @Schema(description = "组件名", example = "SystemUser") |
| | | private String componentName; |
| | | |
| | | @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "状态不能为空") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "是否可见", example = "false") |
| | | private Boolean visible; |
| | | |
| | | @Schema(description = "是否缓存", example = "false") |
| | | private Boolean keepAlive; |
| | | |
| | | @Schema(description = "是否总是显示", example = "false") |
| | | private Boolean alwaysShow; |
| | | |
| | | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") |
| | | private LocalDateTime createTime; |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | import javax.validation.constraints.Size; |
| | | |
| | | @Schema(description = "应用菜单创建/修改 Request VO") |
| | | @Data |
| | | public class AppMenuSaveVO { |
| | | |
| | | @Schema(description = "菜单编号", example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") |
| | | @NotBlank(message = "菜单名称不能为空") |
| | | @Size(max = 50, message = "菜单名称长度不能超过50个字符") |
| | | private String name; |
| | | |
| | | @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") |
| | | @Size(max = 100) |
| | | private String permission; |
| | | |
| | | @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "菜单类型不能为空") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @NotNull(message = "显示顺序不能为空") |
| | | private Integer sort; |
| | | |
| | | @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @NotNull(message = "父菜单 ID 不能为空") |
| | | private Long parentId; |
| | | |
| | | @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") |
| | | @Size(max = 200, message = "路由地址不能超过200个字符") |
| | | private String path; |
| | | |
| | | @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") |
| | | private String icon; |
| | | |
| | | @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") |
| | | @Size(max = 200, message = "组件路径不能超过255个字符") |
| | | private String component; |
| | | |
| | | @Schema(description = "组件名", example = "SystemUser") |
| | | private String componentName; |
| | | |
| | | @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "状态不能为空") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "是否可见", example = "false") |
| | | private Boolean visible; |
| | | |
| | | @Schema(description = "是否缓存", example = "false") |
| | | private Boolean keepAlive; |
| | | |
| | | @Schema(description = "是否总是显示", example = "false") |
| | | private Boolean alwaysShow; |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | @Schema(description = "应用菜单精简信息 Response VO") |
| | | @Data |
| | | public class AppMenuSimpleRespVO { |
| | | |
| | | @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "平台") |
| | | private String name; |
| | | |
| | | @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | private Long parentId; |
| | | |
| | | @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Integer type; |
| | | |
| | | } |
| | |
| | | |
| | | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | |
| | | @ExcelIgnoreUnannotated |
| | | public class AppRespVO { |
| | | |
| | | @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @ExcelProperty("应用编号") |
| | | @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | @ExcelProperty("应用ID") |
| | | private Long id; |
| | | |
| | | @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用编号") |
| | |
| | | @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用名称") |
| | | @ExcelProperty("应用名称") |
| | | private String appName; |
| | | |
| | | @Schema(description = "应用类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用类型") |
| | | @ExcelProperty("应用类型") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "应用域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用域名") |
| | | @ExcelProperty("应用域名") |
| | |
| | | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @ExcelProperty("创建时间") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "租户ID") |
| | | @ExcelProperty("开发者ID") |
| | | private Long tenantId; |
| | | |
| | | @Schema(description = "应用菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用菜单ID") |
| | | private Long appMenuId; |
| | | |
| | | @Schema(description = "应用分组ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "应用分组ID") |
| | | private Long groupId; |
| | | |
| | | /** |
| | | * 应用类型(1-系统菜单, 2-应用菜单) |
| | | */ |
| | | @TableField(exist = false) |
| | | private Integer appType; |
| | | |
| | | } |
| | |
| | | package com.iailab.module.system.controller.admin.app.vo; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelProperty; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | |
| | | @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "应用名称不能为空") |
| | | private String appName; |
| | | |
| | | @Schema(description = "应用类型", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @ExcelProperty("应用类型") |
| | | private Integer type; |
| | | |
| | | @Schema(description = "应用域名", example = "") |
| | | private String appDomain; |
| | |
| | | |
| | | @Schema(description = "备注", example = "") |
| | | private String remark; |
| | | |
| | | @Schema(description = "租户ID", example = "") |
| | | private Long tenantId; |
| | | |
| | | @Schema(description = "分组ID", example = "") |
| | | private Long groupId; |
| | | } |
| | |
| | | import com.iailab.framework.security.config.SecurityProperties; |
| | | import com.iailab.framework.security.core.util.SecurityFrameworkUtils; |
| | | import com.iailab.module.system.controller.admin.auth.vo.*; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.convert.auth.AuthConvert; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleDO; |
| | | import com.iailab.module.system.dal.dataobject.user.AdminUserDO; |
| | | import com.iailab.module.system.enums.logger.LoginLogTypeEnum; |
| | | import com.iailab.module.system.service.app.AppService; |
| | | import com.iailab.module.system.service.auth.AdminAuthService; |
| | | import com.iailab.module.system.service.permission.MenuService; |
| | | import com.iailab.module.system.service.permission.PermissionService; |
| | |
| | | import static com.iailab.framework.common.pojo.CommonResult.success; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | | import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; |
| | | |
| | | |
| | | @Tag(name = "管理后台 - 认证") |
| | |
| | | private PermissionService permissionService; |
| | | @Resource |
| | | private SocialClientService socialClientService; |
| | | |
| | | @Resource |
| | | private SecurityProperties securityProperties; |
| | | @Resource |
| | | private AppService appService; |
| | | |
| | | @PostMapping("/login") |
| | | @PermitAll |
| | |
| | | return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); |
| | | } |
| | | |
| | | @GetMapping("/get-app-permission-info") |
| | | @Operation(summary = "获取登录用户的app权限信息") |
| | | public CommonResult<AuthPermissionInfoRespVO> getAppPermissionInfo() { |
| | | // 1.1 获得用户信息 |
| | | AdminUserDO user = userService.getUser(getLoginUserId()); |
| | | if (user == null) { |
| | | return success(null); |
| | | } |
| | | |
| | | // 1.2 获得角色列表 |
| | | Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); |
| | | if (CollUtil.isEmpty(roleIds)) { |
| | | return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); |
| | | } |
| | | List<RoleDO> roles = roleService.getRoleList(roleIds); |
| | | roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 |
| | | |
| | | // 1.3 获得应用菜单列表 |
| | | MenuListReqVO reqVO = new MenuListReqVO(); |
| | | List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); |
| | | Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); |
| | | List<MenuDO> menuList = menuService.getMenuList(menuIds); |
| | | menuList.retainAll(appMenuList); |
| | | menuList = menuService.filterDisableMenus(menuList); |
| | | // 2. 拼接结果返回 |
| | | return success(AuthConvert.INSTANCE.convertAppMenu(user, roles, menuList)); |
| | | } |
| | | |
| | | // ========== 短信登录相关 ========== |
| | | |
| | | @PostMapping("/sms-login") |
| | |
| | | import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; |
| | | import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; |
| | | import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; |
| | | import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenLoginReqVO; |
| | | import com.iailab.module.system.convert.oauth2.OAuth2OpenConvert; |
| | | import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; |
| | | import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; |
| | |
| | | @PostMapping("/token") |
| | | @PermitAll |
| | | @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") |
| | | @Parameters({ |
| | | @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), |
| | | @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), |
| | | @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.baidu.com"), |
| | | @Parameter(name = "state", description = "状态", example = "1"), |
| | | @Parameter(name = "username", example = "tudou"), |
| | | @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 |
| | | @Parameter(name = "scope", example = "user_info"), |
| | | @Parameter(name = "refresh_token", example = "123424233"), |
| | | }) |
| | | public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request, |
| | | @RequestParam("grant_type") String grantType, |
| | | @RequestParam(value = "code", required = false) String code, // 授权码模式 |
| | | @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 |
| | | @RequestParam(value = "state", required = false) String state, // 授权码模式 |
| | | @RequestParam(value = "username", required = false) String username, // 密码模式 |
| | | @RequestParam(value = "password", required = false) String password, // 密码模式 |
| | | @RequestParam(value = "scope", required = false) String scope, // 密码模式 |
| | | @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 |
| | | @RequestBody OAuth2OpenLoginReqVO openLoginReqVO) { |
| | | String code = openLoginReqVO.getCode(); |
| | | String scope = openLoginReqVO.getScope(); |
| | | String grantType = openLoginReqVO.getGrantType(); |
| | | String redirectUri = openLoginReqVO.getRedirectUri(); |
| | | String state = openLoginReqVO.getState(); |
| | | String username = openLoginReqVO.getUsername(); |
| | | String password = openLoginReqVO.getPassword(); |
| | | String refreshToken = openLoginReqVO.getRefreshToken(); |
| | | List<String> scopes = OAuth2Utils.buildScopes(scope); |
| | | // 1.1 校验授权类型 |
| | | OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); |
| | |
| | | @AllArgsConstructor |
| | | public class OAuth2OpenAccessTokenRespVO { |
| | | |
| | | @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| | | private Long userId; |
| | | |
| | | @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") |
| | | @JsonProperty("access_token") |
| | | private String accessToken; |
| | | |
| | | @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") |
| | | @JsonProperty("refresh_token") |
| | | private String refreshToken; |
| | | |
| | | @Schema(description = "令牌类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bearer") |
| | | @JsonProperty("token_type") |
| | | private String tokenType; |
| | | |
| | | @Schema(description = "过期时间,单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "42430") |
| | | @JsonProperty("expires_in") |
| | | private Long expiresIn; |
| | | private Long expiresTime; |
| | | |
| | | @Schema(description = "授权范围,如果多个授权范围,使用空格分隔", example = "user_info") |
| | | private String scope; |
对比新文件 |
| | |
| | | package com.iailab.module.system.controller.admin.oauth2.vo.open; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.iailab.framework.common.validation.InEnum; |
| | | import com.iailab.module.system.enums.social.SocialTypeEnum; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | import org.hibernate.validator.constraints.Length; |
| | | |
| | | import javax.validation.constraints.AssertTrue; |
| | | import javax.validation.constraints.NotEmpty; |
| | | import javax.validation.constraints.Pattern; |
| | | |
| | | @Schema(description = "管理后台 - 账号密码授权登录 Request VO") |
| | | @Data |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Builder |
| | | public class OAuth2OpenLoginReqVO { |
| | | |
| | | @Schema(description = "授权类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") |
| | | private String grantType; |
| | | |
| | | //授权码模式 |
| | | @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private String code; |
| | | |
| | | @Schema(description = "重定向 URI", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private String redirectUri; |
| | | |
| | | @Schema(description = "状态", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private String state; |
| | | |
| | | //密码模式 |
| | | @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private String scope; |
| | | |
| | | @Schema(description = "账号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "iailabyuanma") |
| | | @Length(min = 4, max = 16, message = "账号长度为 4-16 位") |
| | | @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") |
| | | private String username; |
| | | |
| | | @Schema(description = "密码", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "buzhidao") |
| | | @Length(min = 4, max = 16, message = "密码长度为 4-16 位") |
| | | private String password; |
| | | |
| | | //刷新模式 |
| | | @Schema(description = "刷新token", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private String refreshToken; |
| | | |
| | | } |
| | |
| | | return success(menuId); |
| | | } |
| | | |
| | | @PostMapping("/createAppMenu") |
| | | @Operation(summary = "创建菜单") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:create')") |
| | | public CommonResult<Long> createAppMenu(@Valid @RequestBody MenuSaveVO createReqVO) { |
| | | Long menuId = menuService.createMenu(createReqVO); |
| | | return success(menuId); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "修改菜单") |
| | | @PreAuthorize("@ss.hasPermission('system:menu:update')") |
| | | public CommonResult<Boolean> updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { |
| | | menuService.updateMenu(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @PutMapping("/updateAppMenu") |
| | | @Operation(summary = "修改菜单") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:update')") |
| | | public CommonResult<Boolean> updateAppMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { |
| | | menuService.updateMenu(updateReqVO); |
| | | return success(true); |
| | | } |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/deleteAppMenu") |
| | | @Operation(summary = "删除菜单") |
| | | @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:delete')") |
| | | public CommonResult<Boolean> deleteAppMenu(@RequestParam("id") Long id) { |
| | | menuService.deleteMenu(id); |
| | | return success(true); |
| | | } |
| | | |
| | | |
| | | @GetMapping("/list") |
| | | @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") |
| | | @PreAuthorize("@ss.hasPermission('system:menu:query')") |
| | | public CommonResult<List<MenuRespVO>> getMenuList(MenuListReqVO reqVO) { |
| | | List<MenuDO> list = menuService.getMenuList(reqVO); |
| | | list.sort(Comparator.comparing(MenuDO::getSort)); |
| | | return success(BeanUtils.toBean(list, MenuRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/app-menu-list") |
| | | @Operation(summary = "获取应用菜单列表", description = "用于【应用菜单】界面") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | public CommonResult<List<MenuRespVO>> getAppMenuList(MenuListReqVO reqVO) { |
| | | List<MenuDO> list = menuService.getAppMenuList(reqVO); |
| | | list.sort(Comparator.comparing(MenuDO::getSort)); |
| | | return success(BeanUtils.toBean(list, MenuRespVO.class)); |
| | | } |
| | |
| | | return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping({"simple-app-menus"}) |
| | | @Operation(summary = "获取应用菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + |
| | | "在多租户的场景下,会只返回租户所在套餐有的菜单") |
| | | public CommonResult<List<MenuSimpleRespVO>> getSimpleAppMenuList() { |
| | | List<MenuDO> list = menuService.getAppMenuListByTenant( |
| | | new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| | | list.sort(Comparator.comparing(MenuDO::getSort)); |
| | | return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "获取菜单信息") |
| | | @PreAuthorize("@ss.hasPermission('system:menu:query')") |
| | |
| | | return success(BeanUtils.toBean(menu, MenuRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/getAppMenu") |
| | | @Operation(summary = "获取菜单信息") |
| | | @PreAuthorize("@ss.hasPermission('system:app-menu:query')") |
| | | public CommonResult<MenuRespVO> getAppMenu(Long id) { |
| | | MenuDO menu = menuService.getMenu(id); |
| | | return success(BeanUtils.toBean(menu, MenuRespVO.class)); |
| | | } |
| | | |
| | | } |
| | |
| | | return success(permissionService.getRoleMenuListByRoleId(roleId)); |
| | | } |
| | | |
| | | @Operation(summary = "获得角色拥有的菜单编号") |
| | | @Parameter(name = "roleId", description = "角色编号", required = true) |
| | | @GetMapping("/list-role-app-menus") |
| | | @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") |
| | | public CommonResult<Set<Long>> getRoleAppMenuList(Long roleId) { |
| | | return success(permissionService.getRoleAppMenuListByRoleId(roleId)); |
| | | } |
| | | |
| | | @PostMapping("/assign-role-menu") |
| | | @Operation(summary = "赋予角色菜单") |
| | | @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") |
| | |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/assign-role-app-menu") |
| | | @Operation(summary = "赋予角色菜单") |
| | | @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") |
| | | public CommonResult<Boolean> assignRoleAppMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { |
| | | // 执行菜单的分配 |
| | | permissionService.assignRoleAppMenu(reqVO.getRoleId(), reqVO.getMenuIds()); |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/assign-role-data-scope") |
| | | @Operation(summary = "赋予角色数据权限") |
| | | @PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')") |
| | |
| | | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | private Long appId; |
| | | |
| | | } |
| | |
| | | @Schema(description = "是否总是显示", example = "false") |
| | | private Boolean alwaysShow; |
| | | |
| | | @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | private Long appId; |
| | | |
| | | } |
| | |
| | | return success(BeanUtils.toBean(pageResult, TenantRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/simple-list") |
| | | @Operation(summary = "获得租户精简列表") |
| | | @PreAuthorize("@ss.hasPermission('system:tenant:query')") |
| | | public CommonResult<List<TenantSimpleRespVO>> getSimpleTenant() { |
| | | List<TenantDO> listResult = tenantService.getSimpleTenant(); |
| | | return success(BeanUtils.toBean(listResult, TenantSimpleRespVO.class)); |
| | | } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "导出租户 Excel") |
| | | @PreAuthorize("@ss.hasPermission('system:tenant:export')") |
对比新文件 |
| | |
| | | package com.iailab.module.system.convert.app; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import com.iailab.module.system.api.app.dto.AppMenuRespDTO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.enums.permission.MenuTypeEnum; |
| | | import org.mapstruct.Mapper; |
| | | import org.mapstruct.factory.Mappers; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.*; |
| | | |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.filterList; |
| | | |
| | | @Mapper |
| | | public interface AppConvert { |
| | | |
| | | AppConvert INSTANCE = Mappers.getMapper(AppConvert.class); |
| | | |
| | | AppMenuRespDTO convertTreeNode(AppMenuDO menu); |
| | | |
| | | /** |
| | | * 将菜单列表,构建成菜单树 |
| | | * |
| | | * @param menuList 菜单列表 |
| | | * @return 菜单树 |
| | | */ |
| | | default List<AppMenuRespDTO> buildMenuTree(Long id, List<AppMenuDO> menuList) { |
| | | if (CollUtil.isEmpty(menuList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // 移除按钮 |
| | | menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); |
| | | // 排序,保证菜单的有序性 |
| | | menuList.sort(Comparator.comparing(AppMenuDO::getSort)); |
| | | |
| | | // 构建菜单树 |
| | | // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 |
| | | Map<Long, AppMenuRespDTO> treeNodeMap = new LinkedHashMap<>(); |
| | | menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AppConvert.INSTANCE.convertTreeNode(menu))); |
| | | // 处理父子关系 |
| | | treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(id)).forEach(childNode -> { |
| | | // 获得父节点 |
| | | AppMenuRespDTO parentNode = treeNodeMap.get(childNode.getParentId()); |
| | | if (parentNode == null) { |
| | | LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", |
| | | childNode.getId(), childNode.getParentId()); |
| | | return; |
| | | } |
| | | // 将自己添加到父节点中 |
| | | if (parentNode.getChildren() == null) { |
| | | parentNode.setChildren(new ArrayList<>()); |
| | | } |
| | | parentNode.getChildren().add(childNode); |
| | | }); |
| | | // 获得到所有的根节点 |
| | | return filterList(treeNodeMap.values(), node -> id.equals(node.getParentId())); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | AuthLoginRespVO convert(OAuth2AccessTokenDO bean); |
| | | |
| | | default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { |
| | | default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { |
| | | return AuthPermissionInfoRespVO.builder() |
| | | .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) |
| | | .roles(convertSet(roleList, RoleDO::getCode)) |
| | |
| | | .permissions(convertSet(menuList, MenuDO::getPermission)) |
| | | // 菜单树 |
| | | .menus(buildMenuTree(menuList)) |
| | | .build(); |
| | | } |
| | | |
| | | default AuthPermissionInfoRespVO convertAppMenu(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { |
| | | return AuthPermissionInfoRespVO.builder() |
| | | .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) |
| | | .roles(convertSet(roleList, RoleDO::getCode)) |
| | | // 权限标识信息 |
| | | .permissions(convertSet(menuList, MenuDO::getPermission)) |
| | | // 菜单树 |
| | | .menus(buildAppMenuTree(menuList)) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | if (CollUtil.isEmpty(menuList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // 移除按钮 |
| | | // 移除按钮和应用菜单 |
| | | menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); |
| | | // 排序,保证菜单的有序性 |
| | | menuList.sort(Comparator.comparing(MenuDO::getSort)); |
| | |
| | | return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); |
| | | } |
| | | |
| | | /** |
| | | * 将菜单列表,构建成菜单树 |
| | | * |
| | | * @param menuList 菜单列表 |
| | | * @return 菜单树 |
| | | */ |
| | | default List<AuthPermissionInfoRespVO.MenuVO> buildAppMenuTree(List<MenuDO> menuList) { |
| | | if (CollUtil.isEmpty(menuList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // 移除按钮和应用菜单 |
| | | menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); |
| | | // 排序,保证菜单的有序性 |
| | | menuList.sort(Comparator.comparing(MenuDO::getSort)); |
| | | |
| | | // 构建菜单树 |
| | | // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 |
| | | Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>(); |
| | | menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); |
| | | // 处理父子关系 |
| | | treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { |
| | | // 获得父节点 |
| | | AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); |
| | | if (parentNode == null) { |
| | | LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", |
| | | childNode.getId(), childNode.getParentId()); |
| | | return; |
| | | } |
| | | // 将自己添加到父节点中 |
| | | if (parentNode.getChildren() == null) { |
| | | parentNode.setChildren(new ArrayList<>()); |
| | | } |
| | | parentNode.getChildren().add(childNode); |
| | | }); |
| | | // 获得到所有的根节点 |
| | | return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); |
| | | } |
| | | |
| | | /** |
| | | * 将菜单列表,构建成菜单树 |
| | | * |
| | | * @param menuList 菜单列表 |
| | | * @return 菜单树 |
| | | */ |
| | | default List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList, Long id, String parentPath) { |
| | | if (CollUtil.isEmpty(menuList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // 移除按钮 |
| | | menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); |
| | | // 排序,保证菜单的有序性 |
| | | menuList.sort(Comparator.comparing(MenuDO::getSort)); |
| | | |
| | | // 构建菜单树 |
| | | // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 |
| | | Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>(); |
| | | menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); |
| | | // 处理父子关系 |
| | | treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(id)).forEach(childNode -> { |
| | | // 获得父节点 |
| | | AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); |
| | | if (parentNode == null) { |
| | | LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", |
| | | childNode.getId(), childNode.getParentId()); |
| | | return; |
| | | } |
| | | // 将自己添加到父节点中 |
| | | if (parentNode.getChildren() == null) { |
| | | parentNode.setChildren(new ArrayList<>()); |
| | | } |
| | | parentNode.getChildren().add(childNode); |
| | | |
| | | }); |
| | | // 获得到所有的根节点 |
| | | List<AuthPermissionInfoRespVO.MenuVO> menuVOS = filterList(treeNodeMap.values(), node -> id.equals(node.getParentId())); |
| | | menuVOS.stream().forEach(menuVO -> { |
| | | menuVO.setPath(parentPath + "/" + menuVO.getPath()); |
| | | }); |
| | | return menuVOS; |
| | | } |
| | | |
| | | SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO); |
| | | |
| | | SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); |
| | |
| | | default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) { |
| | | OAuth2OpenAccessTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenAccessTokenRespVO.class); |
| | | respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); |
| | | respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime())); |
| | | respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); |
| | | return respVO; |
| | | } |
| | |
| | | package com.iailab.module.system.dal.dataobject.app; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.iailab.framework.mybatis.core.dataobject.BaseDO; |
| | |
| | | * 应用名称 |
| | | */ |
| | | private String appName; |
| | | |
| | | /** |
| | | * 应用类型 |
| | | */ |
| | | private Integer type; |
| | | |
| | | /** |
| | | * 应用域名 |
| | |
| | | */ |
| | | private String remark; |
| | | |
| | | /** |
| | | * 租户ID |
| | | */ |
| | | private Long tenantId; |
| | | |
| | | /** |
| | | * 分组ID |
| | | */ |
| | | private Long groupId; |
| | | |
| | | /** |
| | | * 应用类型(1-系统菜单, 2-应用菜单) |
| | | */ |
| | | @TableField(exist = false) |
| | | private Integer appType; |
| | | |
| | | /** |
| | | * 应用菜单id |
| | | */ |
| | | @TableField(exist = false) |
| | | private Long appMenuId; |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.dal.dataobject.app; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.iailab.framework.mybatis.core.dataobject.BaseDO; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * 分组分组表 |
| | | * |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | @TableName("system_app_group") |
| | | @KeySequence("system_app_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class AppGroupDO extends BaseDO { |
| | | |
| | | public static final Long PARENT_ID_ROOT = 0L; |
| | | |
| | | /** |
| | | * ID |
| | | */ |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** |
| | | * 分组编号 |
| | | */ |
| | | private String code; |
| | | |
| | | /** |
| | | * 分组名称 |
| | | */ |
| | | private String name; |
| | | |
| | | /** |
| | | * 分组图标 |
| | | */ |
| | | private String icon; |
| | | |
| | | /** |
| | | * 排序 |
| | | */ |
| | | private Integer sort; |
| | | |
| | | /** |
| | | * 备注 |
| | | */ |
| | | private String remark; |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.dal.dataobject.app; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.iailab.framework.common.enums.CommonStatusEnum; |
| | | import com.iailab.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.iailab.framework.tenant.core.db.TenantBaseDO; |
| | | import com.iailab.module.system.enums.permission.MenuTypeEnum; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * 菜单 DO |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @TableName("system_app_menu") |
| | | @KeySequence("system_app_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class AppMenuDO extends BaseDO { |
| | | |
| | | /** |
| | | * 菜单编号 - 根节点 |
| | | */ |
| | | public static final Long ID_ROOT = 0L; |
| | | |
| | | /** |
| | | * 菜单编号 |
| | | */ |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * 菜单名称 |
| | | */ |
| | | private String name; |
| | | /** |
| | | * 权限标识 |
| | | * |
| | | * 一般格式为:${系统}:${模块}:${操作} |
| | | * 例如说:system:admin:add,即 system 服务的添加管理员。 |
| | | * |
| | | * 当我们把该 MenuDO 赋予给角色后,意味着该角色有该资源: |
| | | * - 对于后端,配合 @PreAuthorize 注解,配置 API 接口需要该权限,从而对 API 接口进行权限控制。 |
| | | * - 对于前端,配合前端标签,配置按钮是否展示,避免用户没有该权限时,结果可以看到该操作。 |
| | | */ |
| | | private String permission; |
| | | /** |
| | | * 菜单类型 |
| | | * |
| | | * 枚举 {@link MenuTypeEnum} |
| | | */ |
| | | private Integer type; |
| | | /** |
| | | * 显示顺序 |
| | | */ |
| | | private Integer sort; |
| | | /** |
| | | * 父菜单ID |
| | | */ |
| | | private Long parentId; |
| | | /** |
| | | * 路由地址 |
| | | * |
| | | * 如果 path 为 http(s) 时,则它是外链 |
| | | */ |
| | | private String path; |
| | | /** |
| | | * 菜单图标 |
| | | */ |
| | | private String icon; |
| | | /** |
| | | * 组件路径 |
| | | */ |
| | | private String component; |
| | | /** |
| | | * 组件名 |
| | | */ |
| | | private String componentName; |
| | | /** |
| | | * 状态 |
| | | * |
| | | * 枚举 {@link CommonStatusEnum} |
| | | */ |
| | | private Integer status; |
| | | /** |
| | | * 是否可见 |
| | | * |
| | | * 只有菜单、目录使用 |
| | | * 当设置为 true 时,该菜单不会展示在侧边栏,但是路由还是存在。例如说,一些独立的编辑页面 /edit/1024 等等 |
| | | */ |
| | | private Boolean visible; |
| | | /** |
| | | * 是否缓存 |
| | | * |
| | | * 只有菜单、目录使用,否使用 Vue 路由的 keep-alive 特性 |
| | | * 注意:如果开启缓存,则必须填写 {@link #componentName} 属性,否则无法缓存 |
| | | */ |
| | | private Boolean keepAlive; |
| | | /** |
| | | * 是否总是显示 |
| | | * |
| | | * 如果为 false 时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单 |
| | | */ |
| | | private Boolean alwaysShow; |
| | | |
| | | /** |
| | | * 应用ID |
| | | */ |
| | | private Long appId; |
| | | |
| | | |
| | | } |
| | |
| | | */ |
| | | private Boolean alwaysShow; |
| | | |
| | | /** |
| | | * 应用ID |
| | | */ |
| | | private Long appId; |
| | | |
| | | /** |
| | | * 租户ID |
| | | */ |
| | | private Long tenantId; |
| | | |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.dal.mysql.app; |
| | | |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.mybatis.core.mapper.BaseMapperX; |
| | | import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppGroupDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月10日 |
| | | */ |
| | | @Mapper |
| | | public interface AppGroupMapper extends BaseMapperX<AppGroupDO> { |
| | | default PageResult<AppGroupDO> selectPage(AppGroupPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<AppGroupDO>() |
| | | .likeIfPresent(AppGroupDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(AppGroupDO::getName, reqVO.getName()) |
| | | .orderByDesc(AppGroupDO::getId)); |
| | | } |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.dal.mysql.app; |
| | | |
| | | import com.iailab.framework.mybatis.core.mapper.BaseMapperX; |
| | | import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.dal.dataobject.dept.DeptDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface AppMenuMapper extends BaseMapperX<AppMenuDO> { |
| | | |
| | | default AppMenuDO selectByParentIdAndName(Long parentId, String name) { |
| | | return selectOne(AppMenuDO::getParentId, parentId, AppMenuDO::getName, name); |
| | | } |
| | | |
| | | default Long selectCountByParentId(Long parentId) { |
| | | return selectCount(AppMenuDO::getParentId, parentId); |
| | | } |
| | | |
| | | default List<AppMenuDO> selectListByParentId(Collection<Long> parentIds) { |
| | | return selectList(AppMenuDO::getParentId, parentIds); |
| | | } |
| | | |
| | | default List<AppMenuDO> selectList(MenuListReqVO reqVO) { |
| | | return selectList(new LambdaQueryWrapperX<AppMenuDO>() |
| | | .likeIfPresent(AppMenuDO::getName, reqVO.getName()) |
| | | .eqIfPresent(AppMenuDO::getStatus, reqVO.getStatus())); |
| | | } |
| | | |
| | | default List<AppMenuDO> selectListByPermission(String permission) { |
| | | return selectList(AppMenuDO::getPermission, permission); |
| | | } |
| | | } |
| | |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | |
| | | .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); |
| | | } |
| | | |
| | | default List<MenuDO> selectAppMenuList(Long tenantId, MenuListReqVO reqVO) { |
| | | return selectList(new LambdaQueryWrapperX<MenuDO>() |
| | | .likeIfPresent(MenuDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()) |
| | | .eq(MenuDO::getTenantId, tenantId)); |
| | | } |
| | | |
| | | default List<MenuDO> selectListByPermission(String permission) { |
| | | return selectList(MenuDO::getPermission, permission); |
| | | } |
| | | |
| | | default List<MenuDO> selectListByParentId(Collection<Long> parentIds) { |
| | | return selectList(MenuDO::getParentId, parentIds); |
| | | } |
| | | } |
| | |
| | | package com.iailab.module.system.dal.mysql.user; |
| | | |
| | | import com.baomidou.dynamic.datasource.annotation.Master; |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.mybatis.core.mapper.BaseMapperX; |
| | | import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import com.iailab.framework.tenant.core.db.dynamic.TenantDS; |
| | | import com.iailab.module.system.controller.admin.user.vo.user.UserPageReqVO; |
| | | import com.iailab.module.system.dal.dataobject.user.AdminUserDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | @Master |
| | | public interface AdminUserMapper extends BaseMapperX<AdminUserDO> { |
| | | |
| | | default AdminUserDO selectByUsername(String username) { |
对比新文件 |
| | |
| | | package com.iailab.module.system.service.app; |
| | | |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppGroupSaveReqVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppGroupDO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | public interface AppGroupService { |
| | | |
| | | Long create(AppGroupSaveReqVO createReqVO); |
| | | |
| | | Long update(AppGroupSaveReqVO createReqVO); |
| | | |
| | | void delete(Long id); |
| | | |
| | | AppGroupDO getInfo(Long id); |
| | | |
| | | PageResult<AppGroupDO> getPage(AppGroupPageReqVO pageReqVO); |
| | | |
| | | List<AppGroupDO> getList(); |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.service.app; |
| | | |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppGroupPageReqVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppGroupSaveReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppGroupDO; |
| | | import com.iailab.module.system.dal.mysql.app.AppGroupMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author Houzhongjian |
| | | * @Description |
| | | * @createTime 2024年09月20日 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class AppGroupServiceImpl implements AppGroupService { |
| | | |
| | | @Resource |
| | | private AppGroupMapper appGroupMapper; |
| | | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public Long create(AppGroupSaveReqVO createReqVO) { |
| | | AppGroupDO appGroup = BeanUtils.toBean(createReqVO, AppGroupDO.class); |
| | | appGroupMapper.insert(appGroup); |
| | | return appGroup.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public Long update(AppGroupSaveReqVO createReqVO) { |
| | | AppGroupDO appGroup = BeanUtils.toBean(createReqVO, AppGroupDO.class); |
| | | appGroupMapper.updateById(appGroup); |
| | | return appGroup.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public void delete(Long id) { |
| | | AppGroupDO appGroup = new AppGroupDO(); |
| | | appGroup.setId(id); |
| | | appGroupMapper.deleteById(id); |
| | | } |
| | | |
| | | @Override |
| | | public AppGroupDO getInfo(Long id) { |
| | | return appGroupMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<AppGroupDO> getPage(AppGroupPageReqVO pageReqVO) { |
| | | return appGroupMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppGroupDO> getList(){ |
| | | return appGroupMapper.selectList(); |
| | | } |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.service.app; |
| | | |
| | | |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 应用菜单 Service 接口 |
| | | * |
| | | * @author iailab |
| | | */ |
| | | public interface AppMenuService { |
| | | |
| | | /** |
| | | * 创建应用菜单 |
| | | * |
| | | * @param createReqVO 应用菜单信息 |
| | | * @return 创建出来的应用菜单编号 |
| | | */ |
| | | Long createMenu(MenuSaveVO createReqVO); |
| | | |
| | | /** |
| | | * 更新应用菜单 |
| | | * |
| | | * @param updateReqVO 应用菜单信息 |
| | | */ |
| | | void updateMenu(MenuSaveVO updateReqVO); |
| | | |
| | | /** |
| | | * 删除应用菜单 |
| | | * |
| | | * @param id 应用菜单编号 |
| | | */ |
| | | void deleteMenu(Long id); |
| | | |
| | | /** |
| | | * 获得所有应用菜单列表 |
| | | * |
| | | * @return 应用菜单列表 |
| | | */ |
| | | List<AppMenuDO> getMenuList(); |
| | | |
| | | /** |
| | | * 获得所有应用菜单列表 |
| | | * |
| | | * @return 应用菜单列表(API使用) |
| | | */ |
| | | List<AppMenuDO> getMenuList(Integer type); |
| | | |
| | | /** |
| | | * 基于租户,筛选应用菜单列表 |
| | | * 注意,如果是系统租户,返回的还是全应用菜单 |
| | | * |
| | | * @return 应用菜单列表(API使用) |
| | | */ |
| | | List<AppMenuDO> getMenuListByTenant(Integer type); |
| | | |
| | | /** |
| | | * 根据父菜单ID查询所有子菜单 |
| | | * |
| | | * @return 应用菜单列表(API使用) |
| | | */ |
| | | List<AppMenuDO> selectListByParentId(Collection<Long> parentIds); |
| | | |
| | | /** |
| | | * 基于租户,筛选应用菜单列表 |
| | | * 注意,如果是系统租户,返回的还是全应用菜单 |
| | | * |
| | | * @param reqVO 筛选条件请求 VO |
| | | * @return 应用菜单列表 |
| | | */ |
| | | List<AppMenuDO> getMenuListByTenant(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 过滤掉关闭的应用菜单及其子应用菜单 |
| | | * |
| | | * @param list 应用菜单列表 |
| | | * @return 过滤后的应用菜单列表 |
| | | */ |
| | | List<AppMenuDO> filterDisableMenus(List<AppMenuDO> list); |
| | | |
| | | /** |
| | | * 筛选应用菜单列表 |
| | | * |
| | | * @param reqVO 筛选条件请求 VO |
| | | * @return 应用菜单列表 |
| | | */ |
| | | List<AppMenuDO> getMenuList(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 获得权限对应的应用菜单编号数组 |
| | | * |
| | | * @param permission 权限标识 |
| | | * @return 数组 |
| | | */ |
| | | List<Long> getMenuIdListByPermissionFromCache(String permission); |
| | | |
| | | /** |
| | | * 获得应用菜单 |
| | | * |
| | | * @param id 应用菜单编号 |
| | | * @return 应用菜单 |
| | | */ |
| | | AppMenuDO getMenu(Long id); |
| | | |
| | | /** |
| | | * 获得应用菜单数组 |
| | | * |
| | | * @param ids 应用菜单编号数组 |
| | | * @return 应用菜单数组 |
| | | */ |
| | | List<AppMenuDO> getMenuList(Collection<Long> ids); |
| | | |
| | | } |
对比新文件 |
| | |
| | | package com.iailab.module.system.service.app; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.google.common.annotations.VisibleForTesting; |
| | | import com.google.common.collect.Lists; |
| | | import com.iailab.framework.common.enums.CommonStatusEnum; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppMenuDO; |
| | | import com.iailab.module.system.dal.mysql.app.AppMenuMapper; |
| | | import com.iailab.module.system.dal.redis.RedisKeyConstants; |
| | | import com.iailab.module.system.enums.permission.MenuTypeEnum; |
| | | import com.iailab.module.system.service.tenant.TenantService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.cache.annotation.CacheEvict; |
| | | import org.springframework.cache.annotation.Cacheable; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.*; |
| | | |
| | | import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; |
| | | import static com.iailab.module.system.dal.dataobject.app.AppMenuDO.ID_ROOT; |
| | | import static com.iailab.module.system.enums.ErrorCodeConstants.*; |
| | | |
| | | |
| | | /** |
| | | * 菜单 Service 实现 |
| | | * |
| | | * @author iailab |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class AppMenuServiceImpl implements AppMenuService { |
| | | |
| | | @Resource |
| | | private AppMenuMapper appMenuMapper; |
| | | @Resource |
| | | @Lazy // 延迟,避免循环依赖报错 |
| | | private TenantService tenantService; |
| | | |
| | | @Override |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", |
| | | condition = "#createReqVO.permission != null") |
| | | public Long createMenu(MenuSaveVO createReqVO) { |
| | | // 校验父菜单存在 |
| | | validateParentMenu(createReqVO.getParentId(), null); |
| | | // 校验菜单(自己) |
| | | validateMenu(createReqVO.getParentId(), createReqVO.getName(), null); |
| | | |
| | | // 插入数据库 |
| | | AppMenuDO menu = BeanUtils.toBean(createReqVO, AppMenuDO.class); |
| | | initMenuProperty(menu); |
| | | appMenuMapper.insert(menu); |
| | | // 返回 |
| | | return menu.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, |
| | | allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 |
| | | public void updateMenu(MenuSaveVO updateReqVO) { |
| | | // 校验更新的菜单是否存在 |
| | | if (appMenuMapper.selectById(updateReqVO.getId()) == null) { |
| | | throw exception(MENU_NOT_EXISTS); |
| | | } |
| | | // 校验父菜单存在 |
| | | validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId()); |
| | | // 校验菜单(自己) |
| | | validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId()); |
| | | |
| | | // 更新到数据库 |
| | | AppMenuDO updateObj = BeanUtils.toBean(updateReqVO, AppMenuDO.class); |
| | | initMenuProperty(updateObj); |
| | | appMenuMapper.updateById(updateObj); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, |
| | | allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 |
| | | public void deleteMenu(Long id) { |
| | | // 校验是否还有子菜单 |
| | | if (appMenuMapper.selectCountByParentId(id) > 0) { |
| | | throw exception(MENU_EXISTS_CHILDREN); |
| | | } |
| | | // 校验删除的菜单是否存在 |
| | | if (appMenuMapper.selectById(id) == null) { |
| | | throw exception(MENU_NOT_EXISTS); |
| | | } |
| | | // 标记删除 |
| | | appMenuMapper.deleteById(id); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuList() { |
| | | return appMenuMapper.selectList(); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuList(Integer type) { |
| | | LambdaQueryWrapper<AppMenuDO> queryWrapper = new LambdaQueryWrapper<>(); |
| | | if (type == 1) { |
| | | queryWrapper.eq(AppMenuDO::getType, type); |
| | | } |
| | | return appMenuMapper.selectList(queryWrapper); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuListByTenant(Integer type) { |
| | | // 查询所有菜单,并过滤掉关闭的节点 |
| | | List<AppMenuDO> menus = getMenuList(type); |
| | | // 开启多租户的情况下,需要过滤掉未开通的菜单 |
| | | tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); |
| | | return menus; |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> selectListByParentId(Collection<Long> parentIds) { |
| | | return appMenuMapper.selectListByParentId(parentIds); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuListByTenant(MenuListReqVO reqVO) { |
| | | // 查询所有菜单,并过滤掉关闭的节点 |
| | | List<AppMenuDO> menus = getMenuList(reqVO); |
| | | // 开启多租户的情况下,需要过滤掉未开通的菜单 |
| | | tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); |
| | | return menus; |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> filterDisableMenus(List<AppMenuDO> menuList) { |
| | | if (CollUtil.isEmpty(menuList)){ |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<Long, AppMenuDO> menuMap = convertMap(menuList, AppMenuDO::getId); |
| | | |
| | | // 遍历 menu 菜单,查找不是禁用的菜单,添加到 enabledMenus 结果 |
| | | List<AppMenuDO> enabledMenus = new ArrayList<>(); |
| | | Set<Long> disabledMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索 |
| | | for (AppMenuDO menu : menuList) { |
| | | if (isMenuDisabled(menu, menuMap, disabledMenuCache)) { |
| | | continue; |
| | | } |
| | | enabledMenus.add(menu); |
| | | } |
| | | return enabledMenus; |
| | | } |
| | | |
| | | private boolean isMenuDisabled(AppMenuDO node, Map<Long, AppMenuDO> menuMap, Set<Long> disabledMenuCache) { |
| | | // 如果已经判定是禁用的节点,直接结束 |
| | | if (disabledMenuCache.contains(node.getId())) { |
| | | return true; |
| | | } |
| | | |
| | | // 1. 遍历到 parentId 为根节点,则无需判断 |
| | | Long parentId = node.getParentId(); |
| | | if (ObjUtil.equal(parentId, ID_ROOT)) { |
| | | if (CommonStatusEnum.isDisable(node.getStatus())) { |
| | | disabledMenuCache.add(node.getId()); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // 2. 继续遍历 parent 节点 |
| | | AppMenuDO parent = menuMap.get(parentId); |
| | | if (parent == null || isMenuDisabled(parent, menuMap, disabledMenuCache)) { |
| | | disabledMenuCache.add(node.getId()); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuList(MenuListReqVO reqVO) { |
| | | return appMenuMapper.selectList(reqVO); |
| | | } |
| | | |
| | | @Override |
| | | @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") |
| | | public List<Long> getMenuIdListByPermissionFromCache(String permission) { |
| | | List<AppMenuDO> menus = appMenuMapper.selectListByPermission(permission); |
| | | return convertList(menus, AppMenuDO::getId); |
| | | } |
| | | |
| | | @Override |
| | | public AppMenuDO getMenu(Long id) { |
| | | return appMenuMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppMenuDO> getMenuList(Collection<Long> ids) { |
| | | // 当 ids 为空时,返回一个空的实例对象 |
| | | if (CollUtil.isEmpty(ids)) { |
| | | return Lists.newArrayList(); |
| | | } |
| | | return appMenuMapper.selectBatchIds(ids); |
| | | } |
| | | |
| | | /** |
| | | * 校验父菜单是否合法 |
| | | * <p> |
| | | * 1. 不能设置自己为父菜单 |
| | | * 2. 父菜单不存在 |
| | | * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 |
| | | * |
| | | * @param parentId 父菜单编号 |
| | | * @param childId 当前菜单编号 |
| | | */ |
| | | @VisibleForTesting |
| | | void validateParentMenu(Long parentId, Long childId) { |
| | | if (parentId == null || ID_ROOT.equals(parentId)) { |
| | | return; |
| | | } |
| | | // 不能设置自己为父菜单 |
| | | if (parentId.equals(childId)) { |
| | | throw exception(MENU_PARENT_ERROR); |
| | | } |
| | | AppMenuDO menu = appMenuMapper.selectById(parentId); |
| | | // 父菜单不存在 |
| | | if (menu == null) { |
| | | throw exception(MENU_PARENT_NOT_EXISTS); |
| | | } |
| | | // 父菜单必须是目录或者菜单类型 |
| | | if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) |
| | | && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { |
| | | throw exception(MENU_PARENT_NOT_DIR_OR_MENU); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 校验菜单是否合法 |
| | | * <p> |
| | | * 1. 校验相同父菜单编号下,是否存在相同的菜单名 |
| | | * |
| | | * @param name 菜单名字 |
| | | * @param parentId 父菜单编号 |
| | | * @param id 菜单编号 |
| | | */ |
| | | @VisibleForTesting |
| | | void validateMenu(Long parentId, String name, Long id) { |
| | | AppMenuDO menu = appMenuMapper.selectByParentIdAndName(parentId, name); |
| | | if (menu == null) { |
| | | return; |
| | | } |
| | | // 如果 id 为空,说明不用比较是否为相同 id 的菜单 |
| | | if (id == null) { |
| | | throw exception(MENU_NAME_DUPLICATE); |
| | | } |
| | | if (!menu.getId().equals(id)) { |
| | | throw exception(MENU_NAME_DUPLICATE); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化菜单的通用属性。 |
| | | * <p> |
| | | * 例如说,只有目录或者菜单类型的菜单,才设置 icon |
| | | * |
| | | * @param menu 菜单 |
| | | */ |
| | | private void initMenuProperty(AppMenuDO menu) { |
| | | // 菜单为按钮类型时,无需 component、icon、path 属性,进行置空 |
| | | if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) { |
| | | menu.setComponent(""); |
| | | menu.setComponentName(""); |
| | | menu.setIcon(""); |
| | | menu.setPath(""); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author PanZhibao |
| | | * @Description |
| | |
| | | AppDO getInfo(Long id); |
| | | |
| | | PageResult<AppDO> getPage(AppPageReqVO pageReqVO); |
| | | |
| | | List<AppDO> getList(); |
| | | |
| | | AppDO getAppByTenantId(Long tenantId); |
| | | |
| | | // List<AppMenuRespDTO> getAppMenu(Long id); |
| | | |
| | | } |
| | |
| | | package com.iailab.module.system.service.app; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import com.iailab.framework.security.core.util.SecurityFrameworkUtils; |
| | | import com.iailab.framework.tenant.core.aop.TenantIgnore; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; |
| | | import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; |
| | | import com.iailab.module.system.dal.mysql.app.AppMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.MenuMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.RoleMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; |
| | | import com.iailab.module.system.dal.mysql.tenant.TenantMapper; |
| | | import com.iailab.module.system.dal.mysql.tenant.TenantPackageMapper; |
| | | import com.iailab.module.system.enums.permission.MenuTypeEnum; |
| | | import com.iailab.module.system.service.permission.PermissionService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.ObjectUtils; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.*; |
| | | |
| | | import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; |
| | | import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_EXISTS_CHILDREN; |
| | | import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_NOT_EXISTS; |
| | | |
| | | /** |
| | | * @author PanZhibao |
| | |
| | | @Resource |
| | | private AppMapper appMapper; |
| | | |
| | | @Resource |
| | | private MenuMapper menuMapper; |
| | | |
| | | @Resource |
| | | private RoleMapper roleMapper; |
| | | |
| | | @Resource |
| | | private RoleMenuMapper roleMenuMapper; |
| | | |
| | | @Resource |
| | | private PermissionService permissionService; |
| | | |
| | | @Resource |
| | | private TenantPackageMapper tenantPackageMapper; |
| | | |
| | | @Resource |
| | | private TenantMapper tenantMapper; |
| | | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public Long create(AppSaveReqVO createReqVO) { |
| | | AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); |
| | | appMapper.insert(app); |
| | | // //为应用创建默认菜单并授权 |
| | | dealAppMenu(1, app); |
| | | return app.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public Long update(AppSaveReqVO createReqVO) { |
| | | AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); |
| | | appMapper.updateById(app); |
| | | // //修改默认菜单并授权 |
| | | dealAppMenu(2, app); |
| | | return app.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @TenantIgnore |
| | | public void delete(Long id) { |
| | | AppDO appDO = new AppDO(); |
| | | appDO.setId(id); |
| | | dealAppMenu(3, appDO); |
| | | appMapper.deleteById(id); |
| | | } |
| | | |
| | |
| | | return appMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<AppDO> getList() { |
| | | Long tenantId = getTenantId(); |
| | | LambdaQueryWrapperX<MenuDO> menuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<>(); |
| | | menuDOLambdaQueryWrapperX.eq(MenuDO::getParentId, 0) |
| | | .eq(MenuDO::getAppId, 0); |
| | | if (tenantId != 1) { |
| | | //非系统租户查租户套餐 |
| | | TenantDO tenantDO = tenantMapper.selectById(tenantId); |
| | | TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); |
| | | menuDOLambdaQueryWrapperX.in(MenuDO::getId, tenantPackageDO.getMenuIds()); |
| | | } |
| | | //查询系统应用菜单 |
| | | // List<MenuDO> menuDOS = menuMapper.selectList(menuDOLambdaQueryWrapperX); |
| | | // List<AppDO> systemApps = convertMenuToApp(menuDOS); |
| | | //创建一个系统管理应用菜单 |
| | | AppDO aDo = new AppDO(); |
| | | aDo.setAppType(1); |
| | | aDo.setAppName("系统管理"); |
| | | aDo.setOrderNum(0); |
| | | List<AppDO> systemApps = new ArrayList<>(); |
| | | systemApps.add(aDo); |
| | | List<AppDO> appDOS = appMapper.selectList(); |
| | | //暂时先遍历处理应用菜单和应用类型 |
| | | appDOS.stream().forEach(appDO -> { |
| | | List<MenuDO> menuDOS = menuMapper.selectList(new LambdaQueryWrapper<MenuDO>().eq(MenuDO::getParentId, 0) |
| | | .eq(MenuDO::getAppId, appDO.getId())); |
| | | appDO.setAppMenuId(menuDOS.get(0).getId()); |
| | | appDO.setAppType(2); |
| | | }); |
| | | systemApps.addAll(appDOS); |
| | | return systemApps; |
| | | } |
| | | |
| | | @Override |
| | | public AppDO getAppByTenantId(Long tenantId) { |
| | | //暂时支持一个租户对应一个应用 |
| | | List<AppDO> appDOS = appMapper.selectList(new LambdaQueryWrapper<AppDO>().eq(AppDO::getTenantId, tenantId)); |
| | | if(ObjectUtils.isNotEmpty(appDOS)) { |
| | | return appDOS.get(0); |
| | | } else { |
| | | AppDO appDO = new AppDO(); |
| | | appDO.setTenantId(tenantId); |
| | | appDO.setId(0L); |
| | | return appDO; |
| | | } |
| | | } |
| | | |
| | | // @Override |
| | | // public List<MenuRespDTO> getAppMenu(Long id) { |
| | | // |
| | | // List<MenuDO> children = new LinkedList<>(); |
| | | // // 遍历每一层 |
| | | // Collection<Long> parentIds = Collections.singleton(id); |
| | | // for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 |
| | | // // 查询当前层,所有的子应用菜单 |
| | | // List<MenuDO> menus = menuMapper.selectListByParentId(parentIds); |
| | | // // 1. 如果没有子菜单,则结束遍历 |
| | | // if (CollUtil.isEmpty(menus)) { |
| | | // break; |
| | | // } |
| | | // // 2. 如果有子应用菜单,继续遍历 |
| | | // children.addAll(menus); |
| | | // parentIds = convertSet(menus, MenuDO::getId); |
| | | // } |
| | | // children = menuService.filterDisableMenus(children); |
| | | // return AuthConvert.INSTANCE.buildMenuTree(id, children); |
| | | // |
| | | // } |
| | | |
| | | private void dealAppMenu(Integer type, AppDO app){ |
| | | String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname(); |
| | | MenuDO menuDO = new MenuDO(); |
| | | menuDO.setAppId(app.getId()); |
| | | menuDO.setName(app.getAppName()); |
| | | menuDO.setType(MenuTypeEnum.DIR.getType()); |
| | | menuDO.setSort(app.getOrderNum()); |
| | | menuDO.setPath("/" + app.getAppCode()); |
| | | menuDO.setTenantId(app.getTenantId()); |
| | | if(type == 1){ |
| | | menuDO.setCreator(loginUserNickname); |
| | | menuDO.setCreateTime(app.getCreateTime()); |
| | | menuMapper.insert(menuDO); |
| | | //内置租户角色分配菜单 |
| | | assignRoleMenu(menuDO.getId(), app.getTenantId()); |
| | | } else if(type == 2){ |
| | | LambdaUpdateWrapper<MenuDO> updateWrapper = new LambdaUpdateWrapper<>(); |
| | | updateWrapper.eq(MenuDO::getAppId, app.getId()); |
| | | updateWrapper.eq(MenuDO::getParentId, 0L); |
| | | List<MenuDO> menuDOS = menuMapper.selectList(updateWrapper); |
| | | if(menuDOS.size() > 0){ |
| | | menuDO.setUpdater(loginUserNickname); |
| | | menuDO.setUpdateTime(app.getUpdateTime()); |
| | | menuMapper.update(menuDO, updateWrapper); |
| | | } else { |
| | | menuDO.setCreator(loginUserNickname); |
| | | menuDO.setCreateTime(app.getCreateTime()); |
| | | menuMapper.insert(menuDO); |
| | | //内置租户角色分配菜单 |
| | | assignRoleMenu(menuDO.getId(), app.getTenantId()); |
| | | } |
| | | } else if(type == 3){ |
| | | //删除租户、角色权限 |
| | | app = appMapper.selectById(app.getId()); |
| | | LambdaQueryWrapperX<MenuDO> menuWrapper = new LambdaQueryWrapperX<>(); |
| | | menuWrapper.eq(MenuDO::getAppId, app.getId()); |
| | | menuWrapper.eq(MenuDO::getType, MenuTypeEnum.DIR.getType()); |
| | | MenuDO menu = menuMapper.selectOne(menuWrapper); |
| | | TenantDO tenantDO = tenantMapper.selectById(app.getTenantId()); |
| | | TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); |
| | | Set<Long> menuIds = tenantPackageDO.getMenuIds(); |
| | | menuIds.remove(menu.getId()); |
| | | // 校验是否还有子菜单 |
| | | if (menuMapper.selectCountByParentId(menu.getId()) > 0) { |
| | | throw exception(MENU_EXISTS_CHILDREN); |
| | | } |
| | | // 校验删除的菜单是否存在 |
| | | if (menuMapper.selectById(menu.getId()) == null) { |
| | | throw exception(MENU_NOT_EXISTS); |
| | | } |
| | | // 标记删除 |
| | | menuMapper.deleteById(menu.getId()); |
| | | // 删除授予给角色的权限 |
| | | permissionService.processMenuDeleted(menu.getId()); |
| | | //删除菜单 |
| | | menuMapper.delete(menuWrapper); |
| | | } |
| | | } |
| | | |
| | | private void assignRoleMenu(Long menuId, Long tenantId) { |
| | | //查询内置租户管理员 |
| | | LambdaQueryWrapperX<RoleDO> roleQueryWrapper = new LambdaQueryWrapperX<>(); |
| | | roleQueryWrapper.eq(RoleDO::getCode, "tenant_admin"); |
| | | roleQueryWrapper.eq(RoleDO::getTenantId, tenantId); |
| | | RoleDO roleDO = roleMapper.selectOne(roleQueryWrapper); |
| | | RoleMenuDO entity = new RoleMenuDO(); |
| | | entity.setRoleId(roleDO.getId()); |
| | | entity.setMenuId(menuId); |
| | | entity.setTenantId(tenantId); |
| | | roleMenuMapper.insert(entity); |
| | | TenantDO tenantDO = tenantMapper.selectById(tenantId); |
| | | TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); |
| | | Set<Long> menuIds = tenantPackageDO.getMenuIds(); |
| | | menuIds.add(menuId); |
| | | tenantPackageMapper.updateById(tenantPackageDO); |
| | | } |
| | | |
| | | private List<AppDO> convertMenuToApp(List<MenuDO> menuDOS) { |
| | | List<AppDO> appDOS = new ArrayList<>(); |
| | | menuDOS.stream().forEach(menuDO -> { |
| | | AppDO appDO = new AppDO(); |
| | | appDO.setAppName(menuDO.getName()); |
| | | appDO.setOrderNum(menuDO.getSort()); |
| | | appDO.setAppMenuId(menuDO.getId()); |
| | | appDO.setAppType(1); |
| | | appDOS.add(appDO); |
| | | }); |
| | | return appDOS; |
| | | } |
| | | |
| | | } |
| | |
| | | List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 基于租户,筛选应用菜单列表 |
| | | * 注意,如果是系统租户,返回的还是全菜单 |
| | | * |
| | | * @param reqVO 筛选条件请求 VO |
| | | * @return 应用菜单列表 |
| | | */ |
| | | List<MenuDO> getAppMenuListByTenant(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 过滤掉关闭的菜单及其子菜单 |
| | | * |
| | | * @param list 菜单列表 |
| | |
| | | List<MenuDO> getMenuList(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 筛选菜单列表 |
| | | * |
| | | * @param reqVO 筛选条件请求 VO |
| | | * @return 菜单列表 |
| | | */ |
| | | List<MenuDO> getAppMenuList(MenuListReqVO reqVO); |
| | | |
| | | /** |
| | | * 获得权限对应的菜单编号数组 |
| | | * |
| | | * @param permission 权限标识 |
| | |
| | | import com.iailab.framework.common.util.object.BeanUtils; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuSaveVO; |
| | | import com.iailab.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; |
| | | import com.iailab.module.system.dal.mysql.permission.MenuMapper; |
| | | import com.iailab.module.system.dal.redis.RedisKeyConstants; |
| | | import com.iailab.module.system.enums.permission.MenuTypeEnum; |
| | | import com.iailab.module.system.service.app.AppService; |
| | | import com.iailab.module.system.service.tenant.TenantPackageService; |
| | | import com.iailab.module.system.service.tenant.TenantService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.ObjectUtils; |
| | | import org.springframework.cache.annotation.CacheEvict; |
| | | import org.springframework.cache.annotation.Cacheable; |
| | | import org.springframework.context.annotation.Lazy; |
| | |
| | | import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; |
| | | import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; |
| | | import static com.iailab.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; |
| | | import static com.iailab.module.system.enums.ErrorCodeConstants.*; |
| | | |
| | |
| | | @Lazy // 延迟,避免循环依赖报错 |
| | | private TenantService tenantService; |
| | | |
| | | @Resource |
| | | private TenantPackageService tenantPackageService; |
| | | |
| | | @Resource |
| | | private AppService appService; |
| | | |
| | | @Resource |
| | | private RoleService roleService; |
| | | |
| | | @Override |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", |
| | | condition = "#createReqVO.permission != null") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createMenu(MenuSaveVO createReqVO) { |
| | | // 校验父菜单存在 |
| | | validateParentMenu(createReqVO.getParentId(), null); |
| | |
| | | // 插入数据库 |
| | | MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class); |
| | | initMenuProperty(menu); |
| | | |
| | | //菜单归属租户和应用 |
| | | Long tenantId = getTenantId(); |
| | | menu.setTenantId(tenantId); |
| | | menu.setAppId(createReqVO.getAppId()); |
| | | menuMapper.insert(menu); |
| | | if(tenantId != 1L) { |
| | | dealPermission(menu); |
| | | } |
| | | // 返回 |
| | | return menu.getId(); |
| | | } |
| | |
| | | @Override |
| | | @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, |
| | | allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateMenu(MenuSaveVO updateReqVO) { |
| | | // 校验更新的菜单是否存在 |
| | | if (menuMapper.selectById(updateReqVO.getId()) == null) { |
| | |
| | | // 更新到数据库 |
| | | MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class); |
| | | initMenuProperty(updateObj); |
| | | //菜单归属租户和应用 |
| | | Long tenantId = getTenantId(); |
| | | AppDO appDO = appService.getAppByTenantId(tenantId); |
| | | updateObj.setTenantId(tenantId); |
| | | updateObj.setAppId(appDO.getId()); |
| | | menuMapper.updateById(updateObj); |
| | | } |
| | | |
| | |
| | | public List<MenuDO> getMenuListByTenant(MenuListReqVO reqVO) { |
| | | // 查询所有菜单,并过滤掉关闭的节点 |
| | | List<MenuDO> menus = getMenuList(reqVO); |
| | | // 开启多租户的情况下,需要过滤掉未开通的菜单 |
| | | tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); |
| | | return menus; |
| | | } |
| | | |
| | | @Override |
| | | public List<MenuDO> getAppMenuListByTenant(MenuListReqVO reqVO) { |
| | | // 查询所有菜单,并过滤掉关闭的节点 |
| | | List<MenuDO> menus = getAppMenuList(reqVO); |
| | | // 开启多租户的情况下,需要过滤掉未开通的菜单 |
| | | tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); |
| | | return menus; |
| | |
| | | @Override |
| | | public List<MenuDO> getMenuList(MenuListReqVO reqVO) { |
| | | return menuMapper.selectList(reqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<MenuDO> getAppMenuList(MenuListReqVO reqVO) { |
| | | // 获取 tenantId |
| | | Long tenantId = getTenantId(); |
| | | return menuMapper.selectAppMenuList(tenantId, reqVO); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 新创建菜单赋权给租户管理员 |
| | | */ |
| | | |
| | | private void dealPermission(MenuDO menu) { |
| | | Long tenantId = menu.getTenantId(); |
| | | RoleDO role = roleService.getTenantAdminRole(tenantId); |
| | | TenantDO tenant = tenantService.getTenant(tenantId); |
| | | TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); |
| | | Set<Long> menuIds = tenantPackage.getMenuIds(); |
| | | menuIds.add(menu.getId()); |
| | | tenantPackage.setMenuIds(menuIds); |
| | | tenantPackageService.updateTenantPackage(BeanUtils.toBean(tenantPackage, TenantPackageSaveReqVO.class)); |
| | | permissionService.assignRoleMenu(role.getId(), menuIds); |
| | | } |
| | | |
| | | } |
| | |
| | | void assignRoleMenu(Long roleId, Set<Long> menuIds); |
| | | |
| | | /** |
| | | * 设置角色应用菜单 |
| | | * |
| | | * @param roleId 角色编号 |
| | | * @param menuIds 菜单编号集合 |
| | | */ |
| | | void assignRoleAppMenu(Long roleId, Set<Long> menuIds); |
| | | |
| | | /** |
| | | * 处理角色删除时,删除关联授权数据 |
| | | * |
| | | * @param roleId 角色编号 |
| | |
| | | } |
| | | |
| | | /** |
| | | * 获得角色拥有的应用菜单编号集合 |
| | | * |
| | | * @param roleId 角色编号 |
| | | * @return 菜单编号集合 |
| | | */ |
| | | default Set<Long> getRoleAppMenuListByRoleId(Long roleId) { |
| | | return getRoleAppMenuListByRoleId(singleton(roleId)); |
| | | } |
| | | |
| | | /** |
| | | * 获得角色们拥有的菜单编号集合 |
| | | * |
| | | * @param roleIds 角色编号数组 |
| | |
| | | Set<Long> getRoleMenuListByRoleId(Collection<Long> roleIds); |
| | | |
| | | /** |
| | | * 获得角色们拥有的应用菜单编号集合 |
| | | * |
| | | * @param roleIds 角色编号数组 |
| | | * @return 菜单编号集合 |
| | | */ |
| | | Set<Long> getRoleAppMenuListByRoleId(Collection<Long> roleIds); |
| | | |
| | | /** |
| | | * 获得拥有指定菜单的角色编号数组,从缓存中获取 |
| | | * |
| | | * @param menuId 菜单编号 |
| | |
| | | import com.iailab.framework.common.util.collection.CollectionUtils; |
| | | import com.iailab.framework.datapermission.core.annotation.DataPermission; |
| | | import com.iailab.module.system.api.permission.dto.DeptDataPermissionRespDTO; |
| | | import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| | | import com.iailab.module.system.dal.dataobject.app.AppDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.MenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; |
| | | import com.iailab.module.system.dal.dataobject.permission.UserRoleDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantDO; |
| | | import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; |
| | | import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; |
| | | import com.iailab.module.system.dal.mysql.permission.UserRoleMapper; |
| | | import com.iailab.module.system.dal.redis.RedisKeyConstants; |
| | | import com.iailab.module.system.enums.permission.DataScopeEnum; |
| | | import com.iailab.module.system.service.app.AppService; |
| | | import com.iailab.module.system.service.dept.DeptService; |
| | | import com.iailab.module.system.service.tenant.TenantPackageService; |
| | | import com.iailab.module.system.service.tenant.TenantService; |
| | | import com.iailab.module.system.service.user.AdminUserService; |
| | | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| | | import com.google.common.annotations.VisibleForTesting; |
| | |
| | | |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static com.iailab.framework.common.util.json.JsonUtils.toJsonString; |
| | | import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; |
| | | |
| | | /** |
| | | * 权限 Service 实现类 |
| | |
| | | private DeptService deptService; |
| | | @Resource |
| | | private AdminUserService userService; |
| | | @Resource |
| | | private TenantService tenantService; |
| | | @Resource |
| | | private TenantPackageService tenantPackageService; |
| | | @Resource |
| | | private AppService appService; |
| | | |
| | | |
| | | @Override |
| | | public boolean hasAnyPermissions(Long userId, String... permissions) { |
| | |
| | | } |
| | | } |
| | | |
| | | // ========== 角色-菜单的相关方法 ========== |
| | | |
| | | @Override |
| | | @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 |
| | | @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, |
| | | allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 |
| | | public void assignRoleAppMenu(Long roleId, Set<Long> menuIds) { |
| | | // 获得角色拥有应用菜单编号 |
| | | MenuListReqVO reqVO = new MenuListReqVO(); |
| | | List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); |
| | | Set<Long> appMenuIds = convertSet(appMenuList, MenuDO::getId); |
| | | Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); |
| | | dbMenuIds.retainAll(appMenuIds); |
| | | // 计算新增和删除的菜单编号 |
| | | Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds); |
| | | Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); |
| | | Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); |
| | | // 执行新增和删除。对于已经授权的菜单,不用做任何处理 |
| | | if (CollUtil.isNotEmpty(createMenuIds)) { |
| | | roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { |
| | | RoleMenuDO entity = new RoleMenuDO(); |
| | | entity.setRoleId(roleId); |
| | | entity.setMenuId(menuId); |
| | | return entity; |
| | | })); |
| | | } |
| | | if (CollUtil.isNotEmpty(deleteMenuIds)) { |
| | | roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @Caching(evict = { |
| | |
| | | if (CollUtil.isEmpty(roleIds)) { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | // 如果是管理员的情况下,获取全部菜单编号 |
| | | if (roleService.hasAnySuperAdmin(roleIds)) { |
| | | return convertSet(menuService.getMenuList(), MenuDO::getId); |
| | | } |
| | | // 如果是非管理员的情况下,获得拥有的菜单编号 |
| | | return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); |
| | | } |
| | | |
| | | @Override |
| | | public Set<Long> getRoleAppMenuListByRoleId(Collection<Long> roleIds) { |
| | | if (CollUtil.isEmpty(roleIds)) { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | // 如果是管理员的情况下,获取全部应用菜单编号 |
| | | if (roleService.hasAnySuperAdmin(roleIds)) { |
| | | MenuListReqVO reqVO = new MenuListReqVO(); |
| | | return convertSet(menuService.getAppMenuList(reqVO), MenuDO::getId); |
| | | } |
| | | // 如果是非管理员的情况下,获得拥有的应用菜单编号 |
| | | // 获取 tenantId |
| | | Long tenantId = getTenantId(); |
| | | TenantDO tenant = tenantService.getTenant(tenantId); |
| | | TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); |
| | | Set<Long> menuIds = tenantPackage.getMenuIds(); |
| | | Set<Long> longs = convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); |
| | | longs.retainAll(menuIds); |
| | | return longs; |
| | | } |
| | | |
| | | @Override |
| | | @Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") |
| | | public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) { |
| | | return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); |
| | |
| | | RoleDO getRoleByName(String name); |
| | | |
| | | void insert(RoleDO role); |
| | | |
| | | RoleDO getTenantAdminRole(Long tenantId); |
| | | } |
| | |
| | | return SpringUtil.getBean(getClass()); |
| | | } |
| | | |
| | | /** |
| | | * 查询租户管理员 |
| | | */ |
| | | public RoleDO getTenantAdminRole(Long tenantId) { |
| | | RoleDO roleDO = roleMapper.selectOne(new LambdaQueryWrapperX<RoleDO>().eq(RoleDO::getType, 1L).eq(RoleDO::getTenantId, tenantId)); |
| | | return roleDO; |
| | | } |
| | | |
| | | } |
| | |
| | | PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO); |
| | | |
| | | /** |
| | | * 获得租户列表 |
| | | * |
| | | * @return 租户列表 |
| | | */ |
| | | List<TenantDO> getSimpleTenant(); |
| | | |
| | | /** |
| | | * 获得名字对应的租户 |
| | | * |
| | | * @param name 租户名 |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<TenantDO> getSimpleTenant() { |
| | | return tenantMapper.selectList(); |
| | | } |
| | | |
| | | @Override |
| | | public TenantDO getTenantByName(String name) { |
| | | return tenantMapper.selectByName(name); |
| | | } |
| | |
| | | import cn.hutool.core.collection.CollectionUtil; |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| | | import com.iailab.framework.common.enums.CommonStatusEnum; |
| | | import com.iailab.framework.common.exception.ServiceException; |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | |
| | | private ConfigApi configApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @DSTransactional |
| | | @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", |
| | | success = SYSTEM_USER_CREATE_SUCCESS) |
| | | public Long createUser(UserSaveReqVO createReqVO) { |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @DSTransactional |
| | | @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", |
| | | success = SYSTEM_USER_UPDATE_SUCCESS) |
| | | public void updateUser(UserSaveReqVO updateReqVO) { |