diff --git a/framework/pom.xml b/framework/pom.xml index 2b359058..8dcc90f7 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -15,6 +15,11 @@ jar + + com.belerweb + pinyin4j + 2.5.1 + com.qiniu qiniu-java-sdk diff --git a/framework/src/main/java/cn/lili/common/exception/ServiceException.java b/framework/src/main/java/cn/lili/common/exception/ServiceException.java index feb98e6d..754aec2a 100644 --- a/framework/src/main/java/cn/lili/common/exception/ServiceException.java +++ b/framework/src/main/java/cn/lili/common/exception/ServiceException.java @@ -15,12 +15,11 @@ public class ServiceException extends RuntimeException { private static final long serialVersionUID = 3447728300174142127L; - public static final String DEFAULT_MESSAGE = "网络错误,请稍后重试!"; /** * 异常消息 */ - private String msg = DEFAULT_MESSAGE; + private String msg = ResultCode.ERROR.message(); /** * 错误码 diff --git a/framework/src/main/java/cn/lili/controller/im/ImGroupController.java b/framework/src/main/java/cn/lili/controller/im/ImGroupController.java new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/framework/src/main/java/cn/lili/controller/im/ImGroupController.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java new file mode 100644 index 00000000..19b45a63 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java @@ -0,0 +1,39 @@ +package cn.lili.modules.im.entity.dos; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import java.util.Date; + +@Data +@TableName("li_friend") +public class Friend { + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + // 用户ID + private String userId; + + // 好友ID + private String friendId; + + // 好友昵称 + private String nickname; + + // 好友头像 + private String avatar; + + // 好友备注 + private String remark; + + // 关系状态 (0:待确认 1:已确认 2:已拒绝 3:已解除) + private Integer status; + + // 创建时间 + private Date createTime; + + // 更新时间 + private Date updateTime; +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java new file mode 100644 index 00000000..1387afef --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java @@ -0,0 +1,32 @@ +package cn.lili.modules.im.entity.dos; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import java.util.Date; + +@Data +@TableName("li_im_group") +public class ImGroup { + @TableId(type = IdType.ASSIGN_ID) + private String id; + + // 群名称 + private String name; + + // 群头像 + private String avatar; + + // 群公告 + private String notice; + + // 群主ID + private String ownerId; + + // 创建时间 + private Date createTime; + + // 更新时间 + private Date updateTime; +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java new file mode 100644 index 00000000..44151239 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java @@ -0,0 +1,38 @@ +package cn.lili.modules.im.entity.dos; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import java.util.Date; + +@Data +@TableName("li_im_group_member") +public class ImGroupMember { + @TableId(type = IdType.ASSIGN_ID) + private String id; + + // 群ID + private String groupId; + + // 成员ID + private String memberId; + + // 成员昵称 + private String nickname; + + // 成员角色(0:普通成员 1:管理员 2:群主) + private Integer role; + + // 是否被禁言(0:否 1:是) + private Integer isMuted; + + // 禁言结束时间 + private Date muteEndTime; + + // 加入时间 + private Date joinTime; + + // 更新时间 + private Date updateTime; +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java new file mode 100644 index 00000000..fe2a1635 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java @@ -0,0 +1,21 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.modules.im.entity.dos.Friend; +import lombok.Data; +import java.util.Date; + +@Data +public class FriendVO extends Friend { + // 从 li_member 表获取的字段 + private String username; + private String nickname; + private String face; // 头像 + private String mobile; + private String email; + private String region; + private String gender; + private Date birthday; + // 昵称首字母(用于排序) + private String firstLetter; + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java new file mode 100644 index 00000000..2268608b --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java @@ -0,0 +1,10 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.Friend; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.mapstruct.Mapper; + +@Mapper +public interface FriendMapper extends BaseMapper { +} diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java new file mode 100644 index 00000000..c6591941 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java @@ -0,0 +1,7 @@ +package cn.lili.modules.im.mapper; + +import cn.lili.modules.im.entity.dos.ImGroup; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface ImGroupMapper extends BaseMapper { +} diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java new file mode 100644 index 00000000..0c9b8d04 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java @@ -0,0 +1,8 @@ +package cn.lili.modules.im.mapper; + +import cn.lili.modules.im.entity.dos.ImGroupMember; +import cn.lili.modules.im.entity.dos.ImMessage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface ImGroupMemberMapper extends BaseMapper { +} diff --git a/framework/src/main/java/cn/lili/modules/im/service/FriendService.java b/framework/src/main/java/cn/lili/modules/im/service/FriendService.java new file mode 100644 index 00000000..542009c5 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/FriendService.java @@ -0,0 +1,88 @@ +package cn.lili.modules.im.service; + + +import cn.lili.modules.im.entity.dos.Friend; + +import cn.lili.modules.im.entity.vo.FriendVO; + +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + + + +public interface FriendService extends IService { + + + + /** + + * 获取互相关注的好友列表(包含详细信息) + + * @param userId 用户ID + + * @return 好友列表 + + */ + + List getMutualFriends(String userId); + + + + /** + + * 获取好友详细信息 + + * @param friendId 好友ID + + * @return 好友详细信息 + + */ + + FriendVO getFriendDetails(String friendId); + + + + /** + + * 解除好友关系 + + * @param userId 用户ID + + * @param friendId 好友ID + + */ + + void removeFriend(String userId, String friendId); + + + + /** + + * 添加好友 + + * @param userId 用户ID + + * @param friendId 好友ID + + */ + + void addFriend(String userId, String friendId); + + + + /** + + * 更新好友备注 + + * @param userId 用户ID + + * @param friendId 好友ID + + * @param remark 备注 + + */ + + void updateRemark(String userId, String friendId, String remark); + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java b/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java new file mode 100644 index 00000000..23a4454b --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java @@ -0,0 +1,58 @@ +package cn.lili.modules.im.service; + +import cn.lili.modules.im.entity.dos.ImGroup; +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + +public interface ImGroupService extends IService { + + /** + * 创建群聊 + * @param groupName 群名称 + * @param memberIds 邀请的成员ID列表 + * @return 群聊信息 + */ + ImGroup createGroup(String groupName, List memberIds); + + /** + * 解散群聊 + * @param groupId 群ID + */ + void dismissGroup(String groupId); + + /** + * 邀请成员 + * @param groupId 群ID + * @param memberIds 成员ID列表 + */ + void inviteMembers(String groupId, List memberIds); + + /** + * 设置管理员 + * @param groupId 群ID + * @param memberId 成员ID + */ + void setAdmin(String groupId, String memberId); + + /** + * 取消管理员 + * @param groupId 群ID + * @param memberId 成员ID + */ + void removeAdmin(String groupId, String memberId); + + /** + * 禁言成员 + * @param groupId 群ID + * @param memberId 成员ID + * @param duration 禁言时长(分钟) + */ + void muteMember(String groupId, String memberId, Integer duration); + + /** + * 解除成员禁言 + * @param groupId 群ID + * @param memberId 成员ID + */ + void unmuteMember(String groupId, String memberId); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java new file mode 100644 index 00000000..540e79d2 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java @@ -0,0 +1,344 @@ +package cn.lili.modules.im.serviceimpl; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.security.enums.UserEnums; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.utils.StringUtils; +import cn.lili.modules.im.entity.dos.Friend; +import cn.lili.modules.im.entity.vo.FriendVO; +import cn.lili.modules.im.mapper.FriendMapper; +import cn.lili.modules.im.service.FriendService; + +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.member.mapper.MemberMapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.BeanUtils; + +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.ArrayList; + +import static cn.hutool.extra.pinyin.PinyinUtil.getFirstLetter; + +@Slf4j +@Service +public class FriendServiceImpl extends ServiceImpl implements FriendService { + @Autowired + private MemberMapper memberMapper; + + @Override + public List getMutualFriends(String userId) { + // 获取好友关系列表 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Friend::getUserId, userId) + .eq(Friend::getStatus, 1); // 已确认的好友关系 + List friends = this.list(queryWrapper); + + + // 转换为 FriendVO 列表 + List friendVOs = new ArrayList<>(); + for (Friend friend : friends) { + FriendVO friendVO = new FriendVO(); + BeanUtils.copyProperties(friend, friendVO); + + // 查询好友的详细信息 + Member member = memberMapper.selectById(friend.getFriendId()); + if (member != null) { + // 复制会员信息到 VO + friendVO.setUsername(member.getUsername()); + friendVO.setNickname(member.getNickName()); + friendVO.setFace(member.getFace()); + friendVO.setMobile(member.getMobile()); + friendVO.setEmail(member.getRegion()); + friendVO.setGender(member.getGradeId()); + friendVO.setBirthday(member.getBirthday()); + // 设置昵称首字母 + String firstLetter = getFirstLetter(member.getNickName()); + friendVO.setFirstLetter(firstLetter); + } + + friendVOs.add(friendVO); + } + // 按照昵称首字母排序 + Collections.sort(friendVOs, (a, b) -> { + String letterA = a.getFirstLetter() != null ? a.getFirstLetter() : "#"; + String letterB = b.getFirstLetter() != null ? b.getFirstLetter() : "#"; + return letterA.compareTo(letterB); + }); + + + return friendVOs; + } + /** + * 获取字符串的首字母 + * @param str 字符串 + * @return 首字母(大写) + */ + private String getFirstLetter(String str) { + if (StringUtils.isEmpty(str)) { + return "#"; + } + + try { + // 创建 HanyuPinyinOutputFormat 对象 + HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); + // 设置拼音小写 + format.setCaseType(HanyuPinyinCaseType.LOWERCASE); + // 设置声调不输出 + format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); + + // 取第一个字符 + char firstChar = str.charAt(0); + // 判断是否为汉字 + if (Character.toString(firstChar).matches("[\\u4E00-\\u9FA5]+")) { + // 如果是汉字,转换为拼音 + String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(firstChar, format); + if (pinyinArray != null && pinyinArray.length > 0) { + return pinyinArray[0].substring(0, 1).toUpperCase(); + } + } else if (Character.toString(firstChar).matches("[a-zA-Z]")) { + // 如果是字母,直接返回大写 + return String.valueOf(firstChar).toUpperCase(); + } + + // 其他情况返回 # + return "#"; + } catch (BadHanyuPinyinOutputFormatCombination e) { + log.error("获取拼音首字母失败", e); + return "#"; + } + } + + @Override + public FriendVO getFriendDetails(String friendId) { + String userId = UserContext.getCurrentUser().getId(); + + // 查询好友关系 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Friend::getUserId, userId) + .eq(Friend::getFriendId, friendId); + Friend friend = this.getOne(queryWrapper); + + if (friend == null) { + throw new ServiceException("好友关系不存在"); + } + + // 转换为 VO 并查询详细信息 + FriendVO friendVO = new FriendVO(); + BeanUtils.copyProperties(friend, friendVO); + + // 查询好友的详细信息 + Member member = memberMapper.selectById(friendId); + if (member != null) { + // 复制会员信息到 VO + friendVO.setUsername(member.getUsername()); + friendVO.setNickname(member.getNickName()); + friendVO.setFace(member.getFace()); + friendVO.setMobile(member.getMobile()); + friendVO.setEmail(member.getRegion()); + friendVO.setGender(member.getGradeId()); + friendVO.setBirthday(member.getBirthday()); + } + + return friendVO; + } + + + + @Override + + @Transactional(rollbackFor = Exception.class) + + public void removeFriend(String userId, String friendId) { + + // 删除双向的好友关系 + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + queryWrapper.and(wrapper -> wrapper + + .or(w -> w.eq(Friend::getUserId, userId).eq(Friend::getFriendId, friendId)) + + .or(w -> w.eq(Friend::getUserId, friendId).eq(Friend::getFriendId, userId)) + + ); + + + + if (!this.remove(queryWrapper)) { + + throw new ServiceException("解除好友关系失败"); + + } + + } + + + + @Override + + @Transactional(rollbackFor = Exception.class) + + public void addFriend(String userId, String friendId) { + + // 检查用户ID是否存在 + + if (!isUserExists(userId)) { + + throw new ServiceException("用户ID不存在"); + + } + + + + // 检查好友ID是否存在 + + if (!isUserExists(friendId)) { + + throw new ServiceException("好友ID不存在"); + + } + + + + // 检查是否已经是好友 + + if (checkFriendship(userId, friendId)) { + + throw new ServiceException("已经是好友关系"); + + } + + + + // 创建好友关系 + + Friend friend = new Friend(); + + friend.setUserId(userId); + + friend.setFriendId(friendId); + + friend.setStatus(1); + + friend.setCreateTime(new Date()); + + friend.setUpdateTime(new Date()); + + + + // 保存双向好友关系 + + if (!this.save(friend)) { + + throw new ServiceException("添加好友失败"); + + } + + + + // 创建反向好友关系 + + Friend reverseFriend = new Friend(); + + reverseFriend.setUserId(friendId); + + reverseFriend.setFriendId(userId); + + reverseFriend.setStatus(1); + + reverseFriend.setCreateTime(new Date()); + + reverseFriend.setUpdateTime(new Date()); + + + + if (!this.save(reverseFriend)) { + + throw new ServiceException("添加好友失败"); + + } + + } + + private boolean isUserExists(String userId) { + + return memberMapper.selectById(userId) != null; + + } + + + + @Override + + public void updateRemark(String userId, String friendId, String remark) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + queryWrapper.eq(Friend::getUserId, userId) + + .eq(Friend::getFriendId, friendId); + + + + Friend friend = this.getOne(queryWrapper); + + if (friend == null) { + + throw new ServiceException("好友关系不存在"); + + } + + + + friend.setRemark(remark); + + friend.setUpdateTime(new Date()); + + + + if (!this.updateById(friend)) { + + throw new ServiceException("更新好友备注失败"); + + } + + } + + + + /** + + * 检查是否已经是好友关系 + + */ + + private boolean checkFriendship(String userId, String friendId) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + queryWrapper.eq(Friend::getUserId, userId) + + .eq(Friend::getFriendId, friendId) + + .eq(Friend::getStatus, 1); + + return this.count(queryWrapper) > 0; + + } + + + + + +} diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java new file mode 100644 index 00000000..9a0a1e87 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java @@ -0,0 +1,218 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.common.security.context.UserContext; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.im.entity.dos.ImGroup; +import cn.lili.modules.im.entity.dos.ImGroupMember; +import cn.lili.modules.im.mapper.ImGroupMapper; +import cn.lili.modules.im.mapper.ImGroupMemberMapper; +import cn.lili.modules.im.service.ImGroupService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ImGroupServiceImpl extends ServiceImpl implements ImGroupService { + + private final ImGroupMemberMapper groupMemberMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public ImGroup createGroup(String groupName, List memberIds) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 创建群组 + ImGroup group = new ImGroup(); + group.setName(groupName); + group.setOwnerId(currentUserId); + group.setCreateTime(new Date()); + group.setUpdateTime(new Date()); + + if (!this.save(group)) { + throw new ServiceException("创建群聊失败"); + } + + // 添加群主为成员 + addGroupMember(group.getId(), currentUserId, 2); + + // 添加其他成员 + if (memberIds != null && !memberIds.isEmpty()) { + for (String memberId : memberIds) { + addGroupMember(group.getId(), memberId, 0); + } + } + + return group; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void dismissGroup(String groupId) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查是否是群主 + ImGroupMember owner = getGroupMember(groupId, currentUserId); + if (owner == null || owner.getRole() != 2) { + throw new ServiceException("只有群主能解散群聊"); + } + + // 删除群成员 + LambdaQueryWrapper memberWrapper = new LambdaQueryWrapper<>(); + memberWrapper.eq(ImGroupMember::getGroupId, groupId); + groupMemberMapper.delete(memberWrapper); + + // 删除群组 + this.removeById(groupId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void inviteMembers(String groupId, List memberIds) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查权限 + ImGroupMember operator = getGroupMember(groupId, currentUserId); + if (operator == null || operator.getRole() < 1) { + throw new ServiceException("没有邀请权限"); + } + + // 添加成员 + for (String memberId : memberIds) { + if (getGroupMember(groupId, memberId) == null) { + addGroupMember(groupId, memberId, 0); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void setAdmin(String groupId, String memberId) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查是否是群主 + ImGroupMember owner = getGroupMember(groupId, currentUserId); + if (owner == null || owner.getRole() != 2) { + throw new ServiceException("只有群主能设置管理员"); + } + + // 设置管理员 + ImGroupMember member = getGroupMember(groupId, memberId); + if (member == null) { + throw new ServiceException("该成员不在群中"); + } + + member.setRole(1); + member.setUpdateTime(new Date()); + groupMemberMapper.updateById(member); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeAdmin(String groupId, String memberId) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查是否是群主 + ImGroupMember owner = getGroupMember(groupId, currentUserId); + if (owner == null || owner.getRole() != 2) { + throw new ServiceException("只有群主能取消管理员"); + } + + // 取消管理员 + ImGroupMember member = getGroupMember(groupId, memberId); + if (member == null) { + throw new ServiceException("该成员不在群中"); + } + + member.setRole(0); + member.setUpdateTime(new Date()); + groupMemberMapper.updateById(member); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void muteMember(String groupId, String memberId, Integer duration) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查操作权限 + ImGroupMember operator = getGroupMember(groupId, currentUserId); + if (operator == null || operator.getRole() < 1) { + throw new ServiceException("没有禁言权限"); + } + + // 检查被禁言成员 + ImGroupMember member = getGroupMember(groupId, memberId); + if (member == null) { + throw new ServiceException("该成员不在群中"); + } + + // 管理员不能禁言群主和其他管理员 + if (operator.getRole() == 1 && member.getRole() > 0) { + throw new ServiceException("没有权限禁言该成员"); + } + + // 设置禁言 + member.setIsMuted(1); + member.setMuteEndTime(new Date(System.currentTimeMillis() + duration * 60 * 1000)); + member.setUpdateTime(new Date()); + groupMemberMapper.updateById(member); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void unmuteMember(String groupId, String memberId) { + String currentUserId = UserContext.getCurrentUser().getId(); + + // 检查操作权限 + ImGroupMember operator = getGroupMember(groupId, currentUserId); + if (operator == null || operator.getRole() < 1) { + throw new ServiceException("没有解除禁言权限"); + } + + // 检查被解除禁言成员 + ImGroupMember member = getGroupMember(groupId, memberId); + if (member == null) { + throw new ServiceException("该成员不在群中"); + } + + // 管理员不能解除群主和其他管理员的禁言 + if (operator.getRole() == 1 && member.getRole() > 0) { + throw new ServiceException("没有权限解除该成员的禁言"); + } + + // 解除禁言 + member.setIsMuted(0); + member.setMuteEndTime(null); + member.setUpdateTime(new Date()); + groupMemberMapper.updateById(member); + } + + /** + * 添加群成员 + */ + private void addGroupMember(String groupId, String memberId, Integer role) { + ImGroupMember member = new ImGroupMember(); + member.setGroupId(groupId); + member.setMemberId(memberId); + member.setRole(role); + member.setIsMuted(0); + member.setJoinTime(new Date()); + member.setUpdateTime(new Date()); + groupMemberMapper.insert(member); + } + + /** + * 获取群成员信息 + */ + private ImGroupMember getGroupMember(String groupId, String memberId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImGroupMember::getGroupId, groupId) + .eq(ImGroupMember::getMemberId, memberId); + return groupMemberMapper.selectOne(queryWrapper); + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java b/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java index 32f09fa9..74031963 100644 --- a/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java +++ b/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Constants; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import org.mapstruct.Mapper; import java.util.List; @@ -17,7 +18,9 @@ import java.util.List; * * @author Bulbasaur * @since 2020-02-25 14:10:16 + * @ */ +@Mapper public interface MemberMapper extends BaseMapper { /** diff --git a/im-api/src/main/java/cn/lili/controller/im/FriendController.java b/im-api/src/main/java/cn/lili/controller/im/FriendController.java new file mode 100644 index 00000000..a318ae17 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/FriendController.java @@ -0,0 +1,100 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.Friend; +import cn.lili.modules.im.entity.vo.FriendVO; +import cn.lili.modules.im.service.FriendService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.List; + + + +/** + + * @author Chopper + + */ + +@RestController + +@Api(tags = "好友管理接口") + +@RequestMapping("/im/friend") + +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) + +public class FriendController { + + + + private final FriendService friendService; + + + @GetMapping("/mutual") + @ApiOperation(value = "查看所有互相关注好友") + public ResultMessage> getMutualFriends() { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + List friends = friendService.getMutualFriends(currentUser.getId()); + return ResultUtil.data(friends); + } + + @GetMapping("/{friendId}") + @ApiOperation(value = "查看好友资料") + public ResultMessage getFriendDetails(@PathVariable String friendId) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + FriendVO friend = friendService.getFriendDetails(friendId); + return ResultUtil.data(friend); + } + + @DeleteMapping("/{friendId}") + @ApiOperation(value = "解除好友关系") + public ResultMessage removeFriend(@PathVariable String friendId) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + friendService.removeFriend(currentUser.getId(), friendId); + return ResultUtil.success(); + } + + @PostMapping("/add/{friendId}") + @ApiOperation(value = "添加好友") + public ResultMessage addFriend(@PathVariable String friendId) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + friendService.addFriend(currentUser.getId(), friendId); + return ResultUtil.success(); + } + + @PutMapping("/remark/{friendId}") + @ApiOperation(value = "更新好友备注") + public ResultMessage updateRemark(@PathVariable String friendId, @RequestParam String remark) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + friendService.updateRemark(currentUser.getId(), friendId, remark); + return ResultUtil.success(); + } + + +} \ No newline at end of file diff --git a/im-api/src/main/java/cn/lili/controller/im/ImGroupController.java b/im-api/src/main/java/cn/lili/controller/im/ImGroupController.java new file mode 100644 index 00000000..6de152e0 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/ImGroupController.java @@ -0,0 +1,79 @@ +package cn.lili.controller.im; + + + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.ImGroup; +import cn.lili.modules.im.service.ImGroupService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@Api(tags = "群聊管理接口") +@RequestMapping("/im/group") +@RequiredArgsConstructor +public class ImGroupController { + + private final ImGroupService imGroupService; + + @PostMapping + @ApiOperation(value = "创建群聊") + public ResultMessage createGroup(@RequestParam String groupName, + @RequestParam(required = false) List memberIds) { + ImGroup group = imGroupService.createGroup(groupName, memberIds); + return ResultUtil.data(group); + } + + @DeleteMapping("/{groupId}") + @ApiOperation(value = "解散群聊") + public ResultMessage dismissGroup(@PathVariable String groupId) { + imGroupService.dismissGroup(groupId); + return ResultUtil.success(); + } + + @PostMapping("/{groupId}/invite") + @ApiOperation(value = "邀请成员") + public ResultMessage inviteMembers(@PathVariable String groupId, + @RequestParam List memberIds) { + imGroupService.inviteMembers(groupId, memberIds); + return ResultUtil.success(); + } + + @PostMapping("/{groupId}/admin/{memberId}") + @ApiOperation(value = "设置管理员") + public ResultMessage setAdmin(@PathVariable String groupId, + @PathVariable String memberId) { + imGroupService.setAdmin(groupId, memberId); + return ResultUtil.success(); + } + + @DeleteMapping("/{groupId}/admin/{memberId}") + @ApiOperation(value = "取消管理员") + public ResultMessage removeAdmin(@PathVariable String groupId, + @PathVariable String memberId) { + imGroupService.removeAdmin(groupId, memberId); + return ResultUtil.success(); + } + + @PostMapping("/{groupId}/mute/{memberId}") + @ApiOperation(value = "禁言成员") + public ResultMessage muteMember(@PathVariable String groupId, + @PathVariable String memberId, + @RequestParam Integer duration) { + imGroupService.muteMember(groupId, memberId, duration); + return ResultUtil.success(); + } + + @DeleteMapping("/{groupId}/mute/{memberId}") + @ApiOperation(value = "解除成员禁言") + public ResultMessage unmuteMember(@PathVariable String groupId, + @PathVariable String memberId) { + imGroupService.unmuteMember(groupId, memberId); + return ResultUtil.success(); + } +} \ No newline at end of file diff --git a/im-api/src/main/java/cn/lili/modules/member/entity/Member.java b/im-api/src/main/java/cn/lili/modules/member/entity/Member.java new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/im-api/src/main/java/cn/lili/modules/member/entity/Member.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/im-api/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java b/im-api/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/im-api/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java @@ -0,0 +1 @@ + \ No newline at end of file