package com.ruoyi.im.service.impl; import cn.hutool.core.util.ObjectUtil; import com.alibaba.druid.support.json.JSONUtils; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; 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.netease.nim.server.sdk.core.http.HttpMethod; import com.netease.nim.server.sdk.im.v2.team.TeamV2UrlContext; import com.netease.nim.server.sdk.im.v2.team_member.TeamMemberV2UrlContext; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.im.comm.Result; import com.ruoyi.im.config.AddTeamMembersRequest; import com.ruoyi.im.config.CreateTeamRequest; import com.ruoyi.im.config.AssignmentRequest; import com.ruoyi.im.service.NeteaseTeamService; import com.ruoyi.imenum.ErrorCodeEnum; import com.ruoyi.system.domain.GroupWelcomeConfig; import com.ruoyi.system.domain.NeteaseTeam; import com.ruoyi.system.mapper.NeteaseTeamMapper; import com.ruoyi.system.service.GroupWelcomeConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.Resource; import javax.validation.constraints.NotBlank; import java.util.*; import java.util.stream.Collectors; @Service public class NeteaseTeamServiceImpl extends ServiceImpl implements NeteaseTeamService { @Resource private final YunxinApiHttpClient yunxinClient; @Autowired ImApiServcieImpl imApiServcie; // 使用构造函数注入(推荐) @Autowired public NeteaseTeamServiceImpl(YunxinApiHttpClient yunxinClient) { this.yunxinClient = yunxinClient; } @Autowired GroupWelcomeConfigService groupWelcomeConfigService; @Resource private NeteaseTeamMapper neteaseTeamMapper; /** * 创建群组(根据最新参数说明) */ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult createGroup(CreateTeamRequest request) { try { // 1. 构建请求参数Map Map paramMap = buildCreateTeamParams(request); // 2. 将Map转换为JSON字符串 String jsonBody = JSON.toJSONString(paramMap); // 3. 调用网易云信API创建群组 YunxinApiResponse response = yunxinClient.executeV2Api( HttpMethod.POST, TeamV2UrlContext.CREATE_TEAM, TeamV2UrlContext.CREATE_TEAM, null, jsonBody ); // 4. 处理响应 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code != 200) { log.error("-----------网易云信创建群组失败:"+ ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc()); return AjaxResult.error("创建群组失败:"+ErrorCodeEnum.getByCode(code).getComment()); } // 5. 解析响应获取群组ID JSONObject resultData = json.getJSONObject("data"); JSONObject teamInfo = resultData.getJSONObject("team_info"); String tid = teamInfo.getString("team_id"); String ownerAccountId = teamInfo.getString("owner_account_id"); // 6. 保存群组信息到本地数据库 int count = saveTeamToLocal(request,ownerAccountId, tid); if(count > 0){ return AjaxResult.success("创建群组成功"); } return AjaxResult.error("创建群组失败"); } catch (YunxinSdkException e) { // 云信调用异常时回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); e.printStackTrace(); log.error("网易云信服务调用异常 traceId:"); return AjaxResult.error("创建群组失败,云信服务异常"); } catch (Exception e) { // 其他异常同样回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); e.printStackTrace(); log.error("创建群组过程发生未知异常", e); return AjaxResult.error("创建群组失败,系统异常"); } } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult updateCreate(CreateTeamRequest request) { try { // 1. 构建请求参数Map Map paramMap = buildCreateTeamParams(request); // 2. 将Map转换为JSON字符串 String jsonBody = JSON.toJSONString(paramMap); NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getId()); if(ObjectUtil.isEmpty(neteaseTeam)){ return AjaxResult.error("群不存在!"); } String path = TeamV2UrlContext.UPDATE_TEAM.replace("{team_id}", String.valueOf(neteaseTeam.getTid())); YunxinApiResponse response = yunxinClient.executeV2Api( HttpMethod.PATCH, path, path, null, jsonBody ); // 4. 处理响应 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code != 200) { log.error("-----------网易云信修改群组失败:"+ ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc()); return AjaxResult.error("修改群组失败:"+ErrorCodeEnum.getByCode(code).getComment()); } // 5. 解析响应获取群组ID JSONObject resultData = json.getJSONObject("data"); JSONObject teamInfo = resultData.getJSONObject("team_info"); String tid = teamInfo.getString("team_id"); String ownerAccountId = teamInfo.getString("owner_account_id"); // 6. 跟新群组信息到本地数据库 int count = updateNeteaseTeam(request,neteaseTeam); if(count > 0){ return AjaxResult.success("修改群组成功"); } return AjaxResult.error("修改群组失败"); } catch (YunxinSdkException e) { // 云信调用异常时回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); e.printStackTrace(); log.error("网易云信服务调用异常 traceId:"); return AjaxResult.error("修改群组失败,云信服务异常"); } catch (Exception e) { // 其他异常同样回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); e.printStackTrace(); log.error("修改群组过程发生未知异常", e); return AjaxResult.error("修改群组失败,系统异常"); } } private int updateNeteaseTeam(CreateTeamRequest request, NeteaseTeam neteaseTeam) { neteaseTeam.setName(request.getName()); neteaseTeam.setMembersLimit(request.getMembers_limit()); neteaseTeam.setAnnouncement(request.getAnnouncement()); neteaseTeam.setIntro(request.getIntro()); neteaseTeam.setJoinMode(request.getJoin_mode()); neteaseTeam.setAgreeMode(request.getAgree_mode()); neteaseTeam.setInviteMode(request.getInvite_mode()); neteaseTeam.setUpdateTeamInfoMode(request.getUpdate_team_info_mode()); return neteaseTeamMapper.updateById(neteaseTeam); } /** * 构建创建群组的参数Map */ private Map buildCreateTeamParams(CreateTeamRequest request) { Map paramMap = new HashMap<>(); // 必填参数 paramMap.put("owner_account_id", request.getOwner_account_id()); paramMap.put("team_type", request.getTeam_type()); paramMap.put("name", request.getName()); paramMap.put("invite_account_ids", request.getInvite_account_ids()); paramMap.put("invite_msg", request.getInvite_msg()); // 群组配置 Map configMap = new HashMap<>(); configMap.put("join_mode", request.getJoin_mode()); configMap.put("agree_mode", request.getAgree_mode()); configMap.put("invite_mode", request.getInvite_mode()); configMap.put("update_team_info_mode", request.getUpdate_team_info_mode()); configMap.put("update_extension_mode", request.getUpdate_extension_mode()); paramMap.put("configuration", configMap); // 选填参数 if (request.getIcon() != null) { paramMap.put("icon", request.getIcon()); } if (request.getAnnouncement() != null) { paramMap.put("announcement", request.getAnnouncement()); } if (request.getIntro() != null) { paramMap.put("intro", request.getIntro()); } if (request.getMembers_limit() != null) { paramMap.put("members_limit", request.getMembers_limit()); } if (request.getServer_extension() != null) { paramMap.put("server_extension", request.getServer_extension()); } if (request.getCustomer_extension() != null) { paramMap.put("customer_extension", request.getCustomer_extension()); } if (request.getExtension() != null) { paramMap.put("extension", request.getExtension()); } return paramMap; } /** * 保存群组信息到本地数据库 */ private int saveTeamToLocal(CreateTeamRequest request,String ownerAccountId, String tid) { NeteaseTeam team = new NeteaseTeam(); BeanUtils.copyProperties(request, team); team.setTid(tid); team.setCreateTime(new Date()); team.setUpdateTime(new Date()); team.setStatus(0); // 正常状态 team.setOwnerAccountId(ownerAccountId); team.setTeamType(request.getTeam_type()); team.setName(request.getName()); team.setMembersLimit(request.getMembers_limit()); // 保存配置信息 team.setJoinMode(request.getJoin_mode()); team.setAgreeMode(request.getAgree_mode()); team.setInviteMode(request.getInvite_mode()); team.setUpdateTeamInfoMode(request.getUpdate_team_info_mode()); team.setUpdateExtensionMode(request.getUpdate_extension_mode()); // 保存到数据库 int insert = neteaseTeamMapper.insert(team); return insert; } @Override public AjaxResult inviteTeamMembers(AddTeamMembersRequest request) { try { if(null != request.getNumber() && request.getNumber() > 99){ return AjaxResult.error("拉人数量单次最多99!"); } NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getGroupId()); if(ObjectUtil.isEmpty(neteaseTeam)){ return AjaxResult.error("群不存在!"); } String operatorId; if(StringUtils.isNotEmpty(request.getOperatorId())){ operatorId = request.getOperatorId(); }else{ operatorId = neteaseTeam.getOwnerAccountId(); } List inviteAccountIds = new ArrayList<>(); if(ObjectUtil.isEmpty(request.getInviteAccountIds()) && ObjectUtil.isNotEmpty(request.getNumber()) && request.getNumber() > 0){ Result result = imApiServcie.batchRegister(request.getNumber()); if(result.getCode() != 200){ return AjaxResult.error("生成账号错误!"); } List accountList = (List) result.getData(); inviteAccountIds = accountList; }else{ inviteAccountIds = request.getInviteAccountIds(); } AddTeamMembersRequest build = AddTeamMembersRequest.builder() .inviteAccountIds(inviteAccountIds) .operatorId(operatorId) .msg(request.getMsg()) .teamId(Long.valueOf(neteaseTeam.getTid())) .teamType(neteaseTeam.getTeamType()) .build(); ObjectMapper objectMapper = new ObjectMapper(); String jsonBody = objectMapper.writeValueAsString(build); YunxinApiResponse response = yunxinClient.executeV2Api( HttpMethod.POST, TeamMemberV2UrlContext.INVITE_TEAM_MEMBERS, TeamMemberV2UrlContext.INVITE_TEAM_MEMBERS, null, jsonBody ); // 4. 处理响应 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code != 200) { log.error("-----------网易云信拉人入群失败:"+ ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc()); return AjaxResult.error("拉人入群失败:"+ErrorCodeEnum.getByCode(code).getComment()); } return AjaxResult.success(); } catch (YunxinSdkException e) { // 云信调用异常时回滚事务 e.printStackTrace(); log.error("网易云信服务调用异常 traceId:"); return AjaxResult.error("拉人入群失败,云信服务异常"); } catch (Exception e) { // 其他异常同样回滚 e.printStackTrace(); log.error("拉人入群过程发生未知异常", e); return AjaxResult.error("拉人入群失败,系统异常"); } } @Override public AjaxResult assignment(AssignmentRequest request) { try { NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getGroupId()); if(ObjectUtil.isEmpty(neteaseTeam)){ return AjaxResult.error("群不存在!"); } AssignmentRequest build = AssignmentRequest.builder() .teamId(Long.valueOf(neteaseTeam.getTid())) .team_type(neteaseTeam.getTeamType()) .new_owner_account_id(request.getNew_owner_account_id()) .leave(request.getLeave()) .build(); ObjectMapper objectMapper = new ObjectMapper(); String requestBody = objectMapper.writeValueAsString(build); String path = TeamV2UrlContext.TRANSFER_OWNER.replace("{team_id}",neteaseTeam.getTid().toString()); YunxinApiResponse response = yunxinClient.executeV2Api( HttpMethod.PATCH, TeamV2UrlContext.TRANSFER_OWNER, path, null, requestBody ); // 4. 处理响应 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code != 200) { log.error("-----------网易云信转让群主失败:"+ ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc()); return AjaxResult.error("转让群主失败:"+ErrorCodeEnum.getByCode(code).getComment()); } neteaseTeam.setOwnerAccountId(request.getNew_owner_account_id()); neteaseTeamMapper.updateById(neteaseTeam); return AjaxResult.success(); } catch (YunxinSdkException e) { // 云信调用异常时回滚事务 e.printStackTrace(); log.error("网易云信转让群主服务调用异常 traceId:"); return AjaxResult.error("转让群主失败,云信服务异常"); } catch (Exception e) { // 其他异常同样回滚 e.printStackTrace(); log.error("转让群主过程发生未知异常", e); return AjaxResult.error("转让群主失败,系统异常"); } } @Override public AjaxResult dismiss(Integer id) { try { NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(id); if(ObjectUtil.isEmpty(neteaseTeam)){ return AjaxResult.error("群不存在!"); } Map queryParams = new HashMap<>(); queryParams.put("team_type", String.valueOf(neteaseTeam.getTeamType())); String path = TeamV2UrlContext.DISBAND_TEAM.replace("{team_id}", neteaseTeam.getTid()); YunxinApiResponse response = yunxinClient.executeV2Api( HttpMethod.DELETE, path, path, queryParams, null ); // 4. 处理响应 String data = response.getData(); JSONObject json = JSONObject.parseObject(data); int code = json.getIntValue("code"); if (code != 200) { log.error("-----------网易云信解散群失败:"+ ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc()); return AjaxResult.error("解散群失败:"+ErrorCodeEnum.getByCode(code).getComment()); } neteaseTeam.setStatus(1); neteaseTeamMapper.updateById(neteaseTeam); return AjaxResult.success(); } catch (YunxinSdkException e) { // 云信调用异常时回滚事务 e.printStackTrace(); log.error("网易云信解散群服务调用异常 traceId:"); return AjaxResult.error("解散群失败,云信服务异常"); } catch (Exception e) { // 其他异常同样回滚 e.printStackTrace(); log.error("解散群过程发生未知异常", e); return AjaxResult.error("解散群失败,系统异常"); } } }