Browse Source

群聊功能开发中

master
xie.bx 3 years ago
parent
commit
a9c3100707
  1. 8
      commom/src/main/java/com/lx/common/contant/RedisKey.java
  2. 5
      im-platform/pom.xml
  3. 2
      im-platform/src/main/java/com/lx/implatform/ImplatformApp.java
  4. 2
      im-platform/src/main/java/com/lx/implatform/config/RedisConfig.java
  5. 8
      im-platform/src/main/java/com/lx/implatform/controller/GroupController.java
  6. 34
      im-platform/src/main/java/com/lx/implatform/entity/Friend.java
  7. 8
      im-platform/src/main/java/com/lx/implatform/service/IFriendService.java
  8. 13
      im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java
  9. 4
      im-platform/src/main/java/com/lx/implatform/service/IGroupService.java
  10. 27
      im-platform/src/main/java/com/lx/implatform/service/impl/FriendServiceImpl.java
  11. 63
      im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java
  12. 53
      im-platform/src/main/java/com/lx/implatform/service/impl/GroupServiceImpl.java
  13. 5
      im-ui/src/components/common/FileUpload.vue
  14. 4
      im-ui/src/components/group/GroupMember.vue
  15. 3
      im-ui/src/store/friendStore.js
  16. 9
      im-ui/src/store/groupStore.js
  17. 2
      im-ui/src/view/Chat.vue
  18. 54
      im-ui/src/view/Friend.vue
  19. 135
      im-ui/src/view/Group.vue

8
commom/src/main/java/com/lx/common/contant/RedisKey.java

@ -2,6 +2,14 @@ package com.lx.common.contant;
public class RedisKey { public class RedisKey {
public final static String IM_CACHE = "im:cache:";
public final static String IM_CACHE_FRIEND = IM_CACHE+"friend";
public final static String IM_CACHE_GROUP = IM_CACHE+"group";
public final static String IM_CACHE_GROUP_MEMBER = IM_CACHE+"groupMember";
public final static String IM_USER_SERVER_ID = "im:user_server_id:"; public final static String IM_USER_SERVER_ID = "im:user_server_id:";
public final static String IM_UNREAD_MESSAGE = "im:unread_msg:"; public final static String IM_UNREAD_MESSAGE = "im:unread_msg:";

5
im-platform/pom.xml

@ -52,7 +52,10 @@
<artifactId>springfox-swagger-ui</artifactId> <artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version> <version>${swagger.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- 引入redis --> <!-- 引入redis -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

2
im-platform/src/main/java/com/lx/implatform/ImplatformApp.java

@ -5,9 +5,11 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Slf4j @Slf4j
@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan(basePackages = {"com.lx.implatform.mapper"}) @MapperScan(basePackages = {"com.lx.implatform.mapper"})
@ComponentScan(basePackages={"com.lx"}) @ComponentScan(basePackages={"com.lx"})
@SpringBootApplication @SpringBootApplication

2
im-platform/src/main/java/com/lx/implatform/config/RedisConfig.java

@ -98,7 +98,7 @@ public class RedisConfig extends CachingConfigurerSupport {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig() RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues() .disableCachingNullValues()
.entryTtl(Duration.ofMinutes(15)) .entryTtl(Duration.ofMinutes(10))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer())); .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build(); return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();

8
im-platform/src/main/java/com/lx/implatform/controller/GroupController.java

@ -36,7 +36,7 @@ public class GroupController {
return ResultUtils.success(groupService.modifyGroup(vo)); return ResultUtils.success(groupService.modifyGroup(vo));
} }
@ApiOperation(value = "修改群聊信息",notes="修改群聊信息") @ApiOperation(value = "解散群聊",notes="解散群聊")
@DeleteMapping("/delete/{groupId}") @DeleteMapping("/delete/{groupId}")
public Result<GroupVO> deleteGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){ public Result<GroupVO> deleteGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){
groupService.deleteGroup(groupId); groupService.deleteGroup(groupId);
@ -62,6 +62,12 @@ public class GroupController {
return ResultUtils.success(groupService.findGroupMembers(groupId)); return ResultUtils.success(groupService.findGroupMembers(groupId));
} }
@ApiOperation(value = "退出群聊",notes="退出群聊")
@DeleteMapping("/quit/{groupId}")
public Result<GroupVO> quitGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){
groupService.quitGroup(groupId);
return ResultUtils.success();
}
} }

