!31 fix: 设置取消群管理员时实时更新

Merge pull request !31 from 云裂痕/dev
This commit is contained in:
云裂痕
2025-10-21 12:06:57 +00:00
committed by Gitee
17 changed files with 126 additions and 82 deletions

View File

@@ -131,8 +131,8 @@ HuLa-Server 是一款基于 SpringCloud、SpringBoot3、Netty、MyBatis-Plus 和
8. **目标WS节点消费分发过来的主题消息** 8. **目标WS节点消费分发过来的主题消息**
9. **查找本地会话映射表** 9. **查找本地会话映射表**
10. **推送消息到具体客户端** 10. **推送消息到具体客户端**
11. **客户端返回ACK确认** ![进行中](https://img.shields.io/badge/🐣-进行中-ee9f20?style=flat&labelColor=fef7e6&color=ee9f20) 11. **客户端返回ACK确认**
12. **更新消息状态为已送达** ![进行中](https://img.shields.io/badge/🐣-进行中-ee9f20?style=flat&labelColor=fef7e6&color=ee9f20) 12. **更新消息状态为已送达**
![messageFlow.png](preview/messageFlow.png) ![messageFlow.png](preview/messageFlow.png)
## 🌐 性能对比 WS 服务) ## 🌐 性能对比 WS 服务)

View File

@@ -216,7 +216,7 @@ public class DefUserServiceImpl extends SuperCacheServiceImpl<DefUserManager, Lo
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean updatePassword(DefUserPasswordUpdateVO data) { public Boolean updatePassword(DefUserPasswordUpdateVO data) {
ArgumentAssert.notEmpty(data.getOldPassword(), "请输入旧密码"); // ArgumentAssert.notEmpty(data.getOldPassword(), "请输入旧密码");
DefUser user = superManager.getUserByEmail(2, data.getEmail()); DefUser user = superManager.getUserByEmail(2, data.getEmail());
ArgumentAssert.notNull(user, "用户不存在"); ArgumentAssert.notNull(user, "用户不存在");
ArgumentAssert.equals(user.getId(), ContextUtil.getUid(), "只能修改自己的密码"); ArgumentAssert.equals(user.getId(), ContextUtil.getUid(), "只能修改自己的密码");

View File

@@ -1,8 +1,7 @@
package com.luohuo.flex.im.core.chat.service; package com.luohuo.flex.im.core.chat.service;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.luohuo.flex.im.domain.vo.request.admin.AdminAddReq; import com.luohuo.flex.im.domain.vo.request.admin.AdminSetReq;
import com.luohuo.flex.im.domain.vo.request.admin.AdminRevokeReq;
import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq; import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq;
import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq; import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@@ -189,12 +188,12 @@ public interface RoomAppService {
/** /**
* 添加管理员 * 添加管理员
*/ */
void addAdmin(Long uid, @Valid AdminAddReq request); void addAdmin(Long uid, @Valid AdminSetReq request);
/** /**
* 移除管理员 * 移除管理员
*/ */
void revokeAdmin(Long uid, @Valid AdminRevokeReq request); void revokeAdmin(Long uid, @Valid AdminSetReq request);
/** /**
* 创建系统好友 * 创建系统好友

View File

@@ -11,6 +11,7 @@ import com.luohuo.flex.im.domain.vo.response.msg.BodyDTO;
import com.luohuo.flex.im.domain.vo.response.msg.VideoCallMsgDTO; import com.luohuo.flex.im.domain.vo.response.msg.VideoCallMsgDTO;
import com.luohuo.flex.im.domain.vo.response.msg.MergeMsgDTO; import com.luohuo.flex.im.domain.vo.response.msg.MergeMsgDTO;
import com.luohuo.flex.im.domain.vo.response.msg.NoticeMsgDTO; import com.luohuo.flex.im.domain.vo.response.msg.NoticeMsgDTO;
import com.luohuo.flex.model.entity.ws.AdminChangeDTO;
import com.luohuo.flex.model.entity.ws.WSNotice; import com.luohuo.flex.model.entity.ws.WSNotice;
import com.luohuo.flex.model.enums.MessageMarkTypeEnum; import com.luohuo.flex.model.enums.MessageMarkTypeEnum;
import com.luohuo.flex.im.domain.enums.MessageStatusEnum; import com.luohuo.flex.im.domain.enums.MessageStatusEnum;
@@ -197,6 +198,16 @@ public class MessageAdapter {
return wsBaseResp; return wsBaseResp;
} }
/**
* 构建设置管理员
*/
public static WsBaseResp<AdminChangeDTO> buildSetAdminMessage(AdminChangeDTO adminChangeDTO) {
WsBaseResp<AdminChangeDTO> wsBaseResp = new WsBaseResp<>();
wsBaseResp.setType(WSRespTypeEnum.GROUP_SET_ADMIN.getType());
wsBaseResp.setData(adminChangeDTO);
return wsBaseResp;
}
/** /**
* 已读群公告 * 已读群公告
*/ */

View File

@@ -28,10 +28,10 @@ import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
import com.luohuo.flex.im.domain.entity.*; import com.luohuo.flex.im.domain.entity.*;
import com.luohuo.flex.im.domain.enums.*; import com.luohuo.flex.im.domain.enums.*;
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq; import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
import com.luohuo.flex.im.domain.vo.request.admin.AdminAddReq; import com.luohuo.flex.im.domain.vo.request.admin.AdminSetReq;
import com.luohuo.flex.im.domain.vo.request.admin.AdminRevokeReq;
import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq; import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq;
import com.luohuo.flex.im.domain.entity.msg.TextMsgReq; import com.luohuo.flex.im.domain.entity.msg.TextMsgReq;
import com.luohuo.flex.model.entity.ws.AdminChangeDTO;
import com.luohuo.flex.model.enums.ChatActiveStatusEnum; import com.luohuo.flex.model.enums.ChatActiveStatusEnum;
import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq; import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@@ -110,7 +110,13 @@ import java.util.stream.Collectors;
import static com.luohuo.flex.im.core.chat.constant.GroupConst.MAX_MANAGE_COUNT; import static com.luohuo.flex.im.core.chat.constant.GroupConst.MAX_MANAGE_COUNT;
import static com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum.UNREAD; import static com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum.UNREAD;
/**
* 聊天室应用服务实现类
* - 聊天室创建、管理和维护
* - 群组成员管理(添加、删除、管理员设置)
* - 聊天消息处理与转发
* - 用户会话管理、在线状态管理、公告发布与管理
*/
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @AllArgsConstructor
@@ -307,30 +313,25 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
@Override @Override
@RedissonLock(prefixKey = "addAdmin:", key = "#request.roomId") @RedissonLock(prefixKey = "addAdmin:", key = "#request.roomId")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void addAdmin(Long uid, AdminAddReq request) { public void addAdmin(Long uid, AdminSetReq request) {
// 1. 判断群聊是否存在 // 1. 判断群聊是否存在
RoomGroup roomGroup = roomGroupCache.getByRoomId(request.getRoomId()); RoomGroup roomGroup = verifyGet(uid, request);
AssertUtil.isNotEmpty(roomGroup, GroupErrorEnum.GROUP_NOT_EXIST);
// 2. 判断该用户是否是群主 // 2. 判断管理员数量是否达到上限
Boolean isLord = groupMemberDao.isLord(roomGroup.getId(), uid); // 2.1 查询现有管理员数量
AssertUtil.isTrue(isLord, GroupErrorEnum.NOT_ALLOWED_OPERATION);
// 3. 判断群成员是否在群中
Boolean isGroupShip = groupMemberDao.isGroupShip(roomGroup.getRoomId(), request.getUidList());
AssertUtil.isTrue(isGroupShip, GroupErrorEnum.USER_NOT_IN_GROUP);
// 4. 判断管理员数量是否达到上限
// 4.1 查询现有管理员数量
List<Long> manageUidList = groupMemberDao.getManageUidList(roomGroup.getId()); List<Long> manageUidList = groupMemberDao.getManageUidList(roomGroup.getId());
// 4.2 去重 // 2.2 去重
HashSet<Long> manageUidSet = new HashSet<>(manageUidList); HashSet<Long> manageUidSet = new HashSet<>(manageUidList);
manageUidSet.addAll(request.getUidList()); manageUidSet.addAll(request.getUidList());
AssertUtil.isFalse(manageUidSet.size() > MAX_MANAGE_COUNT, GroupErrorEnum.MANAGE_COUNT_EXCEED); AssertUtil.isFalse(manageUidSet.size() > MAX_MANAGE_COUNT, GroupErrorEnum.MANAGE_COUNT_EXCEED);
// 5. 增加管理员 // 3. 增加管理员
groupMemberDao.addAdmin(roomGroup.getId(), request.getUidList()); groupMemberDao.addAdmin(roomGroup.getId(), request.getUidList());
// 5. 发送给所有群成员
List<Long> memberUidList = groupMemberCache.getMemberUidList(roomGroup.getRoomId());
pushService.sendPushMsg(MessageAdapter.buildSetAdminMessage(new AdminChangeDTO(roomGroup.getRoomId(), request.getUidList(), true)), memberUidList, uid);
// 每个被邀请的人都要收到邀请进群的消息 // 每个被邀请的人都要收到邀请进群的消息
setAdminNotice(NoticeTypeEnum.GROUP_SET_ADMIN, uid, request.getUidList(), manageUidList, roomGroup.getRoomId()); setAdminNotice(NoticeTypeEnum.GROUP_SET_ADMIN, uid, request.getUidList(), manageUidList, roomGroup.getRoomId());
} }
@@ -358,7 +359,8 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
// uid, // uid,
// uuid, // uuid,
// id, // id,
// roomId // roomId,
// ""
// ); // );
}); });
} }
@@ -372,7 +374,22 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
@Override @Override
@RedissonLock(prefixKey = "revokeAdmin:", key = "#request.roomId") @RedissonLock(prefixKey = "revokeAdmin:", key = "#request.roomId")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void revokeAdmin(Long uid, AdminRevokeReq request) { public void revokeAdmin(Long uid, AdminSetReq request) {
// 1. 校验
RoomGroup roomGroup = verifyGet(uid, request);
// 2. 撤销管理员
groupMemberDao.revokeAdmin(roomGroup.getId(), request.getUidList());
List<Long> memberUidList = groupMemberCache.getMemberUidList(roomGroup.getRoomId());
pushService.sendPushMsg(MessageAdapter.buildSetAdminMessage(new AdminChangeDTO(roomGroup.getRoomId(), request.getUidList(), false)), memberUidList, uid);
setAdminNotice(NoticeTypeEnum.GROUP_RECALL_ADMIN, uid, request.getUidList(), new ArrayList<>(), roomGroup.getRoomId());
}
/**
* 校验人员在群里的权限
*/
private RoomGroup verifyGet(Long uid, AdminSetReq request) {
// 1. 判断群聊是否存在 // 1. 判断群聊是否存在
RoomGroup roomGroup = roomGroupCache.getByRoomId(request.getRoomId()); RoomGroup roomGroup = roomGroupCache.getByRoomId(request.getRoomId());
AssertUtil.isNotEmpty(roomGroup, GroupErrorEnum.GROUP_NOT_EXIST); AssertUtil.isNotEmpty(roomGroup, GroupErrorEnum.GROUP_NOT_EXIST);
@@ -384,10 +401,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
// 3. 判断群成员是否在群中 // 3. 判断群成员是否在群中
Boolean isGroupShip = groupMemberDao.isGroupShip(roomGroup.getRoomId(), request.getUidList()); Boolean isGroupShip = groupMemberDao.isGroupShip(roomGroup.getRoomId(), request.getUidList());
AssertUtil.isTrue(isGroupShip, GroupErrorEnum.USER_NOT_IN_GROUP); AssertUtil.isTrue(isGroupShip, GroupErrorEnum.USER_NOT_IN_GROUP);
return roomGroup;
// 4. 撤销管理员
groupMemberDao.revokeAdmin(roomGroup.getId(), request.getUidList());
setAdminNotice(NoticeTypeEnum.GROUP_RECALL_ADMIN, uid, request.getUidList(), new ArrayList<>(), roomGroup.getRoomId());
} }
/** /**

View File

@@ -8,6 +8,9 @@ import com.luohuo.flex.im.domain.vo.res.NoticeVO;
import com.luohuo.flex.im.domain.vo.res.PageBaseResp; import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
import com.luohuo.flex.model.entity.ws.WSNotice; import com.luohuo.flex.model.entity.ws.WSNotice;
/**
* 系统通知服务,群通知、好友通知
*/
public interface NoticeService { public interface NoticeService {
Notice getByApplyId(Long uid, Long applyId); Notice getByApplyId(Long uid, Long applyId);

View File

@@ -19,8 +19,7 @@ import com.luohuo.flex.im.domain.vo.request.ChatMessageMemberReq;
import com.luohuo.flex.im.domain.vo.request.GroupAddReq; import com.luohuo.flex.im.domain.vo.request.GroupAddReq;
import com.luohuo.flex.im.domain.vo.request.RoomInfoReq; import com.luohuo.flex.im.domain.vo.request.RoomInfoReq;
import com.luohuo.flex.im.domain.vo.request.RoomMyInfoReq; import com.luohuo.flex.im.domain.vo.request.RoomMyInfoReq;
import com.luohuo.flex.im.domain.vo.request.admin.AdminAddReq; import com.luohuo.flex.im.domain.vo.request.admin.AdminSetReq;
import com.luohuo.flex.im.domain.vo.request.admin.AdminRevokeReq;
import com.luohuo.flex.im.domain.vo.request.member.MemberAddReq; import com.luohuo.flex.im.domain.vo.request.member.MemberAddReq;
import com.luohuo.flex.im.domain.vo.request.member.MemberDelReq; import com.luohuo.flex.im.domain.vo.request.member.MemberDelReq;
import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq; import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq;
@@ -128,7 +127,7 @@ public class RoomController {
@PutMapping("/group/admin") @PutMapping("/group/admin")
@Operation(summary ="添加管理员") @Operation(summary ="添加管理员")
public R<Boolean> addAdmin(@Valid @RequestBody AdminAddReq request) { public R<Boolean> addAdmin(@Valid @RequestBody AdminSetReq request) {
Long uid = ContextUtil.getUid(); Long uid = ContextUtil.getUid();
roomService.addAdmin(uid, request); roomService.addAdmin(uid, request);
return R.success(); return R.success();
@@ -136,7 +135,7 @@ public class RoomController {
@DeleteMapping("/group/admin") @DeleteMapping("/group/admin")
@Operation(summary ="撤销管理员") @Operation(summary ="撤销管理员")
public R<Boolean> revokeAdmin(@Valid @RequestBody AdminRevokeReq request) { public R<Boolean> revokeAdmin(@Valid @RequestBody AdminSetReq request) {
Long uid = ContextUtil.getUid(); Long uid = ContextUtil.getUid();
roomService.revokeAdmin(uid, request); roomService.revokeAdmin(uid, request);
return R.success(); return R.success();

View File

@@ -1,24 +0,0 @@
package com.luohuo.flex.im.domain.vo.request.admin;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* 撤销管理员请求信息
* @author nyh
*/
@Data
public class AdminRevokeReq {
@NotNull
@Schema(description ="房间号")
private Long roomId;
@NotNull
@Size(min = 1, max = 3)
@Schema(description ="需要撤销管理的列表")
private List<Long> uidList;
}

View File

@@ -12,7 +12,7 @@ import java.util.List;
* @author nyh * @author nyh
*/ */
@Data @Data
public class AdminAddReq { public class AdminSetReq {
@NotNull @NotNull
@Schema(description ="房间号") @Schema(description ="房间号")
private Long roomId; private Long roomId;

View File

@@ -56,6 +56,6 @@ public interface CaptchaService {
* @date 2022/7/26 8:05 PM * @date 2022/7/26 8:05 PM
* @create [2022/7/26 8:05 PM ] [tangyh] [初始创建] * @create [2022/7/26 8:05 PM ] [tangyh] [初始创建]
*/ */
R<Boolean> sendEmailCode(BindEmailReq bindEmailReq); R<Long> sendEmailCode(BindEmailReq bindEmailReq);
} }

View File

@@ -3,6 +3,7 @@ package com.luohuo.flex.oauth.service.impl;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.luohuo.basic.cache.repository.CachePlusOps;
import com.luohuo.basic.utils.TimeUtils; import com.luohuo.basic.utils.TimeUtils;
import com.luohuo.flex.model.vo.query.BindEmailReq; import com.luohuo.flex.model.vo.query.BindEmailReq;
import com.luohuo.flex.service.SysConfigService; import com.luohuo.flex.service.SysConfigService;
@@ -20,7 +21,6 @@ import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.luohuo.basic.base.R; import com.luohuo.basic.base.R;
import com.luohuo.basic.cache.redis2.CacheResult; import com.luohuo.basic.cache.redis2.CacheResult;
import com.luohuo.basic.cache.repository.CacheOps;
import com.luohuo.basic.model.cache.CacheKey; import com.luohuo.basic.model.cache.CacheKey;
import com.luohuo.basic.utils.ArgumentAssert; import com.luohuo.basic.utils.ArgumentAssert;
import com.luohuo.flex.base.service.tenant.DefUserService; import com.luohuo.flex.base.service.tenant.DefUserService;
@@ -49,7 +49,7 @@ import com.luohuo.flex.msg.facade.MsgFacade;
public class CaptchaServiceImpl implements CaptchaService { public class CaptchaServiceImpl implements CaptchaService {
private final SysConfigService configService; private final SysConfigService configService;
private final CacheOps cacheOps; private final CachePlusOps cachePlusOps;
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
private final MsgFacade msgFacade; private final MsgFacade msgFacade;
private final DefUserService defUserService; private final DefUserService defUserService;
@@ -86,7 +86,7 @@ public class CaptchaServiceImpl implements CaptchaService {
Captcha captcha = createCaptcha(); Captcha captcha = createCaptcha();
CacheKey cacheKey = CaptchaCacheKeyBuilder.build(key, CaptchaTokenGranter.GRANT_TYPE); CacheKey cacheKey = CaptchaCacheKeyBuilder.build(key, CaptchaTokenGranter.GRANT_TYPE);
cacheOps.set(cacheKey, captcha.text().toLowerCase()); cachePlusOps.set(cacheKey, captcha.text().toLowerCase());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("uuid", key); map.put("uuid", key);
@@ -114,7 +114,7 @@ public class CaptchaServiceImpl implements CaptchaService {
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
CacheKey cacheKey = CaptchaCacheKeyBuilder.build(mobile, templateCode); CacheKey cacheKey = CaptchaCacheKeyBuilder.build(mobile, templateCode);
// cacheKey.setExpire(Duration.ofMinutes(15)); // 可以修改有效期 // cacheKey.setExpire(Duration.ofMinutes(15)); // 可以修改有效期
cacheOps.set(cacheKey, code); cachePlusOps.set(cacheKey, code);
log.info("短信验证码 cacheKey={}, code={}", cacheKey, code); log.info("短信验证码 cacheKey={}, code={}", cacheKey, code);
@@ -127,7 +127,7 @@ public class CaptchaServiceImpl implements CaptchaService {
} }
@Override @Override
public R<Boolean> sendEmailCode(BindEmailReq bindEmailReq) { public R<Long> sendEmailCode(BindEmailReq bindEmailReq) {
if (MsgTemplateCodeEnum.REGISTER_EMAIL.eq(bindEmailReq.getTemplateCode())) { if (MsgTemplateCodeEnum.REGISTER_EMAIL.eq(bindEmailReq.getTemplateCode())) {
// 查user表判断重复 // 查user表判断重复
boolean flag = defUserService.checkEmail(bindEmailReq.getEmail(), null); boolean flag = defUserService.checkEmail(bindEmailReq.getEmail(), null);
@@ -139,14 +139,16 @@ public class CaptchaServiceImpl implements CaptchaService {
} }
// CacheKey imgKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getClientId(), CaptchaTokenGranter.GRANT_TYPE); // CacheKey imgKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getClientId(), CaptchaTokenGranter.GRANT_TYPE);
// CacheResult<String> result = cacheOps.get(imgKey); // CacheResult<String> result = cachePlusOps.get(imgKey);
// ArgumentAssert.isFalse(!bindEmailReq.getCode().equals(result.getValue()), "图片验证码错误"); // ArgumentAssert.isFalse(!bindEmailReq.getCode().equals(result.getValue()), "图片验证码错误");
String code = RandomUtil.randomNumbers(6); String code = RandomUtil.randomNumbers(6);
CacheKey cacheKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getEmail(), bindEmailReq.getTemplateCode()); CacheKey cacheKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getEmail(), bindEmailReq.getTemplateCode());
ArgumentAssert.isFalse(cacheOps.exists(cacheKey), "请勿重复发送验证码"); if(cachePlusOps.exists(cacheKey)){
return R.success(cachePlusOps.ttl(cacheKey));
}
cacheOps.set(cacheKey, code); cachePlusOps.set(cacheKey, code);
log.info("邮件验证码 cacheKey={}, code={}", cacheKey, code); log.info("邮件验证码 cacheKey={}, code={}", cacheKey, code);
// 在「运营平台」-「消息模板」配置一个「模板标识」为 templateCode 且「模板内容」中需要有 code 占位符 // 在「运营平台」-「消息模板」配置一个「模板标识」为 templateCode 且「模板内容」中需要有 code 占位符
@@ -159,7 +161,8 @@ public class CaptchaServiceImpl implements CaptchaService {
msgSendVO.addParam("currentTime", TimeUtils.nowToStr()); msgSendVO.addParam("currentTime", TimeUtils.nowToStr());
msgSendVO.addRecipient(bindEmailReq.getEmail()); msgSendVO.addRecipient(bindEmailReq.getEmail());
return R.success(msgFacade.sendByTemplate(msgSendVO)); msgFacade.sendByTemplate(msgSendVO);
return R.success(cachePlusOps.ttl(cacheKey));
} }
@Override @Override
@@ -168,14 +171,14 @@ public class CaptchaServiceImpl implements CaptchaService {
return R.fail(CAPTCHA_ERROR.build("请输入验证码")); return R.fail(CAPTCHA_ERROR.build("请输入验证码"));
} }
CacheKey cacheKey = CaptchaCacheKeyBuilder.build(key, templateCode); CacheKey cacheKey = CaptchaCacheKeyBuilder.build(key, templateCode);
CacheResult<String> code = cacheOps.get(cacheKey); CacheResult<String> code = cachePlusOps.get(cacheKey);
if (StrUtil.isEmpty(code.getValue())) { if (StrUtil.isEmpty(code.getValue())) {
return R.fail(CAPTCHA_ERROR.build("验证码已过期")); return R.fail(CAPTCHA_ERROR.build("验证码已过期"));
} }
if (!StrUtil.equalsIgnoreCase(value, code.getValue())) { if (!StrUtil.equalsIgnoreCase(value, code.getValue())) {
return R.fail(CAPTCHA_ERROR.build("验证码不正确")); return R.fail(CAPTCHA_ERROR.build("验证码不正确"));
} }
cacheOps.del(cacheKey); cachePlusOps.del(cacheKey);
return R.success(true); return R.success(true);
} }

View File

@@ -77,7 +77,7 @@ public class CaptchaController {
}) })
@Operation(summary = "发送邮箱验证码", description = "发送邮箱验证码") @Operation(summary = "发送邮箱验证码", description = "发送邮箱验证码")
@PostMapping(value = "/sendEmailCode") @PostMapping(value = "/sendEmailCode")
public R<Boolean> sendEmailCode(@RequestBody BindEmailReq bindEmailReq) { public R<Long> sendEmailCode(@RequestBody BindEmailReq bindEmailReq) {
return captchaService.sendEmailCode(bindEmailReq); return captchaService.sendEmailCode(bindEmailReq);
} }

View File

@@ -35,6 +35,7 @@ public enum WSRespTypeEnum {
REQUEST_APPROVAL_FRIEND("requestApprovalFriend", "同意好友请求", WSFriendApproval.class), REQUEST_APPROVAL_FRIEND("requestApprovalFriend", "同意好友请求", WSFriendApproval.class),
NEW_APPLY("newApply", "好友申请、群聊邀请", WSNotice.class), NEW_APPLY("newApply", "好友申请、群聊邀请", WSNotice.class),
ROOM_DISSOLUTION("roomDissolution", "群解散", null), ROOM_DISSOLUTION("roomDissolution", "群解散", null),
GROUP_SET_ADMIN("groupSetAdmin", "设置管理员", AdminChangeDTO.class),
ROOM_GROUP_NOTICE_READ_MSG("roomGroupNoticeReadMsg", "群公告已读", null), ROOM_GROUP_NOTICE_READ_MSG("roomGroupNoticeReadMsg", "群公告已读", null),
FEED_SEND_MSG("feedSendMsg", "朋友圈发布", null), FEED_SEND_MSG("feedSendMsg", "朋友圈发布", null),

View File

@@ -0,0 +1,38 @@
package com.luohuo.flex.model.entity.ws;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
/**
* 管理员变更数据传输对象
* @author 乾乾
*/
@Data
public class AdminChangeDTO implements Serializable {
/**
* 房间ID
*/
private String roomId;
/**
* 管理员ID列表
*/
private List<String> uids;
/**
* true: 设置 false: 取消
*/
private Boolean status;
public AdminChangeDTO(Long roomId, List<Long> uids, Boolean status) {
this.roomId = roomId != null ? roomId.toString() : null;
this.uids = uids != null ? uids.stream().map(Object::toString).collect(Collectors.toList()) : null;
this.status = status;
}
public AdminChangeDTO() {
}
}

View File

@@ -35,7 +35,7 @@ public class RoomMetadataService {
public Boolean isRoomClosed(Long roomId) { public Boolean isRoomClosed(Long roomId) {
CacheResult<Boolean> result = cachePlusOps.get(CloseRoomCacheKeyBuilder.builder(roomId)); CacheResult<Boolean> result = cachePlusOps.get(CloseRoomCacheKeyBuilder.builder(roomId));
return result.isNull()? true: result.getRawValue(); return result.isNull() || result.isNullVal()? true: result.getRawValue();
} }
/** /**

View File

@@ -146,7 +146,7 @@ public class VideoChatService {
public void forwardSignal(Long senderUid, Long roomId, String signal, String signalType) { public void forwardSignal(Long senderUid, Long roomId, String signal, String signalType) {
// 1. 获取房间内其他成员 // 1. 获取房间内其他成员
try { try {
List<Long> uidList = getOnlineUidList(roomId); List<Long> uidList = getUserList(roomId);
uidList.remove(senderUid); uidList.remove(senderUid);
if (uidList.isEmpty()) return; if (uidList.isEmpty()) return;
@@ -168,7 +168,7 @@ public class VideoChatService {
* 获取房间内所有人员id * 获取房间内所有人员id
* @param roomId 房间id * @param roomId 房间id
*/ */
public List<Long> getOnlineUidList(Long roomId) { public List<Long> getUserList(Long roomId) {
return onlineService.getGroupMembers(roomId); return onlineService.getGroupMembers(roomId);
} }
@@ -276,8 +276,8 @@ public class VideoChatService {
* @param data 通知数据 * @param data 通知数据
*/ */
private <T> List<Long> notifyRoomMembers(Long roomId, Long excludeUid, WSRespTypeEnum respType, T data) { private <T> List<Long> notifyRoomMembers(Long roomId, Long excludeUid, WSRespTypeEnum respType, T data) {
// 1. 获取房间内在线成员 // 1. 获取房间内所有成员
List<Long> uidList = getOnlineUidList(roomId); List<Long> uidList = getUserList(roomId);
if (uidList.isEmpty()) return new ArrayList<>(); if (uidList.isEmpty()) return new ArrayList<>();
// 2. 排除当前用户 // 2. 排除当前用户

View File

@@ -1,18 +1,18 @@
## 本地如何跑hula ## 本地如何跑hula
注意!! 开发环境默认大家已经安装nacos版本我用的是3.0.2web端端口是8080老版本是8848、rocketMQ、mysql、redis这些组件了 注意!! 开发环境默认大家已经安装nacos版本我用的是3.0.2web端端口是8080老版本是8848、rocketMQ、mysql、redis这些组件了
如果没有的话先看一下 [reids、mysql、rocketmq、nacos一键部署.md](../docs/install/docker/reids%E3%80%81mysql%E3%80%81rocketmq%E3%80%81nacos%E4%B8%80%E9%94%AE%E9%83%A8%E7%BD%B2.md) (组件部署文档) 如果没有的话先看一下 [redis、mysql、rocketmq、nacos一键部署.md](install/docker/reids%E3%80%81mysql%E3%80%81rocketmq%E3%80%81nacos%E4%B8%80%E9%94%AE%E9%83%A8%E7%BD%B2.md) (组件部署文档)
下面执行顺序不能乱因为install cloud模块的时候需要将 src/main/filters 里面的配置打到target里面去 下面执行顺序不能乱因为install cloud模块的时候需要将 src/main/filters 里面的配置打到target里面去
1. 将 luohuo-cloud/pom.xml 导入IDEA 1. 将 luohuo-cloud/pom.xml 导入IDEA
2. 导入luohuo-util项目 2. 导入luohuo-util项目
![img.png](preview/img.png)![img_1.png](preview/img_1.png) ![img.png](preview/img.png)![img_1.png](preview/img_1.png)
3. 安装luohuo-util到本地![img_2.png](preview/img_2.png) 3. 安装luohuo-util到本地![img_2.png](preview/img_2.png)
4. 导入nacos环境以我本地为例127.0.0.1:8080![img5.png](preview/img5.png)![img_5.png](preview/img_5.png) 4. 导入nacos环境以我本地为例127.0.0.1:8080![img5.png](preview/img5.png)![img_5.png](preview/img_5.png)
5. 修改redis.yml、mysql.yml、rocketmq.yml、luohuo-im-server.yml的配置![img6.png](preview/img6.png) 5. 修改redis.yml、mysql.yml、rocketmq.yml、luohuo-im-server.yml的配置![img6.png](preview/img6.png)
6. 安装luohuo-cloud到本地![img_3.png](preview/img_3.png) 6. 安装luohuo-cloud到本地![img_3.png](preview/img_3.png)
7. 导入数据库 [luohuo_dev.sql](../docs/install/sql/luohuo_dev.sql)、[luohuo_im_01.sql](../docs/install/sql/luohuo_im_01.sql) 7. 导入数据库 [luohuo_dev.sql](install/sql/luohuo_dev.sql)、[luohuo_im_01.sql](install/sql/luohuo_im_01.sql)
8. 运行效果图![img7.png](preview/img7.png) 8. 运行效果图![img7.png](preview/img7.png)
9. 前端配置访问地址: 9. 前端配置访问地址:
```bash ```bash