邀请码

This commit is contained in:
2024-12-20 11:26:52 +08:00
parent c5c68eb0c6
commit 8b4e6f952b
11 changed files with 125 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ import com.accompany.business.mybatismapper.PrivatePhotoMapper;
import com.accompany.business.mybatismapper.UserInviteCodeMapper;
import com.accompany.business.service.AccountLoginRecordService;
import com.accompany.business.service.family.FamilyClanService;
import com.accompany.business.service.invite.UserInviteCodeService;
import com.accompany.business.service.purse.UserPurseService;
import com.accompany.business.service.user.PrivatePhotoService;
import com.accompany.business.service.user.UsersService;
@@ -79,6 +80,8 @@ public class UserCheckAdminService {
private ApplicationContext applicationContext;
@Autowired
private FamilyClanService familyClanService;
@Autowired
private UserInviteCodeService userInviteCodeService;
private Gson gson = new Gson();
@@ -341,7 +344,7 @@ public class UserCheckAdminService {
users.forEach(user -> {
UserInviteCode inviteCode = new UserInviteCode();
inviteCode.setUid(user.getUid());
inviteCode.setInviteCode(InviteCodeUtil.getInviteCodeByUid(user.getUid()));
inviteCode.setInviteCode(userInviteCodeService.generateUniqueInviteCode(user.getUid()));
inviteCode.setIsPrimary(true);
userInviteCodeMapper.insert(inviteCode);

View File

@@ -9,4 +9,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface AccountMapper extends BaseMapper<Account> {
Account selectByPrimaryKey(Long uid);
Integer selectByRegisterIp(String ipAddress);
}

View File

@@ -52,4 +52,11 @@
from account
where uid = #{uid,jdbcType=BIGINT}
</select>
<select id="selectByRegisterIp" resultType="java.lang.Integer">
select
count(1)
from account
where register_ip = #{ipAddress}
</select>
</mapper>

View File

@@ -430,6 +430,7 @@ public enum BusiStatus {
**/
INVITE_CODE_INVALID(211184, "邀請碼不存在"),
INVITE_CODE_DEVICE_DUPLICATED(211185, "該設備已填寫過邀請碼"),
INVITE_CODE_IP_DUPLICATED(211185, "該設備已填寫過邀請碼"),
TIME_OUT_TO_REFILL_INVITE_CODE(211186, "超出不填時間,無法補填邀請碼"),
/**

View File

@@ -1393,6 +1393,8 @@ public enum RedisKey {
room_user_zset, //房间在线用户
invite_reward_receive, //邀请奖励获取
invite_codes, //邀请码缓存
;
public String getKey() {

View File

@@ -31,7 +31,7 @@ public class InviteFissionInviteListener implements ApplicationListener<NewUserE
Long beInviteUid = user.getUid();
Date createTime = user.getCreateTime();
//todo 同一设备号,手机号,实名身份
//todo 同一设备号,IP已经在注册的时候拦截
userInviteFissionV2Service.bound(beInviteUid, inviterUid, createTime, Constant.Source.msNo);
}

View File

@@ -5,19 +5,26 @@ import com.accompany.business.mybatismapper.UserInviteCodeMapper;
import com.accompany.business.util.InviteCodeUtil;
import com.accompany.business.util.QrCodeUtil;
import com.accompany.common.constant.AppEnum;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.tencent.cos.TencentCosUploadService;
import com.accompany.common.utils.EnvComponent;
import com.accompany.core.base.SpringContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@@ -33,6 +40,12 @@ public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, Use
@Autowired
private UserInviteCodeMapper userInviteCodeMapper;
@Autowired
private RedissonClient redissonClient;
private static final String CHARACTERS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static final int CODE_LENGTH = 5;
private static final SecureRandom random = new SecureRandom();
public static final byte INVITE_CODE_STATUS_VALID = 1;
/**
@@ -75,7 +88,7 @@ public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, Use
}
UserInviteCode userInviteCode = new UserInviteCode();
userInviteCode.setUid(uid);
userInviteCode.setInviteCode(InviteCodeUtil.getInviteCodeByUid(uid));
userInviteCode.setInviteCode(generateUniqueInviteCode(uid));
userInviteCode.setIsPrimary(true);
userInviteCodeMapper.insert(userInviteCode);
}
@@ -111,4 +124,49 @@ public class UserInviteCodeService extends ServiceImpl<UserInviteCodeMapper, Use
userInviteCode.setQrCodeUrl(url);
}
public String generateUniqueInviteCode(Long uid) {
String uniqueCode = null;
try {
String baseCode = Long.toString(uid, CHARACTERS.length());
while (baseCode.length() < CODE_LENGTH) {
// 如果基础码长度不足,添加随机字符
int randomIndex = random.nextInt(CHARACTERS.length());
baseCode += CHARACTERS.charAt(randomIndex);
}
// 确保唯一性
uniqueCode = baseCode.substring(0, CODE_LENGTH);
RSet<String> inviteCodeCache = getInviteCodeCache();
int i = 0;
while (inviteCodeCache.contains(uniqueCode)) {
uniqueCode = baseCode.substring(0, CODE_LENGTH - 1) + CHARACTERS.charAt(random.nextInt(CHARACTERS.length()));
if (i++ > 10) {
break;
}
}
inviteCodeCache.add(uniqueCode);
} catch (Exception e) {
log.error("generateUniqueInviteCode,e:{}", e.getMessage(), e);
return String.valueOf(uid);
}
return uniqueCode;
}
private RSet<String> getInviteCodeCache() {
return redissonClient.getSet(RedisKey.invite_codes.getKey(), StringCodec.INSTANCE);
}
public void loadInviteCodeCache(Date startDate, Date endDate) {
QueryWrapper<UserInviteCode> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().select(UserInviteCode::getInviteCode)
.eq(UserInviteCode::getStatus, INVITE_CODE_STATUS_VALID)
.ge(UserInviteCode::getCreateTime, startDate)
.lt(UserInviteCode::getCreateTime, endDate)
.orderByDesc(UserInviteCode::getCreateTime);
List<UserInviteCode> userInviteCodes = baseMapper.selectList(queryWrapper);
if (CollectionUtils.isEmpty(userInviteCodes)) {
return;
}
getInviteCodeCache().addAll(userInviteCodes.stream().map(UserInviteCode::getInviteCode).collect(Collectors.toList()));
}
}

View File

@@ -22,7 +22,6 @@ import com.accompany.core.model.Users;
import com.accompany.core.service.SysConfService;
import com.accompany.core.service.account.AccountService;
import com.accompany.core.util.I18NMessageSourceUtil;
import com.accompany.core.util.PartitionUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -61,6 +60,7 @@ public class UserInviteFissionV2Service {
public void bound(Long beInviteUid, Long inviterUid, Date createTime, Byte source) {
try {
log.info("UserInviteFissionV2Service.bound,beInviteUid:{},inviterUid:{},createTime,source:{}", beInviteUid, inviterUid, createTime, source);
InviteFissionActConfig config = getConfig();
if (!config.getInviteSwitch()) {
return;

View File

@@ -14,9 +14,11 @@ import com.accompany.common.device.DeviceInfo;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.model.Account;
import com.accompany.core.model.Room;
import com.accompany.core.model.Users;
import com.accompany.core.model.UsersExample;
import com.accompany.core.mybatismapper.AccountMapper;
import com.accompany.core.mybatismapper.UsersMapper;
import com.accompany.core.service.base.BaseService;
import com.accompany.core.service.user.UsersBaseService;
@@ -51,6 +53,8 @@ public class InviteCodeService extends BaseService {
private RoomInviteCodeService roomInviteCodeService;
@Autowired
private RoomService roomService;
@Autowired
private AccountMapper accountMapper;
public Object getInviteCodeList(Long uid, DeviceInfo deviceInfo) {
@@ -106,6 +110,26 @@ public class InviteCodeService extends BaseService {
}
return null;
}
public BusiStatus checkInviteCodeByIp(String inviteCode, String ipAddress) {
if (inviteCode.length() < 4 || inviteCode.length() > 7) {
return BusiStatus.INVITE_CODE_INVALID;
}
inviteCode = inviteCode.toUpperCase();
try {
Long uid = getUidByInviteCode(inviteCode);
if (null == uid) {
return BusiStatus.INVITE_CODE_INVALID;
}
} catch (Exception e) {
return BusiStatus.INVITE_CODE_INVALID;
}
Integer registerIps = accountMapper.selectByRegisterIp(ipAddress);
// 检查ip是否绑定过邀请码
if (registerIps > 0) {
return BusiStatus.INVITE_CODE_IP_DUPLICATED;
}
return null;
}
public Long getUidByInviteCode(String inviteCode) {
QueryWrapper<UserInviteCode> queryWrapper = new QueryWrapper<>();

View File

@@ -1,6 +1,8 @@
package com.accompany.business.controller.user;
import cn.hutool.core.date.DateUtil;
import com.accompany.business.common.BaseController;
import com.accompany.business.service.invite.UserInviteCodeService;
import com.accompany.business.service.user.InviteCodeService;
import com.accompany.common.annotation.Authorization;
import com.accompany.common.result.BusiResult;
@@ -26,6 +28,8 @@ public class InviteCodeController extends BaseController {
@Autowired
private InviteCodeService inviteCodeService;
@Autowired
private UserInviteCodeService userInviteCodeService;
@ApiOperation("获取邀请码数据")
@GetMapping(value = "/getList")
@@ -41,6 +45,13 @@ public class InviteCodeController extends BaseController {
return new BusiResult(inviteCodeService.getInviteCodeListV2(getUid(), getDeviceInfo(request)));
}
@ApiOperation("缓存现存邀请码数据")
@GetMapping(value = "/cache")
public BusiResult<Void> cache(String startTime, String endTime) {
userInviteCodeService.loadInviteCodeCache(DateUtil.parseDateTime(startTime), DateUtil.parseDateTime(endTime));
return BusiResult.success();
}
}

View File

@@ -14,6 +14,7 @@ import com.accompany.common.redis.RedisKey;
import com.accompany.common.result.BusiResult;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.BlankUtil;
import com.accompany.common.utils.IPUtils;
import com.accompany.core.model.Users;
import com.accompany.core.service.user.UsersBaseService;
import com.accompany.core.vo.UserVo;
@@ -28,6 +29,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -50,7 +52,7 @@ public class UsersV2Controller extends BaseController {
@PostMapping("/update")
@Authorization
public BusiResult saveOrUpdateUserByUidV2(UserParam userParam, DeviceInfo deviceInfo) {
public BusiResult saveOrUpdateUserByUidV2(UserParam userParam, DeviceInfo deviceInfo, HttpServletRequest request) {
Long myUid = getUid();
if (myUid != null) {
userParam.setUid(myUid);
@@ -70,11 +72,16 @@ public class UsersV2Controller extends BaseController {
if (userParam.getInviteCode() != null) {
userParam.setInviteCode(userParam.getInviteCode().toUpperCase());
}
if (isNewUser(usersInfo) && !StringUtils.isEmpty(userParam.getInviteCode())
&& !StringUtils.isEmpty(deviceInfo.getDeviceId())) {
BusiStatus check = inviteCodeService.checkInviteCode(userParam.getInviteCode(), deviceInfo.getDeviceId());
if (check != null) {
return new BusiResult(check);
if (isNewUser(usersInfo) && !StringUtils.isEmpty(userParam.getInviteCode())) {
if (!StringUtils.isEmpty(deviceInfo.getDeviceId())) {
BusiStatus check = inviteCodeService.checkInviteCode(userParam.getInviteCode(), deviceInfo.getDeviceId());
if (check != null) {
return new BusiResult(check);
}
}
String realIpAddress = IPUtils.getRealIpAddress(request);
if (org.apache.commons.lang.StringUtils.isNotEmpty(realIpAddress)) {
inviteCodeService.checkInviteCodeByIp(userParam.getInviteCode(), realIpAddress);
}
Long inviteUid = inviteCodeService.getUidByInviteCode(userParam.getInviteCode());
userParam.setInviteUid(inviteUid);