package com.ruoyi.im.service.impl; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.netease.nim.server.sdk.core.BizName; import com.netease.nim.server.sdk.core.YunxinApiHttpClient; import com.netease.nim.server.sdk.core.YunxinApiResponse; import com.netease.nim.server.sdk.core.exception.YunxinSdkException; import com.ruoyi.im.comm.Result; import com.ruoyi.im.config.AppAuthConfig; import com.ruoyi.system.domain.UserAccount; import com.ruoyi.im.service.ImApiServcie; import com.ruoyi.im.dto.RegisterDto; import com.ruoyi.system.service.UserAccountService; import com.ruoyi.im.util.SymmetricCryptoUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import java.time.Instant; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicLong; @Service public class ImApiServcieImpl implements ImApiServcie { @Autowired private UserAccountService userAccountService; // 使用单例客户端,避免重复初始化 private YunxinApiHttpClient yunxinClient; // 使用并发安全的集合存储正在生成的账号,防止重复 private final Set generatingAccounts = Collections.newSetFromMap(new ConcurrentHashMap<>()); // 使用原子计数器优化账号生成 private final AtomicLong lastTimestamp = new AtomicLong(0); private final AtomicLong sequence = new AtomicLong(0); @PostConstruct public void init() { // 初始化云信客户端,只执行一次 String appkey = AppAuthConfig.DEFAULT_CONFIG.getAppKey(); String appsecret = AppAuthConfig.DEFAULT_CONFIG.getAppSecret(); int timeoutMillis = 5000; this.yunxinClient = new YunxinApiHttpClient.Builder(BizName.IM, appkey, appsecret) .timeoutMillis(timeoutMillis) .build(); } @Override public Result register(RegisterDto dto) { // 短信验证 TODO // 手机号是否存在 - 添加分布式锁或数据库唯一索引确保并发安全 List accounts = userAccountService.list( new LambdaQueryWrapper<>(UserAccount.class) .eq(UserAccount::getAccount, dto.getAccount()) ); if(!CollectionUtils.isEmpty(accounts)){ return Result.error("手机号已注册!"); } // // 生成云信账号 // long cloudMessageAccount; // try { // cloudMessageAccount = generateUniqueCloudMessageAccount(); // } catch (RuntimeException e) { // return Result.error("系统繁忙,请稍后重试"); // } // 注册云信 String path = "/user/create.action"; Map paramMap = new HashMap<>(); paramMap.put("accid", String.valueOf(dto.getAccount())); paramMap.put("token", dto.getPassword()); YunxinApiResponse response; try { response = yunxinClient.executeV1Api(path, paramMap); } catch (YunxinSdkException e) { System.err.println("register error, traceId = " + e.getTraceId()); return Result.error("注册失败,系统异常"); } // 获取结果 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code == 200) { // 注册成功 UserAccount userAccount = new UserAccount(); userAccount.setAccount(dto.getAccount()); userAccount.setPhoneNumber(dto.getAccount()); userAccount.setCloudMessageAccount(dto.getAccount()); userAccount.setPassword(SymmetricCryptoUtil.encryptPassword(dto.getPassword())); try { userAccountService.save(userAccount); return Result.success("注册成功"); } catch (Exception e) { // 处理数据库插入异常,可能需要回滚云信账号 return Result.error("注册失败,请重试"); } } else if (code == 414) { return Result.error("账号已被注册!"); } else { System.err.println("register fail, response = " + data + ", traceId=" + response.getTraceId()); return Result.error("注册失败,错误码: " + code); } } /** * 优化的账号生成方法,使用雪花算法变体提高并发性能 */ public long generateUniqueCloudMessageAccount() { final int maxAttempts = 10; // 减少尝试次数,提高效率 for (int attempt = 0; attempt < maxAttempts; attempt++) { long account = generateSnowflakeLikeId(); // 使用并发集合检查是否正在生成相同账号 if (generatingAccounts.add(account)) { try { // 检查数据库是否存在 boolean exists = userAccountService.lambdaQuery() .eq(UserAccount::getCloudMessageAccount, account) .exists(); if (!exists) { return account; } } finally { // 无论成功与否,都从集合中移除 generatingAccounts.remove(account); } } // 短暂等待后重试 try { Thread.sleep(ThreadLocalRandom.current().nextInt(10, 50)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("生成账号被中断", e); } } throw new RuntimeException("无法在" + maxAttempts + "次尝试内生成唯一账号"); } /** * 基于雪花算法的ID生成器,提高并发性能 */ private long generateSnowflakeLikeId() { long currentTime = System.currentTimeMillis(); long timestamp = currentTime % 100_000_000L; // 取时间戳的后8位 // 使用原子操作确保序列号递增 long seq; long lastTime; do { lastTime = lastTimestamp.get(); if (currentTime == lastTime) { seq = sequence.incrementAndGet() % 100; } else { sequence.set(0); lastTimestamp.set(currentTime); seq = 0; } } while (!lastTimestamp.compareAndSet(lastTime, currentTime)); // 组合时间戳和序列号,生成9位ID return timestamp * 100 + seq; } }