init
This commit is contained in:
parent
de4cc4d73f
commit
c79086cf5e
@ -73,9 +73,9 @@ spring:
|
|||||||
default-datasource:
|
default-datasource:
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://127.0.0.1:3306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://82.156.121.2:23306/shop_dev?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
||||||
username: root
|
username: wzj
|
||||||
password: lilishop
|
password: A085F27A43B0
|
||||||
maxActive: 50
|
maxActive: 50
|
||||||
initialSize: 10
|
initialSize: 10
|
||||||
maxWait: 60000
|
maxWait: 60000
|
||||||
|
|||||||
@ -116,10 +116,10 @@
|
|||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <!– Websocket –>-->
|
<!-- <!– Websocket –>-->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
<groupId>org.springframework.boot</groupId>
|
||||||
<!-- <artifactId>spring-boot-starter-websocket</artifactId>-->
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
<!-- MybatisPlus -->
|
<!-- MybatisPlus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
|||||||
@ -1,12 +1,20 @@
|
|||||||
package cn.lili.common.vo;
|
package cn.lili.common.vo;
|
||||||
|
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
|
||||||
import cn.lili.common.utils.StringUtils;
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
* 分页视图对象
|
||||||
|
|
||||||
|
* @author Chopper
|
||||||
|
|
||||||
|
*/
|
||||||
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import cn.lili.common.utils.StringUtils;
|
||||||
/**
|
/**
|
||||||
* 查询参数
|
* 查询参数
|
||||||
*
|
*
|
||||||
@ -42,5 +50,5 @@ public class PageVO implements Serializable {
|
|||||||
}
|
}
|
||||||
return sort;
|
return sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package cn.lili.common.vo;
|
package cn.lili.common.vo;
|
||||||
|
|
||||||
|
import cn.lili.common.enums.ResultCode;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -39,4 +39,81 @@ public class ResultMessage<T> implements Serializable {
|
|||||||
* 结果对象
|
* 结果对象
|
||||||
*/
|
*/
|
||||||
private T result;
|
private T result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造空参对象
|
||||||
|
*/
|
||||||
|
public ResultMessage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建消息对象
|
||||||
|
* @param success 是否成功
|
||||||
|
* @param code 状态码
|
||||||
|
* @param message 消息
|
||||||
|
* @param result 结果
|
||||||
|
*/
|
||||||
|
public ResultMessage(boolean success, Integer code, String message, T result) {
|
||||||
|
this.success = success;
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建成功消息
|
||||||
|
* @param result 结果
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> success(T result) {
|
||||||
|
return new ResultMessage<>(true, ResultCode.SUCCESS.code(), ResultCode.SUCCESS.message(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建成功消息
|
||||||
|
* @param message 消息
|
||||||
|
* @param result 结果
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> success(String message, T result) {
|
||||||
|
return new ResultMessage<>(true, ResultCode.SUCCESS.code(), message, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建错误消息
|
||||||
|
* @param code 错误码
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> error(Integer code) {
|
||||||
|
return new ResultMessage<>(false, code, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建错误消息
|
||||||
|
* @param code 错误码
|
||||||
|
* @param message 错误消息
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> error(Integer code, String message) {
|
||||||
|
return new ResultMessage<>(false, code, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建错误消息
|
||||||
|
* @param resultCode 结果枚举
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> error(ResultCode resultCode) {
|
||||||
|
return new ResultMessage<>(false, resultCode.code(), resultCode.message(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建错误消息
|
||||||
|
* @param resultCode 结果枚举
|
||||||
|
* @param message 错误消息
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
public static <T> ResultMessage<T> error(ResultCode resultCode, String message) {
|
||||||
|
return new ResultMessage<>(false, resultCode.code(), message, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
framework/src/main/java/cn/lili/common/vo/ResultPageVO.java
Normal file
46
framework/src/main/java/cn/lili/common/vo/ResultPageVO.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package cn.lili.common.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页结果视图对象
|
||||||
|
* @author Chopper
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ResultPageVO<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "总条数")
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "当前页数")
|
||||||
|
private Long currentPage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "总页数")
|
||||||
|
private Long pages;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "每页显示的条数")
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "数据列表")
|
||||||
|
private List<T> records;
|
||||||
|
|
||||||
|
public ResultPageVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultPageVO(Long total, Long pages, Long currentPage, Long size, List<T> records) {
|
||||||
|
this.total = total;
|
||||||
|
this.pages = pages;
|
||||||
|
this.currentPage = currentPage;
|
||||||
|
this.size = size;
|
||||||
|
this.records = records;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultPageVO<T> empty() {
|
||||||
|
return new ResultPageVO<>(0L, 0L, 1L, 10L, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
package cn.lili.modules.im.config;
|
package cn.lili.modules.im.config;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.websocket.server.ServerEndpointConfig;
|
import javax.websocket.server.ServerEndpointConfig;
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ import javax.websocket.server.ServerEndpointConfig;
|
|||||||
* @version v1.0
|
* @version v1.0
|
||||||
* 2021-12-31 11:53
|
* 2021-12-31 11:53
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class CustomSpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
|
public class CustomSpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,13 +23,13 @@ public class CustomSpringConfigurator extends ServerEndpointConfig.Configurator
|
|||||||
*/
|
*/
|
||||||
private static volatile BeanFactory context;
|
private static volatile BeanFactory context;
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
|
|
||||||
return context.getBean(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
CustomSpringConfigurator.context = applicationContext;
|
CustomSpringConfigurator.context = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
|
||||||
|
return context.getBean(clazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cn.lili.modules.im.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServerEndpointExporter serverEndpointExporter() {
|
||||||
|
return new ServerEndpointExporter();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package cn.lili.modules.im.config;
|
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSocketConfigurator
|
|
||||||
*
|
|
||||||
* @author Chopper
|
|
||||||
* @version v1.0
|
|
||||||
* 2021-12-31 11:53
|
|
||||||
*/
|
|
||||||
@ConditionalOnWebApplication
|
|
||||||
@Configuration
|
|
||||||
public class WebSocketConfigurator {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CustomSpringConfigurator customSpringConfigurator() {
|
|
||||||
// This is just to get context
|
|
||||||
return new CustomSpringConfigurator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +1,82 @@
|
|||||||
package cn.lili.modules.im.entity.dos;
|
package cn.lili.modules.im.entity.dos;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import cn.lili.common.vo.SerializableStream;
|
||||||
|
import cn.lili.mybatis.BaseEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|
||||||
@TableName("li_friend")
|
@TableName("li_friend")
|
||||||
public class Friend {
|
|
||||||
|
@ApiModel(value = "好友关系")
|
||||||
|
|
||||||
|
public class Friend implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "ID")
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
// 用户ID
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户ID")
|
||||||
|
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
// 好友ID
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "好友ID")
|
||||||
|
|
||||||
private String friendId;
|
private String friendId;
|
||||||
|
|
||||||
// 好友昵称
|
|
||||||
private String nickname;
|
|
||||||
|
@ApiModelProperty(value = "好友备注")
|
||||||
// 好友头像
|
|
||||||
private String avatar;
|
|
||||||
|
|
||||||
// 好友备注
|
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
// 关系状态 (0:待确认 1:已确认 2:已拒绝 3:已解除)
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态 1:已关注")
|
||||||
|
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
// 创建时间
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否是店铺 0:否 1:是")
|
||||||
|
|
||||||
|
private Integer storeFlag;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
// 更新时间
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
|
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
}
|
@ApiModelProperty(value = "是否关注")
|
||||||
|
private Integer isMutual;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +1,51 @@
|
|||||||
package cn.lili.modules.im.entity.dos;
|
package cn.lili.modules.im.entity.dos;
|
||||||
|
|
||||||
|
import cn.lili.mybatis.BaseEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import io.swagger.annotations.ApiModel;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("li_im_group_member")
|
@TableName("li_im_group_member")
|
||||||
public class ImGroupMember {
|
@ApiModel(value = "群成员")
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
public class ImGroupMember extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ApiModelProperty(value = "成员ID")
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
// 群ID
|
@ApiModelProperty(value = "群ID")
|
||||||
private String groupId;
|
private String groupId;
|
||||||
|
|
||||||
// 成员ID
|
@ApiModelProperty(value = "成员ID")
|
||||||
private String memberId;
|
private String memberId;
|
||||||
|
|
||||||
// 成员昵称
|
@ApiModelProperty(value = "成员昵称")
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
// 成员角色(0:普通成员 1:管理员 2:群主)
|
@ApiModelProperty(value = "角色(0:普通成员 1:管理员 2:群主)")
|
||||||
private Integer role;
|
private Integer role;
|
||||||
|
|
||||||
// 是否被禁言(0:否 1:是)
|
@ApiModelProperty(value = "是否被禁言")
|
||||||
private Integer isMuted;
|
private int isMuted;
|
||||||
|
|
||||||
// 禁言结束时间
|
@ApiModelProperty(value = "禁言结束时间")
|
||||||
private Date muteEndTime;
|
private Date muteEndTime;
|
||||||
|
|
||||||
// 加入时间
|
@ApiModelProperty(value = "加入时间")
|
||||||
private Date joinTime;
|
private Date joinTime;
|
||||||
|
|
||||||
// 更新时间
|
@ApiModelProperty(value = "创建者")
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
}
|
|
||||||
|
@ApiModelProperty(value = "删除标志")
|
||||||
|
private Boolean deleteFlag;
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package cn.lili.modules.im.entity.dos;
|
||||||
|
|
||||||
|
import cn.lili.mybatis.BaseEntity;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@TableName("li_im_member")
|
||||||
|
@ApiModel(value = "IM用户")
|
||||||
|
public class ImMember extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户名")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "昵称")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
// 其他需要的字段...
|
||||||
|
}
|
||||||
@ -4,8 +4,10 @@ import cn.lili.common.utils.SnowFlake;
|
|||||||
import cn.lili.modules.im.entity.enums.MessageTypeEnum;
|
import cn.lili.modules.im.entity.enums.MessageTypeEnum;
|
||||||
import cn.lili.modules.im.entity.vo.MessageOperation;
|
import cn.lili.modules.im.entity.vo.MessageOperation;
|
||||||
import cn.lili.mybatis.BaseEntity;
|
import cn.lili.mybatis.BaseEntity;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@ -17,48 +19,83 @@ import java.util.Date;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@TableName("li_im_message")
|
@TableName("li_im_message")
|
||||||
@ApiModel(value = "Im消息")
|
@ApiModel(value = "即时通讯消息")
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class ImMessage extends BaseEntity {
|
public class ImMessage extends BaseEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@TableField("talk_id")
|
||||||
/**
|
@ApiModelProperty(value = "会话ID")
|
||||||
* 发送者
|
private String talkId;
|
||||||
*/
|
@TableField("from_user")
|
||||||
|
@ApiModelProperty(value = "发送者ID")
|
||||||
private String fromUser;
|
private String fromUser;
|
||||||
|
@TableField("to_user")
|
||||||
/**
|
@ApiModelProperty(value = "接收者ID")
|
||||||
* 接收者
|
|
||||||
*/
|
|
||||||
private String toUser;
|
private String toUser;
|
||||||
|
|
||||||
/**
|
@ApiModelProperty(value = "消息内容")
|
||||||
* 已阅
|
|
||||||
*/
|
|
||||||
private Boolean isRead;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息类型
|
|
||||||
*/
|
|
||||||
private MessageTypeEnum messageType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聊天id
|
|
||||||
*/
|
|
||||||
private String talkId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息实体
|
|
||||||
*/
|
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@TableField("message_type")
|
||||||
|
@ApiModelProperty(value = "聊天类型")
|
||||||
|
private MessageTypeEnum messageType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息状态")
|
||||||
|
private Integer status;
|
||||||
|
@TableField("is_read")
|
||||||
|
@ApiModelProperty(value = "是否已读")
|
||||||
|
private Boolean isRead;
|
||||||
|
// @TableField("read_time")
|
||||||
|
// @ApiModelProperty(value = "阅读时间")
|
||||||
|
// private Date readTime; // 确保类型为 Date
|
||||||
|
|
||||||
|
// 文件相关字段
|
||||||
|
@TableField("file_name")
|
||||||
|
@ApiModelProperty(value = "文件名")
|
||||||
|
private String fileName;
|
||||||
|
@TableField("file_size")
|
||||||
|
@ApiModelProperty(value = "文件大小")
|
||||||
|
private Long fileSize;
|
||||||
|
@TableField("file_url")
|
||||||
|
@ApiModelProperty(value = "文件URL")
|
||||||
|
private String fileUrl;
|
||||||
|
|
||||||
|
// 图片相关字段
|
||||||
|
@TableField("image_url")
|
||||||
|
@ApiModelProperty(value = "图片URL")
|
||||||
|
private String imageUrl;
|
||||||
|
@TableField("image_width")
|
||||||
|
@ApiModelProperty(value = "图片宽度")
|
||||||
|
private Integer imageWidth;
|
||||||
|
@TableField("image_height")
|
||||||
|
@ApiModelProperty(value = "图片高度")
|
||||||
|
private Integer imageHeight;
|
||||||
|
@TableField("thumbnail_url")
|
||||||
|
@ApiModelProperty(value = "缩略图URL")
|
||||||
|
private String thumbnailUrl;
|
||||||
|
|
||||||
|
// 语音相关字段
|
||||||
|
@TableField("voice_url")
|
||||||
|
@ApiModelProperty(value = "语音URL")
|
||||||
|
private String voiceUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "语音时长")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "额外信息")
|
||||||
|
private String extra;
|
||||||
|
private String groupId;
|
||||||
|
|
||||||
public ImMessage(MessageOperation messageOperation){
|
public ImMessage(MessageOperation messageOperation){
|
||||||
this.setFromUser(messageOperation.getFrom());
|
this.setFromUser(messageOperation.getFrom());
|
||||||
this.setMessageType(messageOperation.getMessageType());
|
this.setMessageType(messageOperation.getMessageType());
|
||||||
this.setIsRead(false);
|
this.setIsRead(false);
|
||||||
|
// this.setReadTime(new Date());
|
||||||
this.setText(messageOperation.getContext());
|
this.setText(messageOperation.getContext());
|
||||||
this.setTalkId(messageOperation.getTalkId());
|
this.setTalkId(messageOperation.getTalkId());
|
||||||
this.setCreateTime(new Date());
|
this.setCreateTime(new Date());
|
||||||
@ -66,4 +103,11 @@ public class ImMessage extends BaseEntity {
|
|||||||
this.setId(SnowFlake.getIdStr());
|
this.setId(SnowFlake.getIdStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMessageType(MessageTypeEnum messageType) {
|
||||||
|
this.messageType = messageType;
|
||||||
|
// if (messageType != null) {
|
||||||
|
// this.messageType = MessageTypeEnum.valueOf(messageType.getType()); // 确保type字段也使用大写
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -80,6 +80,8 @@ public class ImTalk extends BaseTenantEntity {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "坐席名称")
|
@ApiModelProperty(value = "坐席名称")
|
||||||
private String tenantName;
|
private String tenantName;
|
||||||
|
@ApiModelProperty(value = "是否关注")
|
||||||
|
private Integer isMutual;
|
||||||
|
|
||||||
|
|
||||||
public ImTalk(String userId1, String userId2,
|
public ImTalk(String userId1, String userId2,
|
||||||
@ -135,6 +137,14 @@ public class ImTalk extends BaseTenantEntity {
|
|||||||
this.name2 = member2.getNickName();
|
this.name2 = member2.getNickName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// public ImTalk2(String userId1, String userId2, String face1, String face2, String name1, String name2) {
|
||||||
|
// this.userId1 = userId1;
|
||||||
|
// this.userId2 = userId2;
|
||||||
|
// this.face1 = face1;
|
||||||
|
// this.face2 = face2;
|
||||||
|
// this.name1 = name1;
|
||||||
|
// this.name2 = name2;
|
||||||
|
// }
|
||||||
public ImTalk(Member member, Store store){
|
public ImTalk(Member member, Store store){
|
||||||
if(Long.parseLong(member.getId()) > Long.parseLong(store.getId())){
|
if(Long.parseLong(member.getId()) > Long.parseLong(store.getId())){
|
||||||
this.userId1 = store.getId();
|
this.userId1 = store.getId();
|
||||||
|
|||||||
@ -0,0 +1,84 @@
|
|||||||
|
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_member")
|
||||||
|
public class Member {
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
// 创建者
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
// 创建时间
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
// 删除标志 true/false
|
||||||
|
private Boolean deleteFlag;
|
||||||
|
|
||||||
|
// 更新者
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
// 会员生日
|
||||||
|
private Date birthday;
|
||||||
|
|
||||||
|
// 会员状态
|
||||||
|
private Boolean disabled;
|
||||||
|
|
||||||
|
// 会员头像
|
||||||
|
private String face;
|
||||||
|
|
||||||
|
// 是否开通店铺
|
||||||
|
private Boolean haveStore;
|
||||||
|
|
||||||
|
// 手机号码
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
// 会员昵称
|
||||||
|
private String nickName;
|
||||||
|
|
||||||
|
// 会员密码
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// 积分数量
|
||||||
|
private Long point;
|
||||||
|
|
||||||
|
// 会员性别
|
||||||
|
private Integer sex;
|
||||||
|
|
||||||
|
// 店铺ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
|
// 会员用户名
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
// 会员地址
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
// 会员地址ID
|
||||||
|
private String regionId;
|
||||||
|
|
||||||
|
// 客户端
|
||||||
|
private String clientEnum;
|
||||||
|
|
||||||
|
// 最后一次登录时间
|
||||||
|
private Date lastLoginDate;
|
||||||
|
|
||||||
|
// 等级ID
|
||||||
|
private String gradeId;
|
||||||
|
|
||||||
|
// 经验值
|
||||||
|
private Long experience;
|
||||||
|
|
||||||
|
// 总积分
|
||||||
|
private Long totalPoint;
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package cn.lili.modules.im.entity.dos;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("li_store") // 表名
|
||||||
|
public class Store {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id; // 主键 ID
|
||||||
|
|
||||||
|
private String createBy; // 创建者
|
||||||
|
private Date createTime; // 创建时间
|
||||||
|
private Boolean deleteFlag; // 删除标志
|
||||||
|
private String updateBy; // 更新者
|
||||||
|
private Date updateTime; // 更新时间
|
||||||
|
private String memberId; // 会员 ID
|
||||||
|
private String memberName; // 会员名称
|
||||||
|
private Boolean selfOperated; // 是否自营
|
||||||
|
private String storeDisable; // 店铺状态
|
||||||
|
private Date storeEndTime; // 店铺结束时间
|
||||||
|
private String storeLogo; // 店铺 logo
|
||||||
|
private String storeName; // 店铺名称
|
||||||
|
private String storeAddressDetail; // 详细地址
|
||||||
|
private String storeAddressIdPath; // 地址 ID 路径
|
||||||
|
private String storeAddressPath; // 地址路径
|
||||||
|
private String storeCenter; // 经纬度
|
||||||
|
private String storeDesc; // 店铺介绍
|
||||||
|
private BigDecimal deliveryScore; // 送货评分
|
||||||
|
private BigDecimal descriptionScore; // 描述评分
|
||||||
|
private BigDecimal serviceScore; // 服务评分
|
||||||
|
private Integer goodsNum; // 商品数量
|
||||||
|
private Integer collectionNum; // 收藏数量
|
||||||
|
private String yzfMpSign; // yzf mp sign
|
||||||
|
private String yzfSign; // yzf sign
|
||||||
|
|
||||||
|
// 其他字段可以根据需要添加
|
||||||
|
}
|
||||||
@ -6,9 +6,13 @@ import cn.lili.common.exception.ServiceException;
|
|||||||
import cn.lili.common.vo.PageVO;
|
import cn.lili.common.vo.PageVO;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MessageQueryParams
|
* MessageQueryParams
|
||||||
*
|
*
|
||||||
@ -18,6 +22,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
*/
|
*/
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
|
@ApiModel(value = "消息查询参数")
|
||||||
public class MessageQueryParams extends PageVO {
|
public class MessageQueryParams extends PageVO {
|
||||||
|
|
||||||
private static final long serialVersionUID = 3504156704697214077L;
|
private static final long serialVersionUID = 3504156704697214077L;
|
||||||
@ -25,15 +30,39 @@ public class MessageQueryParams extends PageVO {
|
|||||||
/**
|
/**
|
||||||
* 聊天窗口
|
* 聊天窗口
|
||||||
*/
|
*/
|
||||||
|
@ApiModelProperty(value = "会话ID")
|
||||||
private String talkId;
|
private String talkId;
|
||||||
/**
|
/**
|
||||||
* 最后一个消息
|
* 最早消息ID(用于向上加载历史消息)
|
||||||
*/
|
*/
|
||||||
private String lastMessageId;
|
@ApiModelProperty(value = "最早消息ID(用于向上加载历史消息)")
|
||||||
|
private String earliestMsgId;
|
||||||
|
/**
|
||||||
|
* 最新消息ID(用于获取新消息)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "最新消息ID(用于获取新消息)")
|
||||||
|
private String latestMsgId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取消息数量
|
* 获取消息数量
|
||||||
*/
|
*/
|
||||||
|
@ApiModelProperty(value = "返回消息数量", example = "20")
|
||||||
private Integer num;
|
private Integer num;
|
||||||
|
/**
|
||||||
|
* 消息类型(text:文本,image:图片等)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "消息类型(text:文本,image:图片等)")
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 发送者ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "发送者ID")
|
||||||
|
private String fromUser;
|
||||||
|
/**
|
||||||
|
* 接收者ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "接收者ID")
|
||||||
|
private String toUser;
|
||||||
|
|
||||||
public LambdaQueryWrapper<ImMessage> initQueryWrapper() {
|
public LambdaQueryWrapper<ImMessage> initQueryWrapper() {
|
||||||
if (CharSequenceUtil.isEmpty(talkId)) {
|
if (CharSequenceUtil.isEmpty(talkId)) {
|
||||||
@ -45,8 +74,11 @@ public class MessageQueryParams extends PageVO {
|
|||||||
|
|
||||||
LambdaQueryWrapper<ImMessage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImMessage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
lambdaQueryWrapper.eq(ImMessage::getTalkId, talkId);
|
lambdaQueryWrapper.eq(ImMessage::getTalkId, talkId);
|
||||||
if (CharSequenceUtil.isNotEmpty(lastMessageId)) {
|
if (CharSequenceUtil.isNotEmpty(earliestMsgId)) {
|
||||||
lambdaQueryWrapper.lt(ImMessage::getId, lastMessageId);
|
lambdaQueryWrapper.ge(ImMessage::getId, earliestMsgId);
|
||||||
|
}
|
||||||
|
if (CharSequenceUtil.isNotEmpty(latestMsgId)) {
|
||||||
|
lambdaQueryWrapper.le(ImMessage::getId, latestMsgId);
|
||||||
}
|
}
|
||||||
lambdaQueryWrapper.orderByDesc(ImMessage::getCreateTime);
|
lambdaQueryWrapper.orderByDesc(ImMessage::getCreateTime);
|
||||||
// lambdaQueryWrapper.last("limit " + num);
|
// lambdaQueryWrapper.last("limit " + num);
|
||||||
|
|||||||
@ -1,31 +1,53 @@
|
|||||||
package cn.lili.modules.im.entity.enums;
|
package cn.lili.modules.im.entity.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息的类型
|
* 消息状态枚举
|
||||||
*
|
|
||||||
* @author liushuai(liushuai711 @ gmail.com)
|
|
||||||
* @version v4.0
|
|
||||||
* @Description:
|
|
||||||
* @since 2022/2/10 16:36
|
|
||||||
*/
|
*/
|
||||||
public enum MessageStatusEnum {
|
public enum MessageStatusEnum {
|
||||||
//socket刚打开时发送的消息,这个一般是是刚打开socket链接,进行登录,传入token用
|
|
||||||
CONNECT,
|
NORMAL(0, "正常"),
|
||||||
//心跳类型的消息,此种类型的消息只有 type 、 text 两种属性
|
DELETED(1, "已删除"),
|
||||||
HEARTBEAT,
|
RECALLED(2, "已撤回"),
|
||||||
//用户打开一个对话框,准备跟某人聊天时
|
|
||||||
OPEN,
|
// WebSocket相关状态
|
||||||
//客服进行自动回复。客户端发起这种类型请求,则是在拉取对方是否有自动回复,如果有,服务端就会给客户端发送过自动回复的信息
|
CONNECT(100, "连接"),
|
||||||
AUTO_REPLY,
|
HEARTBEAT(101, "心跳"),
|
||||||
//正常收发消息沟通,文字、表情等沟通
|
OPEN(102, "打开对话"),
|
||||||
MSG,
|
AUTO_REPLY(103, "自动回复"),
|
||||||
//扩展。比如发送商品、发送订单
|
MSG(104, "普通消息"),
|
||||||
EXTEND,
|
EXTEND(105, "扩展消息"),
|
||||||
//系统提示,如提示 对方已离线
|
SYSTEM(106, "系统消息"),
|
||||||
SYSTEM,
|
SET_USER(107, "设置用户"),
|
||||||
//服务端发送到客户端,用于设置客户端的用户信息。会吧 com.xnx3.yunkefu.core.vo.bean.User 传过去
|
CLOSE_SERVICE(108, "结束服务");
|
||||||
SET_USER,
|
|
||||||
//结束服务
|
|
||||||
CLOSE_SERVICE;
|
|
||||||
|
|
||||||
|
private final Integer status;
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
MessageStatusEnum(Integer status, String description) {
|
||||||
|
this.status = status;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态码获取枚举
|
||||||
|
*/
|
||||||
|
public static MessageStatusEnum getByStatus(Integer status) {
|
||||||
|
if (status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (MessageStatusEnum statusEnum : values()) {
|
||||||
|
if (statusEnum.getStatus().equals(status)) {
|
||||||
|
return statusEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,45 @@
|
|||||||
package cn.lili.modules.im.entity.enums;
|
package cn.lili.modules.im.entity.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息类型
|
* 消息类型枚举
|
||||||
*
|
|
||||||
* @author liushuai
|
|
||||||
*/
|
*/
|
||||||
public enum MessageTypeEnum {
|
public enum MessageTypeEnum {
|
||||||
/**
|
MESSAGE("message", "普通消息"),
|
||||||
* 消息类型枚举
|
TEXT("TEXT", "文本消息"),
|
||||||
* <p>
|
IMAGE("IMAGE", "图片消息"),
|
||||||
* 普通消息
|
FILE("FILE", "文件消息"),
|
||||||
* 图片
|
VOICE("VOICE", "语音消息"),
|
||||||
* 语音
|
VIDEO("VIDEO", "视频消息"),
|
||||||
* 视频
|
SYSTEM("SYSTEM", "系统消息"),
|
||||||
*/
|
GROUP("GROUP", "群聊消息"),
|
||||||
MESSAGE,
|
LOCATION("LOCATION", "位置消息");
|
||||||
PICTURE,
|
|
||||||
VOICE,
|
private final String type;
|
||||||
GOODS,
|
private final String description;
|
||||||
ORDER,
|
|
||||||
VIDEO
|
MessageTypeEnum(String type, String description) {
|
||||||
|
this.type = type;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageTypeEnum fromType(String type) {
|
||||||
|
if (type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MessageTypeEnum typeEnum : MessageTypeEnum.values()) {
|
||||||
|
if (typeEnum.getType().equalsIgnoreCase(type)) {
|
||||||
|
return typeEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,5 @@ public enum OperationType {
|
|||||||
MESSAGE,
|
MESSAGE,
|
||||||
HISTORY,
|
HISTORY,
|
||||||
READ,
|
READ,
|
||||||
UNREAD,
|
UNREAD
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
package cn.lili.modules.im.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "好友申请VO")
|
||||||
|
public class FriendRequestVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请者ID")
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请者昵称")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请者头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请者手机号")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态(0:待处理 1:已接受 2:已拒绝)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "申请时间")
|
||||||
|
private Date createTime;
|
||||||
|
}
|
||||||
@ -4,18 +4,64 @@ import cn.lili.modules.im.entity.dos.Friend;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.util.Date;
|
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;
|
|
||||||
|
|
||||||
}
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
|
||||||
|
@ApiModel(value = "好友VO")
|
||||||
|
|
||||||
|
public class FriendVO implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "关系ID")
|
||||||
|
private String friendId;
|
||||||
|
private String talkId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "昵称")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "地区")
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否是店铺 0:否 1:是")
|
||||||
|
private Integer storeFlag;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否互相关注")
|
||||||
|
private Integer isMutual;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "关注时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package cn.lili.modules.im.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "群成员信息")
|
||||||
|
public class ImGroupMemberVO {
|
||||||
|
@ApiModelProperty(value = "成员ID")
|
||||||
|
private String memberId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "成员昵称")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "成员头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "角色(0:普通成员 1:管理员 2:群主)")
|
||||||
|
private Integer role;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否被禁言")
|
||||||
|
private Integer isMuted;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "禁言结束时间")
|
||||||
|
private Date muteEndTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "加入时间")
|
||||||
|
private Date joinTime;
|
||||||
|
private String displayName;
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package cn.lili.modules.im.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "群聊信息")
|
||||||
|
public class ImGroupVO {
|
||||||
|
@ApiModelProperty(value = "群ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "群名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "群头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "群公告")
|
||||||
|
private String notice;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "群主ID")
|
||||||
|
private String ownerId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "成员数量")
|
||||||
|
private Integer memberCount;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
private Integer role;
|
||||||
|
private String displayName;
|
||||||
|
@ApiModelProperty(value = "最后一条消息")
|
||||||
|
private ImMessageVO lastMessage;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "未读消息数")
|
||||||
|
private Integer unreadCount;
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package cn.lili.modules.im.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "即时通讯消息VO")
|
||||||
|
public class ImMessageVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "会话ID")
|
||||||
|
private String talkId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "发送者ID")
|
||||||
|
private String fromUser;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "发送者昵称")
|
||||||
|
private String fromName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "发送者头像")
|
||||||
|
private String fromAvatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "接收者ID")
|
||||||
|
private String toUser;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息内容")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "聊天类型(单聊/群聊)")
|
||||||
|
private String messageType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "消息状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否已读")
|
||||||
|
private Boolean isRead;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
// 扩展字段
|
||||||
|
@ApiModelProperty(value = "文件名")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件大小")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件URL")
|
||||||
|
private String fileUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "图片URL")
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "图片宽度")
|
||||||
|
private Integer imageWidth;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "图片高度")
|
||||||
|
private Integer imageHeight;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "缩略图URL")
|
||||||
|
private String thumbnailUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "语音URL")
|
||||||
|
private String voiceUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "语音时长")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "额外信息")
|
||||||
|
private String extra;
|
||||||
|
}
|
||||||
@ -53,6 +53,8 @@ public class ImTalkVO extends BaseTenantEntity {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "未读数量")
|
@ApiModelProperty(value = "未读数量")
|
||||||
private Long unread;
|
private Long unread;
|
||||||
|
@ApiModelProperty(value = "是否关注")
|
||||||
|
private Integer isMutual;
|
||||||
|
|
||||||
public ImTalkVO() {
|
public ImTalkVO() {
|
||||||
|
|
||||||
@ -66,6 +68,7 @@ public class ImTalkVO extends BaseTenantEntity {
|
|||||||
name = imTalk.getName1();
|
name = imTalk.getName1();
|
||||||
face = imTalk.getFace1();
|
face = imTalk.getFace1();
|
||||||
storeFlag = imTalk.getStoreFlag1();
|
storeFlag = imTalk.getStoreFlag1();
|
||||||
|
isMutual=imTalk.getIsMutual();
|
||||||
} else {
|
} else {
|
||||||
userId = imTalk.getUserId2();
|
userId = imTalk.getUserId2();
|
||||||
top = imTalk.getTop2();
|
top = imTalk.getTop2();
|
||||||
@ -73,6 +76,7 @@ public class ImTalkVO extends BaseTenantEntity {
|
|||||||
name = imTalk.getName2();
|
name = imTalk.getName2();
|
||||||
face = imTalk.getFace2();
|
face = imTalk.getFace2();
|
||||||
storeFlag = imTalk.getStoreFlag2();
|
storeFlag = imTalk.getStoreFlag2();
|
||||||
|
isMutual=imTalk.getIsMutual();
|
||||||
}
|
}
|
||||||
lastTalkMessage = imTalk.getLastTalkMessage();
|
lastTalkMessage = imTalk.getLastTalkMessage();
|
||||||
lastTalkTime = imTalk.getLastTalkTime();
|
lastTalkTime = imTalk.getLastTalkTime();
|
||||||
|
|||||||
@ -41,13 +41,13 @@ public class MessageOperation {
|
|||||||
|
|
||||||
public void setOperationType(String operationType) {
|
public void setOperationType(String operationType) {
|
||||||
if (!StringUtils.isEmpty(operationType)) {
|
if (!StringUtils.isEmpty(operationType)) {
|
||||||
this.operationType = OperationType.valueOf(operationType);
|
this.operationType = OperationType.valueOf(operationType.toUpperCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessageType(String messageType) {
|
public void setMessageType(String messageType) {
|
||||||
if (!StringUtils.isEmpty(messageType)) {
|
if (!StringUtils.isEmpty(messageType)) {
|
||||||
this.messageType = MessageTypeEnum.valueOf(messageType);
|
this.messageType = MessageTypeEnum.valueOf(messageType.toUpperCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,15 @@ package cn.lili.modules.im.mapper;
|
|||||||
|
|
||||||
|
|
||||||
import cn.lili.modules.im.entity.dos.Friend;
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
|
|
||||||
public interface FriendMapper extends BaseMapper<Friend> {
|
public interface FriendMapper extends BaseMapper<Friend> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
package cn.lili.modules.im.mapper;
|
package cn.lili.modules.im.mapper;
|
||||||
|
|
||||||
import cn.lili.modules.im.entity.dos.ImGroupMember;
|
import cn.lili.modules.im.entity.dos.ImGroupMember;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
|
||||||
public interface ImGroupMemberMapper extends BaseMapper<ImGroupMember> {
|
public interface ImGroupMemberMapper extends BaseMapper<ImGroupMember> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,88 +1,88 @@
|
|||||||
package cn.lili.modules.im.service;
|
package cn.lili.modules.im.service;
|
||||||
|
|
||||||
|
|
||||||
import cn.lili.modules.im.entity.dos.Friend;
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
|
|
||||||
import cn.lili.modules.im.entity.vo.FriendVO;
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.FriendRequestVO;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友关系业务层
|
||||||
|
*
|
||||||
|
* @author Chopper
|
||||||
|
*/
|
||||||
public interface FriendService extends IService<Friend> {
|
public interface FriendService extends IService<Friend> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取关注列表
|
||||||
* 获取互相关注的好友列表(包含详细信息)
|
|
||||||
|
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
|
* @return 关注的用户列表
|
||||||
* @return 好友列表
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
List<FriendVO> getMutualFriends(String userId);
|
List<FriendVO> getMutualFriends(String userId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取用户详细信息
|
||||||
* 获取好友详细信息
|
* @param friendId 用户ID
|
||||||
|
* @return 用户详细信息
|
||||||
* @param friendId 好友ID
|
|
||||||
|
|
||||||
* @return 好友详细信息
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FriendVO getFriendDetails(String friendId);
|
FriendVO getFriendDetails(String friendId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 取消关注
|
||||||
* 解除好友关系
|
* @param userId 当前用户ID
|
||||||
|
* @param friendId 要取消关注的用户ID
|
||||||
* @param userId 用户ID
|
|
||||||
|
|
||||||
* @param friendId 好友ID
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void removeFriend(String userId, String friendId);
|
void removeFriend(String userId, String friendId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 关注用户
|
||||||
* 添加好友
|
* @param userId 当前用户ID
|
||||||
|
* @param friendId 要关注的用户ID
|
||||||
* @param userId 用户ID
|
|
||||||
|
|
||||||
* @param friendId 好友ID
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void addFriend(String userId, String friendId);
|
void addFriend(String userId, String friendId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 通过手机号关注用户
|
||||||
* 更新好友备注
|
* @param mobile 手机号
|
||||||
|
* @param remark 备注
|
||||||
* @param userId 用户ID
|
*/
|
||||||
|
void addFriendByMobile(String mobile, String remark);
|
||||||
* @param friendId 好友ID
|
|
||||||
|
/**
|
||||||
|
* 更新备注
|
||||||
|
* @param userId 当前用户ID
|
||||||
|
* @param friendId 关注的用户ID
|
||||||
* @param remark 备注
|
* @param remark 备注
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void updateRemark(String userId, String friendId, String remark);
|
void updateRemark(String userId, String friendId, String remark);
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 获取好友申请列表
|
||||||
|
// * @param userId 用户ID
|
||||||
|
// * @return 申请列表
|
||||||
|
// */
|
||||||
|
// List<FriendRequestVO> getFriendRequests(String userId);
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 接受好友申请
|
||||||
|
// * @param requestId 申请ID
|
||||||
|
// * @param userId 当前用户ID
|
||||||
|
// */
|
||||||
|
// void acceptFriendRequest(String requestId, String userId);
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 拒绝好友申请
|
||||||
|
// * @param requestId 申请ID
|
||||||
|
// * @param userId 当前用户ID
|
||||||
|
// */
|
||||||
|
// void rejectFriendRequest(String requestId, String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索用户
|
||||||
|
* @param keyword 搜索关键词(用户名/手机号)
|
||||||
|
* @param onlyStore 是否只搜索店铺
|
||||||
|
* @param currentUserId 当前用户ID
|
||||||
|
* @return 用户列表
|
||||||
|
*/
|
||||||
|
List<FriendVO> searchUsers(String keyword, Boolean onlyStore, String currentUserId);
|
||||||
}
|
}
|
||||||
@ -1,58 +1,154 @@
|
|||||||
package cn.lili.modules.im.service;
|
package cn.lili.modules.im.service;
|
||||||
|
|
||||||
import cn.lili.modules.im.entity.dos.ImGroup;
|
import cn.lili.modules.im.entity.dos.ImGroup;
|
||||||
|
|
||||||
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupMemberVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupVO;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface ImGroupService extends IService<ImGroup> {
|
public interface ImGroupService extends IService<ImGroup> {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建群聊
|
* 获取用户加入的群聊列表
|
||||||
* @param groupName 群名称
|
* @param userId 用户ID
|
||||||
* @param memberIds 邀请的成员ID列表
|
* @return 群聊列表
|
||||||
* @return 群聊信息
|
|
||||||
*/
|
*/
|
||||||
|
List<ImGroupVO> getUserGroups(String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群聊详情
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @return 群聊详情
|
||||||
|
*/
|
||||||
|
ImGroupVO getGroupDetail(String groupId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群成员列表
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @return 群成员列表
|
||||||
|
*/
|
||||||
|
List<ImGroupMemberVO> getGroupMembers(String groupId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出群聊
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
void quitGroup(String groupId, String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改群信息
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @param groupName 群名称
|
||||||
|
* @param notice 群公告
|
||||||
|
* @param avatar 群头像
|
||||||
|
*/
|
||||||
|
void updateGroupInfo(String groupId, String groupName, String notice, String avatar);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
* 创建群聊
|
||||||
|
|
||||||
|
* @param groupName 群名称
|
||||||
|
|
||||||
|
* @param memberIds 邀请的成员ID列表
|
||||||
|
|
||||||
|
* @return 群聊信息
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
ImGroup createGroup(String groupName, List<String> memberIds);
|
ImGroup createGroup(String groupName, List<String> memberIds);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* 解散群聊
|
* 解散群聊
|
||||||
|
|
||||||
* @param groupId 群ID
|
* @param groupId 群ID
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void dismissGroup(String groupId);
|
void dismissGroup(String groupId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* 邀请成员
|
* 邀请成员
|
||||||
|
|
||||||
* @param groupId 群ID
|
* @param groupId 群ID
|
||||||
|
|
||||||
* @param memberIds 成员ID列表
|
* @param memberIds 成员ID列表
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void inviteMembers(String groupId, List<String> memberIds);
|
void inviteMembers(String groupId, List<String> memberIds);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* 设置管理员
|
* 设置管理员
|
||||||
|
|
||||||
* @param groupId 群ID
|
* @param groupId 群ID
|
||||||
|
|
||||||
* @param memberId 成员ID
|
* @param memberId 成员ID
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void setAdmin(String groupId, String memberId);
|
void setAdmin(String groupId, String memberId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* 取消管理员
|
* 取消管理员
|
||||||
|
|
||||||
* @param groupId 群ID
|
* @param groupId 群ID
|
||||||
|
|
||||||
* @param memberId 成员ID
|
* @param memberId 成员ID
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void removeAdmin(String groupId, String memberId);
|
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 groupId 群ID
|
||||||
|
|
||||||
* @param memberId 成员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);
|
void unmuteMember(String groupId, String memberId);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,10 @@
|
|||||||
package cn.lili.modules.im.service;
|
package cn.lili.modules.im.service;
|
||||||
|
|
||||||
|
import cn.lili.common.vo.PageVO;
|
||||||
|
import cn.lili.common.vo.ResultPageVO;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||||
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImMessageVO;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,6 +16,33 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface ImMessageService extends IService<ImMessage> {
|
public interface ImMessageService extends IService<ImMessage> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取历史消息
|
||||||
|
* @param talkId 对话ID
|
||||||
|
* @param earliestMsgId 最早消息ID
|
||||||
|
* @param pageSize 每页大小
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
List<ImMessageVO> getHistoryMessages(String talkId, String earliestMsgId, Integer pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最近消息
|
||||||
|
* @param talkId 对话ID
|
||||||
|
* @param latestMsgId 最新消息ID
|
||||||
|
* @param pageSize 每页大小
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
List<ImMessageVO> getRecentMessages(String talkId, String latestMsgId, Integer pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
* @param toId 接收者ID
|
||||||
|
* @param content 消息内容
|
||||||
|
* @param type 消息类型
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
ImMessageVO sendMessage(String toId, String content, String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 阅读消息
|
* 阅读消息
|
||||||
*
|
*
|
||||||
@ -63,4 +93,60 @@ public interface ImMessageService extends IService<ImMessage> {
|
|||||||
* 清空所有未读消息
|
* 清空所有未读消息
|
||||||
*/
|
*/
|
||||||
void cleanUnreadMessage();
|
void cleanUnreadMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群聊消息历史
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @param pageNumber 页码
|
||||||
|
* @param pageSize 每页大小
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
ResultPageVO<ImMessageVO> getGroupMessages(String groupId, Integer pageNumber, Integer pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送群聊消息
|
||||||
|
* @param groupId 群ID
|
||||||
|
* @param content 消息内容
|
||||||
|
* @param type 消息类型
|
||||||
|
* @return 消息对象
|
||||||
|
*/
|
||||||
|
ImMessageVO sendGroupMessage(String groupId, String content, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回消息
|
||||||
|
* @param messageId 消息ID
|
||||||
|
*/
|
||||||
|
void recallMessage(String messageId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载历史消息
|
||||||
|
* @param talkId 会话ID
|
||||||
|
* @param earliestMsgId 最早消息ID
|
||||||
|
* @param size 每页大小
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
List<ImMessageVO> loadHistoryMessages(String talkId, String earliestMsgId, Integer size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载最新消息
|
||||||
|
* @param talkId 会话ID
|
||||||
|
* @param size 每页大小
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
List<ImMessageVO> loadLatestMessages(String talkId, Integer size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取新消息
|
||||||
|
* @param talkId 会话ID
|
||||||
|
* @param latestMsgId 最新消息ID
|
||||||
|
* @return 新消息列表
|
||||||
|
*/
|
||||||
|
List<ImMessageVO> getNewerMessages(String talkId, String latestMsgId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记消息已读
|
||||||
|
* @param messages 消息列表
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
void readMessages(List<ImMessage> messages, String userId);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package cn.lili.modules.im.service;
|
||||||
|
|
||||||
|
import cn.lili.modules.im.entity.vo.MessageVO;
|
||||||
|
|
||||||
|
public interface MessageSender {
|
||||||
|
void sendMessage(String sessionId, MessageVO message);
|
||||||
|
}
|
||||||
@ -1,344 +1,404 @@
|
|||||||
package cn.lili.modules.im.serviceimpl;
|
package cn.lili.modules.im.serviceimpl;
|
||||||
import cn.lili.common.security.context.UserContext;
|
|
||||||
import cn.lili.common.security.enums.UserEnums;
|
import cn.lili.common.enums.ResultCode;
|
||||||
import cn.lili.common.exception.ServiceException;
|
import cn.lili.common.exception.ServiceException;
|
||||||
import cn.lili.common.utils.StringUtils;
|
import cn.lili.common.security.AuthUser;
|
||||||
|
import cn.lili.common.security.context.UserContext;
|
||||||
import cn.lili.modules.im.entity.dos.Friend;
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
|
import cn.lili.modules.im.entity.dos.ImTalk;
|
||||||
import cn.lili.modules.im.entity.vo.FriendVO;
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.FriendRequestVO;
|
||||||
import cn.lili.modules.im.mapper.FriendMapper;
|
import cn.lili.modules.im.mapper.FriendMapper;
|
||||||
import cn.lili.modules.im.service.FriendService;
|
import cn.lili.modules.im.service.FriendService;
|
||||||
|
import cn.lili.modules.im.service.ImTalkService;
|
||||||
import cn.lili.modules.member.entity.dos.Member;
|
import cn.lili.modules.member.entity.dos.Member;
|
||||||
import cn.lili.modules.member.mapper.MemberMapper;
|
import cn.lili.modules.member.service.MemberService;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import static cn.hutool.extra.pinyin.PinyinUtil.getFirstLetter;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友业务层实现
|
||||||
|
*
|
||||||
|
* @author Chopper
|
||||||
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements FriendService {
|
public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements FriendService {
|
||||||
@Autowired
|
private final ImTalkService imTalkService;
|
||||||
private MemberMapper memberMapper;
|
private final MemberService memberService;
|
||||||
|
private final FriendMapper friendMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FriendVO> getMutualFriends(String userId) {
|
public List<FriendVO> getMutualFriends(String userId) {
|
||||||
// 获取好友关系列表
|
// 验证用户登录状态
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户的ID
|
||||||
|
String currentUserId = currentUser.getId();
|
||||||
|
|
||||||
|
// 构建查询条件
|
||||||
|
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(Friend::getUserId, currentUserId) // 查询当前用户的关注列表
|
||||||
|
.eq(Friend::getStatus, 1); // 只查询状态为1的记录
|
||||||
|
|
||||||
|
// 查询关注列表
|
||||||
|
List<Friend> friends = this.list(queryWrapper);
|
||||||
|
if (friends.isEmpty()) {
|
||||||
|
return new ArrayList<>(); // 如果没有找到,返回空列表
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收集所有关注的用户ID
|
||||||
|
List<String> friendIds = friends.stream()
|
||||||
|
.map(Friend::getFriendId) // 获取 friendId
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 检查 friendIds 是否为空
|
||||||
|
if (friendIds.isEmpty()) {
|
||||||
|
log.warn("No friend IDs found for user: {}", currentUserId);
|
||||||
|
return new ArrayList<>(); // 或者抛出异常
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量查询用户信息
|
||||||
|
List<Member> members = memberService.listByIds(friendIds);
|
||||||
|
Map<String, Member> memberMap = members.stream()
|
||||||
|
.collect(Collectors.toMap(Member::getId, member -> member));
|
||||||
|
|
||||||
|
// 组装VO对象
|
||||||
|
return friends.stream().map(friend -> {
|
||||||
|
Member member = memberMap.get(friend.getFriendId());
|
||||||
|
if (member != null) {
|
||||||
|
FriendVO vo = new FriendVO();
|
||||||
|
vo.setId(member.getId().toString()); // 设置为用户的 ID
|
||||||
|
vo.setFriendId(friend.getFriendId()); // 设置为 Friend 的 ID
|
||||||
|
vo.setNickname(member.getNickName());
|
||||||
|
vo.setAvatar(member.getFace());
|
||||||
|
// 其他字段设置...
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 假设这个方法用于从 ImTalk 表中获取 talkId
|
||||||
|
private String getTalkId(String userId1, String userId2) {
|
||||||
|
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper
|
||||||
|
.or().eq(ImTalk::getUserId1, userId1).eq(ImTalk::getUserId2, userId2)
|
||||||
|
.or().eq(ImTalk::getUserId1, userId2).eq(ImTalk::getUserId2, userId1);
|
||||||
|
|
||||||
|
ImTalk imTalk = imTalkService.getOne(queryWrapper);
|
||||||
|
return imTalk != null ? imTalk.getId() : null; // 返回 talkId
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void addFriend(String userId, String friendId) {
|
||||||
|
// 验证用户登录状态
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已经关注
|
||||||
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(Friend::getUserId, userId)
|
queryWrapper.eq(Friend::getUserId, userId)
|
||||||
.eq(Friend::getStatus, 1); // 已确认的好友关系
|
.eq(Friend::getFriendId, friendId);
|
||||||
List<Friend> friends = this.list(queryWrapper);
|
|
||||||
|
|
||||||
|
// 如果已经关注,抛出异常
|
||||||
// 转换为 FriendVO 列表
|
if (this.count(queryWrapper) > 0) {
|
||||||
List<FriendVO> friendVOs = new ArrayList<>();
|
throw new ServiceException("您已经关注过该用户");
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 创建新的关注关系
|
||||||
|
Friend friend = new Friend();
|
||||||
|
friend.setUserId(userId);
|
||||||
|
friend.setFriendId(friendId);
|
||||||
|
friend.setStatus(1); // 设置为已关注状态
|
||||||
|
friend.setIsMutual(1);
|
||||||
|
friend.setCreateTime(new Date());
|
||||||
|
// friend.setUpdateTime(new Date());
|
||||||
|
|
||||||
return friendVOs;
|
// 检查对方是否也关注了当前用户
|
||||||
|
Integer mutualStatus = isFollowing(friendId, userId); // 检查 friendId 是否关注了 userId
|
||||||
|
|
||||||
|
// 设置互相关注状态
|
||||||
|
if (mutualStatus == 1) {
|
||||||
|
friend.setIsMutual(2); // 设置为互相关注
|
||||||
|
} else {
|
||||||
|
friend.setIsMutual(1); // 设置为单向关注
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存关注关系
|
||||||
|
this.save(friend);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 获取字符串的首字母
|
|
||||||
* @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
|
@Override
|
||||||
public FriendVO getFriendDetails(String friendId) {
|
public FriendVO getFriendDetails(String friendId) {
|
||||||
String userId = UserContext.getCurrentUser().getId();
|
// 验证用户登录状态
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
// 查询好友关系
|
// 获取好友信息
|
||||||
|
Member member = memberService.getById(friendId);
|
||||||
|
if (member == null) {
|
||||||
|
throw new ServiceException("用户不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
FriendVO vo = new FriendVO();
|
||||||
|
vo.setId(member.getId().toString());
|
||||||
|
vo.setNickname(member.getNickName());
|
||||||
|
vo.setAvatar(member.getFace());
|
||||||
|
vo.setRegion(member.getRegion());
|
||||||
|
vo.setMobile(member.getMobile());
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
vo.setRemark(""); // 或者设置为 null
|
||||||
|
vo.setStoreFlag(member.getHaveStore() ? 1 : 0); // 假设你有这个字段
|
||||||
|
vo.setCreateTime(new Date()); // 或者设置为 null
|
||||||
|
|
||||||
|
// 获取当前用户ID
|
||||||
|
String currentUserId = currentUser.getId();
|
||||||
|
|
||||||
|
// 查询Friend表以获取isMutual值
|
||||||
|
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(Friend::getUserId, currentUserId)
|
||||||
|
.eq(Friend::getFriendId, friendId);
|
||||||
|
|
||||||
|
Friend friendRelation = this.getOne(queryWrapper);
|
||||||
|
if (friendRelation != null) {
|
||||||
|
vo.setIsMutual(friendRelation.getIsMutual()); // 设置isMutual值
|
||||||
|
vo.setFriendId(friendRelation.getFriendId());
|
||||||
|
} else {
|
||||||
|
vo.setIsMutual(0); // 如果没有找到关系,设置为未关注
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeFriend(String userId, String friendId) {
|
||||||
|
// 验证用户登录状态
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证操作权限
|
||||||
|
if (!currentUser.getId().equals(userId)) {
|
||||||
|
throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消关注
|
||||||
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(Friend::getUserId, userId)
|
queryWrapper.eq(Friend::getUserId, userId)
|
||||||
.eq(Friend::getFriendId, friendId);
|
.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<Friend> 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)) {
|
if (!this.remove(queryWrapper)) {
|
||||||
|
throw new ServiceException("取消关注失败");
|
||||||
throw new ServiceException("解除好友关系失败");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@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) {
|
public void updateRemark(String userId, String friendId, String remark) {
|
||||||
|
// 验证用户登录状态
|
||||||
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
queryWrapper.eq(Friend::getUserId, userId)
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
|
||||||
.eq(Friend::getFriendId, friendId);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Friend friend = this.getOne(queryWrapper);
|
|
||||||
|
|
||||||
if (friend == null) {
|
|
||||||
|
|
||||||
throw new ServiceException("好友关系不存在");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证操作权限
|
||||||
|
if (!currentUser.getId().equals(userId)) {
|
||||||
friend.setRemark(remark);
|
throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
|
||||||
|
|
||||||
friend.setUpdateTime(new Date());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!this.updateById(friend)) {
|
|
||||||
|
|
||||||
throw new ServiceException("更新好友备注失败");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// 更新备注
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
* 检查是否已经是好友关系
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
private boolean checkFriendship(String userId, String friendId) {
|
|
||||||
|
|
||||||
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<Friend> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
||||||
queryWrapper.eq(Friend::getUserId, userId)
|
queryWrapper.eq(Friend::getUserId, userId)
|
||||||
|
|
||||||
.eq(Friend::getFriendId, friendId)
|
.eq(Friend::getFriendId, friendId)
|
||||||
|
|
||||||
.eq(Friend::getStatus, 1);
|
.eq(Friend::getStatus, 1);
|
||||||
|
|
||||||
return this.count(queryWrapper) > 0;
|
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("更新备注失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFriendByMobile(String mobile, String remark) {
|
||||||
|
// 查找目标用户
|
||||||
|
Member targetMember = memberService.findByMobile(mobile);
|
||||||
|
if (targetMember == null) {
|
||||||
|
throw new ServiceException("该手机号未注册");
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
String targetUserId = targetMember.getId().toString();
|
||||||
|
|
||||||
|
// 不能关注自己
|
||||||
|
if (currentUserId.equals(targetUserId)) {
|
||||||
|
throw new ServiceException("不能关注自己");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已经关注
|
||||||
|
if (isFollowing(currentUserId, targetUserId) > 0) {
|
||||||
|
throw new ServiceException("已经关注该用户");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
// 创建关注关系
|
||||||
|
Friend friend = new Friend();
|
||||||
|
friend.setUserId(currentUserId);
|
||||||
|
friend.setFriendId(targetUserId);
|
||||||
|
friend.setRemark(remark);
|
||||||
|
friend.setStatus(1);
|
||||||
|
friend.setIsMutual(1); // 直接设置为已关注状态
|
||||||
|
friend.setStoreFlag(targetMember.getHaveStore() ? 1 : 0); // 设置是否是店铺
|
||||||
|
friend.setCreateTime(new Date());
|
||||||
|
// friend.setUpdateTime(new Date());
|
||||||
|
|
||||||
|
// 检查对方是否也关注了当前用户
|
||||||
|
Integer mutualStatus = isFollowing(targetUserId, currentUserId);
|
||||||
|
|
||||||
|
// 设置互相关注状态
|
||||||
|
if (mutualStatus == 1) {
|
||||||
|
friend.setIsMutual(2); // 设置为互相关注
|
||||||
|
} else {
|
||||||
|
friend.setIsMutual(1); // 设置为单向关注
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存关注关系
|
||||||
|
this.save(friend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否是好友关系(互相关注)
|
||||||
|
*/
|
||||||
|
private Integer isFriend(String userId, String friendId) {
|
||||||
|
// 检查是否互相关注
|
||||||
|
Integer isUserFollowingFriend = isFollowing(userId, friendId);
|
||||||
|
Integer isFriendFollowingUser = isFollowing(friendId, userId);
|
||||||
|
|
||||||
|
// 如果双方都关注,返回 2;如果只有一个方向关注,返回 1;否则返回 0
|
||||||
|
if (isUserFollowingFriend == 1 && isFriendFollowingUser == 1) {
|
||||||
|
return 2; // 互相关注
|
||||||
|
} else if (isUserFollowingFriend == 1 || isFriendFollowingUser == 1) {
|
||||||
|
return 1; // 单向关注
|
||||||
|
}
|
||||||
|
return 0; // 未关注
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否已关注
|
||||||
|
*/
|
||||||
|
public Integer isFollowing(String currentUserId, String targetUserId) {
|
||||||
|
// 查询当前用户是否关注目标用户
|
||||||
|
Long count = friendMapper.selectCount(new LambdaQueryWrapper<Friend>()
|
||||||
|
.eq(Friend::getUserId, currentUserId)
|
||||||
|
.eq(Friend::getFriendId, targetUserId)
|
||||||
|
.eq(Friend::getIsMutual, 1)); // 确保状态为已关注
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// 查询目标用户是否也关注当前用户
|
||||||
|
Long mutualCount = friendMapper.selectCount(new LambdaQueryWrapper<Friend>()
|
||||||
|
.eq(Friend::getUserId, targetUserId)
|
||||||
|
.eq(Friend::getFriendId, currentUserId)
|
||||||
|
.eq(Friend::getIsMutual, 1)); // 确保状态为已关注
|
||||||
|
|
||||||
|
return mutualCount > 0 ? 2 : 1; // 2 表示互相关注,1 表示单向关注
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // 未关注
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FriendVO> searchUsers(String keyword, Boolean onlyStore, String currentUserId) {
|
||||||
|
// 构建查询条件
|
||||||
|
LambdaQueryWrapper<Member> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.and(wrapper -> wrapper
|
||||||
|
.like(Member::getNickName, keyword)
|
||||||
|
.or()
|
||||||
|
.like(Member::getMobile, keyword)
|
||||||
|
)
|
||||||
|
.ne(Member::getId, currentUserId); // 排除自己
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(onlyStore)) {
|
||||||
|
queryWrapper.eq(Member::getHaveStore, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制返回数量
|
||||||
|
queryWrapper.last("LIMIT 20");
|
||||||
|
|
||||||
|
// 查询用户
|
||||||
|
List<Member> members = memberService.list(queryWrapper);
|
||||||
|
if (members.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取已关注的用户ID
|
||||||
|
List<String> memberIds = members.stream()
|
||||||
|
.map(member -> member.getId().toString())
|
||||||
|
.distinct() // 确保唯一
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 查询当前用户与这些用户的关注关系
|
||||||
|
LambdaQueryWrapper<Friend> friendWrapper = new LambdaQueryWrapper<>();
|
||||||
|
friendWrapper.eq(Friend::getUserId, currentUserId)
|
||||||
|
.in(Friend::getFriendId, memberIds)
|
||||||
|
.eq(Friend::getStatus, 1);
|
||||||
|
List<Friend> friends = this.list(friendWrapper);
|
||||||
|
|
||||||
|
// 构建已关注用户的Map
|
||||||
|
Map<String, Friend> friendMap = friends.stream()
|
||||||
|
.collect(Collectors.toMap(Friend::getFriendId, friend -> friend, (existing, replacement) -> existing)); // 处理重复键
|
||||||
|
|
||||||
|
// 转换为VO对象
|
||||||
|
return members.stream().map(member -> {
|
||||||
|
FriendVO vo = new FriendVO();
|
||||||
|
vo.setId(member.getId().toString());
|
||||||
|
vo.setNickname(member.getNickName());
|
||||||
|
vo.setAvatar(member.getFace());
|
||||||
|
vo.setRegion(member.getRegion());
|
||||||
|
vo.setMobile(member.getMobile());
|
||||||
|
vo.setStoreFlag(member.getHaveStore() ? 1 : 0);
|
||||||
|
|
||||||
|
// 设置是否互相关注
|
||||||
|
Friend friend = friendMap.get(member.getId().toString());
|
||||||
|
if (friend != null) {
|
||||||
|
vo.setFriendId(friend.getId());
|
||||||
|
vo.setRemark(friend.getRemark());
|
||||||
|
vo.setCreateTime(friend.getCreateTime());
|
||||||
|
// 检查是否互相关注
|
||||||
|
vo.setIsMutual(friend.getIsMutual() != null ? friend.getIsMutual() : 0);
|
||||||
|
} else {
|
||||||
|
vo.setIsMutual(0); // 如果没有找到对应的 Friend 记录,设置为 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}).distinct() // 确保返回的 VO 对象唯一
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,50 +1,216 @@
|
|||||||
package cn.lili.modules.im.serviceimpl;
|
package cn.lili.modules.im.serviceimpl;
|
||||||
|
|
||||||
|
import cn.lili.common.enums.ResultCode;
|
||||||
|
import cn.lili.common.security.AuthUser;
|
||||||
import cn.lili.common.security.context.UserContext;
|
import cn.lili.common.security.context.UserContext;
|
||||||
import cn.lili.common.exception.ServiceException;
|
import cn.lili.common.exception.ServiceException;
|
||||||
import cn.lili.modules.im.entity.dos.ImGroup;
|
import cn.lili.modules.im.entity.dos.ImGroup;
|
||||||
import cn.lili.modules.im.entity.dos.ImGroupMember;
|
import cn.lili.modules.im.entity.dos.ImGroupMember;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupMemberVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupVO;
|
||||||
import cn.lili.modules.im.mapper.ImGroupMapper;
|
import cn.lili.modules.im.mapper.ImGroupMapper;
|
||||||
import cn.lili.modules.im.mapper.ImGroupMemberMapper;
|
import cn.lili.modules.im.mapper.ImGroupMemberMapper;
|
||||||
import cn.lili.modules.im.service.ImGroupService;
|
import cn.lili.modules.im.service.ImGroupService;
|
||||||
|
import cn.lili.modules.im.service.FriendService;
|
||||||
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
|
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.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> implements ImGroupService {
|
public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> implements ImGroupService {
|
||||||
|
|
||||||
private final ImGroupMemberMapper groupMemberMapper;
|
private final ImGroupMemberMapper groupMemberMapper;
|
||||||
|
private final MemberMapper memberMapper;
|
||||||
|
private final FriendService friendService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
public List<ImGroupVO> getUserGroups(String userId) {
|
||||||
public ImGroup createGroup(String groupName, List<String> memberIds) {
|
// 查询用户加入的群组
|
||||||
|
LambdaQueryWrapper<ImGroupMember> memberQuery = new LambdaQueryWrapper<>();
|
||||||
|
memberQuery.eq(ImGroupMember::getMemberId, userId);
|
||||||
|
List<ImGroupMember> groupMembers = groupMemberMapper.selectList(memberQuery);
|
||||||
|
|
||||||
|
if (groupMembers.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群组ID列表
|
||||||
|
List<String> groupIds = groupMembers.stream()
|
||||||
|
.map(ImGroupMember::getGroupId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 批量查询群组信息
|
||||||
|
List<ImGroup> groups = this.listByIds(groupIds);
|
||||||
|
|
||||||
|
// 转换为VO对象
|
||||||
|
return groups.stream().map(group -> {
|
||||||
|
ImGroupVO vo = new ImGroupVO();
|
||||||
|
BeanUtils.copyProperties(group, vo);
|
||||||
|
|
||||||
|
// 设置成员数量
|
||||||
|
vo.setMemberCount(getGroupMemberCount(group.getId()));
|
||||||
|
|
||||||
|
// TODO: 设置最后一条消息和未读数
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImGroupVO getGroupDetail(String groupId) {
|
||||||
|
// 获取群组基本信息
|
||||||
|
ImGroup group = this.getById(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
throw new ServiceException("群组不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
ImGroupVO vo = new ImGroupVO();
|
||||||
|
BeanUtils.copyProperties(group, vo);
|
||||||
|
|
||||||
|
// 设置成员数量
|
||||||
|
vo.setMemberCount(getGroupMemberCount(groupId));
|
||||||
|
|
||||||
|
// TODO: 设置最后一条消息和未读数
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImGroupMemberVO> getGroupMembers(String groupId) {
|
||||||
|
// 查询群成员
|
||||||
|
LambdaQueryWrapper<ImGroupMember> memberQuery = new LambdaQueryWrapper<>();
|
||||||
|
memberQuery.eq(ImGroupMember::getGroupId, groupId)
|
||||||
|
.orderByDesc(ImGroupMember::getRole)
|
||||||
|
.orderByAsc(ImGroupMember::getJoinTime);
|
||||||
|
|
||||||
|
List<ImGroupMember> members = groupMemberMapper.selectList(memberQuery);
|
||||||
|
|
||||||
|
if (members.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取成员用户信息
|
||||||
|
List<String> memberIds = members.stream()
|
||||||
|
.map(ImGroupMember::getMemberId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Member> users = memberMapper.selectBatchIds(memberIds);
|
||||||
|
Map<String, Member> userMap = users.stream()
|
||||||
|
.collect(Collectors.toMap(member -> member.getId().toString(), member -> member));
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
return members.stream().map(member -> {
|
||||||
|
ImGroupMemberVO vo = new ImGroupMemberVO();
|
||||||
|
BeanUtils.copyProperties(member, vo);
|
||||||
|
|
||||||
|
Member user = userMap.get(member.getMemberId());
|
||||||
|
if (user != null) {
|
||||||
|
vo.setNickname(user.getNickName());
|
||||||
|
vo.setAvatar(user.getFace());
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void quitGroup(String groupId, String userId) {
|
||||||
|
// 验证群组是否存在
|
||||||
|
ImGroup group = this.getById(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
throw new ServiceException("群组不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 群主不能退群
|
||||||
|
if (group.getOwnerId().equals(userId)) {
|
||||||
|
throw new ServiceException("群主不能退群");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除群成员记录
|
||||||
|
LambdaQueryWrapper<ImGroupMember> memberQuery = new LambdaQueryWrapper<>();
|
||||||
|
memberQuery.eq(ImGroupMember::getGroupId, groupId)
|
||||||
|
.eq(ImGroupMember::getMemberId, userId);
|
||||||
|
|
||||||
|
groupMemberMapper.delete(memberQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateGroupInfo(String groupId, String groupName, String notice, String avatar) {
|
||||||
|
// 验证群组是否存在
|
||||||
|
ImGroup group = this.getById(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
throw new ServiceException("群组不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证操作权限
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
LambdaQueryWrapper<ImGroupMember> memberQuery = new LambdaQueryWrapper<>();
|
||||||
|
memberQuery.eq(ImGroupMember::getGroupId, groupId)
|
||||||
|
.eq(ImGroupMember::getMemberId, currentUserId)
|
||||||
|
.ge(ImGroupMember::getRole, 1); // 管理员及以上权限
|
||||||
|
|
||||||
|
if (groupMemberMapper.selectCount(memberQuery) == 0) {
|
||||||
|
throw new ServiceException("没有权限修改群信息");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新群信息
|
||||||
|
ImGroup updateGroup = new ImGroup();
|
||||||
|
updateGroup.setId(groupId);
|
||||||
|
if (groupName != null) {
|
||||||
|
updateGroup.setName(groupName);
|
||||||
|
}
|
||||||
|
if (notice != null) {
|
||||||
|
updateGroup.setNotice(notice);
|
||||||
|
}
|
||||||
|
if (avatar != null) {
|
||||||
|
updateGroup.setAvatar(avatar);
|
||||||
|
}
|
||||||
|
updateGroup.setUpdateTime(new Date());
|
||||||
|
|
||||||
|
this.updateById(updateGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImGroup createGroup(String groupName, List<String> memberIds) {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
// 创建群组
|
// 创建群组
|
||||||
ImGroup group = new ImGroup();
|
ImGroup group = new ImGroup();
|
||||||
group.setName(groupName);
|
group.setName(groupName);
|
||||||
group.setOwnerId(currentUserId);
|
group.setOwnerId(currentUser.getId());
|
||||||
group.setCreateTime(new Date());
|
group.setCreateTime(new Date());
|
||||||
group.setUpdateTime(new Date());
|
group.setUpdateTime(new Date());
|
||||||
|
|
||||||
if (!this.save(group)) {
|
if (!this.save(group)) {
|
||||||
throw new ServiceException("创建群聊失败");
|
throw new ServiceException("创建群组失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加群主为成员
|
// 添加群主为群成员
|
||||||
addGroupMember(group.getId(), currentUserId, 2);
|
addGroupMember(group.getId(), currentUser.getId(), 2); // 2表示群主
|
||||||
|
|
||||||
// 添加其他成员
|
// 添加初始成员
|
||||||
if (memberIds != null && !memberIds.isEmpty()) {
|
if (memberIds != null && !memberIds.isEmpty()) {
|
||||||
for (String memberId : memberIds) {
|
for (String memberId : memberIds) {
|
||||||
addGroupMember(group.getId(), memberId, 0);
|
addGroupMember(group.getId(), memberId, 0); // 0表示普通成员
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,20 +218,23 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void dismissGroup(String groupId) {
|
public void dismissGroup(String groupId) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
// 验证群组是否存在
|
||||||
|
ImGroup group = this.getById(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
throw new ServiceException("群组不存在");
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否是群主
|
// 验证是否是群主
|
||||||
ImGroupMember owner = getGroupMember(groupId, currentUserId);
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
if (owner == null || owner.getRole() != 2) {
|
if (!group.getOwnerId().equals(currentUserId)) {
|
||||||
throw new ServiceException("只有群主能解散群聊");
|
throw new ServiceException("只有群主能解散群组");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除群成员
|
// 删除群成员
|
||||||
LambdaQueryWrapper<ImGroupMember> memberWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImGroupMember> memberQuery = new LambdaQueryWrapper<>();
|
||||||
memberWrapper.eq(ImGroupMember::getGroupId, groupId);
|
memberQuery.eq(ImGroupMember::getGroupId, groupId);
|
||||||
groupMemberMapper.delete(memberWrapper);
|
groupMemberMapper.delete(memberQuery);
|
||||||
|
|
||||||
// 删除群组
|
// 删除群组
|
||||||
this.removeById(groupId);
|
this.removeById(groupId);
|
||||||
@ -75,13 +244,13 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void inviteMembers(String groupId, List<String> memberIds) {
|
public void inviteMembers(String groupId, List<String> memberIds) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
|
||||||
// 检查权限
|
// 检查权限
|
||||||
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
||||||
if (operator == null || operator.getRole() < 1) {
|
if (operator == null || operator.getRole() < 1) {
|
||||||
throw new ServiceException("没有邀请权限");
|
throw new ServiceException("没有邀请权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加成员
|
// 添加成员
|
||||||
for (String memberId : memberIds) {
|
for (String memberId : memberIds) {
|
||||||
if (getGroupMember(groupId, memberId) == null) {
|
if (getGroupMember(groupId, memberId) == null) {
|
||||||
@ -94,19 +263,19 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void setAdmin(String groupId, String memberId) {
|
public void setAdmin(String groupId, String memberId) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
|
||||||
// 检查是否是群主
|
// 检查是否是群主
|
||||||
ImGroupMember owner = getGroupMember(groupId, currentUserId);
|
ImGroupMember owner = getGroupMember(groupId, currentUserId);
|
||||||
if (owner == null || owner.getRole() != 2) {
|
if (owner == null || owner.getRole() != 2) {
|
||||||
throw new ServiceException("只有群主能设置管理员");
|
throw new ServiceException("只有群主能设置管理员");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置管理员
|
// 设置管理员
|
||||||
ImGroupMember member = getGroupMember(groupId, memberId);
|
ImGroupMember member = getGroupMember(groupId, memberId);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
throw new ServiceException("该成员不在群中");
|
throw new ServiceException("该成员不在群中");
|
||||||
}
|
}
|
||||||
|
|
||||||
member.setRole(1);
|
member.setRole(1);
|
||||||
member.setUpdateTime(new Date());
|
member.setUpdateTime(new Date());
|
||||||
groupMemberMapper.updateById(member);
|
groupMemberMapper.updateById(member);
|
||||||
@ -116,19 +285,19 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void removeAdmin(String groupId, String memberId) {
|
public void removeAdmin(String groupId, String memberId) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
|
||||||
// 检查是否是群主
|
// 检查是否是群主
|
||||||
ImGroupMember owner = getGroupMember(groupId, currentUserId);
|
ImGroupMember owner = getGroupMember(groupId, currentUserId);
|
||||||
if (owner == null || owner.getRole() != 2) {
|
if (owner == null || owner.getRole() != 2) {
|
||||||
throw new ServiceException("只有群主能取消管理员");
|
throw new ServiceException("只有群主能取消管理员");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消管理员
|
// 取消管理员
|
||||||
ImGroupMember member = getGroupMember(groupId, memberId);
|
ImGroupMember member = getGroupMember(groupId, memberId);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
throw new ServiceException("该成员不在群中");
|
throw new ServiceException("该成员不在群中");
|
||||||
}
|
}
|
||||||
|
|
||||||
member.setRole(0);
|
member.setRole(0);
|
||||||
member.setUpdateTime(new Date());
|
member.setUpdateTime(new Date());
|
||||||
groupMemberMapper.updateById(member);
|
groupMemberMapper.updateById(member);
|
||||||
@ -138,24 +307,24 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void muteMember(String groupId, String memberId, Integer duration) {
|
public void muteMember(String groupId, String memberId, Integer duration) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
|
||||||
// 检查操作权限
|
// 检查操作权限
|
||||||
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
||||||
if (operator == null || operator.getRole() < 1) {
|
if (operator == null || operator.getRole() < 1) {
|
||||||
throw new ServiceException("没有禁言权限");
|
throw new ServiceException("没有禁言权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查被禁言成员
|
// 检查被禁言成员
|
||||||
ImGroupMember member = getGroupMember(groupId, memberId);
|
ImGroupMember member = getGroupMember(groupId, memberId);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
throw new ServiceException("该成员不在群中");
|
throw new ServiceException("该成员不在群中");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理员不能禁言群主和其他管理员
|
// 管理员不能禁言群主和其他管理员
|
||||||
if (operator.getRole() == 1 && member.getRole() > 0) {
|
if (operator.getRole() == 1 && member.getRole() > 0) {
|
||||||
throw new ServiceException("没有权限禁言该成员");
|
throw new ServiceException("没有权限禁言该成员");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置禁言
|
// 设置禁言
|
||||||
member.setIsMuted(1);
|
member.setIsMuted(1);
|
||||||
member.setMuteEndTime(new Date(System.currentTimeMillis() + duration * 60 * 1000));
|
member.setMuteEndTime(new Date(System.currentTimeMillis() + duration * 60 * 1000));
|
||||||
@ -167,24 +336,24 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void unmuteMember(String groupId, String memberId) {
|
public void unmuteMember(String groupId, String memberId) {
|
||||||
String currentUserId = UserContext.getCurrentUser().getId();
|
String currentUserId = UserContext.getCurrentUser().getId();
|
||||||
|
|
||||||
// 检查操作权限
|
// 检查操作权限
|
||||||
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
ImGroupMember operator = getGroupMember(groupId, currentUserId);
|
||||||
if (operator == null || operator.getRole() < 1) {
|
if (operator == null || operator.getRole() < 1) {
|
||||||
throw new ServiceException("没有解除禁言权限");
|
throw new ServiceException("没有解除禁言权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查被解除禁言成员
|
// 检查被解除禁言成员
|
||||||
ImGroupMember member = getGroupMember(groupId, memberId);
|
ImGroupMember member = getGroupMember(groupId, memberId);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
throw new ServiceException("该成员不在群中");
|
throw new ServiceException("该成员不在群中");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理员不能解除群主和其他管理员的禁言
|
// 管理员不能解除群主和其他管理员的禁言
|
||||||
if (operator.getRole() == 1 && member.getRole() > 0) {
|
if (operator.getRole() == 1 && member.getRole() > 0) {
|
||||||
throw new ServiceException("没有权限解除该成员的禁言");
|
throw new ServiceException("没有权限解除该成员的禁言");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解除禁言
|
// 解除禁言
|
||||||
member.setIsMuted(0);
|
member.setIsMuted(0);
|
||||||
member.setMuteEndTime(null);
|
member.setMuteEndTime(null);
|
||||||
@ -192,6 +361,15 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
groupMemberMapper.updateById(member);
|
groupMemberMapper.updateById(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群成员数量
|
||||||
|
*/
|
||||||
|
private Integer getGroupMemberCount(String groupId) {
|
||||||
|
LambdaQueryWrapper<ImGroupMember> countQuery = new LambdaQueryWrapper<>();
|
||||||
|
countQuery.eq(ImGroupMember::getGroupId, groupId);
|
||||||
|
return Math.toIntExact(groupMemberMapper.selectCount(countQuery));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加群成员
|
* 添加群成员
|
||||||
*/
|
*/
|
||||||
@ -200,9 +378,9 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
member.setGroupId(groupId);
|
member.setGroupId(groupId);
|
||||||
member.setMemberId(memberId);
|
member.setMemberId(memberId);
|
||||||
member.setRole(role);
|
member.setRole(role);
|
||||||
member.setIsMuted(0);
|
|
||||||
member.setJoinTime(new Date());
|
member.setJoinTime(new Date());
|
||||||
member.setUpdateTime(new Date());
|
member.setIsMuted(0);
|
||||||
|
|
||||||
groupMemberMapper.insert(member);
|
groupMemberMapper.insert(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +390,16 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupMapper, ImGroup> impl
|
|||||||
private ImGroupMember getGroupMember(String groupId, String memberId) {
|
private ImGroupMember getGroupMember(String groupId, String memberId) {
|
||||||
LambdaQueryWrapper<ImGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(ImGroupMember::getGroupId, groupId)
|
queryWrapper.eq(ImGroupMember::getGroupId, groupId)
|
||||||
.eq(ImGroupMember::getMemberId, memberId);
|
.eq(ImGroupMember::getMemberId, memberId);
|
||||||
return groupMemberMapper.selectOne(queryWrapper);
|
return groupMemberMapper.selectOne(queryWrapper);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* 检查是否是好友关系
|
||||||
|
*/
|
||||||
|
private boolean isFriend(String userId, String friendId) {
|
||||||
|
List<FriendVO> friends = friendService.getMutualFriends(userId);
|
||||||
|
return friends.stream()
|
||||||
|
.anyMatch(friend -> friend.getFriendId().equals(friendId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,10 +6,12 @@ import cn.lili.common.security.AuthUser;
|
|||||||
import cn.lili.common.security.context.UserContext;
|
import cn.lili.common.security.context.UserContext;
|
||||||
import cn.lili.common.security.enums.UserEnums;
|
import cn.lili.common.security.enums.UserEnums;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||||
|
import cn.lili.modules.im.entity.dos.ImTalk;
|
||||||
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
||||||
import cn.lili.modules.im.mapper.ImMessageMapper;
|
import cn.lili.modules.im.mapper.ImMessageMapper;
|
||||||
import cn.lili.modules.im.service.ImMessageService;
|
import cn.lili.modules.im.service.ImMessageService;
|
||||||
import cn.lili.modules.im.service.ImTalkService;
|
import cn.lili.modules.im.service.ImTalkService;
|
||||||
|
import cn.lili.modules.im.websocket.WebSocketServer;
|
||||||
import cn.lili.mybatis.util.PageUtil;
|
import cn.lili.mybatis.util.PageUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
@ -19,9 +21,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.stream.Collectors;
|
||||||
import java.util.Objects;
|
|
||||||
|
import cn.lili.modules.im.entity.vo.ImMessageVO;
|
||||||
|
import cn.lili.modules.im.entity.dos.ImGroup;
|
||||||
|
import cn.lili.modules.im.mapper.ImGroupMapper;
|
||||||
|
import cn.lili.modules.im.entity.vo.MessageOperation;
|
||||||
|
import cn.lili.common.vo.ResultPageVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Im消息 业务实现
|
* Im消息 业务实现
|
||||||
@ -33,8 +40,26 @@ import java.util.Objects;
|
|||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage> implements ImMessageService {
|
public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage> implements ImMessageService {
|
||||||
|
|
||||||
|
// @Autowired
|
||||||
|
// private final WebSocketServer imTalkService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ImTalkService imTalkService;
|
private ImGroupMapper imGroupMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImMessageVO> getHistoryMessages(String talkId, String earliestMsgId, Integer pageSize) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImMessageVO> getRecentMessages(String talkId, String latestMsgId, Integer pageSize) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImMessageVO sendMessage(String toId, String content, String type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(String talkId, String accessToken) {
|
public void read(String talkId, String accessToken) {
|
||||||
@ -43,6 +68,7 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
|||||||
updateWrapper.eq(ImMessage::getTalkId, talkId);
|
updateWrapper.eq(ImMessage::getTalkId, talkId);
|
||||||
updateWrapper.eq(ImMessage::getToUser, userId);
|
updateWrapper.eq(ImMessage::getToUser, userId);
|
||||||
updateWrapper.set(ImMessage::getIsRead, true);
|
updateWrapper.set(ImMessage::getIsRead, true);
|
||||||
|
// updateWrapper.set(ImMessage::getReadTime,new Date());
|
||||||
this.update(updateWrapper);
|
this.update(updateWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +77,7 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
|||||||
String userId = UserContext.getAuthUser(accessToken).getId();
|
String userId = UserContext.getAuthUser(accessToken).getId();
|
||||||
LambdaQueryWrapper<ImMessage> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImMessage> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(ImMessage::getToUser, userId);
|
queryWrapper.eq(ImMessage::getToUser, userId);
|
||||||
queryWrapper.eq(ImMessage::getIsRead, false);
|
// queryWrapper.eq(ImMessage::getIsRead, false);
|
||||||
return this.list(queryWrapper);
|
return this.list(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +103,23 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ImMessage> getList(MessageQueryParams messageQueryParams) {
|
public List<ImMessage> getList(MessageQueryParams messageQueryParams) {
|
||||||
List<ImMessage> messageList = this.page(PageUtil.initPage(messageQueryParams), messageQueryParams.initQueryWrapper()).getRecords();
|
// 使用 LambdaQueryWrapper 创建查询条件
|
||||||
|
LambdaQueryWrapper<ImMessage> queryWrapper = messageQueryParams.initQueryWrapper();
|
||||||
|
|
||||||
|
// 关联查询,假设 ImTalkMapper 是你的 Mapper 类
|
||||||
|
queryWrapper.eq(ImMessage::getTalkId, messageQueryParams.getTalkId());
|
||||||
|
|
||||||
|
// 执行分页查询
|
||||||
|
List<ImMessage> messageList = this.page(PageUtil.initPage(messageQueryParams), queryWrapper).getRecords();
|
||||||
|
|
||||||
|
// 对消息列表进行排序和已读处理
|
||||||
ListSort(messageList);
|
ListSort(messageList);
|
||||||
readMessage(messageList);
|
readMessage(messageList);
|
||||||
|
|
||||||
return messageList;
|
return messageList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long unreadMessageCount() {
|
public Long unreadMessageCount() {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
@ -101,6 +138,63 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
|||||||
this.update(new LambdaUpdateWrapper<ImMessage>().eq(ImMessage::getToUser,currentUser.getId()).set(ImMessage::getIsRead,true));
|
this.update(new LambdaUpdateWrapper<ImMessage>().eq(ImMessage::getToUser,currentUser.getId()).set(ImMessage::getIsRead,true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultPageVO<ImMessageVO> getGroupMessages(String groupId, Integer pageNumber, Integer pageSize) {
|
||||||
|
List<ImMessage> messages = this.getMessagesByGroupId(groupId, pageNumber, pageSize);
|
||||||
|
|
||||||
|
List<ImMessageVO> messageVOs = messages.stream()
|
||||||
|
.map(message -> new ImMessageVO())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Long total = this.count(new LambdaQueryWrapper<ImMessage>().eq(ImMessage::getGroupId, groupId));
|
||||||
|
|
||||||
|
return new ResultPageVO<>(total, (long) Math.ceil((double) total / pageSize), (long) pageNumber, (long) pageSize, messageVOs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImMessageVO sendGroupMessage(String groupId, String content, String type) {
|
||||||
|
ImMessage imMessage = new ImMessage();
|
||||||
|
imMessage.setText(content);
|
||||||
|
imMessage.setType(type);
|
||||||
|
imMessage.setGroupId(groupId);
|
||||||
|
imMessage.setCreateTime(new Date());
|
||||||
|
|
||||||
|
this.save(imMessage);
|
||||||
|
|
||||||
|
return new ImMessageVO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recallMessage(String messageId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImMessageVO> loadHistoryMessages(String talkId, String earliestMsgId, Integer size) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImMessageVO> loadLatestMessages(String talkId, Integer size) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImMessageVO> getNewerMessages(String talkId, String latestMsgId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readMessages(List<ImMessage> messages, String userId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImMessage> getMessagesByGroupId(String groupId, Integer pageNumber, Integer pageSize) {
|
||||||
|
return this.list(new LambdaQueryWrapper<ImMessage>().eq(ImMessage::getGroupId, groupId)
|
||||||
|
.orderByDesc(ImMessage::getCreateTime)
|
||||||
|
.last("LIMIT " + (pageNumber - 1) * pageSize + ", " + pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据时间倒叙
|
* 根据时间倒叙
|
||||||
*
|
*
|
||||||
@ -144,6 +238,7 @@ public class ImMessageServiceImpl extends ServiceImpl<ImMessageMapper, ImMessage
|
|||||||
for (ImMessage imMessage : messageList) {
|
for (ImMessage imMessage : messageList) {
|
||||||
if(Boolean.FALSE.equals(imMessage.getIsRead()) && imMessage.getToUser().equals(toUserId)){
|
if(Boolean.FALSE.equals(imMessage.getIsRead()) && imMessage.getToUser().equals(toUserId)){
|
||||||
imMessage.setIsRead(true);
|
imMessage.setIsRead(true);
|
||||||
|
// imMessage.setReadTime(new Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,12 @@ import cn.lili.common.exception.ServiceException;
|
|||||||
import cn.lili.common.security.AuthUser;
|
import cn.lili.common.security.AuthUser;
|
||||||
import cn.lili.common.security.context.UserContext;
|
import cn.lili.common.security.context.UserContext;
|
||||||
import cn.lili.common.security.enums.UserEnums;
|
import cn.lili.common.security.enums.UserEnums;
|
||||||
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||||
import cn.lili.modules.im.entity.dos.ImTalk;
|
import cn.lili.modules.im.entity.dos.ImTalk;
|
||||||
import cn.lili.modules.im.entity.dto.IMTalkQueryParams;
|
import cn.lili.modules.im.entity.dto.IMTalkQueryParams;
|
||||||
import cn.lili.modules.im.entity.vo.ImTalkVO;
|
import cn.lili.modules.im.entity.vo.ImTalkVO;
|
||||||
|
import cn.lili.modules.im.mapper.FriendMapper;
|
||||||
import cn.lili.modules.im.mapper.ImTalkMapper;
|
import cn.lili.modules.im.mapper.ImTalkMapper;
|
||||||
import cn.lili.modules.im.service.ImMessageService;
|
import cn.lili.modules.im.service.ImMessageService;
|
||||||
import cn.lili.modules.im.service.ImTalkService;
|
import cn.lili.modules.im.service.ImTalkService;
|
||||||
@ -20,33 +22,43 @@ import cn.lili.modules.store.service.StoreService;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天 业务实现
|
* 聊天 业务实现
|
||||||
*
|
*
|
||||||
* @author Chopper
|
* @author Chopper
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
//@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> implements ImTalkService {
|
public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> implements ImTalkService {
|
||||||
|
|
||||||
|
private final ImMessageService imMessageService;
|
||||||
|
@Autowired
|
||||||
|
public ImTalkServiceImpl(@Lazy ImMessageService imMessageService) {
|
||||||
|
this.imMessageService = imMessageService;
|
||||||
|
}
|
||||||
|
@Autowired
|
||||||
|
FriendMapper friendMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MemberService memberService;
|
private MemberService memberService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private StoreService storeService;
|
private StoreService storeService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ImMessageService imMessageService;
|
|
||||||
|
|
||||||
public ImTalk getTalkByUser(String userId) {
|
public ImTalk getTalkByUser(String userId) {
|
||||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
|
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
|
||||||
@ -180,14 +192,52 @@ public class ImTalkServiceImpl extends ServiceImpl<ImTalkMapper, ImTalk> impleme
|
|||||||
if (authUser == null) {
|
if (authUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.and(wq -> wq.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2, authUser.getId()));
|
queryWrapper.and(wq -> wq.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2, authUser.getId()));
|
||||||
|
|
||||||
if (CharSequenceUtil.isNotEmpty(imTalkQueryParams.getUserName())) {
|
if (CharSequenceUtil.isNotEmpty(imTalkQueryParams.getUserName())) {
|
||||||
queryWrapper.and(wq -> wq.ne(ImTalk::getUserId1, authUser.getId()).like(ImTalk::getName1, imTalkQueryParams.getUserName()).or().ne(ImTalk::getUserId2, authUser.getId()).like(ImTalk::getName2, imTalkQueryParams.getUserName()));
|
queryWrapper.and(wq -> wq.ne(ImTalk::getUserId1, authUser.getId())
|
||||||
|
.like(ImTalk::getName1, imTalkQueryParams.getUserName())
|
||||||
|
.or()
|
||||||
|
.ne(ImTalk::getUserId2, authUser.getId())
|
||||||
|
.like(ImTalk::getName2, imTalkQueryParams.getUserName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
|
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
|
||||||
List<ImTalk> imTalks = this.list(queryWrapper);
|
List<ImTalk> imTalks = this.list(queryWrapper);
|
||||||
List<ImTalkVO> imTalkVOList = imTalks.stream().map(imTalk -> new ImTalkVO(imTalk, authUser.getId())).collect(Collectors.toList());
|
|
||||||
|
// 获取好友关系
|
||||||
|
List<String> friendIds = imTalks.stream()
|
||||||
|
.flatMap(imTalk -> Stream.of(imTalk.getUserId1(), imTalk.getUserId2()))
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 查询好友关系
|
||||||
|
List<Friend> friends = friendMapper.selectList(new LambdaQueryWrapper<Friend>()
|
||||||
|
.in(Friend::getFriendId, friendIds)
|
||||||
|
.eq(Friend::getUserId, authUser.getId())
|
||||||
|
.eq(Friend::getStatus, 1)); // 只查询状态为1的记录
|
||||||
|
|
||||||
|
// 创建一个 Set 来存储已关注的用户 ID
|
||||||
|
Set<String> mutualFriends = friends.stream()
|
||||||
|
.map(Friend::getFriendId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
// 更新 isMutual 字段
|
||||||
|
for (ImTalk imTalk : imTalks) {
|
||||||
|
if (mutualFriends.contains(imTalk.getUserId1()) || mutualFriends.contains(imTalk.getUserId2())) {
|
||||||
|
imTalk.setIsMutual(1); // 设置为单向关注
|
||||||
|
} else {
|
||||||
|
imTalk.setIsMutual(0); // 设置为未关注
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将更新后的 imTalk 转换为 VO 对象
|
||||||
|
List<ImTalkVO> imTalkVOList = imTalks.stream()
|
||||||
|
.map(imTalk -> new ImTalkVO(imTalk, authUser.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
getUnread(imTalkVOList);
|
getUnread(imTalkVOList);
|
||||||
return imTalkVOList;
|
return imTalkVOList;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package cn.lili.controller.im;
|
package cn.lili.modules.im.websocket;
|
||||||
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.lili.cache.Cache;
|
import cn.lili.cache.Cache;
|
||||||
|
import cn.lili.common.exception.ServiceException;
|
||||||
import cn.lili.common.security.AuthUser;
|
import cn.lili.common.security.AuthUser;
|
||||||
import cn.lili.common.security.context.UserContext;
|
import cn.lili.common.security.context.UserContext;
|
||||||
import cn.lili.common.security.enums.UserEnums;
|
import cn.lili.common.security.enums.UserEnums;
|
||||||
@ -13,8 +14,11 @@ import cn.lili.modules.im.entity.vo.MessageOperation;
|
|||||||
import cn.lili.modules.im.entity.vo.MessageVO;
|
import cn.lili.modules.im.entity.vo.MessageVO;
|
||||||
import cn.lili.modules.im.service.ImMessageService;
|
import cn.lili.modules.im.service.ImMessageService;
|
||||||
import cn.lili.modules.im.service.ImTalkService;
|
import cn.lili.modules.im.service.ImTalkService;
|
||||||
|
import cn.lili.modules.member.entity.dos.Member;
|
||||||
|
import cn.lili.modules.member.service.MemberService;
|
||||||
import com.alibaba.druid.util.StringUtils;
|
import com.alibaba.druid.util.StringUtils;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -40,6 +44,7 @@ import org.springframework.stereotype.Component;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class WebSocketServer {
|
public class WebSocketServer {
|
||||||
|
private final MemberService memberService;
|
||||||
/**
|
/**
|
||||||
* 在线人数 PS 注意,只能单节点,如果多节点部署需要自行寻找方案
|
* 在线人数 PS 注意,只能单节点,如果多节点部署需要自行寻找方案
|
||||||
*/
|
*/
|
||||||
@ -107,21 +112,36 @@ public class WebSocketServer {
|
|||||||
* @param messageOperation
|
* @param messageOperation
|
||||||
*/
|
*/
|
||||||
private void operation(String accessToken, MessageOperation messageOperation) {
|
private void operation(String accessToken, MessageOperation messageOperation) {
|
||||||
|
|
||||||
AuthUser authUser = UserContext.getAuthUser(accessToken);
|
AuthUser authUser = UserContext.getAuthUser(accessToken);
|
||||||
|
|
||||||
switch (messageOperation.getOperationType()) {
|
switch (messageOperation.getOperationType()) {
|
||||||
case PING:
|
case PING:
|
||||||
break;
|
break;
|
||||||
case MESSAGE:
|
case MESSAGE:
|
||||||
//保存消息
|
// 获取或创建聊天记录
|
||||||
|
ImTalk imTalk = getOrCreateTalk(authUser.getId(), messageOperation.getTo());
|
||||||
|
|
||||||
|
// 如果 imTalk 为 null,说明创建失败,记录日志并返回
|
||||||
|
if (imTalk == null) {
|
||||||
|
log.warn("Failed to create ImTalk for users: {} and {}", authUser.getId(), messageOperation.getTo());
|
||||||
|
return; // 或者抛出异常
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存消息
|
||||||
ImMessage imMessage = new ImMessage(messageOperation);
|
ImMessage imMessage = new ImMessage(messageOperation);
|
||||||
|
imMessage.setCreateBy(authUser.getNickName());
|
||||||
|
imMessage.setTalkId(imTalk.getId()); // 设置 talk_id 为 imTalk 的 id
|
||||||
imMessageService.save(imMessage);
|
imMessageService.save(imMessage);
|
||||||
//修改最后消息信息
|
log.info("Message saved: {}", imMessage);
|
||||||
imTalkService.update(new LambdaUpdateWrapper<ImTalk>().eq(ImTalk::getId, messageOperation.getTalkId())
|
|
||||||
.set(ImTalk::getLastTalkMessage, messageOperation.getContext())
|
// 更新最后消息信息
|
||||||
.set(ImTalk::getLastTalkTime, imMessage.getCreateTime())
|
imTalkService.update(new LambdaUpdateWrapper<ImTalk>()
|
||||||
.set(ImTalk::getLastMessageType, imMessage.getMessageType()));
|
.eq(ImTalk::getId, imTalk.getId())
|
||||||
//发送消息
|
.set(ImTalk::getLastTalkMessage, messageOperation.getContext())
|
||||||
|
.set(ImTalk::getLastTalkTime, imMessage.getCreateTime())
|
||||||
|
.set(ImTalk::getLastMessageType, imMessage.getMessageType()));
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
sendMessage(messageOperation.getTo(), new MessageVO(MessageResultType.MESSAGE, imMessage));
|
sendMessage(messageOperation.getTo(), new MessageVO(MessageResultType.MESSAGE, imMessage));
|
||||||
break;
|
break;
|
||||||
case READ:
|
case READ:
|
||||||
@ -131,17 +151,55 @@ public class WebSocketServer {
|
|||||||
break;
|
break;
|
||||||
case UNREAD:
|
case UNREAD:
|
||||||
sendMessage(authUser.getId(),
|
sendMessage(authUser.getId(),
|
||||||
new MessageVO(MessageResultType.UN_READ, imMessageService.unReadMessages(accessToken)));
|
new MessageVO(MessageResultType.UN_READ, imMessageService.unReadMessages(accessToken)));
|
||||||
break;
|
break;
|
||||||
case HISTORY:
|
case HISTORY:
|
||||||
sendMessage(authUser.getId(), new MessageVO(MessageResultType.HISTORY,
|
sendMessage(authUser.getId(), new MessageVO(MessageResultType.HISTORY,
|
||||||
imMessageService.historyMessage(accessToken, messageOperation.getTo())));
|
imMessageService.historyMessage(accessToken, messageOperation.getTo())));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 获取或创建聊天记录
|
||||||
|
public ImTalk getOrCreateTalk(String userId1, String userId2) {
|
||||||
|
// 查询现有的聊天记录
|
||||||
|
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper
|
||||||
|
.or().eq(ImTalk::getUserId1, userId1).eq(ImTalk::getUserId2, userId2)
|
||||||
|
.or().eq(ImTalk::getUserId1, userId2).eq(ImTalk::getUserId2, userId1);
|
||||||
|
|
||||||
|
ImTalk imTalk = imTalkService.getOne(queryWrapper);
|
||||||
|
if (imTalk != null) {
|
||||||
|
log.info("Found existing talk: {}", imTalk);
|
||||||
|
return imTalk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有找到,创建新的聊天记录
|
||||||
|
log.info("Creating new talk between {} and {}", userId1, userId2);
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
Member member1 = memberService.getById(userId1);
|
||||||
|
Member member2 = memberService.getById(userId2);
|
||||||
|
|
||||||
|
// 检查用户是否存在
|
||||||
|
if (member1 == null || member2 == null) {
|
||||||
|
log.warn("One of the members does not exist: member1={}, member2={}", member1, member2);
|
||||||
|
throw new ServiceException("One of the users does not exist."); // 或者根据需要处理
|
||||||
|
}
|
||||||
|
|
||||||
|
String face1 = member1.getFace() != null ? member1.getFace() : ""; // 获取头像
|
||||||
|
String face2 = member2.getFace() != null ? member2.getFace() : ""; // 获取头像
|
||||||
|
String name1 = member1.getNickName() != null ? member1.getNickName() : ""; // 获取昵称
|
||||||
|
String name2 = member2.getNickName() != null ? member2.getNickName() : ""; // 获取昵称
|
||||||
|
|
||||||
|
// 创建新的聊天记录
|
||||||
|
imTalk = new ImTalk(userId1, userId2, face1, face2, name1, name2);
|
||||||
|
imTalkService.save(imTalk);
|
||||||
|
log.info("New talk created: {}", imTalk);
|
||||||
|
|
||||||
|
return imTalk;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
*
|
*
|
||||||
@ -6,6 +6,8 @@ import cn.lili.common.security.sensitive.enums.SensitiveStrategy;
|
|||||||
import cn.lili.common.utils.CommonUtil;
|
import cn.lili.common.utils.CommonUtil;
|
||||||
import cn.lili.mybatis.BaseEntity;
|
import cn.lili.mybatis.BaseEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
@ -31,6 +33,24 @@ public class Member extends BaseEntity {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
// 创建者
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
// 创建时间
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
// 删除标志 true/false
|
||||||
|
private Boolean deleteFlag;
|
||||||
|
|
||||||
|
// 更新者
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "会员用户名")
|
@ApiModelProperty(value = "会员用户名")
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@ -97,13 +117,13 @@ public class Member extends BaseEntity {
|
|||||||
@ApiModelProperty(value = "经验值数量")
|
@ApiModelProperty(value = "经验值数量")
|
||||||
private Long experience;
|
private Long experience;
|
||||||
|
|
||||||
|
|
||||||
public Member(String username, String password, String mobile) {
|
public Member(String username, String password, String mobile) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.mobile = mobile;
|
this.mobile = mobile;
|
||||||
this.nickName = CommonUtil.getSpecialStr("用户");
|
this.nickName = CommonUtil.getSpecialStr("用户");
|
||||||
this.disabled = true;
|
this.disabled = true;
|
||||||
|
this.deleteFlag=false;
|
||||||
this.haveStore = false;
|
this.haveStore = false;
|
||||||
this.sex = 0;
|
this.sex = 0;
|
||||||
this.point = 0L;
|
this.point = 0L;
|
||||||
@ -115,6 +135,7 @@ public class Member extends BaseEntity {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.mobile = mobile;
|
this.mobile = mobile;
|
||||||
|
this.deleteFlag=false;
|
||||||
this.nickName = nickName;
|
this.nickName = nickName;
|
||||||
this.disabled = true;
|
this.disabled = true;
|
||||||
this.haveStore = false;
|
this.haveStore = false;
|
||||||
|
|||||||
@ -19,11 +19,6 @@
|
|||||||
<artifactId>framework</artifactId>
|
<artifactId>framework</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -2,8 +2,6 @@ package cn.lili;
|
|||||||
|
|
||||||
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.Bean;
|
|
||||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,17 +13,4 @@ public class ImApiApplication {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ImApiApplication.class, args);
|
SpringApplication.run(ImApiApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 如果使用独立的servlet容器,
|
|
||||||
* 而不是直接使用springboot的内置容器,
|
|
||||||
* 就不要注入ServerEndpointExporter,
|
|
||||||
* 因为它将由容器自己提供和管理
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public ServerEndpointExporter serverEndpointExporter() {
|
|
||||||
return new ServerEndpointExporter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,48 +2,49 @@ package cn.lili.controller.im;
|
|||||||
|
|
||||||
import cn.lili.common.enums.ResultCode;
|
import cn.lili.common.enums.ResultCode;
|
||||||
import cn.lili.common.enums.ResultUtil;
|
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.security.context.UserContext;
|
||||||
|
import cn.lili.common.security.AuthUser;
|
||||||
|
import cn.lili.common.exception.ServiceException;
|
||||||
import cn.lili.common.vo.ResultMessage;
|
import cn.lili.common.vo.ResultMessage;
|
||||||
import cn.lili.modules.im.entity.dos.Friend;
|
import cn.lili.modules.im.entity.dos.Friend;
|
||||||
import cn.lili.modules.im.entity.vo.FriendVO;
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
import cn.lili.modules.im.service.FriendService;
|
import cn.lili.modules.im.service.FriendService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* @author Chopper
|
* @author Chopper
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@Api(tags = "关注管理接口")
|
||||||
@Api(tags = "好友管理接口")
|
|
||||||
|
|
||||||
@RequestMapping("/im/friend")
|
@RequestMapping("/im/friend")
|
||||||
|
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
|
|
||||||
public class FriendController {
|
public class FriendController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final FriendService friendService;
|
private final FriendService friendService;
|
||||||
|
|
||||||
|
@GetMapping("/search")
|
||||||
|
@ApiOperation(value = "搜索用户")
|
||||||
|
public ResultMessage<List<FriendVO>> searchUsers(
|
||||||
|
@ApiParam(value = "搜索关键词(用户名/手机号)") @RequestParam String keyword,
|
||||||
|
@ApiParam(value = "是否只搜索店铺") @RequestParam(required = false) Boolean onlyStore) {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
List<FriendVO> users = friendService.searchUsers(keyword, onlyStore, currentUser.getId());
|
||||||
|
return ResultUtil.data(users);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/mutual")
|
@GetMapping("/following")
|
||||||
@ApiOperation(value = "查看所有互相关注好友")
|
@ApiOperation(value = "获取关注列表")
|
||||||
public ResultMessage<List<FriendVO>> getMutualFriends() {
|
public ResultMessage<List<FriendVO>> getFollowingList() {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
@ -52,49 +53,65 @@ public class FriendController {
|
|||||||
return ResultUtil.data(friends);
|
return ResultUtil.data(friends);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{friendId}")
|
@GetMapping("/user/{userId}")
|
||||||
@ApiOperation(value = "查看好友资料")
|
@ApiOperation(value = "获取用户详情")
|
||||||
public ResultMessage<FriendVO> getFriendDetails(@PathVariable String friendId) {
|
public ResultMessage<FriendVO> getUserDetails(
|
||||||
|
@ApiParam(value = "用户ID", required = true) @PathVariable String userId) {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
}
|
}
|
||||||
FriendVO friend = friendService.getFriendDetails(friendId);
|
FriendVO friend = friendService.getFriendDetails(userId);
|
||||||
return ResultUtil.data(friend);
|
return ResultUtil.data(friend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{friendId}")
|
@PostMapping("/follow/{userId}")
|
||||||
@ApiOperation(value = "解除好友关系")
|
@ApiOperation(value = "关注用户")
|
||||||
public ResultMessage<Object> removeFriend(@PathVariable String friendId) {
|
public ResultMessage<Object> followUser(
|
||||||
|
@ApiParam(value = "要关注的用户ID", required = true) @PathVariable String userId) {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
}
|
}
|
||||||
friendService.removeFriend(currentUser.getId(), friendId);
|
friendService.addFriend(currentUser.getId(), userId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/add/{friendId}")
|
@PostMapping("/follow-by-mobile")
|
||||||
@ApiOperation(value = "添加好友")
|
@ApiOperation(value = "通过手机号关注用户")
|
||||||
public ResultMessage<Object> addFriend(@PathVariable String friendId) {
|
public ResultMessage<Object> followByMobile(
|
||||||
|
@ApiParam(value = "手机号", required = true) @RequestParam String mobile,
|
||||||
|
@ApiParam(value = "备注") @RequestParam(required = false) String remark) {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
}
|
}
|
||||||
friendService.addFriend(currentUser.getId(), friendId);
|
friendService.addFriendByMobile(mobile, remark);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/remark/{friendId}")
|
@DeleteMapping("/unfollow/{userId}")
|
||||||
@ApiOperation(value = "更新好友备注")
|
@ApiOperation(value = "取消关注")
|
||||||
public ResultMessage<Object> updateRemark(@PathVariable String friendId, @RequestParam String remark) {
|
public ResultMessage<Object> unfollowUser(
|
||||||
|
@ApiParam(value = "要取消关注的用户ID", required = true) @PathVariable String userId) {
|
||||||
AuthUser currentUser = UserContext.getCurrentUser();
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
}
|
}
|
||||||
friendService.updateRemark(currentUser.getId(), friendId, remark);
|
friendService.removeFriend(currentUser.getId(), userId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/remark/{userId}")
|
||||||
|
@ApiOperation(value = "更新备注")
|
||||||
|
public ResultMessage<Object> updateRemark(
|
||||||
|
@ApiParam(value = "用户ID", required = true) @PathVariable String userId,
|
||||||
|
@ApiParam(value = "备注", required = true) @RequestParam String remark) {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
friendService.updateRemark(currentUser.getId(), userId, remark);
|
||||||
|
return ResultUtil.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,78 +1,182 @@
|
|||||||
package cn.lili.controller.im;
|
package cn.lili.controller.im;
|
||||||
|
|
||||||
|
import cn.lili.common.enums.ResultCode;
|
||||||
|
|
||||||
import cn.lili.common.enums.ResultUtil;
|
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.common.vo.ResultMessage;
|
||||||
|
import cn.lili.common.vo.ResultPageVO;
|
||||||
import cn.lili.modules.im.entity.dos.ImGroup;
|
import cn.lili.modules.im.entity.dos.ImGroup;
|
||||||
|
import cn.lili.modules.im.entity.vo.FriendVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImGroupMemberVO;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImMessageVO;
|
||||||
import cn.lili.modules.im.service.ImGroupService;
|
import cn.lili.modules.im.service.ImGroupService;
|
||||||
|
import cn.lili.modules.im.service.FriendService;
|
||||||
|
import cn.lili.modules.im.service.ImMessageService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群聊管理接口
|
||||||
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@Api(tags = "群聊管理接口")
|
@Api(tags = "群聊管理接口")
|
||||||
@RequestMapping("/im/group")
|
@RequestMapping("/im/group")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class ImGroupController {
|
public class ImGroupController {
|
||||||
|
|
||||||
private final ImGroupService imGroupService;
|
private final ImGroupService imGroupService;
|
||||||
|
private final FriendService friendService;
|
||||||
|
private final ImMessageService imMessageService;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
@ApiOperation(value = "获取我的群聊列表")
|
||||||
|
public ResultMessage<List<ImGroupVO>> getMyGroups() {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
List<ImGroupVO> groups = imGroupService.getUserGroups(currentUser.getId());
|
||||||
|
return ResultUtil.data(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{groupId}")
|
||||||
|
@ApiOperation(value = "获取群聊详情")
|
||||||
|
public ResultMessage<ImGroupVO> getGroupDetail(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId) {
|
||||||
|
ImGroupVO group = imGroupService.getGroupDetail(groupId);
|
||||||
|
return ResultUtil.data(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{groupId}/members")
|
||||||
|
@ApiOperation(value = "获取群成员列表")
|
||||||
|
public ResultMessage<List<ImGroupMemberVO>> getGroupMembers(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId) {
|
||||||
|
List<ImGroupMemberVO> members = imGroupService.getGroupMembers(groupId);
|
||||||
|
return ResultUtil.data(members);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{groupId}/quit")
|
||||||
|
@ApiOperation(value = "退出群聊")
|
||||||
|
public ResultMessage<Void> quitGroup(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId) {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
imGroupService.quitGroup(groupId, currentUser.getId());
|
||||||
|
return ResultUtil.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{groupId}")
|
||||||
|
@ApiOperation(value = "修改群信息")
|
||||||
|
public ResultMessage<Void> updateGroupInfo(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "群名称") @RequestParam(required = false) String groupName,
|
||||||
|
@ApiParam(value = "群公告") @RequestParam(required = false) String notice,
|
||||||
|
@ApiParam(value = "群头像") @RequestParam(required = false) String avatar) {
|
||||||
|
imGroupService.updateGroupInfo(groupId, groupName, notice, avatar);
|
||||||
|
return ResultUtil.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{groupId}/messages")
|
||||||
|
@ApiOperation(value = "获取群聊消息历史")
|
||||||
|
public ResultMessage<ResultPageVO<ImMessageVO>> getGroupMessages(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "页码") @RequestParam(defaultValue = "1") Integer pageNumber,
|
||||||
|
@ApiParam(value = "每页大小") @RequestParam(defaultValue = "20") Integer pageSize) {
|
||||||
|
ResultPageVO<ImMessageVO> messages = imMessageService.getGroupMessages(groupId, pageNumber, pageSize);
|
||||||
|
return ResultUtil.data(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{groupId}/message")
|
||||||
|
@ApiOperation(value = "发送群聊消息")
|
||||||
|
public ResultMessage<ImMessageVO> sendGroupMessage(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "消息内容", required = true) @RequestParam String content,
|
||||||
|
@ApiParam(value = "消息类型", required = true) @RequestParam String type) {
|
||||||
|
ImMessageVO message = imMessageService.sendGroupMessage(groupId, content, type);
|
||||||
|
return ResultUtil.data(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/friends")
|
||||||
|
@ApiOperation(value = "获取可邀请的好友列表")
|
||||||
|
public ResultMessage<List<FriendVO>> getInvitableFriends() {
|
||||||
|
AuthUser currentUser = UserContext.getCurrentUser();
|
||||||
|
if (currentUser == null) {
|
||||||
|
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
|
||||||
|
}
|
||||||
|
List<FriendVO> friends = friendService.getMutualFriends(currentUser.getId());
|
||||||
|
return ResultUtil.data(friends);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@ApiOperation(value = "创建群聊")
|
@ApiOperation(value = "创建群聊")
|
||||||
public ResultMessage<ImGroup> createGroup(@RequestParam String groupName,
|
public ResultMessage<ImGroup> createGroup(
|
||||||
@RequestParam(required = false) List<String> memberIds) {
|
@ApiParam(value = "群名称", required = true) @RequestParam String groupName,
|
||||||
|
@ApiParam(value = "初始成员ID列表") @RequestParam(required = false) List<String> memberIds) {
|
||||||
ImGroup group = imGroupService.createGroup(groupName, memberIds);
|
ImGroup group = imGroupService.createGroup(groupName, memberIds);
|
||||||
return ResultUtil.data(group);
|
return ResultUtil.data(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{groupId}")
|
@DeleteMapping("/{groupId}")
|
||||||
@ApiOperation(value = "解散群聊")
|
@ApiOperation(value = "解散群聊")
|
||||||
public ResultMessage<Void> dismissGroup(@PathVariable String groupId) {
|
public ResultMessage<Void> dismissGroup(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId) {
|
||||||
imGroupService.dismissGroup(groupId);
|
imGroupService.dismissGroup(groupId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{groupId}/invite")
|
@PostMapping("/{groupId}/invite")
|
||||||
@ApiOperation(value = "邀请成员")
|
@ApiOperation(value = "邀请成员")
|
||||||
public ResultMessage<Void> inviteMembers(@PathVariable String groupId,
|
public ResultMessage<Void> inviteMembers(
|
||||||
@RequestParam List<String> memberIds) {
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "成员ID列表", required = true) @RequestParam List<String> memberIds) {
|
||||||
imGroupService.inviteMembers(groupId, memberIds);
|
imGroupService.inviteMembers(groupId, memberIds);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{groupId}/admin/{memberId}")
|
@PostMapping("/{groupId}/admin/{memberId}")
|
||||||
@ApiOperation(value = "设置管理员")
|
@ApiOperation(value = "设置管理员")
|
||||||
public ResultMessage<Void> setAdmin(@PathVariable String groupId,
|
public ResultMessage<Void> setAdmin(
|
||||||
@PathVariable String memberId) {
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "成员ID", required = true) @PathVariable String memberId) {
|
||||||
imGroupService.setAdmin(groupId, memberId);
|
imGroupService.setAdmin(groupId, memberId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{groupId}/admin/{memberId}")
|
@DeleteMapping("/{groupId}/admin/{memberId}")
|
||||||
@ApiOperation(value = "取消管理员")
|
@ApiOperation(value = "取消管理员")
|
||||||
public ResultMessage<Void> removeAdmin(@PathVariable String groupId,
|
public ResultMessage<Void> removeAdmin(
|
||||||
@PathVariable String memberId) {
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "成员ID", required = true) @PathVariable String memberId) {
|
||||||
imGroupService.removeAdmin(groupId, memberId);
|
imGroupService.removeAdmin(groupId, memberId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{groupId}/mute/{memberId}")
|
@PostMapping("/{groupId}/mute/{memberId}")
|
||||||
@ApiOperation(value = "禁言成员")
|
@ApiOperation(value = "禁言成员")
|
||||||
public ResultMessage<Void> muteMember(@PathVariable String groupId,
|
public ResultMessage<Void> muteMember(
|
||||||
@PathVariable String memberId,
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
@RequestParam Integer duration) {
|
@ApiParam(value = "成员ID", required = true) @PathVariable String memberId,
|
||||||
|
@ApiParam(value = "禁言时长(分钟)", required = true) @RequestParam Integer duration) {
|
||||||
imGroupService.muteMember(groupId, memberId, duration);
|
imGroupService.muteMember(groupId, memberId, duration);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{groupId}/mute/{memberId}")
|
@DeleteMapping("/{groupId}/mute/{memberId}")
|
||||||
@ApiOperation(value = "解除成员禁言")
|
@ApiOperation(value = "解除成员禁言")
|
||||||
public ResultMessage<Void> unmuteMember(@PathVariable String groupId,
|
public ResultMessage<Void> unmuteMember(
|
||||||
@PathVariable String memberId) {
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "成员ID", required = true) @PathVariable String memberId) {
|
||||||
imGroupService.unmuteMember(groupId, memberId);
|
imGroupService.unmuteMember(groupId, memberId);
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,14 @@ import cn.lili.common.enums.ResultCode;
|
|||||||
import cn.lili.common.enums.ResultUtil;
|
import cn.lili.common.enums.ResultUtil;
|
||||||
import cn.lili.common.exception.ServiceException;
|
import cn.lili.common.exception.ServiceException;
|
||||||
import cn.lili.common.vo.ResultMessage;
|
import cn.lili.common.vo.ResultMessage;
|
||||||
|
import cn.lili.common.vo.ResultPageVO;
|
||||||
import cn.lili.modules.im.entity.dos.ImMessage;
|
import cn.lili.modules.im.entity.dos.ImMessage;
|
||||||
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
import cn.lili.modules.im.entity.dto.MessageQueryParams;
|
||||||
|
import cn.lili.modules.im.entity.vo.ImMessageVO;
|
||||||
import cn.lili.modules.im.service.ImMessageService;
|
import cn.lili.modules.im.service.ImMessageService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -87,4 +90,24 @@ public class ImMessageController {
|
|||||||
imMessageService.cleanUnreadMessage();
|
imMessageService.cleanUnreadMessage();
|
||||||
return ResultUtil.success();
|
return ResultUtil.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{groupId}/messages")
|
||||||
|
@ApiOperation(value = "获取群聊消息历史")
|
||||||
|
public ResultMessage<ResultPageVO<ImMessageVO>> getGroupMessages(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "页码") @RequestParam(defaultValue = "1") Integer pageNumber,
|
||||||
|
@ApiParam(value = "每页大小") @RequestParam(defaultValue = "20") Integer pageSize) {
|
||||||
|
ResultPageVO<ImMessageVO> messages = imMessageService.getGroupMessages(groupId, pageNumber, pageSize);
|
||||||
|
return ResultUtil.data(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{groupId}/message")
|
||||||
|
@ApiOperation(value = "发送群聊消息")
|
||||||
|
public ResultMessage<ImMessageVO> sendGroupMessage(
|
||||||
|
@ApiParam(value = "群ID", required = true) @PathVariable String groupId,
|
||||||
|
@ApiParam(value = "消息内容", required = true) @RequestParam String content,
|
||||||
|
@ApiParam(value = "消息类型", required = true) @RequestParam String type) {
|
||||||
|
ImMessageVO message = imMessageService.sendGroupMessage(groupId, content, type);
|
||||||
|
return ResultUtil.data(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-24.zip
Normal file
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-24.zip
Normal file
Binary file not shown.
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-25.zip
Normal file
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-25.zip
Normal file
Binary file not shown.
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-26.zip
Normal file
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-02-26.zip
Normal file
Binary file not shown.
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-03-03.zip
Normal file
BIN
xxl-job/xxl-job/xxl-job-admin.log.2025-03-03.zip
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user