34
im-platform/src/main/java/com/lx/implatform/entity/Friend.java

@ -13,7 +13,7 @@ import java.util.Date;
/** /**
* <p> * <p>
* *
* </p> * </p>
* *
* @author blue * @author blue
@ -24,48 +24,48 @@ import java.util.Date;
@TableName("im_friend") @TableName("im_friend")
public class Friend extends Model<Friend> { public class Friend extends Model<Friend> {
private static final long serialVersionUID=1L; private static final long serialVersionUID = 1L;
/** /**
* id * id
*/ */
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Long id; private Long id;
/** /**
* 用户id * 用户id
*/ */
@TableField("user_id") @TableField("user_id")
private Long userId; private Long userId;
/** /**
* 好友id * 好友id
*/ */
@TableField("friend_id") @TableField("friend_id")
private Long friendId; private Long friendId;
/** /**
* 用户昵称 * 用户昵称
*/ */
@TableField("friend_nick_name") @TableField("friend_nick_name")
private String friendNickName; private String friendNickName;
/** /**
* 用户头像 * 用户头像
*/ */
@TableField("friend_head_image") @TableField("friend_head_image")
private String friendHeadImage; private String friendHeadImage;
/** /**
* 创建时间 * 创建时间
*/ */
@TableField("created_time") @TableField("created_time")
private Date createdTime; private Date createdTime;
@Override @Override
protected Serializable pkVal() { protected Serializable pkVal() {
return this.id; return this.id;
} }
} }

8
im-platform/src/main/java/com/lx/implatform/service/IFriendService.java

@ -16,13 +16,13 @@ import java.util.List;
*/ */
public interface IFriendService extends IService<Friend> { public interface IFriendService extends IService<Friend> {
Boolean isFriend(Long userId1, long userId2); Boolean isFriend(Long userId1, Long userId2);
List<Friend> findFriendByUserId(long UserId); List<Friend> findFriendByUserId(Long UserId);
void addFriend(long friendId); void addFriend(Long friendId);
void delFriend(long friendId); void delFriend(Long friendId);
void update(FriendVO vo); void update(FriendVO vo);

13
im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java

@ -3,6 +3,7 @@ package com.lx.implatform.service;
import com.lx.implatform.entity.GroupMember; import com.lx.implatform.entity.GroupMember;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -17,11 +18,17 @@ public interface IGroupMemberService extends IService<GroupMember> {
GroupMember findByGroupAndUserId(Long groupId,Long userId); GroupMember findByGroupAndUserId(long groupId,long userId);
List<GroupMember> findByUserId(Long userId); List<GroupMember> findByUserId(long userId);
List<GroupMember> findByGroupId(Long groupId); List<GroupMember> findByGroupId(long groupId);
boolean save(GroupMember member);
boolean saveBatch(long groupId,List<GroupMember> members);
void removeByGroupId(long groupId); void removeByGroupId(long groupId);
void removeByGroupAndUserId(long groupId,long userId);
} }

4
im-platform/src/main/java/com/lx/implatform/service/IGroupService.java

@ -25,9 +25,13 @@ public interface IGroupService extends IService<Group> {
void deleteGroup(Long groupId); void deleteGroup(Long groupId);
void quitGroup(Long groupId);
List<GroupVO> findGroups(); List<GroupVO> findGroups();
void invite(GroupInviteVO vo); void invite(GroupInviteVO vo);
Group findById(Long id);
List<GroupMemberVO> findGroupMembers(Long groupId); List<GroupMemberVO> findGroupMembers(Long groupId);
} }

27
im-platform/src/main/java/com/lx/implatform/service/impl/FriendServiceImpl.java

