Browse Source

修改事件监听问题

master
glx 1 month ago
parent
commit
a17a42814b
  1. 3
      src/main/java/com/youlai/boot/common/enums/LogModuleEnum.java
  2. 20
      src/main/java/com/youlai/boot/mini/controller/PointAdminController.java
  3. 13
      src/main/java/com/youlai/boot/mini/controller/PointController.java
  4. 21
      src/main/java/com/youlai/boot/mini/listener/UserRegisterPointListener.java
  5. 6
      src/main/java/com/youlai/boot/mini/model/form/AdjustUserPointForm.java
  6. 13
      src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java

3
src/main/java/com/youlai/boot/common/enums/LogModuleEnum.java

@ -31,7 +31,8 @@ public enum LogModuleEnum implements IBaseEnum<Integer> {
OTHER(99, "其他"), OTHER(99, "其他"),
POINT_ACCOUNT(100, "积分账户"), POINT_ACCOUNT(100, "积分账户"),
POINT_RECORD(101, "积分流水"), POINT_RECORD(101, "积分流水"),
POINT_RULE(102, "积分规则"); POINT_RULE(102, "积分规则"),
SIGN_RECORD(103, "签到记录");
@EnumValue @EnumValue
private final Integer value; private final Integer value;

20
src/main/java/com/youlai/boot/mini/controller/PointAdminController.java

@ -37,14 +37,15 @@ public class PointAdminController {
@Operation(summary = "分页查询用户积分账户") @Operation(summary = "分页查询用户积分账户")
@GetMapping("/accounts") @GetMapping("/accounts")
@PreAuthorize("@ss.hasPerm('mini:point:account:list')") // @PreAuthorize("@ss.hasPerm('mini:point:account:list')")
@Log(module = LogModuleEnum.POINT_ACCOUNT, value = ActionTypeEnum.LIST)
public PageResult<PointAccountVO> pageAccount(PointAccountQuery query) { public PageResult<PointAccountVO> pageAccount(PointAccountQuery query) {
return PageResult.success(pointAccountService.pageAccount(query)); return PageResult.success(pointAccountService.pageAccount(query));
} }
@Operation(summary = "查询积分规则列表") @Operation(summary = "查询积分规则列表")
@GetMapping @GetMapping
@PreAuthorize("@ss.hasPerm('mini:point:rule:list')") // @PreAuthorize("@ss.hasPerm('mini:point:rule:list')")
@Log(module = LogModuleEnum.POINT_RULE, value = ActionTypeEnum.LIST) @Log(module = LogModuleEnum.POINT_RULE, value = ActionTypeEnum.LIST)
public PageResult<RuleListVO> page(@ParameterObject RulePageQuery queryParams) { public PageResult<RuleListVO> page(@ParameterObject RulePageQuery queryParams) {
IPage<RuleListVO> result = pointRuleService.pageRule(queryParams); IPage<RuleListVO> result = pointRuleService.pageRule(queryParams);
@ -53,7 +54,8 @@ public class PointAdminController {
@Operation(summary = "新增积分规则") @Operation(summary = "新增积分规则")
@PostMapping("/add/rules") @PostMapping("/add/rules")
@PreAuthorize("@ss.hasPerm('mini:point:rule:add')") // @PreAuthorize("@ss.hasPerm('mini:point:rule:add')")
@Log(module = LogModuleEnum.POINT_RULE, value = ActionTypeEnum.INSERT)
public Result<Void> addRule(@RequestBody AddPointRuleForm form) { public Result<Void> addRule(@RequestBody AddPointRuleForm form) {
pointRuleService.addRule(form); pointRuleService.addRule(form);
return Result.success(); return Result.success();
@ -61,7 +63,8 @@ public class PointAdminController {
@Operation(summary = "逻辑删除积分规则") @Operation(summary = "逻辑删除积分规则")
@PostMapping("/delete/rules") @PostMapping("/delete/rules")
@PreAuthorize("@ss.hasPerm('mini:point:rule:delete')") // @PreAuthorize("@ss.hasPerm('mini:point:rule:delete')")
@Log(module = LogModuleEnum.POINT_RULE, value = ActionTypeEnum.DELETE)
public Result<Void> deleteRule(@RequestParam Long id) { public Result<Void> deleteRule(@RequestParam Long id) {
pointRuleService.deleteRule(id); pointRuleService.deleteRule(id);
return Result.success(); return Result.success();
@ -69,7 +72,8 @@ public class PointAdminController {
@Operation(summary = "启用/禁用积分规则") @Operation(summary = "启用/禁用积分规则")
@PatchMapping("/rules/{id}/status") @PatchMapping("/rules/{id}/status")
@PreAuthorize("@ss.hasPerm('mini:point:rule:edit')") // @PreAuthorize("@ss.hasPerm('mini:point:rule:edit')")
@Log(module = LogModuleEnum.POINT_RULE, value = ActionTypeEnum.ENABLE)
public Result<Void> changeRuleStatus(@PathVariable Long id, @RequestParam Boolean status) { public Result<Void> changeRuleStatus(@PathVariable Long id, @RequestParam Boolean status) {
pointRuleService.changeStatus(id, status); pointRuleService.changeStatus(id, status);
return Result.success(); return Result.success();
@ -77,7 +81,8 @@ public class PointAdminController {
@Operation(summary = "手动调整用户积分") @Operation(summary = "手动调整用户积分")
@PutMapping("/adjustPoint") @PutMapping("/adjustPoint")
@PreAuthorize("@ss.hasPerm('mini:point:record:edit')") // @PreAuthorize("@ss.hasPerm('mini:point:record:edit')")
@Log(module = LogModuleEnum.POINT_ACCOUNT, value = ActionTypeEnum.UPDATE)
public Result<Void> adjustPoint(@RequestBody AdjustUserPointForm adjustUserPointForm) { public Result<Void> adjustPoint(@RequestBody AdjustUserPointForm adjustUserPointForm) {
pointRecordService.adjustPoint(adjustUserPointForm); pointRecordService.adjustPoint(adjustUserPointForm);
return Result.success(); return Result.success();
@ -85,7 +90,8 @@ public class PointAdminController {
@Operation(summary = "分页查询所有积分记录") @Operation(summary = "分页查询所有积分记录")
@GetMapping("/records") @GetMapping("/records")
@PreAuthorize("@ss.hasPerm('mini:point:record:list')") // @PreAuthorize("@ss.hasPerm('mini:point:record:list')")
@Log(module = LogModuleEnum.POINT_RECORD, value = ActionTypeEnum.LIST)
public PageResult<PointRecordVO> pageRecord(PointRecordQuery query) { public PageResult<PointRecordVO> pageRecord(PointRecordQuery query) {
return PageResult.success(pointRecordService.pageAllRecord(query)); return PageResult.success(pointRecordService.pageAllRecord(query));
} }

13
src/main/java/com/youlai/boot/mini/controller/PointController.java

@ -1,5 +1,9 @@
package com.youlai.boot.mini.controller; package com.youlai.boot.mini.controller;
import com.youlai.boot.common.annotation.Log;
import com.youlai.boot.common.annotation.RepeatSubmit;
import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.result.PageResult; import com.youlai.boot.common.result.PageResult;
import com.youlai.boot.common.result.Result; import com.youlai.boot.common.result.Result;
import com.youlai.boot.framework.security.util.SecurityUtils; import com.youlai.boot.framework.security.util.SecurityUtils;
@ -26,12 +30,12 @@ import org.springframework.web.bind.annotation.*;
public class PointController { public class PointController {
private final MiniPointAccountService pointAccountService; private final MiniPointAccountService pointAccountService;
private final MiniPointRuleService pointRuleService;
private final MiniPointRecordService pointRecordService; private final MiniPointRecordService pointRecordService;
private final MiniSignService signService; private final MiniSignService signService;
@Operation(summary = "查询当前用户的积分账户信息") @Operation(summary = "查询当前用户的积分账户信息")
@GetMapping("/my") @GetMapping("/my")
@Log(module = LogModuleEnum.POINT_ACCOUNT, value = ActionTypeEnum.LIST)
public Result<MyPointVO> getMyPoint() { public Result<MyPointVO> getMyPoint() {
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
MyPointVO myPoint = pointAccountService.getUserPoint(userId); MyPointVO myPoint = pointAccountService.getUserPoint(userId);
@ -40,6 +44,7 @@ public class PointController {
@Operation(summary = "分页查询当前用户的积分流水列表") @Operation(summary = "分页查询当前用户的积分流水列表")
@GetMapping("/records") @GetMapping("/records")
@Log(module = LogModuleEnum.POINT_RECORD, value = ActionTypeEnum.LIST)
public PageResult<MyPointRecordVO> getMyPointRecords(@ParameterObject MyPointRecordQuery query) { public PageResult<MyPointRecordVO> getMyPointRecords(@ParameterObject MyPointRecordQuery query) {
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
return PageResult.success(pointRecordService.pageMyPointRecord(userId, query)); return PageResult.success(pointRecordService.pageMyPointRecord(userId, query));
@ -47,18 +52,22 @@ public class PointController {
@Operation(summary = "用户签到") @Operation(summary = "用户签到")
@PostMapping("/sign") @PostMapping("/sign")
@RepeatSubmit
@Log(module = LogModuleEnum.SIGN_RECORD, value = ActionTypeEnum.INSERT)
public Result<SignResultVO> sign() { public Result<SignResultVO> sign() {
return Result.success(signService.sign()); return Result.success(signService.sign());
} }
@Operation(summary = "查询用户签到状态/当月签到日历") @Operation(summary = "查询用户签到状态/当月签到日历")
@GetMapping("/sign/status") @GetMapping("/sign/status")
@Log(module = LogModuleEnum.SIGN_RECORD, value = ActionTypeEnum.LIST)
public Result<SignStatusVO> getSignStatus() { public Result<SignStatusVO> getSignStatus() {
return Result.success(signService.getSignStatus()); return Result.success(signService.getSignStatus());
} }
@Operation(summary = "用户分享领取奖励") @Operation(summary = "用户分享领取奖励")
@PostMapping("/share/reward") @PostMapping("/share/reward")
@Log(module = LogModuleEnum.OTHER, value = ActionTypeEnum.OTHER)
public Result<Integer> shareReward() { public Result<Integer> shareReward() {
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
Integer point = pointRecordService.giveShareReward(userId); Integer point = pointRecordService.giveShareReward(userId);
@ -67,6 +76,7 @@ public class PointController {
@Operation(summary = "登记流浪动物领取积分") @Operation(summary = "登记流浪动物领取积分")
@PostMapping("/register-animal/reward") @PostMapping("/register-animal/reward")
@Log(module = LogModuleEnum.OTHER, value = ActionTypeEnum.OTHER)
public Result<Integer> registerAnimalReward( public Result<Integer> registerAnimalReward(
@Parameter(description = "登记的流浪动物ID", required = true) @RequestParam Long animalId) { @Parameter(description = "登记的流浪动物ID", required = true) @RequestParam Long animalId) {
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
@ -76,6 +86,7 @@ public class PointController {
@Operation(summary = "AI生成扣除积分") @Operation(summary = "AI生成扣除积分")
@PostMapping("/ai-generate/deduct") @PostMapping("/ai-generate/deduct")
@Log(module = LogModuleEnum.OTHER, value = ActionTypeEnum.OTHER)
public Result<Integer> aiGenerateImageDeduct( public Result<Integer> aiGenerateImageDeduct(
@Parameter(description = "AI生成任务唯一ID(用于幂等)", required = true) @RequestParam String taskId) { @Parameter(description = "AI生成任务唯一ID(用于幂等)", required = true) @RequestParam String taskId) {
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();

21
src/main/java/com/youlai/boot/mini/listener/UserRegisterPointListener.java

@ -9,10 +9,12 @@ import com.youlai.boot.mini.service.MiniPointRecordService;
import com.youlai.boot.mini.service.MiniPointRuleService; import com.youlai.boot.mini.service.MiniPointRuleService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/** /**
* 用户注册成功监听器赠送新用户注册积分 * 用户注册成功监听器赠送新用户注册积分
@ -27,19 +29,21 @@ public class UserRegisterPointListener {
private final MiniPointRuleService pointRuleService; private final MiniPointRuleService pointRuleService;
/** /**
* 异步监听用户注册成功事件赠送积分 * 监听用户注册成功事件事务提交后再赠送积分
* 异步执行不影响主线登录流程就算赠送积分失败也不会影响用户正常登录 * phase = AFTER_COMMIT用户注册事务完全提交成功后才执行完全和主注册逻辑解耦
* fallbackExecution = true无事务上下文也能兼容执行
* 即使赠送积分失败也不会影响用户注册主流程最多日志告警手动补发
*/ */
@Async @Async
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
@EventListener(UserRegisterEvent.class) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
public void handleUserRegisterGivePoint(UserRegisterEvent event) { public void handleUserRegisterGivePoint(UserRegisterEvent event) {
Long userId = event.getUserId(); Long userId = event.getUserId();
String source = event.getRegisterSource(); String source = event.getRegisterSource();
log.info("监听到新用户注册成功,userId={}, 注册来源={}, 开始处理注册赠送积分逻辑", userId, source); log.info("监听到新用户注册成功,userId={}, 注册来源={}, 开始处理注册赠送积分逻辑", userId, source);
try { try {
// ================= 1. 幂等校验:避免重复赠送积分 ================= //1. 幂等校验:避免重复赠送积分
long count = pointRecordService.count(new LambdaQueryWrapper<MiniPointRecord>() long count = pointRecordService.count(new LambdaQueryWrapper<MiniPointRecord>()
.eq(MiniPointRecord::getUserId, userId) .eq(MiniPointRecord::getUserId, userId)
.eq(MiniPointRecord::getBizType, "REGISTER_GIFT") .eq(MiniPointRecord::getBizType, "REGISTER_GIFT")
@ -49,7 +53,7 @@ public class UserRegisterPointListener {
return; return;
} }
// ================= 2. 查询注册积分规则,可配置无需改代码 ================= //2. 查询注册积分规则,可配置无需改代码
MiniPointRule registerRule = pointRuleService.getOne(new LambdaQueryWrapper<MiniPointRule>() MiniPointRule registerRule = pointRuleService.getOne(new LambdaQueryWrapper<MiniPointRule>()
.eq(MiniPointRule::getRuleCode, "REGISTER_GIFT") .eq(MiniPointRule::getRuleCode, "REGISTER_GIFT")
.eq(MiniPointRule::getStatus, false) // 0=启用状态 .eq(MiniPointRule::getStatus, false) // 0=启用状态
@ -60,7 +64,7 @@ public class UserRegisterPointListener {
} }
Integer giftPoint = registerRule.getPoints(); Integer giftPoint = registerRule.getPoints();
// ================= 3. 调用现有积分调整接口赠送积分 ================= //3. 调用现有积分调整接口赠送积分
AdjustUserPointForm adjustForm = new AdjustUserPointForm(); AdjustUserPointForm adjustForm = new AdjustUserPointForm();
adjustForm.setUserId(userId); adjustForm.setUserId(userId);
adjustForm.setBizType("REGISTER_GIFT"); adjustForm.setBizType("REGISTER_GIFT");
@ -71,7 +75,6 @@ public class UserRegisterPointListener {
log.info("新用户{}注册赠送{}积分成功", userId, giftPoint); log.info("新用户{}注册赠送{}积分成功", userId, giftPoint);
} catch (Exception e) { } catch (Exception e) {
log.error("新用户{}注册赠送积分失败,请手动排查补发", userId, e); log.error("新用户{}注册赠送积分失败,请手动排查补发", userId, e);
// 这里可以加告警通知,比如钉钉/企业微信推送,不影响用户登录
} }
} }
} }

6
src/main/java/com/youlai/boot/mini/model/form/AdjustUserPointForm.java

@ -18,8 +18,7 @@ public class AdjustUserPointForm {
private Long userId; private Long userId;
@NotBlank(message = "业务类型不能为空") @NotBlank(message = "业务类型不能为空")
// @EnumValid(enumClass = AdjustUserPointEnum.class, message = "业务类型不合法") @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "业务类型 system_increase system_reduce", requiredMode = Schema.RequiredMode.REQUIRED)
private String bizType; private String bizType;
@NotNull(message = "积分不能为空") @NotNull(message = "积分不能为空")
@ -29,7 +28,4 @@ public class AdjustUserPointForm {
@Schema(description = "业务唯一ID,幂等用,比如AI生成任务ID") @Schema(description = "业务唯一ID,幂等用,比如AI生成任务ID")
private String bizId; private String bizId;
@Schema(description = "备注,存业务关联信息")
private String remark;
} }

13
src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java

@ -1,6 +1,7 @@
package com.youlai.boot.mini.service.impl; package com.youlai.boot.mini.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
@ -63,8 +64,16 @@ public class MiniPointRecordServiceImpl extends ServiceImpl<MiniPointRecordMappe
MiniPointAccount account = miniPointAccountService.getOne(new LambdaQueryWrapper<MiniPointAccount>() MiniPointAccount account = miniPointAccountService.getOne(new LambdaQueryWrapper<MiniPointAccount>()
.eq(MiniPointAccount::getUserId, form.getUserId()) .eq(MiniPointAccount::getUserId, form.getUserId())
.eq(MiniPointAccount::getDeleted, false)); .eq(MiniPointAccount::getDeleted, false));
// 账户不存在自动创建,新用户第一次获得积分的时候自动初始化账户
if (account == null) { if (account == null) {
throw new MsgException("用户积分账户不存在"); account = new MiniPointAccount();
account.setUuid(IdUtil.fastSimpleUUID());
account.setUserId(form.getUserId());
account.setPoints(0);
account.setCreateBy(form.getUserId());
account.setCreateTime(new java.util.Date());
account.setCreateTimestamp(System.currentTimeMillis());
miniPointAccountService.save(account);
} }
// 4. 计算变更后余额,校验扣减后不能为负数 // 4. 计算变更后余额,校验扣减后不能为负数
@ -341,7 +350,7 @@ public class MiniPointRecordServiceImpl extends ServiceImpl<MiniPointRecordMappe
adjustForm.setBizType("AI_GENERATE_IMAGE"); adjustForm.setBizType("AI_GENERATE_IMAGE");
adjustForm.setChangeAmount(deductPoint); adjustForm.setChangeAmount(deductPoint);
adjustForm.setBizId(taskId); adjustForm.setBizId(taskId);
adjustForm.setRemark("AI生成图片扣费,任务ID:" + taskId); // adjustForm.setRemark("AI生成图片扣费,任务ID:" + taskId);
adjustPoint(adjustForm); adjustPoint(adjustForm);
// 5. 更新周期计数缓存 // 5. 更新周期计数缓存

Loading…
Cancel
Save