src/main/java/cc/mrbird/febs/common/utils/ValidateEntityUtils.java
New file @@ -0,0 +1,280 @@ package cc.mrbird.febs.common.utils; import cc.mrbird.febs.common.exception.FebsException; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * 实体验证工具类 */ public class ValidateEntityUtils { /** * 确保指定列的有效性,并返回相应的实体对象 * selectOne方法 * 此方法用于验证数据库中某列的值是否存在,并返回包含该值的实体对象 * 如果指定的值不存在或为null,将抛出异常 * * @param valueToCheck 需要验证的值 * @param columnExtractor 列值提取器,用于指定需要验证的列 * @param queryWrapperExtractor 查询包装器提取器,用于执行数据库查询 * @param errMsg 错误消息格式字符串 * @param columnExtractors 可变参数(varargs)查询字段,可选,如果没有就是查询全部 * @param <T> 实体类类型 * @param <R> 列值类型 * @param <V> 需要验证的值的类型 * @return 返回包含指定列值的实体对象 * @throws IllegalArgumentException 如果需要验证的值为null * @throws FebsException 如果查询结果为空或列值为null,或查询过程中发生异常 */ public static <T, R, V> T ensureColumnReturnEntity( V valueToCheck, SFunction<T, R> columnExtractor, SFunction<LambdaQueryWrapper<T>, T> queryWrapperExtractor, String errMsg, SFunction<T, R>... columnExtractors) { // 检查输入参数是否为null if (valueToCheck == null) { throw new IllegalArgumentException("The value to check cannot be null while ensureColumnReturnEntity column"); } if (columnExtractor == null || queryWrapperExtractor == null) { throw new IllegalArgumentException("Column extractor and query wrapper extractor cannot be null while ensureColumnReturnEntity column"); } T entity = null; try { // 创建LambdaQueryWrapper并配置查询条件 LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery(); if (columnExtractors != null && columnExtractors.length > 0) { wrapper.select(columnExtractors); } wrapper.eq(columnExtractor, valueToCheck) .last("limit 1"); // 执行查询并获取结果实体 entity = queryWrapperExtractor.apply(wrapper); // 如果查询结果为空,则抛出异常 if (entity == null) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } // 提取查询结果中的列值 R columnValue = columnExtractor.apply(entity); // 如果列值为null,则抛出异常 if (columnValue == null) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } } catch (FebsException e) { // 记录异常日志 throw e; } catch (Exception e) { // 记录异常日志 throw new FebsException(StrUtil.format("An error occurred while ensuring column return entity: {}", valueToCheck)); } // 返回查询到的实体类对象 return entity; } /** * 确保指定列的有效性,并返回相应的实体对象列表 * selectList方法 * 此方法用于验证数据库中某列的值是否存在,并返回包含该值的实体对象列表 * 如果指定的值不存在或为null,将抛出异常 * * @param valueToCheck 需要验证的值 * @param columnExtractor 列值提取器,用于指定需要验证的列 * @param queryWrapperExtractor 查询包装器提取器,用于执行数据库查询 * @param errMsg 错误消息格式字符串 * @param columnExtractors 可变参数(varargs)查询字段,可选,如果没有就是查询全部 * @param <T> 实体类类型 * @param <R> 列值类型 * @param <V> 需要验证的值的类型 * @return 返回包含指定列值的实体对象列表 * @throws IllegalArgumentException 如果需要验证的值为null * @throws FebsException 如果查询结果为空或列值为null,或查询过程中发生异常 */ public static <T, R, V> List<T> ensureColumnReturnEntityList( V valueToCheck, SFunction<T, R> columnExtractor, SFunction<LambdaQueryWrapper<T>, List<T>> queryWrapperExtractor, String errMsg, SFunction<T, R>... columnExtractors) { // 检查需要验证的值是否为null if (valueToCheck == null) { throw new IllegalArgumentException("The value to check cannot be null while ensureColumnReturnEntityList column"); } List<T> entities = new ArrayList<>(); try { // 创建LambdaQueryWrapper并配置查询条件 LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery(); if (columnExtractors != null && columnExtractors.length > 0) { wrapper.select(columnExtractors); } wrapper.eq(columnExtractor, valueToCheck); // 执行查询并获取结果实体列表 entities = queryWrapperExtractor.apply(wrapper); } catch (Exception e) { // 记录异常日志 throw new FebsException(StrUtil.format("An error occurred while ensureColumnReturnEntityList column: {}", valueToCheck)); } // 如果查询结果为空,则抛出异常 if (entities == null || entities.isEmpty()) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } // 返回查询到的实体类对象列表 return entities; } /** * 确保指定列的值在数据库中是存在的 * selectOne方法 * 该方法通过查询数据库来验证给定的列值是否存在如果不存在,则抛出异常 * * @param valueToCheck 需要验证的列值 * @param columnExtractor 用于提取实体类中列值的函数式接口 * @param queryWrapperExtractor 用于构建查询条件并返回实体类的函数式接口 * @param errMsg 当列值无效时抛出的异常消息格式字符串 * @throws IllegalArgumentException 如果需要验证的值为null * @throws FebsException 如果在数据库中找不到指定的列值或列值为null,或者在查询过程中发生异常 */ public static <T, R, V> void ensureColumnValid( V valueToCheck, SFunction<T, R> columnExtractor, SFunction<LambdaQueryWrapper<T>, T> queryWrapperExtractor, String errMsg) { // 检查需要验证的值是否为null if (valueToCheck == null) { throw new IllegalArgumentException("The value to check cannot be null while ensureColumnValid column"); } try { // 创建LambdaQueryWrapper并配置查询条件 LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(); wrapper.select(columnExtractor) .eq(columnExtractor, valueToCheck) .last("limit 1"); // 执行查询并获取结果实体 T entity = queryWrapperExtractor.apply(wrapper); // 如果查询结果为空,则抛出异常 if (entity == null) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } // 提取查询结果中的列值 R columnValue = columnExtractor.apply(entity); // 如果列值为null,则抛出异常 if (columnValue == null) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } } catch (Exception e) { // 记录异常日志 throw new FebsException(e.getMessage()); } } /** * 确保指定值在数据库中是唯一的 * selectCount方法 * 该方法通过查询数据库来验证给定的列值是否已经存在,如果存在,则抛出异常,以确保数据的唯一性 * * @param valueToCheck 需要检查的值 * @param columnExtractor 用于提取实体类字段的函数式接口 * @param countWrapperExtractor 用于获取查询条件包装器中记录数的函数式接口 * @param errMsg 错误消息模板,当值不唯一时使用 * @param <T> 实体类类型 * @param <R> 字段类型 * @param <V> 需要检查的值的类型 * @throws IllegalArgumentException 如果需要检查的值为null,则抛出此异常 * @throws FebsException 如果值已存在或在检查过程中发生错误,则抛出此异常 */ public static <T, R, V> void ensureUnique( V valueToCheck, SFunction<T, R> columnExtractor, SFunction<LambdaQueryWrapper<T>, Integer> countWrapperExtractor, String errMsg) { // 检查输入值是否为null,如果为null,则抛出IllegalArgumentException异常 if (valueToCheck == null) { throw new IllegalArgumentException("The value to check cannot be null while ensureUnique column"); } if (columnExtractor == null) { throw new IllegalArgumentException("The columnExtractor cannot be null while ensureUnique column"); } if (countWrapperExtractor == null) { throw new IllegalArgumentException("The countWrapperExtractor cannot be null while ensureUnique column"); } int count = 0; try { // 创建LambdaQueryWrapper对象,用于构建查询条件 LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>(); // 添加等于条件,检查的字段=需要检查的值 wrapper.eq(columnExtractor, valueToCheck); // 执行查询并获取结果数量 count = countWrapperExtractor.apply(wrapper); } catch (Exception e) { // 记录异常日志 throw new FebsException(StrUtil.format("An error occurred while ensureUnique column: {}", valueToCheck)); } // 如果结果数量大于0,说明值已存在,抛出FebsException异常 if (count > 0) { throw new FebsException(StrUtil.format(errMsg, valueToCheck)); } } /** * 确保两个参数相等,如果不相等则抛出异常 * * @param value1 第一个参数 * @param value2 第二个参数 * @param errMsg 当两个参数不相等时抛出的异常消息格式字符串 * @throws FebsException 如果两个参数不相等 */ public static <T> void ensureEqual( T value1, T value2, String errMsg) { // 使用 Objects.equals 处理 null 值,避免显式 null 检查 if (!Objects.equals(value1, value2)) { // 延迟字符串格式化,只在需要抛出异常时进行 throw new FebsException(StrUtil.format(errMsg, value1, value2)); } } /** * 确保两个参数不相等,如果相等则抛出异常 * * @param value1 第一个参数 * @param value2 第二个参数 * @param errMsg 当两个参数相等时抛出的异常消息格式字符串 * @throws FebsException 如果两个参数相等 */ public static <T> void ensureNotEqual( T value1, T value2, String errMsg) { // 使用 Objects.equals 处理 null 值,避免显式 null 检查 if (Objects.equals(value1, value2)) { // 延迟字符串格式化,只在需要抛出异常时进行 throw new FebsException(StrUtil.format(errMsg, value1, value2)); } } } src/main/java/cc/mrbird/febs/user/contant/MemberConstant.java
New file @@ -0,0 +1,36 @@ package cc.mrbird.febs.user.contant; public class MemberConstant { //添加途径 1-正常注册 0-后台添加 public static final Integer ADD_TYPE_NORMAL = 1; public static final Integer ADD_TYPE_BACK = 0; //性别 0-女 1-男性 2-未填写 public static final Integer FEMALE = 0; public static final Integer MALE = 1; public static final Integer UNKNOWN = 2; /** * 账户状态;1-正常 0-禁用 */ public static final Integer ACCOUNT_STATUS_NORMAL = 1; public static final Integer ACCOUNT_STATUS_TEST = 0; /** * 账户类型;1-正常用户 0-测试账户 */ public static final Integer ACCOUNT_TYPE_NORMAL = 1; public static final Integer ACCOUNT_TYPE_TEST = 0; /** * 是否是主账号 1-是 0-否 */ public static final Integer DIRECTER_YES = 1; public static final Integer DIRECTER_NO = 0; } src/main/java/cc/mrbird/febs/user/entity/ChatMember.java
@@ -18,7 +18,6 @@ `invite_id` varchar(8) DEFAULT NULL COMMENT '邀请码', `referrer_id` varchar(8) DEFAULT NULL COMMENT '推荐人邀请码', `referrer_ids` text COMMENT '推荐人线路', `level` varchar(255) DEFAULT NULL COMMENT '代理层级', `account_status` int DEFAULT '1' COMMENT '账户状态;1-正常 0-禁用', `account_type` int DEFAULT '0' COMMENT '账户类型;1-正常用户 0-测试账户', `avatar` varchar(500) DEFAULT NULL COMMENT '头像', @@ -42,7 +41,6 @@ private String inviteId;//邀请码 private String referrerId;//推荐人邀请码 private String referrerIds;//推荐人线路 private String level;//代理层级 private Integer accountStatus;//账户状态;1-正常 0-禁用 private Integer accountType;//账户类型;1-正常用户 0-测试账户 private String avatar;//头像 src/main/java/cc/mrbird/febs/user/entity/ChatWallet.java
New file @@ -0,0 +1,23 @@ package cc.mrbird.febs.user.entity; import cc.mrbird.febs.common.entity.BaseEntity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; @Data @TableName("chat_wallet") public class ChatWallet extends BaseEntity { /** * 用户ID */ private Long memberId; /** * 余额 */ private BigDecimal balance; } src/main/java/cc/mrbird/febs/user/mapper/ChatWalletMapper.java
New file @@ -0,0 +1,10 @@ package cc.mrbird.febs.user.mapper; import cc.mrbird.febs.user.entity.ChatWallet; import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface ChatWalletMapper extends BaseMapper<ChatWallet> { int updateBalanceWithVersion(ChatWallet wallet); } src/main/java/cc/mrbird/febs/user/req/ApiRegisterDto.java
@@ -14,10 +14,6 @@ @ApiModelProperty(value = "邮箱", example = "152@163.com") private String account; @NotBlank(message = "类型不能为空!") @ApiModelProperty(value = "类型 1-手机号 2-邮箱", example = "1") private String type = "1"; @NotBlank(message = "验证码不能为空") @ApiModelProperty(value = "验证码", example = "123456") private String code; @@ -33,7 +29,6 @@ @ApiModelProperty(value = "邀请码") private String inviteId; @NotBlank(message = "注册类型不能为空") @ApiModelProperty(value = "注册类型 1-正常注册 0-手动添加子账号", example = "1") private Integer registerType;//注册类型 1-正常注册 0-手动添加子账号 @ApiModelProperty(hidden = true) private Integer addType;//添加途径 1-正常注册 0-后台添加 } src/main/java/cc/mrbird/febs/user/service/AsyncService.java
New file @@ -0,0 +1,23 @@ package cc.mrbird.febs.user.service; import cc.mrbird.febs.common.entity.FebsConstant; import cc.mrbird.febs.user.entity.ChatMember; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.scheduling.annotation.Async; public interface AsyncService extends IService<ChatMember> { /** * 初始化钱包信息 * @param memberId */ @Async(FebsConstant.ASYNC_POOL) void initWallet(Long memberId); /** * 初始化推荐人信息 * @param memberId */ @Async(FebsConstant.ASYNC_POOL) void initMemberReferrerIds(Long memberId,String referrerId); } src/main/java/cc/mrbird/febs/user/service/IChatWalletService.java
New file @@ -0,0 +1,13 @@ package cc.mrbird.febs.user.service; import cc.mrbird.febs.user.entity.ChatWallet; import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; public interface IChatWalletService extends IService<ChatWallet> { void addBalance(BigDecimal amount, Long member); void reduceBalance(BigDecimal amount, Long memberId); } src/main/java/cc/mrbird/febs/user/service/Impl/AsyncServiceImpl.java
New file @@ -0,0 +1,60 @@ package cc.mrbird.febs.user.service.Impl; import cc.mrbird.febs.user.entity.ChatMember; import cc.mrbird.febs.user.entity.ChatWallet; import cc.mrbird.febs.user.mapper.ChatMemberMapper; import cc.mrbird.febs.user.mapper.ChatWalletMapper; import cc.mrbird.febs.user.service.AsyncService; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; @Slf4j @Service @RequiredArgsConstructor public class AsyncServiceImpl extends ServiceImpl<ChatMemberMapper, ChatMember> implements AsyncService { private final ChatWalletMapper chatWalletMapper; @Override public void initWallet(Long memberId) { ChatWallet wallet = new ChatWallet(); wallet.setBalance(BigDecimal.ZERO); wallet.setMemberId(memberId); chatWalletMapper.insert(wallet); } @Override public void initMemberReferrerIds(Long memberId, String parentId) { boolean flag = false; if (StrUtil.isBlank(parentId)) { flag = true; } String ids = ""; while (!flag) { if (StrUtil.isBlank(ids)) { ids += parentId; } else { ids += ("," + parentId); } ChatMember chatMemberParent = this.baseMapper.selectOne(new LambdaQueryWrapper<ChatMember>().eq(ChatMember::getInviteId, parentId)); if (chatMemberParent == null) { break; } parentId = chatMemberParent.getReferrerId(); if (StrUtil.isBlank(chatMemberParent.getReferrerId())) { flag = true; } } ChatMember chatMember = this.baseMapper.selectById(memberId); if (StrUtil.isNotBlank(ids)) { chatMember.setReferrerIds(ids); this.baseMapper.updateById(chatMember); } } } src/main/java/cc/mrbird/febs/user/service/Impl/ChatMemberServiceImpl.java
@@ -1,30 +1,24 @@ package cc.mrbird.febs.user.service.Impl; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.enumerates.YesOrNoEnum; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.common.utils.AppContants; import cc.mrbird.febs.common.utils.ShareCodeUtil; import cc.mrbird.febs.mall.entity.MallMember; import cc.mrbird.febs.mall.entity.MallMemberWallet; import cc.mrbird.febs.mall.entity.RunVip; import cc.mrbird.febs.common.utils.ValidateEntityUtils; import cc.mrbird.febs.mall.service.impl.CommonService; import cc.mrbird.febs.user.contant.MemberConstant; import cc.mrbird.febs.user.entity.ChatMember; import cc.mrbird.febs.user.mapper.ChatMemberMapper; import cc.mrbird.febs.user.req.ApiRegisterDto; import cc.mrbird.febs.user.service.AsyncService; import cc.mrbird.febs.user.service.IChatMemberService; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.List; @Slf4j @Service @@ -32,116 +26,58 @@ @Transactional public class ChatMemberServiceImpl extends ServiceImpl<ChatMemberMapper, ChatMember> implements IChatMemberService { private final CommonService commonService; private final AsyncService asyncService; @Override public FebsResponse register(ApiRegisterDto apiRegisterDto) { String account = apiRegisterDto.getAccount(); MallMember mallMember = this.baseMapper.selectInfoByAccount(account); if (mallMember != null) { throw new FebsException("手机号已注册"); } /** * 验证两次密码是否一致 */ String password = registerDto.getPassword(); String passwordAgain = registerDto.getPasswordAgain(); if(!password.equals(passwordAgain)){ throw new FebsException("密码不一致"); } //邀请码为admin的时候(后台添加用户),不需要验证验证码 if (!"admin".equals(registerDto.getRegistType())) { String code = registerDto.getCode(); String password = apiRegisterDto.getPassword(); String passwordAgain = apiRegisterDto.getPasswordAgain(); String refInviteId = apiRegisterDto.getInviteId(); String code = apiRegisterDto.getCode(); //后台添加用户,不需要验证验证码 Integer addType = apiRegisterDto.getAddType(); if (MemberConstant.ADD_TYPE_NORMAL == addType) { boolean flags = commonService.verifyCode(account, code); if (!flags) { throw new FebsException("验证码错误"); } } ValidateEntityUtils.ensureEqual(password, passwordAgain, "两次密码不一致"); ValidateEntityUtils.ensureUnique(account, ChatMember::getEmail, this.baseMapper::selectCount, "邮箱已使用"); mallMember = new MallMember(); mallMember.setPassword(SecureUtil.md5(registerDto.getPassword())); ChatMember chatMember = new ChatMember(); chatMember.setEmail(account); chatMember.setPassword(SecureUtil.md5(password)); chatMember.setName(account); chatMember.setSex(MemberConstant.UNKNOWN); // 判断账号类型 if (AppContants.ACCOUNT_TYPE_MOBILE.equals(registerDto.getType())) { mallMember.setPhone(registerDto.getAccount()); } else { mallMember.setEmail(registerDto.getAccount()); } //对于邀请码的验证和上级联系人的验证 Integer count = this.baseMapper.selectCount(null); if (count != null && count != 0) { if(StrUtil.isEmpty(registerDto.getInviteId())){ throw new FebsException("请输入邀请码"); } String inviteId = registerDto.getInviteId(); MallMember inviteMember = this.baseMapper.selectInfoByInviteId(inviteId); if (inviteMember == null) { throw new FebsException("邀请码不存在"); } mallMember.setReferrerId(registerDto.getInviteId()); // if(!StrUtil.isEmpty(registerDto.getInviteId())){ // String inviteId = registerDto.getInviteId(); // MallMember inviteMember = this.baseMapper.selectInfoByInviteId(inviteId); // if (inviteMember == null) { // throw new FebsException("邀请码不存在"); // } // mallMember.setReferrerId(registerDto.getInviteId()); // } } mallMember.setName(account); mallMember.setAvatar("https://res.runstep.cc/rslogo.png"); mallMember.setAccountStatus(YesOrNoEnum.YES.getValue()); mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL); mallMember.setSex("男"); mallMember.setDirector(YesOrNoEnum.NO.getValue()); mallMember.setDirectorTime(DateUtil.date()); mallMember.setBindPhone(account); this.baseMapper.insert(mallMember); String inviteId = ShareCodeUtil.toSerialCode(mallMember.getId()); mallMember.setInviteId(inviteId); //推荐人和推荐人链 boolean flag = false; String parentId = mallMember.getReferrerId(); if (StrUtil.isBlank(parentId)) { flag = true; } String ids = ""; while (!flag) { if (StrUtil.isBlank(ids)) { ids += parentId; } else { ids += ("," + parentId); } MallMember parentMember = this.baseMapper.selectInfoByInviteId(parentId); if (parentMember == null) { break; } parentId = parentMember.getReferrerId(); if (StrUtil.isBlank(parentMember.getReferrerId())) { flag = true; if(StrUtil.isNotEmpty(refInviteId)){ ChatMember chatMemberInvite = ValidateEntityUtils.ensureColumnReturnEntity(refInviteId, ChatMember::getInviteId, this.baseMapper::selectOne, "邀请码不存在"); chatMember.setReferrerId(chatMemberInvite.getInviteId()); } } chatMember.setAccountStatus(MemberConstant.ACCOUNT_STATUS_NORMAL); chatMember.setAccountType(MemberConstant.ACCOUNT_TYPE_NORMAL); // --todo 默认头像为空 // chatMember.setAvatar("https://res.runstep.cc/rslogo.png"); chatMember.setDirector(MemberConstant.DIRECTER_YES); chatMember.setLastLoginTime(DateUtil.date()); // -- todo 默认主账号的角色设置没有设置 chatMember.setRoleId(0L); this.baseMapper.insert(chatMember); if (StrUtil.isNotBlank(ids)) { mallMember.setReferrerIds(ids); } //会员VIP等级 List<RunVip> runVips = runVipMapper.selectList(new LambdaQueryWrapper<RunVip>().orderByAsc(RunVip::getOrderNumber)); if (StrUtil.isBlank(mallMember.getLevel()) && CollUtil.isNotEmpty(runVips)) { RunVip runVip = runVips.get(0); mallMember.setLevel(runVip.getVipCode()); } this.baseMapper.updateById(mallMember); //公司ID默认为主账号的会员ID chatMember.setCompanyId(chatMember.getId()); chatMember.setInviteId(ShareCodeUtil.toSerialCode(chatMember.getId())); //推荐人链 asyncService.initMemberReferrerIds(chatMember.getId(),chatMember.getReferrerId()); asyncService.initWallet(chatMember.getId()); MallMemberWallet wallet = new MallMemberWallet(); wallet.setBalance(BigDecimal.ZERO); wallet.setMemberId(mallMember.getId()); mallMemberWalletMapper.insert(wallet); agentProducer.sendNodeUpMsg(mallMember.getId()); return new FebsResponse().success().message("注册成功"); } } src/main/java/cc/mrbird/febs/user/service/Impl/ChatWalletServiceImpl.java
New file @@ -0,0 +1,69 @@ package cc.mrbird.febs.user.service.Impl; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.common.utils.ValidateEntityUtils; import cc.mrbird.febs.user.entity.ChatWallet; import cc.mrbird.febs.user.mapper.ChatWalletMapper; import cc.mrbird.febs.user.service.IChatWalletService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; @Slf4j @Service @RequiredArgsConstructor public class ChatWalletServiceImpl extends ServiceImpl<ChatWalletMapper, ChatWallet> implements IChatWalletService { @Override public void addBalance(BigDecimal amount, Long memberId) { if (BigDecimal.ZERO.compareTo(amount) > 0) { throw new FebsException("增加余额异常"); } int i = 0; boolean flag = true; while (flag) { i++; ChatWallet wallet = ValidateEntityUtils.ensureColumnReturnEntity(memberId, ChatWallet::getMemberId, this.baseMapper::selectOne, "钱包不存在"); wallet.setBalance(wallet.getBalance().add(amount)); int result = this.baseMapper.updateBalanceWithVersion(wallet); if (result > 0) { flag = false; } else { if (i > 2) { throw new FebsException("操作失败"); } } } } @Override public void reduceBalance(BigDecimal amount, Long memberId) { int i = 0; boolean flag = true; while (flag) { i++; ChatWallet wallet = ValidateEntityUtils.ensureColumnReturnEntity(memberId, ChatWallet::getMemberId, this.baseMapper::selectOne, "钱包不存在"); if (amount.compareTo(wallet.getBalance()) > 0) { throw new FebsException("余额不足"); } wallet.setBalance(wallet.getBalance().subtract(amount)); int result = this.baseMapper.updateBalanceWithVersion(wallet); if (result > 0) { flag = false; } else { if (i > 2) { throw new FebsException("操作失败"); } } } } } src/main/resources/mapper/modules/ChatWalletMapper.xml
New file @@ -0,0 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.mrbird.febs.user.mapper.ChatWalletMapper"> <update id="updateBalanceWithVersion"> update chat_wallet set revision = revision + 1, balance = #{record.balance} where id=#{record.id} and revision=#{record.revision} </update> </mapper>