From c3a471276ad5f972b7c6059c43344ef12401e074 Mon Sep 17 00:00:00 2001 From: lym <1994302445@qq.com> Date: Tue, 10 Sep 2024 17:53:13 +0800 Subject: [PATCH 1/2] =?UTF-8?q?xml=E5=AF=BC=E5=85=A5-=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executor/controller/admin/order/OrderController.java | 4 ++-- .../util/fileConversion/admin/files/xml/XmlBuilder.java | 4 +--- .../util/fileConversion/admin/files/xml/XmlTypeRealize.java | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java index c5f1cda5f..9a115c258 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/OrderController.java @@ -311,6 +311,7 @@ public class OrderController { } else { list = (List) map.get("plate"); mapOrder = (Map) map.get("order"); + orderDO = (OrderDO) mapOrder.get("order"); if (list.size() == 0) { orderDO.setStatus(OrderStatusEnum.EMPTY.getStatus()); } else { @@ -327,6 +328,7 @@ public class OrderController { // } assert orderXmlVO != null; mapOrder = xmlTypeRealize.changeOrder(orderXmlVO, getUserOrganId()); + orderDO = (OrderDO) mapOrder.get("order"); if (orderXmlVO.getMaterialXmlVO().getPlateXmlVOS().getPlateXmlVOList().size() == 0) { orderDO.setStatus(OrderStatusEnum.EMPTY.getStatus()); } else { @@ -335,8 +337,6 @@ public class OrderController { } if (index == null || index == 0) { // 整单导入 - assert mapOrder != null; - orderDO = (OrderDO) mapOrder.get("order"); err = ((String) mapOrder.get("error")); orderDO.setOrderType(OrderTypeEnum.MAIN_ORDER.getStatus()); if (!orderService.customOrderNoIsExists(orderDO.getCustomOrderNo())) { diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlBuilder.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlBuilder.java index fe2fa57d5..f1793cba4 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlBuilder.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlBuilder.java @@ -8,9 +8,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; /** - * @projectName: cf_imes_server - * @author: 晨丰科技 - * @date: 2024/8/21 17:58 + * xml 转换工具 */ public class XmlBuilder { diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlTypeRealize.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlTypeRealize.java index 78f57af1f..b1ac1cb6b 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlTypeRealize.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/util/fileConversion/admin/files/xml/XmlTypeRealize.java @@ -582,9 +582,9 @@ public class XmlTypeRealize { long plateNo = idWorker.nextId(); long obtainingTime = idWorker.obtainingTime(); Long plateId = (Long) identifierGenerator.nextId(null); - BigDecimal area = BigDecimal.valueOf((Double.parseDouble(blockXmlVO.getWidth()) / 1000) * (Double.parseDouble(blockXmlVO.getLength())) ); + BigDecimal area = BigDecimal.valueOf((Double.parseDouble(blockXmlVO.getWidth()) / 1000) * (Double.parseDouble(blockXmlVO.getLength()) / 1000) ); // 开料面积 - BigDecimal sealAcreage = BigDecimal.valueOf( (Double.parseDouble(blockXmlVO.getCuttingWidth()) / 1000) * ( Double.parseDouble(blockXmlVO.getCuttingLength()) / 1000)); + BigDecimal sealAcreage = BigDecimal.valueOf( (Double.parseDouble(blockXmlVO.getCuttingWidth()) / 1000) * ( Double.parseDouble(blockXmlVO.getCuttingLength()) / 1000)); // 开门类型获取 Integer doorType = Integer.valueOf(dictDataApi.parseDictData(DictTypeConstants.DOOR_OPENING_DIRECTIONS, blockXmlVO.getOpenDirection()).getData().getValue()); From e7192ff6cd8ddac92eca0c7781580fcfa663f545 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Tue, 10 Sep 2024 18:28:34 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=A6=85=E9=81=93=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A1=E3=80=81=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E5=A5=97=E9=A4=90=E5=85=81=E8=AE=B8=E8=B6=85=E7=AE=A1=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=EF=BC=9B2=E3=80=81=E8=A7=92=E8=89=B2=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BF=AE=E6=94=B9=E8=A7=A6=E5=8F=91=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E4=B8=8B=E7=94=A8=E6=88=B7=E7=9A=84token=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=88=A0=E9=99=A4=EF=BC=9B3=E3=80=81=E7=BD=91=E5=85=B3checktok?= =?UTF-8?q?en=E7=A7=BB=E9=99=A4=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8C=E7=9B=B4=E6=8E=A5=E6=9F=A5feignapi=EF=BC=9B4=E3=80=81?= =?UTF-8?q?order=5Fgoods=E7=9A=84goods=5Fid=E8=BD=AC=E4=B8=BA=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E7=B1=BB=E5=9E=8B=E7=9A=84=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=80=82=E9=85=8D=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/TokenAuthenticationFilter.java | 38 +---- .../order/vo/order/OrderGoodsPlateRespVO.java | 2 +- .../plate/OrderPlateStatisticsMapper.java | 4 +- .../order/OrderStatisticsServiceImpl.java | 27 ++- .../dal/mysql/permission/UserRoleMapper.java | 22 +++ .../organ/TenantPackageServiceImpl.java | 4 +- .../permission/PermissionServiceImpl.java | 159 +++++++++++++----- .../module/system/util/organ/OrganUtils.java | 24 +++ 8 files changed, 182 insertions(+), 98 deletions(-) create mode 100644 cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/util/organ/OrganUtils.java diff --git a/cf-gateway/src/main/java/com/cf/imes/gateway/filter/security/TokenAuthenticationFilter.java b/cf-gateway/src/main/java/com/cf/imes/gateway/filter/security/TokenAuthenticationFilter.java index 8da358fce..67c0b73eb 100644 --- a/cf-gateway/src/main/java/com/cf/imes/gateway/filter/security/TokenAuthenticationFilter.java +++ b/cf-gateway/src/main/java/com/cf/imes/gateway/filter/security/TokenAuthenticationFilter.java @@ -1,17 +1,13 @@ package com.cf.imes.gateway.filter.security; -import cn.hutool.core.util.StrUtil; -import com.cf.imes.framework.common.core.KeyValue; +import cn.hutool.core.text.CharSequenceUtil; import com.cf.imes.framework.common.pojo.CommonResult; -import com.cf.imes.framework.common.util.cache.CacheUtils; import com.cf.imes.framework.common.util.json.JsonUtils; import com.cf.imes.gateway.util.SecurityFrameworkUtils; import com.cf.imes.gateway.util.WebFrameworkUtils; import com.cf.imes.module.system.api.oauth2.OAuth2TokenApi; import com.cf.imes.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -22,7 +18,6 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -import java.time.Duration; import java.util.Objects; import java.util.function.Function; @@ -53,23 +48,6 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered { private final WebClient webClient; - /** - * 登录用户的本地缓存 - * - * key1:多组织的编号 - * key2:访问令牌 - */ - private final LoadingCache, LoginUser> loginUserCache = CacheUtils.buildAsyncReloadingCache(Duration.ofMinutes(1), - new CacheLoader, LoginUser>() { - - @Override - public LoginUser load(KeyValue token) { - String body = checkAccessToken(token.getKey(), token.getValue()).block(); - return buildUser(body); - } - - }); - public TokenAuthenticationFilter(ReactorLoadBalancerExchangeFilterFunction lbFunction) { // Q:为什么不使用 OAuth2TokenApi 进行调用? // A1:Spring Cloud OpenFeign 官方未内置 Reactive 的支持 https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#reactive-support @@ -85,7 +63,7 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered { // 情况一,如果没有 Token 令牌,则直接继续 filter String token = SecurityFrameworkUtils.obtainAuthorization(exchange); - if (StrUtil.isEmpty(token)) { + if (CharSequenceUtil.isEmpty(token)) { return chain.filter(exchange); } @@ -108,21 +86,11 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered { } private Mono getLoginUser(ServerWebExchange exchange, String token) { - //Long organId = organIdCache.getIfPresent(token); - // 从缓存中,获取 LoginUser + // 用token从checktoken api中获取当前用户 Long organId = WebFrameworkUtils.getOrganId(exchange); - KeyValue cacheKey = new KeyValue().setKey(organId).setValue(token); - LoginUser localUser = loginUserCache.getIfPresent(cacheKey); - if (localUser != null) { - return Mono.just(localUser); - } - - // 缓存不存在,则请求远程服务 return checkAccessToken(organId, token).flatMap((Function>) body -> { LoginUser remoteUser = buildUser(body); if (remoteUser != null) { - // 非空,则进行缓存 - loginUserCache.put(cacheKey, remoteUser); return Mono.just(remoteUser); } return Mono.empty(); diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/vo/order/OrderGoodsPlateRespVO.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/vo/order/OrderGoodsPlateRespVO.java index e3cc50467..27645b32f 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/vo/order/OrderGoodsPlateRespVO.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/controller/admin/order/vo/order/OrderGoodsPlateRespVO.java @@ -15,7 +15,7 @@ import java.math.BigDecimal; public class OrderGoodsPlateRespVO implements Comparable { @Schema(description = "商品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "243") - private Long goodsId; + private String goodsId; @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "晨丰") private String goodsName; diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/plate/OrderPlateStatisticsMapper.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/plate/OrderPlateStatisticsMapper.java index 78e34ff98..798872894 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/plate/OrderPlateStatisticsMapper.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/dal/mysql/plate/OrderPlateStatisticsMapper.java @@ -32,7 +32,7 @@ public interface OrderPlateStatisticsMapper extends BaseMapperX { * @param reqVO * @return */ - List selectTopTenPlateCountListGroupByOrderDate(@Param("goodsIds") List goodsIdList, @Param("req") OrderStatisticsReqVO reqVO); + List selectTopTenPlateCountListGroupByOrderDate(@Param("goodsIds") List goodsIdList, @Param("req") OrderStatisticsReqVO reqVO); /** @@ -49,6 +49,6 @@ public interface OrderPlateStatisticsMapper extends BaseMapperX { * @param reqVO * @return */ - List selectTopTenPlateAreaListGroupByOrderDate(@Param("goodsIds") List goodsIdList, @Param("req") OrderStatisticsReqVO reqVO); + List selectTopTenPlateAreaListGroupByOrderDate(@Param("goodsIds") List goodsIdList, @Param("req") OrderStatisticsReqVO reqVO); } diff --git a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/order/OrderStatisticsServiceImpl.java b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/order/OrderStatisticsServiceImpl.java index 7af9befd8..fb98eed97 100644 --- a/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/order/OrderStatisticsServiceImpl.java +++ b/cf-module-prod-executor/cf-module-prod-executor-biz/src/main/java/com/cf/imes/module/executor/service/order/OrderStatisticsServiceImpl.java @@ -240,7 +240,7 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { List dateList = getDateList(reqVO); // 查询时间段内数量最多的小板,列出数量前10的goods_id - List topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateCountList(reqVO).stream() + List topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateCountList(reqVO).stream() .map(OrderGoodsPlateRespVO::getGoodsId) .toList(); @@ -254,8 +254,8 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { // 获取所有商品{goodsId:respvo},根据top10排序 - Map goodsMap = new LinkedHashMap<>(); - for (Long id : topTenCountGoodsId) { + Map goodsMap = new LinkedHashMap<>(); + for (String id : topTenCountGoodsId) { List list = orderGoodsPlateRespMap.values().stream() .flatMap(List::stream) .filter(vo -> vo.getGoodsId().equals(id)) @@ -268,7 +268,7 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { // 遍历所有goods_id List> series = new ArrayList<>(); - for (Map.Entry entry : goodsMap.entrySet()) { + for (Map.Entry entry : goodsMap.entrySet()) { Map seriesItem = new HashMap<>(); int[] sumArr = new int[dateList.size()]; @@ -310,7 +310,7 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { List dateList = getDateList(reqVO); // 查询时间段内面积最多的小板,列出前10面积的goods_id - List topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateAreaList(reqVO).stream() + List topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateAreaList(reqVO).stream() .map(OrderGoodsPlateRespVO::getGoodsId) .toList(); @@ -324,8 +324,8 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { // 获取所有商品{goodsId:respvo},根据top10排序 - Map goodsMap = new LinkedHashMap<>(); - for (Long id : topTenCountGoodsId) { + Map goodsMap = new LinkedHashMap<>(); + for (String id : topTenCountGoodsId) { List list = orderGoodsPlateRespMap.values().stream() .flatMap(List::stream) .filter(vo -> vo.getGoodsId().equals(id)) @@ -338,7 +338,7 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { // 遍历所有goods_id List> series = new ArrayList<>(); - for (Map.Entry entry : goodsMap.entrySet()) { + for (Map.Entry entry : goodsMap.entrySet()) { Map seriesItem = new HashMap<>(); BigDecimal[] areaArr = new BigDecimal[dateList.size()]; @@ -402,13 +402,13 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { Map goodsCountAggMap = response.aggregations(); Aggregate goodsCountAgg = goodsCountAggMap.get(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME); - List goodsIds = new ArrayList<>(); + List goodsIds = new ArrayList<>(); // 构建map:{日期:{goodsId、count}} Map> goodsDateGroupMap = new HashMap<>(); /** * 获取数量最大前十的goodsId列表 */ - goodsCountAgg.lterms().buckets().array().forEach(e -> goodsIds.add(e.key())); + goodsCountAgg.sterms().buckets().array().forEach(e -> goodsIds.add(e.key().stringValue())); if (CollUtil.isNotEmpty(goodsIds)) { List goodsIdFieldValueList = goodsIds.stream().map(FieldValue::of).toList(); @@ -433,12 +433,11 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { Aggregate goodsDateAgg = goodsDateCountAggMap.get(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME); - goodsDateAgg.lterms().buckets().array().forEach(goodsDateAggBucket -> { - Long goodsId = goodsDateAggBucket.key(); + goodsDateAgg.sterms().buckets().array().forEach(goodsDateAggBucket -> { // todo 目前没有发现好的es统计月周的方式,先把年月日查出来转周,后续优化 String dateStr = dateToWeekMonth(goodsDateAggBucket.aggregations().get("date_group").dateHistogram().buckets().array().get(0).keyAsString(), unit); double goodsCount = goodsDateAggBucket.aggregations().get(ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME).sum().value(); - OrderGoodsPlateRespVO vo = OrderGoodsPlateRespVO.builder().goodsId(goodsId).orderDate(dateStr).orderCount((int) goodsCount).build(); + OrderGoodsPlateRespVO vo = OrderGoodsPlateRespVO.builder().goodsId(goodsDateAggBucket.key().stringValue()).orderDate(dateStr).orderCount((int) goodsCount).build(); List orderGoodsPlateRespVOS = goodsDateGroupMap.get(dateStr); if (ObjectUtil.isNotNull(orderGoodsPlateRespVOS)) { orderGoodsPlateRespVOS.add(vo); @@ -452,7 +451,7 @@ public class OrderStatisticsServiceImpl implements OrderStatisticsService { // 遍历所有goods_id List> series = new ArrayList<>(); - for (Long goodsId : goodsIds) { + for (String goodsId : goodsIds) { Map seriesItem = new HashMap<>(); int[] countArr = new int[dateList.size()]; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/UserRoleMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/UserRoleMapper.java index 4b3186b86..d445768e6 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/UserRoleMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/permission/UserRoleMapper.java @@ -1,6 +1,8 @@ package com.cf.imes.module.system.dal.mysql.permission; import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; +import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.framework.organ.core.aop.OrganIgnore; import com.cf.imes.module.system.dal.dataobject.permission.UserRoleDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; @@ -45,4 +47,24 @@ public interface UserRoleMapper extends BaseMapperX { return selectList(UserRoleDO::getRoleId, roleIds); } + /** + * 忽视多组织查询角色下的用户id列表 + * + * @param roleId + * @return + */ + @OrganIgnore + default List selectRoleUserIds(Long roleId) { + return selectList(new LambdaQueryWrapperX().eq(UserRoleDO::getRoleId, roleId).select(UserRoleDO::getUserId)); + } + + /** + * 查询角色下的用户id列表 + * + * @param roleId + * @return + */ + default List selectOrgRoleUserIds(Long roleId) { + return selectList(new LambdaQueryWrapperX().eq(UserRoleDO::getRoleId, roleId).select(UserRoleDO::getUserId)); + } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java index 610f5a637..ab2c6f778 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java @@ -7,6 +7,7 @@ import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; import com.cf.imes.module.system.controller.admin.organ.vo.packages.TenantPackagePageReqVO; import com.cf.imes.module.system.controller.admin.organ.vo.packages.TenantPackageSaveReqVO; import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO; @@ -58,7 +59,8 @@ public class TenantPackageServiceImpl implements TenantPackageService { validateTenantPackageUnique(updateReqVO); // 校验存在 TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId()); - if(Objects.equals(tenantPackage.getId(), SYSTEM_ORGAN_PACKAGE_ID) || Objects.equals(tenantPackage.getId(), SYSTEM_SUPER_PACKAGE_ID)) { + if (Boolean.FALSE.equals(SecurityFrameworkUtils.isSuperAdmin()) && + (Objects.equals(tenantPackage.getId(), SYSTEM_ORGAN_PACKAGE_ID) || Objects.equals(tenantPackage.getId(), SYSTEM_SUPER_PACKAGE_ID))) { throw exception(TENANT_PACKAGE_DEPT_EXIT); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java index a7eec5271..73a89bc2e 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java @@ -1,13 +1,13 @@ package com.cf.imes.module.system.service.permission; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.extra.spring.SpringUtil; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.util.collection.CollectionUtils; +import com.cf.imes.framework.common.util.json.JsonUtils; import com.cf.imes.framework.datapermission.core.annotation.DataPermission; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.framework.organ.core.aop.OrganIgnore; @@ -18,7 +18,7 @@ import com.cf.imes.module.system.api.permission.dto.DeptDataPermissionRespDTO; import com.cf.imes.module.system.constants.permission.InternalRoleConstants; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleUserReqVO; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; -import com.cf.imes.module.system.convert.auth.AuthConvert; +import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import com.cf.imes.module.system.dal.dataobject.permission.MenuDO; import com.cf.imes.module.system.dal.dataobject.permission.RoleDO; import com.cf.imes.module.system.dal.dataobject.permission.RoleMenuDO; @@ -32,17 +32,17 @@ import com.cf.imes.module.system.enums.permission.DataScopeEnum; import com.cf.imes.module.system.service.dept.DeptService; import com.cf.imes.module.system.service.user.AdminUserService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.cf.imes.module.system.util.organ.OrganUtils; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -54,10 +54,10 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; -import static com.cf.imes.framework.common.pojo.CommonResult.success; import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet; import static com.cf.imes.framework.common.util.json.JsonUtils.toJsonString; import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ROLE_ME_ERROR; /** @@ -83,8 +83,8 @@ public class PermissionServiceImpl implements PermissionService { @Resource private AdminUserService userService; - @Autowired - private RedisTemplate redisTemplate; + @Resource + private StringRedisTemplate stringRedisTemplate; @Override public boolean hasAnyPermissions(Long userId, String... permissions) { @@ -164,18 +164,15 @@ public class PermissionServiceImpl implements PermissionService { allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 public void assignRoleMenu(Long roleId, Set menuIds, Long organId) { // 获得角色拥有菜单编号 - Set dbMenuIds = null; - boolean isOrganRole = Objects.equals(roleId, InternalRoleConstants.ORGAN_ADMIN_ROLE_ID) || Objects.equals(roleId, InternalRoleConstants.ORGAN_STAFF_ROLE_ID); + Set dbMenuIds; + boolean isOrganRole = OrganUtils.isOrgRole(roleId); if (isOrganRole) { dbMenuIds = convertSet(roleMenuMapper.selectListByRoleIdWithOrganAdmin(List.of(roleId)), RoleMenuDO::getMenuId); }else { dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); } // 查询角色获取角色的组织id,如果没有传入组织id就跟角色的组织统一 - RoleDO role = roleService.getRole(roleId); - if (Objects.isNull(role)) { - throw new ServiceException(ErrorCodeConstants.ROLE_NOT_EXISTS); - } + RoleDO role = validateRole(roleId); // 前端没传或者查一次后切换了组织导致跟角色组织不一致的统一为角色的组织 Long roleOrganId = role.getOrganId(); if (Objects.isNull(organId) || ObjectUtil.notEqual(roleOrganId, organId)) { @@ -206,25 +203,75 @@ public class PermissionServiceImpl implements PermissionService { roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); } + // 角色菜单权限发生修改,通知刷新本地缓存 + flushRoleMenuCache(roleId, isOrganRole, createMenuIds, deleteMenuIds, finalOrganId); + } + + /** + * 跨机构清理角色菜单缓存 + 通知刷新本地缓存 + * + * @param roleId 操作的角色id + * @param isOrganRole 是否内置角色 + * @param createMenuIds 新增角色-菜单关联id + * @param deleteMenuIds 删除角色-菜单关联id + * @param organId 角色所属机构id + */ + private void flushRoleMenuCache(Long roleId, boolean isOrganRole, Collection createMenuIds, Collection deleteMenuIds, Long organId) { Long currentOrganId = SecurityFrameworkUtils.getUserOrganId(); // 角色菜单权限发生修改,通知刷新本地缓存 - if (CollectionUtil.isNotEmpty(createMenuIds) || CollectionUtil.isNotEmpty(deleteMenuIds)) { + if (CollUtil.isNotEmpty(createMenuIds) || CollUtil.isNotEmpty(deleteMenuIds)) { CompletableFuture.runAsync(() -> { - // 当前操作人和所操作的目标菜单机构不同时,清空MENU_ROLE_ID_LIST:*:菜单id的缓存 - if (ObjectUtil.notEqual(finalOrganId, currentOrganId)) { - // 获取新增和删除菜单id的并集 - Collection delMenuIds = CollUtil.union(createMenuIds, deleteMenuIds); - delMenuIds.forEach(delMenuId -> { - String patternKey = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.MENU_ROLE_ID_LIST).append(":*:%s")), delMenuId); - Long batchDelNum = scanAndDelKeys(patternKey); - log.info("[assignRoleMenu] 批量删除redis[{}]数量:{}", patternKey, batchDelNum); + // 当前操作人和所操作的目标菜单机构不同时,清空MENU_ROLE_ID_LIST:*:菜单id的缓存 + if (ObjectUtil.notEqual(organId, currentOrganId)) { + // 获取新增和删除菜单id的并集 + Collection delMenuIds = CollUtil.union(createMenuIds, deleteMenuIds); + delMenuIds.forEach(delMenuId -> { + String patternKey = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.MENU_ROLE_ID_LIST).append(":*:%s")), delMenuId); + Long batchDelNum = scanAndDelKeys(patternKey); + log.info("[assignRoleMenu] 批量删除redis[{}]数量:{}", patternKey, batchDelNum); + }); + } + stringRedisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); + }) + .thenRunAsync(() -> { + // 清空角色下用户的token缓存 + List userIds; + if(isOrganRole) { + userIds = userRoleMapper.selectRoleUserIds(roleId).stream().map(UserRoleDO::getUserId).toList(); + } else { + userIds = userRoleMapper.selectOrgRoleUserIds(roleId).stream().map(UserRoleDO::getUserId).toList(); + } + scanAndCompareUserAndDelKeys(String.format(OAUTH2_ACCESS_TOKEN, "*"), userIds); + }) + .exceptionally(e -> { + log.error("[assignRoleMenu][flushRoleMenuCache]失败, 异常:{}", e); + return null; }); + } + } + + /** + * scan匹配oauth2_access_token:下缓存并删除缓存 + * @param keyPattern + * @param userIds + */ + private void scanAndCompareUserAndDelKeys(String keyPattern, List userIds) { + // 根据keyPattern scan匹配的redis key + List matchKeys = new ArrayList<>(); + Cursor cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build()); + while (cursor.hasNext()) { + matchKeys.add(cursor.next()); + } + cursor.close(); + if (CollUtil.isNotEmpty(matchKeys)) { + for (String key : matchKeys) { + // 获取key下的用户信息 + OAuth2AccessTokenDO oAuth2AccessTokenDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), OAuth2AccessTokenDO.class); + if (CollUtil.contains(userIds, oAuth2AccessTokenDO.getUserId())) { + // 角色下的用户id匹配上了删除redis中的token缓存 + stringRedisTemplate.delete(key); } - redisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); - }).exceptionally(e -> { - log.error("[assignRoleMenu] redis 清空MENU_ROLE_ID_LIST或message发送失败, topic:{}, 异常:{}", RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, e); - return null; - }); + } } } @@ -236,18 +283,32 @@ public class PermissionServiceImpl implements PermissionService { private Long scanAndDelKeys(String keyPattern) { // 根据keyPattern scan匹配的redis key List delKeys = new ArrayList<>(); - Cursor cursor = redisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build()); + Cursor cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build()); while (cursor.hasNext()) { delKeys.add(cursor.next()); } cursor.close(); // 删除匹配到的key - if (CollectionUtil.isNotEmpty(delKeys)) { - return redisTemplate.delete(delKeys); + if (CollUtil.isNotEmpty(delKeys)) { + return stringRedisTemplate.delete(delKeys); } return 0L; } + + /** + * 校验角色 + * + * @param roleId + */ + private RoleDO validateRole(Long roleId) { + RoleDO role = roleService.getRole(roleId); + if (Objects.isNull(role)) { + throw new ServiceException(ErrorCodeConstants.ROLE_NOT_EXISTS); + } + return role; + } + @Override @Transactional(rollbackFor = Exception.class) @Caching(evict = { @@ -343,13 +404,10 @@ public class PermissionServiceImpl implements PermissionService { } } // 查询角色获取角色的组织id,如果没有传入组织id就跟角色的组织统一 - RoleDO role = roleService.getRole(roleId); - if (Objects.isNull(role)) { - throw new ServiceException(ErrorCodeConstants.ROLE_NOT_EXISTS); - } + RoleDO role = validateRole(roleId); // 前端没传或者查一次后切换了组织导致跟角色组织不一致的统一为角色的组织 Long roleOrganId = role.getOrganId(); - boolean isOrganRole = Objects.equals(roleId, InternalRoleConstants.ORGAN_ADMIN_ROLE_ID) || Objects.equals(roleId, InternalRoleConstants.ORGAN_STAFF_ROLE_ID); + boolean isOrganRole = OrganUtils.isOrgRole(roleId); // 内置角色还是按照机构来存 if (!isOrganRole && (Objects.isNull(organId) || ObjectUtil.notEqual(roleOrganId, organId))) { organId = roleOrganId; @@ -364,7 +422,7 @@ public class PermissionServiceImpl implements PermissionService { // 筛选要新增的userRole:前端有,数据库没有 Collection createRoleUserIds = CollUtil.subtract(userIds, roleUserIds); - if (!CollectionUtil.isEmpty(createRoleUserIds)) { + if (CollUtil.isNotEmpty(createRoleUserIds)) { userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleUserIds, userId -> { UserRoleDO entity = new UserRoleDO(); entity.setUserId(userId).setRoleId(roleId).setOrganId(finalOrganId); @@ -374,7 +432,7 @@ public class PermissionServiceImpl implements PermissionService { // 筛选要删除的userRole:前端没有,数据库有 Collection deleteRoleUserIds = CollUtil.subtract(roleUserIds, userIds); - if (!CollectionUtil.isEmpty(deleteRoleUserIds)) { + if (CollUtil.isNotEmpty(deleteRoleUserIds)) { // 当前用户不能移除自身的角色 Long incloudSelf = deleteRoleUserIds.stream().filter(userId -> userId.equals(loginUser.getId())).findAny().orElse(null); if (incloudSelf != null) { @@ -382,13 +440,24 @@ public class PermissionServiceImpl implements PermissionService { } userRoleMapper.deleteListByRoleIdAndUserIds(roleId, deleteRoleUserIds); } + // 角色菜单权限发生修改,通知刷新本地缓存 + flushRoleUserCache(createRoleUserIds, deleteRoleUserIds, finalOrganId); + } + /** + * 跨机构清理角色用户缓存 + 通知刷新本地缓存 + * + * @param createRoleUserIds 新增角色-用户关联id + * @param deleteRoleUserIds 删除角色-用户关联id + * @param organId 角色所属机构 + */ + private void flushRoleUserCache(Collection createRoleUserIds, Collection deleteRoleUserIds, Long organId) { Long currentOrganId = SecurityFrameworkUtils.getUserOrganId(); // 角色菜单权限发生修改,通知刷新本地缓存 - if (CollectionUtil.isNotEmpty(createRoleUserIds) || CollectionUtil.isNotEmpty(deleteRoleUserIds)) { + if (CollUtil.isNotEmpty(createRoleUserIds) || CollUtil.isNotEmpty(deleteRoleUserIds)) { CompletableFuture.runAsync(() -> { // 当前操作人和所操作的目标菜单机构不同时,清空USER_ROLE_ID_LIST:*:用户id的缓存 - if (ObjectUtil.notEqual(finalOrganId, currentOrganId)) { + if (ObjectUtil.notEqual(organId, currentOrganId)) { // 获取新增和删除用户id的并集 Collection delRoleUserIds = CollUtil.union(createRoleUserIds, deleteRoleUserIds); delRoleUserIds.forEach(delRoleUserId -> { @@ -397,7 +466,7 @@ public class PermissionServiceImpl implements PermissionService { log.info("[batchAssignRoleUsers] 批量删除redis[{}]数量:{}", patternKey, batchDelNum); }); } - redisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); + stringRedisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); }).exceptionally(e -> { log.error("[batchAssignRoleUsers] redis 清空USER_ROLE_ID_LIST或message发送失败, topic:{}, 异常:{}", RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, e); return null; @@ -461,7 +530,7 @@ public class PermissionServiceImpl implements PermissionService { Collection createRoleIds = CollUtil.subtract(roleIdList, dbRoleIds); Collection deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIdList); // 执行新增和删除。对于已经授权的角色,不用做任何处理 - if (!CollectionUtil.isEmpty(createRoleIds)) { + if (CollUtil.isNotEmpty(createRoleIds)) { userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> { UserRoleDO entity = new UserRoleDO(); entity.setUserId(userId); @@ -470,16 +539,16 @@ public class PermissionServiceImpl implements PermissionService { return entity; })); } - if (!CollectionUtil.isEmpty(deleteMenuIds)) { + if (CollUtil.isNotEmpty(deleteMenuIds)) { userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); } // 角色菜单权限发生修改,通知刷新本地缓存 - if (CollectionUtil.isNotEmpty(createRoleIds) || CollectionUtil.isNotEmpty(deleteMenuIds)) { + if (CollUtil.isNotEmpty(createRoleIds) || CollUtil.isNotEmpty(deleteMenuIds)) { CompletableFuture.runAsync(() -> { // 移除redis中的缓存 - redisTemplate.delete(String.format(String.valueOf(new StringBuffer(RedisKeyConstants.USER_ROLE_ID_LIST).append(":%s:%s")), organId, userId)); - redisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); + stringRedisTemplate.delete(String.format(String.valueOf(new StringBuffer(RedisKeyConstants.USER_ROLE_ID_LIST).append(":%s:%s")), organId, userId)); + stringRedisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); }).exceptionally(e -> { log.error("[assignUserRole] redis message发送失败, topic:{}, 异常:{}", RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, e); return null; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/util/organ/OrganUtils.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/util/organ/OrganUtils.java new file mode 100644 index 000000000..2dfc59091 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/util/organ/OrganUtils.java @@ -0,0 +1,24 @@ +package com.cf.imes.module.system.util.organ; + +import com.cf.imes.module.system.constants.permission.InternalRoleConstants; + +import java.util.Objects; + +/** + * 组织相关工具类 + * + * @author Gqr + * @since 2024/9/10 15:59 + */ +public class OrganUtils { + + /** + * 是否内置角色 + * + * @param roleId + * @return + */ + public static boolean isOrgRole(Long roleId) { + return Objects.equals(roleId, InternalRoleConstants.ORGAN_ADMIN_ROLE_ID) || Objects.equals(roleId, InternalRoleConstants.ORGAN_STAFF_ROLE_ID); + } +}