@ -2,6 +2,7 @@ package com.lx.implatform.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lx.common.contant.RedisKey;
import com.lx.common.enums.ResultCode; import com.lx.common.enums.ResultCode;
import com.lx.implatform.entity.Friend; import com.lx.implatform.entity.Friend;
import com.lx.implatform.entity.User; import com.lx.implatform.entity.User;
@ -11,7 +12,11 @@ import com.lx.implatform.service.IFriendService;
import com.lx.implatform.service.IUserService; import com.lx.implatform.service.IUserService;
import com.lx.implatform.session.SessionContext; import com.lx.implatform.session.SessionContext;
import com.lx.implatform.vo.FriendVO; import com.lx.implatform.vo.FriendVO;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -25,6 +30,7 @@ import java.util.List;
* @author blue * @author blue
* @since 2022-10-22 * @since 2022-10-22
*/ */
@CacheConfig(cacheNames= RedisKey.IM_CACHE_FRIEND)
@Service @Service
public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements IFriendService { public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements IFriendService {
@ -32,7 +38,7 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
private IUserService userService; private IUserService userService;
@Override @Override
public List<Friend> findFriendByUserId(long UserId) { public List<Friend> findFriendByUserId(Long UserId) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(Friend::getUserId,UserId); queryWrapper.lambda().eq(Friend::getUserId,UserId);
List<Friend> friends = this.list(queryWrapper); List<Friend> friends = this.list(queryWrapper);
@ -42,7 +48,7 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
@Transactional @Transactional
@Override @Override
public void addFriend(long friendId) { public void addFriend(Long friendId) {
long userId = SessionContext.getSession().getId(); long userId = SessionContext.getSession().getId();
if(userId == friendId){ if(userId == friendId){
throw new GlobalException(ResultCode.PROGRAM_ERROR,"不允许添加自己为好友"); throw new GlobalException(ResultCode.PROGRAM_ERROR,"不允许添加自己为好友");
@ -55,17 +61,18 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
@Transactional @Transactional
@Override @Override
public void delFriend(long friendId) { public void delFriend(Long friendId) {
long userId = SessionContext.getSession().getId(); long userId = SessionContext.getSession().getId();
// 互相解除好友关系 // 互相解除好友关系
unbindFriend(userId,friendId); FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy();
unbindFriend(friendId,userId); proxy.unbindFriend(userId,friendId);
proxy.unbindFriend(friendId,userId);
} }
@Cacheable(key="#userId1+':'+#userId2")
@Override @Override
public Boolean isFriend(Long userId1, long userId2) { public Boolean isFriend(Long userId1, Long userId2) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId1) .eq(Friend::getUserId,userId1)
@ -92,7 +99,7 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
this.updateById(f); this.updateById(f);
} }
private void bindFriend(long userId, long friendId) { public void bindFriend(Long userId, Long friendId) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId) .eq(Friend::getUserId,userId)
@ -108,8 +115,8 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
} }
} }
@CacheEvict(key="#userId+':'+#friendId")
private void unbindFriend(long userId, long friendId) { public void unbindFriend(Long userId, Long friendId) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId) .eq(Friend::getUserId,userId)

63
im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java

@ -1,26 +1,50 @@
package com.lx.implatform.service.impl; package com.lx.implatform.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lx.common.contant.RedisKey;
import com.lx.implatform.entity.GroupMember; import com.lx.implatform.entity.GroupMember;
import com.lx.implatform.mapper.GroupMemberMapper; import com.lx.implatform.mapper.GroupMemberMapper;
import com.lx.implatform.service.IGroupMemberService; import com.lx.implatform.service.IGroupMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List; import java.util.List;
/**
* <p> @CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER)
* 群成员 服务实现类
* </p>
*
* @author blue
* @since 2022-10-31
*/
@Service @Service
public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, GroupMember> implements IGroupMemberService { public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, GroupMember> implements IGroupMemberService {
/**
* 添加群聊成员
*
* @param member 成员
* @return
*/
@CacheEvict(key="#member.getGroupId()")
@Override
public boolean save(GroupMember member) {
return super.save(member);
}
/**
* 批量添加成员
*
* @param groupId 群聊id
* @param members 成员列表
* @return
*/
@CacheEvict(key="#groupId")
@Override
public boolean saveBatch(long groupId,List<GroupMember> members) {
return super.saveBatch(members);
}
/** /**
* 根据群聊id和用户id查询群聊成员 * 根据群聊id和用户id查询群聊成员
* *
@ -29,7 +53,7 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
* @return * @return
*/ */
@Override @Override
public GroupMember findByGroupAndUserId(Long groupId, Long userId) { public GroupMember findByGroupAndUserId(long groupId, long userId) {
QueryWrapper<GroupMember> wrapper = new QueryWrapper<>(); QueryWrapper<GroupMember> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(GroupMember::getGroupId,groupId) wrapper.lambda().eq(GroupMember::getGroupId,groupId)
.eq(GroupMember::getUserId,userId); .eq(GroupMember::getUserId,userId);
@ -43,7 +67,7 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
* @return * @return
*/ */
@Override @Override
public List<GroupMember> findByUserId(Long userId) { public List<GroupMember> findByUserId(long userId) {
QueryWrapper<GroupMember> memberWrapper = new QueryWrapper(); QueryWrapper<GroupMember> memberWrapper = new QueryWrapper();
memberWrapper.lambda().eq(GroupMember::getUserId, userId); memberWrapper.lambda().eq(GroupMember::getUserId, userId);
return this.list(memberWrapper); return this.list(memberWrapper);
@ -56,7 +80,7 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
* @return * @return
*/ */
@Override @Override
public List<GroupMember> findByGroupId(Long groupId) { public List<GroupMember> findByGroupId(long groupId) {
QueryWrapper<GroupMember> memberWrapper = new QueryWrapper(); QueryWrapper<GroupMember> memberWrapper = new QueryWrapper();
memberWrapper.lambda().eq(GroupMember::getGroupId, groupId); memberWrapper.lambda().eq(GroupMember::getGroupId, groupId);
return this.list(memberWrapper); return this.list(memberWrapper);
@ -68,10 +92,27 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
* @param groupId 群聊id * @param groupId 群聊id
* @return * @return
*/ */
@CacheEvict(key = "#groupId")
@Override @Override
public void removeByGroupId(long groupId) { public void removeByGroupId(long groupId) {
QueryWrapper<GroupMember> wrapper = new QueryWrapper(); QueryWrapper<GroupMember> wrapper = new QueryWrapper();
wrapper.lambda().eq(GroupMember::getGroupId,groupId); wrapper.lambda().eq(GroupMember::getGroupId,groupId);
this.remove(wrapper); this.remove(wrapper);
} }
/**
*根据群聊id和用户id删除成员信息
*
* @param groupId 群聊id
* @param userId 用户id
* @return
*/
@CacheEvict(key = "#groupId")
@Override
public void removeByGroupAndUserId(long groupId, long userId) {
QueryWrapper<GroupMember> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(GroupMember::getGroupId,groupId)
.eq(GroupMember::getUserId,userId);
this.remove(wrapper);
}
} }

53
im-platform/src/main/java/com/lx/implatform/service/impl/GroupServiceImpl.java

@ -2,6 +2,7 @@ package com.lx.implatform.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lx.common.contant.Constant; import com.lx.common.contant.Constant;
import com.lx.common.contant.RedisKey;
import com.lx.common.enums.ResultCode; import com.lx.common.enums.ResultCode;
import com.lx.common.util.BeanUtils; import com.lx.common.util.BeanUtils;
import com.lx.implatform.entity.Friend; import com.lx.implatform.entity.Friend;
@ -22,14 +23,20 @@ import com.lx.implatform.vo.GroupMemberVO;
import com.lx.implatform.vo.GroupVO; import com.lx.implatform.vo.GroupVO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Member;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP)
@Service @Service
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService { public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService {
@ -42,6 +49,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
@Autowired @Autowired
private IFriendService friendsService; private IFriendService friendsService;
/** /**
* 创建新群聊 * 创建新群聊
* *
@ -77,6 +85,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
* @Param GroupVO 群聊信息 * @Param GroupVO 群聊信息
* @return GroupVO * @return GroupVO
**/ **/
@CacheEvict(value = "#vo.getId()")
@Transactional @Transactional
@Override @Override
public GroupVO modifyGroup(GroupVO vo) { public GroupVO modifyGroup(GroupVO vo) {
@ -86,7 +95,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
// 群主有权修改群基本信息 // 群主有权修改群基本信息
if(group.getOwnerId() == session.getId()){ if(group.getOwnerId() == session.getId()){
group = BeanUtils.copyProperties(vo,Group.class); group = BeanUtils.copyProperties(vo,Group.class);
this.save(group); this.updateById(group);
} }
// 更新成员信息 // 更新成员信息
GroupMember member = groupMemberService.findByGroupAndUserId(vo.getId(),session.getId()); GroupMember member = groupMemberService.findByGroupAndUserId(vo.getId(),session.getId());
@ -106,6 +115,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
* @return * @return
**/ **/
@Transactional @Transactional
@CacheEvict(value = "#groupId")
@Override @Override
public void deleteGroup(Long groupId) { public void deleteGroup(Long groupId) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
@ -122,6 +132,38 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
groupMemberService.removeByGroupId(groupId); groupMemberService.removeByGroupId(groupId);
} }
/**
*退出群聊
*
* @param groupId 群聊id
* @return
*/
@Override
public void quitGroup(Long groupId) {
UserSession session = SessionContext.getSession();
Group group = this.getById(groupId);
if(group == null){
throw new GlobalException(ResultCode.PROGRAM_ERROR,"群组不存在");
}
if(group.getOwnerId() == session.getId()){
throw new GlobalException(ResultCode.PROGRAM_ERROR,"您是群主,不可退出群聊");
}
// 删除群聊成员
groupMemberService.removeByGroupAndUserId(groupId,session.getId());
}
/**
*根据id查找群聊并进行缓存
*
* @param groupId 群聊id
* @return
*/
@Cacheable(value = "#groupId")
@Override
public Group findById(Long groupId){
return super.getById(groupId);
}
/** /**
* 查询当前用户的所有群聊 * 查询当前用户的所有群聊
* *
@ -160,6 +202,10 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
@Override @Override
public void invite(GroupInviteVO vo) { public void invite(GroupInviteVO vo) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
Group group = this.getById(vo.getGroupId());
if(group == null){
throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊不存在");
}
// 群聊人数校验 // 群聊人数校验
List<GroupMember> members = groupMemberService.findByGroupId(vo.getGroupId()); List<GroupMember> members = groupMemberService.findByGroupId(vo.getGroupId());
if(vo.getFriendIds().size() + members.size() > Constant.MAX_GROUP_MEMBER){ if(vo.getFriendIds().size() + members.size() > Constant.MAX_GROUP_MEMBER){
@ -186,11 +232,12 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
groupMember.setGroupId(vo.getGroupId()); groupMember.setGroupId(vo.getGroupId());
groupMember.setUserId(f.getFriendId()); groupMember.setUserId(f.getFriendId());
groupMember.setAliasName(f.getFriendNickName()); groupMember.setAliasName(f.getFriendNickName());
groupMember.setRemark(group.getName());
groupMember.setHeadImage(f.getFriendHeadImage()); groupMember.setHeadImage(f.getFriendHeadImage());
return groupMember; return groupMember;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
if(!groupMembers.isEmpty()) { if(!groupMembers.isEmpty()) {
groupMemberService.saveBatch(groupMembers); groupMemberService.saveBatch(group.getId(),groupMembers);
} }
} }
@ -209,4 +256,6 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
}).collect(Collectors.toList()); }).collect(Collectors.toList());
return vos; return vos;
} }
} }

5
im-ui/src/components/common/FileUpload.vue

@ -4,6 +4,7 @@
:show-file-list="false" :show-file-list="false"
:on-success="handleSuccess" :on-success="handleSuccess"
:on-error="handleError" :on-error="handleError"
:disabled="disabled"
:before-upload="beforeUpload"> :before-upload="beforeUpload">
<slot></slot> <slot></slot>
</el-upload> </el-upload>
@ -33,6 +34,10 @@
showLoading: { showLoading: {
type: Boolean, type: Boolean,
default: false default: false
},
disabled: {
type: Boolean,
default: false
} }
}, },
methods: { methods: {

4
im-ui/src/components/group/GroupMember.vue

@ -1,7 +1,7 @@
<template> <template>
<div class="group-member"> <div class="group-member">
<head-image :url="member.headImage" :size="60" class=""></head-image> <head-image :url="member.headImage" :size="60" class=""></head-image>
<div class="member-name">{{member.aliasName}}121212121212</div> <div class="member-name">{{member.aliasName}}</div>
</div> </div>
</template> </template>
@ -34,7 +34,7 @@
align-items: center; align-items: center;
width: 60px; width: 60px;
.member-name { .member-name {
font-size: 16px; font-size: 12px;
text-align: center; text-align: center;
width: 100%; width: 100%;
height: 30px; height: 30px;

3
im-ui/src/store/friendStore.js

@ -24,7 +24,8 @@ export default {
updateFriend(state,friend){ updateFriend(state,friend){
state.friends.forEach((f,index)=>{ state.friends.forEach((f,index)=>{
if(f.id==friend.id){ if(f.id==friend.id){
state.friends[index] = friend; // 拷贝属性
state.friends[index] = Object.assign(state.friends[index], friend);
} }
}) })
}, },

9
im-ui/src/store/groupStore.js

@ -24,10 +24,17 @@ export default {
addGroup(state,group){ addGroup(state,group){
state.groups.unshift(group); state.groups.unshift(group);
}, },
removeGroup(state,index){
state.groups.splice(index, 1);
if(state.activeIndex >= state.groups.length){
state.activeIndex = state.groups.length-1;
}
},
updateGroup(state,group){ updateGroup(state,group){
state.groups.forEach((g,index)=>{ state.groups.forEach((g,index)=>{
if(g.id==group.id){ if(g.id==group.id){
state.groups[index] = group; // 拷贝属性
state.groups[index] = Object.assign(state.groups[index], group);
} }
}) })
} }

2
im-ui/src/view/Chat.vue

@ -248,7 +248,7 @@
headImage: user.headImageThumb headImage: user.headImageThumb
}; };
this.$http({ this.$http({
url: "/api/friends/update", url: "/api/friend/update",
method: "put", method: "put",
data: friendInfo data: friendInfo
}).then(() => { }).then(() => {

54
im-ui/src/view/Friend.vue

@ -20,17 +20,17 @@
</div> </div>
</el-aside> </el-aside>
<el-container class="r-friend-box"> <el-container class="r-friend-box">
<div v-show="activeUser.id"> <div v-show="userInfo.id">
<div class="user-detail"> <div class="user-detail">
<head-image class="detail-head-image" :size="200" :url="activeUser.headImage"></head-image> <head-image class="detail-head-image" :size="200" :url="userInfo.headImage"></head-image>
<div class="info-item"> <div class="info-item">
<el-descriptions title="好友信息" class="description" :column="1"> <el-descriptions title="好友信息" class="description" :column="1">
<el-descriptions-item label="用户名">{{ activeUser.userName }} <el-descriptions-item label="用户名">{{ userInfo.userName }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="昵称">{{ activeUser.nickName }} <el-descriptions-item label="昵称">{{ userInfo.nickName }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="性别">{{ activeUser.sex==0?"男":"女" }}</el-descriptions-item> <el-descriptions-item label="性别">{{ userInfo.sex==0?"男":"女" }}</el-descriptions-item>
<el-descriptions-item label="签名">{{ activeUser.signature }}</el-descriptions-item> <el-descriptions-item label="签名">{{ userInfo.signature }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</div> </div>
</div> </div>
@ -58,7 +58,7 @@
return { return {
searchText: "", searchText: "",
showAddFriend: false, showAddFriend: false,
activeUser: {} userInfo: {}
} }
}, },
methods: { methods: {
@ -70,17 +70,7 @@
}, },
handleActiveItem(friend, index) { handleActiveItem(friend, index) {
this.$store.commit("activeFriend", index); this.$store.commit("activeFriend", index);
this.$http({ this.loadUserInfo(friend,index);
url: `/api/user/find/${friend.id}`,
method: 'get'
}).then((user) => {
this.activeUser = user;
//
if (user.headImageThumb != friend.headImage ||
user.nickName != friend.nickName) {
this.updateFriendInfo(friend, user, index)
}
})
}, },
handleDelItem(friend, index) { handleDelItem(friend, index) {
this.$http({ this.$http({
@ -95,7 +85,7 @@
}) })
}, },
handleSendMessage() { handleSendMessage() {
let user = this.activeUser; let user = this.userInfo;
let chat = { let chat = {
type: 'single', type: 'single',
targetId: user.id, targetId: user.id,
@ -108,6 +98,8 @@
this.$router.push("/home/chat"); this.$router.push("/home/chat");
}, },
updateFriendInfo(friend, user, index) { updateFriendInfo(friend, user, index) {
// storestore
friend = JSON.parse(JSON.stringify(friend));
friend.headImage = user.headImageThumb; friend.headImage = user.headImageThumb;
friend.nickName = user.nickName; friend.nickName = user.nickName;
this.$http({ this.$http({
@ -118,6 +110,30 @@
this.$store.commit("updateFriend", friend); this.$store.commit("updateFriend", friend);
this.$store.commit("updateChatFromUser", user); this.$store.commit("updateChatFromUser", user);
}) })
},
loadUserInfo(friend,index){
this.$http({
url: `/api/user/find/${friend.id}`,
method: 'get'
}).then((user) => {
this.userInfo = user;
//
if (user.headImageThumb != friend.headImage ||
user.nickName != friend.nickName) {
this.updateFriendInfo(friend, user, index)
}
})
}
},
computed:{
friendStore(){
return this.$store.state.friendStore;
}
},
mounted() {
if(this.friendStore.activeIndex>=0){
let friend = this.friendStore.friends[this.friendStore.activeIndex];
this.loadUserInfo(friend,this.friendStore.activeIndex);
} }
} }

135
im-ui/src/view/Group.vue

@ -18,20 +18,26 @@
</div> </div>
</el-aside> </el-aside>
<el-container class="r-group-box"> <el-container class="r-group-box">
<div class="r-group-header"> <div class="r-group-header" v-show="groupStore.activeIndex>=0">
{{activeGroup.remark}} {{activeGroup.remark}}({{groupMembers.length}})
</div> </div>
<div class="r-group-container"> <div class="r-group-container">
<div v-show="groupStore.activeIndex>=0"> <div v-show="groupStore.activeIndex>=0">
<div class="r-group-info"> <div class="r-group-info">
<file-upload class="avatar-uploader" action="/api/image/upload" :showLoading="true" :maxSize="maxSize" @success="handleUploadSuccess" <div>
:fileTypes="['image/jpeg', 'image/png', 'image/jpg']"> <file-upload class="avatar-uploader" action="/api/image/upload" :disabled="!isOwner" :showLoading="true"
<img v-if="activeGroup.headImage" :src="activeGroup.headImage" class="avatar"> :maxSize="maxSize" @success="handleUploadSuccess" :fileTypes="['image/jpeg', 'image/png', 'image/jpg']">
<i v-else class="el-icon-plus avatar-uploader-icon"></i> <img v-if="activeGroup.headImage" :src="activeGroup.headImage" class="avatar">
</file-upload> <i v-else class="el-icon-plus avatar-uploader-icon"></i>
<el-form class="r-group-form" label-width="130px" :model="activeGroup"> </file-upload>
<el-form-item label="群聊名称"> <el-button class="send-btn" @click="handleSendMessage()">发送消息</el-button>
<el-input v-model="activeGroup.name"></el-input> </div>
<el-form class="r-group-form" label-width="130px" :model="activeGroup" :rules="rules" ref="groupForm">
<el-form-item label="群聊名称" prop="name">
<el-input v-model="activeGroup.name" :disabled="!isOwner" maxlength="50"></el-input>
</el-form-item>
<el-form-item label="群主">
<el-input :value="ownerName" disabled maxlength="50"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="备注"> <el-form-item label="备注">
<el-input v-model="activeGroup.remark" placeholder="群聊的备注仅自己可见"></el-input> <el-input v-model="activeGroup.remark" placeholder="群聊的备注仅自己可见"></el-input>
@ -40,16 +46,16 @@
<el-input v-model="activeGroup.aliasName" placeholder=""></el-input> <el-input v-model="activeGroup.aliasName" placeholder=""></el-input>
</el-form-item> </el-form-item>
<el-form-item label="群公告"> <el-form-item label="群公告">
<el-input v-model="activeGroup.notice" type="textarea" placeholder="群主未设置"></el-input> <el-input v-model="activeGroup.notice" :disabled="!isOwner" type="textarea" placeholder="群主未设置"></el-input>
</el-form-item> </el-form-item>
<div class="btn-group">
<el-button type="success" @click="handleSaveGroup()">提交</el-button>
<el-button type="danger" v-show="!isOwner" @click="handleQuit()">退出群聊</el-button>
<el-button type="danger" v-show="isOwner" @click="handleDissolve()">解散群聊</el-button>
</div>
</el-form> </el-form>
</div> </div>
<div class="btn-group">
<el-button class="send-btn" @click="handleSaveGroup()">保存</el-button>
<el-button class="send-btn" @click="handleSendMessage()">发消息</el-button>
<el-button type="danger" class="send-btn" @click="handleSendMessage()">退出</el-button>
<el-button type="danger" class="send-btn" @click="handleSendMessage()">解散</el-button>
</div>
<el-divider content-position="center"></el-divider> <el-divider content-position="center"></el-divider>
<el-scrollbar style="height:400px;"> <el-scrollbar style="height:400px;">
<div class="r-group-member-list"> <div class="r-group-member-list">
@ -96,7 +102,14 @@
remark: "" remark: ""
}, },
groupMembers: [], groupMembers: [],
showAddGroupMember: false showAddGroupMember: false,
rules: {
name: [{
required: true,
message: '请输入群聊名称',
trigger: 'blur'
}]
}
}; };
}, },
methods: { methods: {
@ -128,21 +141,56 @@
handleCloseAddGroupMember() { handleCloseAddGroupMember() {
this.showAddGroupMember = false; this.showAddGroupMember = false;
}, },
handleUploadSuccess(res) { handleUploadSuccess(res) {
this.activeGroup.headImage = res.data.originUrl; this.activeGroup.headImage = res.data.originUrl;
this.activeGroup.headImageThumb = res.data.thumbUrl; this.activeGroup.headImageThumb = res.data.thumbUrl;
}, },
handleSaveGroup() { handleSaveGroup() {
let vo = this.activeGroup; this.$refs['groupForm'].validate((valid) => {
this.$http({ if (valid) {
url: "/api/group/modify", let vo = this.activeGroup;
method: "put", this.$http({
data: vo url: "/api/group/modify",
}).then((group) => { method: "put",
this.$store.commit("updateGroup",group); data: vo
this.$message.success("修改成功"); }).then((group) => {
this.$store.commit("updateGroup", group);
this.$message.success("修改成功");
})
}
});
},
handleDissolve() {
this.$confirm('确认要解散群聊吗?', '确认解散?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: `/api/group/delete/${this.activeGroup.id}`,
method: 'delete'
}).then(() => {
this.$store.commit("removeGroup", this.groupStore.activeIndex);
this.$store.commit("activeGroup", -1);
});
}) })
},
handleQuit() {
this.$confirm('退出群聊后将不再接受群里的消息,确认退出吗?', '确认退出?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: `/api/group/quit/${this.activeGroup.id}`,
method: 'delete'
}).then(() => {
this.$store.commit("removeGroup", this.groupStore.activeIndex);
this.$store.commit("activeGroup", -1);
});
})
}, },
handleSendMessage() { handleSendMessage() {
@ -159,6 +207,22 @@
computed: { computed: {
groupStore() { groupStore() {
return this.$store.state.groupStore; return this.$store.state.groupStore;
},
ownerName() {
let member = this.groupMembers.find((m) => m.userId == this.activeGroup.ownerId);
return member && member.aliasName;
},
isOwner() {
return this.activeGroup.ownerId == this.$store.state.userStore.userInfo.id;
}
},
mounted() {
if(this.groupStore.activeIndex>=0){
let activeGroup = this.groupStore.groups[this.groupStore.activeIndex];
// store
this.activeGroup = JSON.parse(JSON.stringify(activeGroup));
//
this.loadGroupMembers();
} }
} }
} }
@ -193,7 +257,9 @@
height: 50px; height: 50px;
padding: 5px; padding: 5px;
line-height: 50px; line-height: 50px;
font-size: 22px; font-size: 20px;
text-align: left;
text-indent: 10px;
background-color: white; background-color: white;
border: #dddddd solid 1px; border: #dddddd solid 1px;
} }
@ -207,7 +273,8 @@
.r-group-form { .r-group-form {
flex: 1; flex: 1;
padding-left: 20px; padding-left: 40px;
max-width: 800px;
} }
.avatar-uploader { .avatar-uploader {
@ -228,15 +295,15 @@
.avatar-uploader-icon { .avatar-uploader-icon {
font-size: 28px; font-size: 28px;
color: #8c939d; color: #8c939d;
width: 178px; width: 200px;
height: 178px; height: 200px;
line-height: 178px; line-height: 200px;
text-align: center; text-align: center;
} }
.avatar { .avatar {
width: 178px; width: 200px;
height: 178px; height: 200px;
display: block; display: block;
} }
} }

Loading…
Cancel
Save