Commit d874346d4298f66c14da529277eed7254f3b5a30

Authored by 芋道源码
Committed by Gitee
2 parents 1f910992 b7359706

!649 Review代码修改

Merge pull request !649 from 疯狂的世界/feature/mall_product
Showing 15 changed files with 139 additions and 158 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -78,6 +78,13 @@ public class CollectionUtils {
78 78 return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
79 79 }
80 80  
  81 + public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
  82 + if (CollUtil.isEmpty(from)) {
  83 + return new HashMap<>();
  84 + }
  85 + return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
  86 + }
  87 +
81 88 public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
82 89 if (CollUtil.isEmpty(from)) {
83 90 return new HashMap<>();
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/RegisterCouponSendConsumer.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/UserCreateConsumer.java
1 1 package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
2 2  
3 3 import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
4   -import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
  4 +import cn.iocoder.yudao.module.promotion.mq.message.coupon.UserCreateMessage;
5 5 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
6 6 import lombok.extern.slf4j.Slf4j;
7 7 import org.springframework.stereotype.Component;
... ... @@ -9,19 +9,19 @@ import org.springframework.stereotype.Component;
9 9 import javax.annotation.Resource;
10 10  
11 11 /**
12   - * 针对 {@link RegisterCouponSendMessage} 的消费者
  12 + * 针对 {@link UserCreateMessage} 的消费者
13 13 *
14 14 * @author owen
15 15 */
16 16 @Component
17 17 @Slf4j
18   -public class RegisterCouponSendConsumer extends AbstractStreamMessageListener<RegisterCouponSendMessage> {
  18 +public class UserCreateConsumer extends AbstractStreamMessageListener<UserCreateMessage> {
19 19  
20 20 @Resource
21 21 private CouponService couponService;
22 22  
23 23 @Override
24   - public void onMessage(RegisterCouponSendMessage message) {
  24 + public void onMessage(UserCreateMessage message) {
25 25 log.info("[onMessage][消息内容({})]", message);
26 26 couponService.takeCouponByRegister(message.getUserId());
27 27 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/coupon/UserCreateMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.mq.message.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +/**
  10 + * 会员用户创建消息
  11 + *
  12 + * @author owen
  13 + */
  14 +@Data
  15 +@EqualsAndHashCode(callSuper = true)
  16 +public class UserCreateMessage extends AbstractStreamMessage {
  17 +
  18 + /**
  19 + * 用户编号
  20 + */
  21 + @NotNull(message = "用户编号不能为空")
  22 + private Long userId;
  23 +
  24 + @Override
  25 + public String getStreamKey() {
  26 + return "member.create.send";
  27 + }
  28 +
  29 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -178,7 +178,7 @@ public class CouponServiceImpl implements CouponService {
178 178 }
179 179  
180 180 @Override
181   - // TODO @疯狂:搞个事务;
  181 + @Transactional(rollbackFor = Exception.class)
182 182 public void takeCouponByRegister(Long userId) {
183 183 List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER);
184 184 for (CouponTemplateDO template : templates) {
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -81,6 +81,7 @@ public interface ErrorCodeConstants {
81 81 ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1_011_007_005, "只有在注册时可以绑定");
82 82 ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1_011_007_006, "已绑定了推广人");
83 83 ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1_011_007_007, "下级不能绑定自己的上级");
  84 + ErrorCode BROKERAGE_USER_LEVEL_NOT_SUPPORT = new ErrorCode(1_011_007_008, "目前只支持 level 小于等于 2");
84 85  
85 86  
86 87 // ========== 分销提现 模块 1-011-008-000 ==========
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java
1 1 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage;
2 2  
  3 +import cn.hutool.core.convert.Convert;
3 4 import cn.hutool.core.lang.Assert;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.common.pojo.SortingField;
... ... @@ -17,6 +18,8 @@ import org.apache.ibatis.annotations.Param;
17 18 import org.apache.ibatis.annotations.Select;
18 19  
19 20 import java.time.LocalDateTime;
  21 +import java.util.Collection;
  22 +import java.util.Collections;
20 23 import java.util.List;
21 24  
22 25 /**
... ... @@ -27,12 +30,12 @@ import java.util.List;
27 30 @Mapper
28 31 public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
29 32  
30   - default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Long> bindUserIds) {
  33 + default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Long> ids) {
31 34 return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
  35 + .inIfPresent(BrokerageUserDO::getId, ids)
32 36 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
33 37 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
34 38 .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
35   - .inIfPresent(BrokerageUserDO::getBindUserId, bindUserIds)
36 39 .orderByDesc(BrokerageUserDO::getId));
37 40 }
38 41  
... ... @@ -124,11 +127,6 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
124 127 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
125 128 }
126 129  
127   - default Long selectCountByBindUserIdIn(List<Long> bindUserIds) {
128   - return selectCount(new LambdaQueryWrapperX<BrokerageUserDO>()
129   - .inIfPresent(BrokerageUserDO::getBindUserId, bindUserIds));
130   - }
131   -
132 130 @Select("SELECT bind_user_id AS id, COUNT(1) AS brokerageUserCount FROM trade_brokerage_user " +
133 131 "WHERE bind_user_id IS NOT NULL AND deleted = FALSE " +
134 132 "AND bind_user_time BETWEEN #{beginTime} AND #{endTime} " +
... ... @@ -143,32 +141,21 @@ public interface BrokerageUserMapper extends BaseMapperX&lt;BrokerageUserDO&gt; {
143 141 *
144 142 * @param bizType 业务类型
145 143 * @param status 状态
146   - * @param bindUserIds 绑定用户编号列表
  144 + * @param ids 用户编号列表
147 145 * @param sortingField 排序字段
148 146 * @return 下级分销统计分页列表
149 147 */
150 148 IPage<AppBrokerageUserChildSummaryRespVO> selectSummaryPageByUserId(Page<?> page,
151 149 @Param("bizType") Integer bizType,
152 150 @Param("status") Integer status,
153   - @Param("bindUserIds") List<Long> bindUserIds,
  151 + @Param("ids") Collection<Long> ids,
154 152 @Param("sortingField") SortingField sortingField);
155 153  
156   - /**
157   - * 下级分销统计(不分页)
158   - *
159   - * @param bizType 业务类型
160   - * @param status 状态
161   - * @param bindUserIds 绑定用户编号列表
162   - * @param sortingField 排序字段
163   - * @return 下级分销统计列表
164   - */
165   - List<AppBrokerageUserChildSummaryRespVO> selectSummaryListByUserId(@Param("bizType") Integer bizType,
166   - @Param("status") Integer status,
167   - @Param("bindUserIds") List<Long> bindUserIds,
168   - @Param("sortingField") SortingField sortingField);
169   -
170   - default List<BrokerageUserDO> selectListByBindUserId(Long bindUserId) {
171   - return selectList(BrokerageUserDO::getBindUserId, bindUserId);
  154 + default List<Long> selectIdListByBindUserIdIn(Collection<Long> bindUserIds) {
  155 + return Convert.toList(Long.class,
  156 + selectObjs(new LambdaQueryWrapperX<BrokerageUserDO>()
  157 + .select(Collections.singletonList(BrokerageUserDO::getId))
  158 + .in(BrokerageUserDO::getBindUserId, bindUserIds)));
172 159 }
173 160  
174 161 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
... ... @@ -31,10 +31,9 @@ import org.springframework.validation.annotation.Validated;
31 31 import javax.annotation.Resource;
32 32 import java.time.LocalDateTime;
33 33 import java.util.*;
34   -import java.util.stream.Collectors;
35 34  
36 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
37   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMapByFilter;
38 37 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
39 38  
40 39 /**
... ... @@ -67,8 +66,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
67 66  
68 67 @Override
69 68 public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
70   - List<Long> bindUserIds = buildBindUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel());
71   - return brokerageUserMapper.selectPage(pageReqVO, bindUserIds);
  69 + List<Long> childIds = getChildUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel());
  70 + // 有”绑定用户编号“查询条件时,没有查到下级会员,直接返回空
  71 + if (pageReqVO.getBindUserId() != null && CollUtil.isEmpty(childIds)) {
  72 + return PageResult.empty();
  73 + }
  74 + return brokerageUserMapper.selectPage(pageReqVO, childIds);
72 75 }
73 76  
74 77 @Override
... ... @@ -154,11 +157,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
154 157  
155 158 @Override
156 159 public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) {
157   - List<Long> bindUserIds = buildBindUserIdsByLevel(bindUserId, level);
158   - if (CollUtil.isEmpty(bindUserIds)) {
159   - return 0L;
160   - }
161   - return brokerageUserMapper.selectCountByBindUserIdIn(bindUserIds);
  160 + List<Long> childIds = getChildUserIdsByLevel(bindUserId, level);
  161 + return (long) CollUtil.size(childIds);
162 162 }
163 163  
164 164 @Override
... ... @@ -226,70 +226,29 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
226 226  
227 227 @Override
228 228 public PageResult<AppBrokerageUserChildSummaryRespVO> getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId) {
229   - // 生成推广员编号列表
230   - List<Long> bindUserIds = buildBindUserIdsByLevel(userId, pageReqVO.getLevel());
231   -
232   - // TODO @疯狂:情况一和情况二,可以合并哈;
233   - // 如果有 nickname 的时候,相当于提前查询 users,然后 nickname 过滤掉 bindUserIds;
234   - // 之后,继续使用 selectSummaryPageByUserId 里面 in bindUserIds 查询;
235   -
236   - // 情况一:没有昵称过滤条件时,直接使用数据库的分页查询
237   - if (StrUtil.isBlank(pageReqVO.getNickname())) {
238   - // 1.1 分页查询
239   - IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
240   - MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(),
241   - BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), bindUserIds, pageReqVO.getSortingField()
242   - );
243   -
244   - // 1.2 拼接数据并返回
245   - List<Long> userIds = convertList(pageResult.getRecords(), AppBrokerageUserChildSummaryRespVO::getId);
246   - Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
247   - BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap);
248   - return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
249   - }
250   -
251   - // 情况二:有昵称过滤条件时,需要跨模块(Member)过滤
252   - // 2.1 查询所有匹配的分销用户
253   - List<AppBrokerageUserChildSummaryRespVO> list = brokerageUserMapper.selectSummaryListByUserId(
254   - BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(),
255   - bindUserIds, pageReqVO.getSortingField()
256   - );
257   - if (CollUtil.isEmpty(list)) {
  229 + // 1.1 查询下级用户编号列表
  230 + List<Long> childIds = getChildUserIdsByLevel(userId, pageReqVO.getLevel());
  231 + if (CollUtil.isEmpty(childIds)) {
258 232 return PageResult.empty();
259 233 }
260 234  
261   - // 2.2 查出对应的用户信息
262   - List<MemberUserRespDTO> users = memberUserApi.getUserList(convertList(list, AppBrokerageUserChildSummaryRespVO::getId));
263   - if (CollUtil.isEmpty(users)) {
264   - return PageResult.empty();
265   - }
266   -
267   - // 2.3 根据昵称过滤出用户编号
268   - Map<Long, MemberUserRespDTO> userMap = users.stream()
269   - .filter(user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()))
270   - .collect(Collectors.toMap(MemberUserRespDTO::getId, dto -> dto));
  235 + // 1.2 根据昵称过滤下级用户
  236 + Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(memberUserApi.getUserList(childIds),
  237 + user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()),
  238 + MemberUserRespDTO::getId);
271 239 if (CollUtil.isEmpty(userMap)) {
272 240 return PageResult.empty();
273 241 }
274 242  
275   - // 2.4 根据用户编号过滤结果
276   - list.removeIf(vo -> !userMap.containsKey(vo.getId()));
277   - if (CollUtil.isEmpty(list)) {
278   - return PageResult.empty();
279   - }
280   -
281   - // 2.5 处理分页
282   - List<AppBrokerageUserChildSummaryRespVO> result = list.stream()
283   - .skip((long) (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize())
284   - .limit(pageReqVO.getPageSize())
285   - .collect(Collectors.toList());
286   - if (CollUtil.isEmpty(result)) {
287   - return PageResult.empty();
288   - }
  243 + // 2 分页查询
  244 + IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
  245 + MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(),
  246 + BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), userMap.keySet(), pageReqVO.getSortingField()
  247 + );
289 248  
290   - // 2.6 拼接数据并返回
291   - BrokerageUserConvert.INSTANCE.copyTo(result, userMap);
292   - return new PageResult<>(result, (long) list.size());
  249 + // 3 拼接数据并返回
  250 + BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap);
  251 + return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
293 252 }
294 253  
295 254 private boolean isUserCanBind(BrokerageUserDO user) {
... ... @@ -360,24 +319,35 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
360 319 }
361 320  
362 321 /**
363   - * 根据绑定用户编号,获得绑定用户编号列表
  322 + * 根据绑定用户编号,获得下级用户编号列表
364 323 *
365 324 * @param bindUserId 绑定用户编号
366   - * @param level 绑定用户的层级。
  325 + * @param level 下级用户的层级。
367 326 * 如果 level 为空,则查询 1+2 两个层级
368   - * @return 绑定用户编号列表
  327 + * @return 下级用户编号列表
369 328 */
370   - private List<Long> buildBindUserIdsByLevel(Long bindUserId, Integer level) {
  329 + private List<Long> getChildUserIdsByLevel(Long bindUserId, Integer level) {
371 330 if (bindUserId == null) {
372 331 return Collections.emptyList();
373 332 }
374   - Assert.isTrue(level == null || level <= 2, "目前只支持 level 小于等于 2");
375   - List<Long> bindUserIds = CollUtil.newArrayList();
376   - if (level == null || level == 1) {
377   - bindUserIds.add(bindUserId);
  333 +
  334 + // 先查第 1 级
  335 + List<Long> bindUserIds = brokerageUserMapper.selectIdListByBindUserIdIn(Collections.singleton(bindUserId));
  336 + if (CollUtil.isEmpty(bindUserIds)) {
  337 + return Collections.emptyList();
378 338 }
379   - if (level == null || level == 2) {
380   - bindUserIds.addAll(convertList(brokerageUserMapper.selectListByBindUserId(bindUserId), BrokerageUserDO::getId));
  339 +
  340 + if (level == null) {
  341 + // level 为空,再查第 2 级,并合并结果
  342 + bindUserIds.addAll(brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds));
  343 + } else if (level == 2) {
  344 + // 只查第 2 级
  345 + bindUserIds = brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds);
  346 + } else if (level == 1) {
  347 + // 只查第 1 级
  348 + return bindUserIds;
  349 + } else {
  350 + throw exception(BROKERAGE_USER_LEVEL_NOT_SUPPORT);
381 351 }
382 352 return bindUserIds;
383 353 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml
... ... @@ -2,7 +2,9 @@
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 3 <mapper namespace="cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper">
4 4  
5   - <sql id="selectSummaryListByUserId">
  5 + <select id="selectSummaryPageByUserId"
  6 + resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
  7 +
6 8 SELECT bu.id, bu.bind_user_time AS brokerageTime,
7 9 (SELECT SUM(price) FROM trade_brokerage_record r
8 10 WHERE r.user_id = bu.id AND biz_type = #{bizType} AND r.status = #{status} AND r.deleted = FALSE) AS brokeragePrice,
... ... @@ -13,10 +15,10 @@
13 15 FROM trade_brokerage_user AS bu
14 16 <where>
15 17 bu.deleted = false
16   - <if test="bindUserIds != null and bindUserIds.size() > 0">
17   - and bu.bind_user_id in
18   - <foreach collection="bindUserIds" open="(" item="bindUserId" separator="," close=")">
19   - #{bindUserId}
  18 + <if test="ids != null and ids.size() > 0">
  19 + and bu.id in
  20 + <foreach collection="ids" open="(" item="id" separator="," close=")">
  21 + #{id}
20 22 </foreach>
21 23 </if>
22 24 </where>
... ... @@ -34,15 +36,6 @@
34 36 ORDER BY bu.bind_user_time DESC
35 37 </otherwise>
36 38 </choose>
37   - </sql>
38   -
39   - <select id="selectSummaryPageByUserId"
40   - resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
41   - <include refid="selectSummaryListByUserId" />
42   - </select>
43   - <select id="selectSummaryListByUserId"
44   - resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
45   - <include refid="selectSummaryListByUserId" />
46 39 </select>
47 40  
48 41 </mapper>
... ...
yudao-module-member/yudao-module-member-api/pom.xml
... ... @@ -22,13 +22,6 @@
22 22 <artifactId>yudao-common</artifactId>
23 23 </dependency>
24 24  
25   - <!-- TODO @疯狂:biz 引入哈;api 保持低依赖 -->
26   - <dependency>
27   - <groupId>cn.iocoder.boot</groupId>
28   - <artifactId>yudao-spring-boot-starter-mq</artifactId>
29   - <scope>compile</scope>
30   - </dependency>
31   -
32 25 <!-- 参数校验 -->
33 26 <dependency>
34 27 <groupId>org.springframework.boot</groupId>
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
... ... @@ -38,11 +38,9 @@ public interface ErrorCodeConstants {
38 38 //========== 签到配置 1-004-009-000 ==========
39 39 ErrorCode SIGN_IN_CONFIG_NOT_EXISTS = new ErrorCode(1_004_009_000, "签到天数规则不存在");
40 40 ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1_004_009_001, "签到天数规则已存在");
41   - // TODO @疯狂:这个可以用 validator 去做;通过在 BaseVO 里,增加一个 @AssertTrue 注解的方式
42   - ErrorCode SIGN_IN_CONFIG_AWARD_EMPTY = new ErrorCode(1_004_009_002, "签到奖励积分和经验不能同时为空");
43 41  
44 42 //========== 签到配置 1-004-010-000 ==========
45   - ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000,"今日已签到,请勿重复签到");
  43 + ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000, "今日已签到,请勿重复签到");
46 44  
47 45 //========== 用户等级 1-004-011-000 ==========
48 46 ErrorCode LEVEL_NOT_EXISTS = new ErrorCode(1_004_011_000, "用户等级不存在");
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java
1 1 package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 5 import cn.iocoder.yudao.framework.common.validation.InEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
5 7 import io.swagger.v3.oas.annotations.media.Schema;
6 8 import lombok.Data;
7 9  
  10 +import javax.validation.constraints.AssertTrue;
8 11 import javax.validation.constraints.NotNull;
9 12 import javax.validation.constraints.PositiveOrZero;
10 13  
... ... @@ -34,4 +37,9 @@ public class MemberSignInConfigBaseVO {
34 37 @InEnum(CommonStatusEnum.class)
35 38 private Integer status;
36 39  
  40 + @AssertTrue(message = "签到奖励积分和经验不能同时为空")
  41 + @JsonIgnore
  42 + public boolean isConfigAward() {
  43 + return ObjUtil.notEqual(point, 0) || ObjUtil.notEqual(experience, 0);
  44 + }
37 45 }
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/RegisterCouponSendMessage.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/UserCreateMessage.java
... ... @@ -7,13 +7,13 @@ import lombok.EqualsAndHashCode;
7 7 import javax.validation.constraints.NotNull;
8 8  
9 9 /**
10   - * 新人券发放消息
  10 + * 会员用户创建消息
11 11 *
12 12 * @author owen
13 13 */
14 14 @Data
15 15 @EqualsAndHashCode(callSuper = true)
16   -public class RegisterCouponSendMessage extends AbstractStreamMessage {
  16 +public class UserCreateMessage extends AbstractStreamMessage {
17 17  
18 18 /**
19 19 * 用户编号
... ... @@ -23,7 +23,7 @@ public class RegisterCouponSendMessage extends AbstractStreamMessage {
23 23  
24 24 @Override
25 25 public String getStreamKey() {
26   - return "member.register-coupon.send";
  26 + return "member.create.send";
27 27 }
28 28  
29 29 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/RegisterCouponProducer.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/UserCreateProducer.java
1 1 package cn.iocoder.yudao.module.member.mq.producer.user;
2 2  
3 3 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
4   -import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
  4 +import cn.iocoder.yudao.module.member.mq.message.user.UserCreateMessage;
5 5 import lombok.extern.slf4j.Slf4j;
6 6 import org.springframework.stereotype.Component;
7 7  
8 8 import javax.annotation.Resource;
9 9  
10   -// TODO @疯狂:发 UserCreateMessage;解耦,然后优惠劵监听到,去发卷;
11 10 /**
12   - * 新人券发放 Producer
  11 + * 会员用户创建 Producer
13 12 *
14 13 * @author owen
15 14 */
16 15 @Slf4j
17 16 @Component
18   -public class RegisterCouponProducer {
  17 +public class UserCreateProducer {
19 18  
20 19 @Resource
21 20 private RedisMQTemplate redisMQTemplate;
22 21  
23 22 /**
24   - * 发送 {@link RegisterCouponSendMessage} 消息
  23 + * 发送 {@link UserCreateMessage} 消息
25 24 *
26 25 * @param userId 用户编号
27 26 */
28   - public void sendMailSendMessage(Long userId) {
29   - redisMQTemplate.send(new RegisterCouponSendMessage().setUserId(userId));
  27 + public void sendUserCreateMessage(Long userId) {
  28 + redisMQTemplate.send(new UserCreateMessage().setUserId(userId));
30 29 }
31 30  
32 31 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java
... ... @@ -11,10 +11,10 @@ import org.springframework.validation.annotation.Validated;
11 11 import javax.annotation.Resource;
12 12 import java.util.Comparator;
13 13 import java.util.List;
14   -import java.util.Objects;
15 14  
16 15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17   -import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
  16 +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_EXISTS;
  17 +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_NOT_EXISTS;
18 18  
19 19 /**
20 20 * 签到规则 Service 实现类
... ... @@ -30,8 +30,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
30 30  
31 31 @Override
32 32 public Long createSignInConfig(MemberSignInConfigCreateReqVO createReqVO) {
33   - // 校验奖励积分、奖励经验
34   - validatePointAndExperience(createReqVO.getPoint(), createReqVO.getExperience());
35 33 // 判断是否重复插入签到天数
36 34 validateSignInConfigDayDuplicate(createReqVO.getDay(), null);
37 35  
... ... @@ -44,8 +42,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
44 42  
45 43 @Override
46 44 public void updateSignInConfig(MemberSignInConfigUpdateReqVO updateReqVO) {
47   - // 校验奖励积分、奖励经验
48   - validatePointAndExperience(updateReqVO.getPoint(), updateReqVO.getExperience());
49 45 // 校验存在
50 46 validateSignInConfigExists(updateReqVO.getId());
51 47 // 判断是否重复插入签到天数
... ... @@ -88,13 +84,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
88 84 }
89 85 }
90 86  
91   - private void validatePointAndExperience(Integer point, Integer experience) {
92   - // 奖励积分、经验 至少要配置一个,否则没有意义
93   - if (Objects.equals(point, 0) && Objects.equals(experience, 0)) {
94   - throw exception(SIGN_IN_CONFIG_AWARD_EMPTY);
95   - }
96   - }
97   -
98 87 @Override
99 88 public MemberSignInConfigDO getSignInConfig(Long id) {
100 89 return memberSignInConfigMapper.selectById(id);
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.service.user;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.ListUtil;
  5 +import cn.hutool.core.util.BooleanUtil;
5 6 import cn.hutool.core.util.IdUtil;
6 7 import cn.hutool.core.util.ObjectUtil;
7 8 import cn.hutool.core.util.StrUtil;
... ... @@ -18,7 +19,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
18 19 import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
19 20 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
20 21 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
21   -import cn.iocoder.yudao.module.member.mq.producer.user.RegisterCouponProducer;
  22 +import cn.iocoder.yudao.module.member.mq.producer.user.UserCreateProducer;
22 23 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
23 24 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
24 25 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
... ... @@ -27,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
27 28 import org.springframework.security.crypto.password.PasswordEncoder;
28 29 import org.springframework.stereotype.Service;
29 30 import org.springframework.transaction.annotation.Transactional;
  31 +import org.springframework.transaction.support.TransactionTemplate;
30 32  
31 33 import javax.annotation.Resource;
32 34 import javax.validation.Valid;
... ... @@ -60,7 +62,10 @@ public class MemberUserServiceImpl implements MemberUserService {
60 62 private PasswordEncoder passwordEncoder;
61 63  
62 64 @Resource
63   - private RegisterCouponProducer registerCouponProducer;
  65 + private UserCreateProducer registerCouponProducer;
  66 +
  67 + @Resource
  68 + private TransactionTemplate transactionTemplate;
64 69  
65 70 @Override
66 71 public MemberUserDO getUserByMobile(String mobile) {
... ... @@ -92,11 +97,13 @@ public class MemberUserServiceImpl implements MemberUserService {
92 97 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
93 98 user.setPassword(encodePassword(password)); // 加密密码
94 99 user.setRegisterIp(registerIp);
95   - memberUserMapper.insert(user);
96 100  
97   - // 发送 MQ 消息,发放新人券
98   - // TODO @疯狂:事务结束后,在发送 MQ 消息;避免出现消息已经发了,事务没提交,或者回滚了
99   - registerCouponProducer.sendMailSendMessage(user.getId());
  101 + Boolean success = transactionTemplate.execute(status -> memberUserMapper.insert(user) > 0);
  102 + if (BooleanUtil.isTrue(success)) {
  103 + // 发送 MQ 消息:用户创建
  104 + registerCouponProducer.sendUserCreateMessage(user.getId());
  105 + }
  106 +
100 107 return user;
101 108 }
102 109  
... ...