diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/recent/vo/OperationRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/recent/vo/OperationRespVO.java index 71ad269..ed8ab9b 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/recent/vo/OperationRespVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/recent/vo/OperationRespVO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.member.controller.admin.recent.vo; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.module.member.service.user.BO.MemberExtBO; import cn.iocoder.yudao.module.member.service.user.BO.MemberTagExtBO; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/opentype/AppOpenTypeController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/opentype/AppOpenTypeController.java index 4dd060a..d33b53e 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/opentype/AppOpenTypeController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/opentype/AppOpenTypeController.java @@ -22,7 +22,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -@Tag(name = "管理后台 - 会员类型") +@Tag(name = "用户 App - 会员类型") @RestController @RequestMapping("/member/open-type") @Validated diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/RedisKeyConstants.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..cedc72d --- /dev/null +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/RedisKeyConstants.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.member.dal.redis; + +/** + * 会员 Redis Key 枚举类 + */ +public interface RedisKeyConstants { + + String MEMBER_RECENT_CFG = "member:recent:cfg:%d"; + +} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/recent/MemberRecentRedisDAO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/recent/MemberRecentRedisDAO.java new file mode 100644 index 0000000..26cb9a0 --- /dev/null +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/recent/MemberRecentRedisDAO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.member.dal.redis.recent; + +import cn.iocoder.yudao.module.member.dal.redis.RedisKeyConstants; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +/** + * 朋友圈的锁 Redis DAO + */ +@Repository +public class MemberRecentRedisDAO { + + @Resource + private RedissonClient redissonClient; + + public V lock(Long id, Long timeoutMillis, Callable callable) throws Exception { + String lockKey = formatKey(id); + RLock lock = redissonClient.getLock(lockKey); + try { + lock.lock(timeoutMillis, TimeUnit.MILLISECONDS); + // 执行逻辑 + return callable.call(); + } catch (Exception e) { + throw e; + } finally { + lock.unlock(); + } + } + + private static String formatKey(Long id) { + return String.format(RedisKeyConstants.MEMBER_RECENT_CFG, id); + } + +} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/opentype/OpenTypeServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/opentype/OpenTypeServiceImpl.java index 02282c9..fe9bd30 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/opentype/OpenTypeServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/opentype/OpenTypeServiceImpl.java @@ -367,7 +367,7 @@ public class OpenTypeServiceImpl implements OpenTypeService { .set(OpenTypeUserDO::getPayChannelCode, payOrder.getChannelCode()) .set(OpenTypeUserDO::getPayStatus, true) .set(OpenTypeUserDO::getPayTime, LocalDateTime.now()) - .eq(OpenTypeUserDO::getId, openTypeUserDO.getOpenTypeId()) + .eq(OpenTypeUserDO::getId, openTypeUserDO.getId()) .eq(OpenTypeUserDO::getPayStatus, false); int updateCount = openTypeUserMapper.update(updateWrapper); if (updateCount == 0) { diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/recent/ViewRecordServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/recent/ViewRecordServiceImpl.java index e26bc68..0b1d71a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/recent/ViewRecordServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/recent/ViewRecordServiceImpl.java @@ -121,7 +121,13 @@ public class ViewRecordServiceImpl implements ViewRecordService { ); List list = pageList.getList(); if (ObjectUtil.isEmpty(list)) return resultPageList; - List resultList = BeanUtils.toBean(list, OperationRespVO.class); + List resultList = list.stream().map(item -> { + OperationRespVO entity = new OperationRespVO(); + entity.setBizType(item.getBizType()); + entity.setMemberId(item.getBizId()); + entity.setCreateTime(item.getViewStartTime()); + return entity; + }).collect(Collectors.toList()); // 为ViewRecordPageReqVO设置Member信息 convertViewRecordPageReqVOSetupMember(resultList); resultPageList.setList(resultList); diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberRecentCfgServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberRecentCfgServiceImpl.java index 69f7fd0..95a71b3 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberRecentCfgServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberRecentCfgServiceImpl.java @@ -2,16 +2,20 @@ package cn.iocoder.yudao.module.member.service.user; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.member.controller.app.user.vo.recentcfg.MemberRecentCfgReqVo; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberRecentCfgDO; import cn.iocoder.yudao.module.member.dal.mysql.user.RecentCfgMapper; +import cn.iocoder.yudao.module.member.dal.redis.recent.MemberRecentRedisDAO; import cn.iocoder.yudao.module.member.enums.MemberErrorCode; import cn.iocoder.yudao.module.member.service.opentype.OpenTypeService; +import lombok.SneakyThrows; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; @@ -32,6 +36,14 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @Validated public class MemberRecentCfgServiceImpl implements MemberRecentCfgService { + /** + * 通知超时时间,单位:毫秒 + */ + public static final long UPDATE_TIMEOUT_MILLIS = 120 * DateUtils.SECOND_MILLIS; + + @Resource + private MemberRecentRedisDAO memberRecentRedisDAO; + @Resource private RecentCfgMapper recentCfgMapper; @Resource @@ -61,8 +73,8 @@ public class MemberRecentCfgServiceImpl implements MemberRecentCfgService { recentCfgMapper.insert(entity); } else { // 判断是否修改了`全局隐身`和`首页隐身` - if (ObjectUtil.isNotEmpty(dto.getGlobalHide()) && ObjectUtil.isNotEmpty(dto.getHomeHide())) { - if (dto.getGlobalHide() || dto.getHomeHide()) { + if (ObjectUtil.isNotEmpty(dto.getHomeHide())) { + if (dto.getHomeHide()) { // 判断是否为会员 if (!openTypeService.isUserOpenType()) { throw exception(MemberErrorCode.USER_UPDATE_CONFIG_ERROR, "全局隐身或首页隐身"); @@ -79,6 +91,8 @@ public class MemberRecentCfgServiceImpl implements MemberRecentCfgService { * 查询或者创建配置 */ @Override + @SneakyThrows + @Transactional(rollbackFor = Exception.class) public MemberRecentCfgDO getOrCreate(Long memberId) { MemberRecentCfgDO detail = recentCfgMapper.selectOne(new LambdaQueryWrapperX() .eq(MemberRecentCfgDO::getMemberId, memberId) @@ -86,14 +100,16 @@ public class MemberRecentCfgServiceImpl implements MemberRecentCfgService { if (ObjectUtil.isNotEmpty(detail)) { return detail; } - MemberRecentCfgDO insertObj = MemberRecentCfgDO.builder() - .memberId(memberId) - .homeHide(false) - .privacySecure(false) - .shortNote(false) - .build(); - recentCfgMapper.insert(insertObj); - return insertObj; + return memberRecentRedisDAO.lock(memberId, UPDATE_TIMEOUT_MILLIS, () -> { + MemberRecentCfgDO insertObj = MemberRecentCfgDO.builder() + .memberId(memberId) + .homeHide(false) + .privacySecure(false) + .shortNote(false) + .build(); + recentCfgMapper.insert(insertObj); + return insertObj; + }); } /** diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index b9dc0af..04fffc4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -46,7 +46,7 @@ public class TenantController { return success(tenant != null ? tenant.getId() : null); } - @GetMapping({ "simple-list" }) + @GetMapping({"simple-list"}) @PermitAll @Operation(summary = "获取租户精简信息列表", description = "只包含被开启的租户,用于【首页】功能的选择租户选项") public CommonResult> getTenantSimpleList() { @@ -116,8 +116,7 @@ public class TenantController { exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = tenantService.getTenantPage(exportReqVO).getList(); // 导出 Excel - ExcelUtils.write(response, "租户.xls", "数据", TenantRespVO.class, - BeanUtils.toBean(list, TenantRespVO.class)); + ExcelUtils.write(response, "租户.xls", "数据", TenantRespVO.class, BeanUtils.toBean(list, TenantRespVO.class)); } } diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index cdeb7cb..a4ecc61 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -170,9 +170,9 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta # 芋道配置项,设置当前项目所有自定义的配置 yudao: pay: - order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 - refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 - transfer-notify-url: https://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 + order-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + transfer-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 demo: false # 开启演示模式 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 6c3bae0..96f6377 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -179,7 +179,7 @@ wx: key-prefix: wx # Redis Key 的前缀 http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 - appid: wx2b4e4d3feff8267f # 测试号(puhui 提供的) + appid: wx2b4e4d3feff8267f secret: cf47cf478af51adf2e65fc626537c1c0 config-storage: type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 @@ -195,9 +195,9 @@ yudao: security: mock-enable: true pay: - order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 - refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 - transfer-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 + order-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + transfer-notify-url: https://rj4jv5rwqs.by.takin.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 access-log: # 访问日志的配置项 enable: false demo: false # 关闭演示模式 diff --git a/yudao-server/src/main/resources/application-prod.yaml b/yudao-server/src/main/resources/application-prod.yaml index 7473fe0..df6b01b 100644 --- a/yudao-server/src/main/resources/application-prod.yaml +++ b/yudao-server/src/main/resources/application-prod.yaml @@ -175,7 +175,7 @@ wx: key-prefix: wx # Redis Key 的前缀 http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 - appid: wx2b4e4d3feff8267f # 测试号(puhui 提供的) + appid: wx2b4e4d3feff8267f secret: cf47cf478af51adf2e65fc626537c1c0 config-storage: type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 @@ -191,8 +191,9 @@ yudao: security: mock-enable: true pay: - order-notify-url: http://mxshop.zianxin.com:48080/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 - refund-notify-url: http://mxshop.zianxin.com:48080/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + order-notify-url: https://chatapi.zianxin.com/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: https://chatapi.zianxin.com/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + transfer-notify-url: https://chatapi.zianxin.com/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 access-log: # 访问日志的配置项 enable: false demo: false # 关闭演示模式 @@ -244,7 +245,7 @@ al-config: access-key-id: LTAI5tJ7sSxB96XaY9T3Vq3D access-key-secret: EVXWFTS2SB6UkjUVFLhTDBfIvIXgI3 face-scene-id: 1000016045 - face-verify-callback-url: https://rj4jv5rwqs.by.takin.cc + face-verify-callback-url: https://chatapi.zianxin.com face-verify-callback-token: uVuYOzoiQBWPp4A5kPgTddZlKWoSQlzc brokerage: