Commit a638f8bd by hweeeeeei

Merge branch 'master' of https://gitlab.aillo.cc/hewei/wecloud_im_server into feature-cluster

 Conflicts:
	common/src/main/java/com/wecloud/im/netty/core/WsReadHandler.java
	common/src/main/java/com/wecloud/im/ws/service/impl/MangerChannelServiceImpl.java
	common/src/main/java/com/wecloud/im/ws/service/impl/WriteDataServiceImpl.java
	common/src/main/java/com/wecloud/im/ws/strategy/concrete/ImChatConcrete.java
	docs/md/内部/wecloud-im前端Websocket对接文档.md
	开发记录.md
parents b159ce53 c7cc42a7
# 四恩慈善 - 后端项目 # IM 后端项目
## 框架介绍 ## 框架介绍
> 本项目使用第三方开源脚手架项目: spring-boot-plus 参考:README-zh.md > 本项目使用第三方开源脚手架项目: spring-boot-plus 参考:README-zh.md
......
package com.wecloud.im.controller; package com.wecloud.im.controller;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.param.GetClientInfoParam;
import com.wecloud.im.param.GetOnlineStatusParam; import com.wecloud.im.param.GetOnlineStatusParam;
import com.wecloud.im.param.add.ImClientDeviceInfoAdd; import com.wecloud.im.param.add.ImClientDeviceInfoAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAndNicknameUpdate;
import com.wecloud.im.param.add.ImClientNicknameAdd;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService; import com.wecloud.im.service.ImClientService;
import com.wecloud.im.vo.GetInfoListVo;
import com.wecloud.im.vo.ImOnlineStatusVo; import com.wecloud.im.vo.ImOnlineStatusVo;
import com.wecloud.im.ws.service.MangerChannelService; import com.wecloud.im.ws.service.MangerChannelService;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -46,6 +51,14 @@ public class ImClientController extends BaseController { ...@@ -46,6 +51,14 @@ public class ImClientController extends BaseController {
@Autowired @Autowired
private ImApplicationService imApplicationService; private ImApplicationService imApplicationService;
@PostMapping("/infoList")
@ApiOperation(value = "根据id获取Client的头像昵称")
public ApiResult<List<GetInfoListVo>> getInfoList(@Validated(Add.class) @RequestBody GetClientInfoParam getClientInfoParam) throws Exception {
return imClientService.getInfoList(getClientInfoParam);
}
/** /**
* 添加或修改推送设备信息 * 添加或修改推送设备信息
*/ */
...@@ -57,6 +70,29 @@ public class ImClientController extends BaseController { ...@@ -57,6 +70,29 @@ public class ImClientController extends BaseController {
} }
@PostMapping("/updateHeadAndNickname")
@ApiOperation(value = "添加或修改头像和昵称")
public ApiResult<Boolean> updateHeadAndNickname(@Validated(Add.class) @RequestBody ImClientHeadPortraitAndNicknameUpdate imClientHeadPortraitAndNicknameUpdate) throws Exception {
boolean flag = imClientService.updateHeadAndNickname(imClientHeadPortraitAndNicknameUpdate);
return ApiResult.result(flag);
}
@PostMapping("/updateHeadPortrait")
@ApiOperation(value = "添加或修改头像")
public ApiResult<Boolean> updateHeadPortrait(@Validated(Add.class) @RequestBody ImClientHeadPortraitAdd imClientHeadPortraitAdd) throws Exception {
boolean flag = imClientService.updateHeadPortrait(imClientHeadPortraitAdd);
return ApiResult.result(flag);
}
@PostMapping("/updateNickname")
@ApiOperation(value = "添加或修改主昵称")
public ApiResult<Boolean> updateNickname(@Validated(Add.class) @RequestBody ImClientNicknameAdd imClientNicknameAdd) throws Exception {
boolean flag = imClientService.updateNickname(imClientNicknameAdd);
return ApiResult.result(flag);
}
/** /**
* 退出登陆 * 退出登陆
* *
......
package com.wecloud.im.controller; package com.wecloud.im.controller;
import com.wecloud.im.param.add.ImClientLeaveConversation;
import com.wecloud.im.param.add.ImClientToConversation;
import com.wecloud.im.param.add.ImConversationAttrUpdate;
import com.wecloud.im.param.add.ImConversationCreate; import com.wecloud.im.param.add.ImConversationCreate;
import com.wecloud.im.param.add.ImConversationDisplayUpdate; import com.wecloud.im.param.add.ImConversationDisplayUpdate;
import com.wecloud.im.param.add.ImConversationNameUpdate;
import com.wecloud.im.service.ImConversationService; import com.wecloud.im.service.ImConversationService;
import com.wecloud.im.vo.ImConversationCreateVo; import com.wecloud.im.vo.ImConversationCreateVo;
import com.wecloud.im.vo.MyConversationListVo; import com.wecloud.im.vo.MyConversationListVo;
...@@ -33,6 +37,56 @@ public class ImConversationController extends BaseController { ...@@ -33,6 +37,56 @@ public class ImConversationController extends BaseController {
@Autowired @Autowired
private ImConversationService imConversationService; private ImConversationService imConversationService;
/**
* 添加或修改会话名称
*/
@PostMapping("/saveOrUpdateName")
@ApiOperation(value = "添加或修改会话名称", notes = "权限:目前只有创建者有权限操作")
public ApiResult<Boolean> saveOrUpdateName(@RequestBody ImConversationNameUpdate imConversationNameUpdate) throws Exception {
return imConversationService.saveOrUpdateName(imConversationNameUpdate);
}
/**
* 添加或修改会话拓展字段
*/
@PostMapping("/saveOrUpdateAttr")
@ApiOperation(value = "添加或修改会话拓展字段", notes = "权限:所有client都权限操作")
public ApiResult<Boolean> saveOrUpdateAttr(@RequestBody ImConversationAttrUpdate imConversationAttrUpdate) throws Exception {
return imConversationService.saveOrUpdateAttr(imConversationAttrUpdate);
}
/**
* client退出会话
*/
@PostMapping("/leave")
@ApiOperation(value = "client退出会话", notes = "若是创建者退出,[创建者]权限将会转移给按加入会话时间排序的下一个client")
public ApiResult<Boolean> leaveConversation(@RequestBody ImClientLeaveConversation imClientToConversation) throws Exception {
return imConversationService.leaveConversation(imClientToConversation);
}
/**
* 将client从会话移除
*/
@PostMapping("/delClient")
@ApiOperation(value = "将client从会话移除", notes = "权限:目前只有创建者有权限操作")
public ApiResult<Boolean> delClientToConversation(@RequestBody ImClientToConversation imClientToConversation) throws Exception {
return imConversationService.delClientToConversation(imClientToConversation);
}
/**
* 将用户添加进会话
*/
@PostMapping("/addClient")
@ApiOperation(value = "将用户添加进会话", notes = "权限:会话中所有client都有权限操作")
public ApiResult<Boolean> addClientToConversation(@RequestBody ImClientToConversation imClientToConversation) throws Exception {
return imConversationService.addClientToConversation(imClientToConversation);
}
/** /**
* 创建会话 * 创建会话
*/ */
......
package com.wecloud.im.controller; package com.wecloud.im.controller;
import com.wecloud.im.param.ImConvMemeClientRemarkNameParam;
import com.wecloud.im.param.ImConversationMembersListParam;
import com.wecloud.im.param.add.ImConversationMemAttrUpdate;
import com.wecloud.im.service.ImConversationMembersService; import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.vo.ImConversationMemberListVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController; import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 会话成员表 控制器 * 会话成员表 控制器
* *
...@@ -23,6 +34,37 @@ public class ImConversationMembersController extends BaseController { ...@@ -23,6 +34,37 @@ public class ImConversationMembersController extends BaseController {
@Autowired @Autowired
private ImConversationMembersService imConversationMembersService; private ImConversationMembersService imConversationMembersService;
/**
* 添加或修改会话成员备注
*/
@PostMapping("/updateClientRemarkName")
@ApiOperation(value = "添加或修改会话成员备注", notes = "权限:目前只有client成员自己有权限操作")
public ApiResult<Boolean> saveOrUpdateClientRemarkName(@RequestBody ImConvMemeClientRemarkNameParam imConvMemeClientRemarkNameParam) throws Exception {
return imConversationMembersService.saveOrUpdateClientRemarkName(imConvMemeClientRemarkNameParam);
}
/**
* 添加或修改会话成员拓展字段
*/
@PostMapping("/updateAttr")
@ApiOperation(value = "添加或修改会话成员拓展字段", notes = "权限:目前只有client成员自己有权限操作")
public ApiResult<Boolean> saveOrUpdateAttr(@RequestBody ImConversationMemAttrUpdate imConversationMemAttrUpdate) throws Exception {
return imConversationMembersService.saveOrUpdateAttr(imConversationMemAttrUpdate);
}
/**
* 会话中成员表列表
*/
@PostMapping("/getList")
// @OperationLog(name = "会话中成员表列表", type = OperationLogType.PAGE)
@ApiOperation(value = "获取会话中成员表列表")
public ApiResult<List<ImConversationMemberListVo>> getImConversationMembersList(@Validated @RequestBody ImConversationMembersListParam imConversationMembersListParam) throws Exception {
// Paging<ImConversationMembersQueryVo> paging = imConversationMembersService.getImConversationMembersPageList(imConversationMembersPageParam);
// return ApiResult.ok(paging);
return ApiResult.ok(imConversationMembersService.getImConversationMembersList(imConversationMembersListParam));
}
// /** // /**
// * 添加会话成员表 // * 添加会话成员表
......
package com.wecloud.im.controller.serverapi;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.param.ApiImConversationMembersPageParam;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImConversationMembersService;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 会话成员表 控制器
*
* @author wei
* @since 2021-05-07
*/
@Slf4j
@RestController
@RequestMapping("/server/imConversationMembers")
@Api(value = "服务端rest-API-会话成员表", tags = {"服务端API-会话成员表"})
public class ApiImConversationMembersController extends BaseController {
@Autowired
private ImConversationMembersService imConversationMembersService;
@Autowired
private ImApplicationService imApplicationService;
/**
* 会话成员表分页列表
*/
@PostMapping("/findList")
@OperationLog(name = "rest-api-会话成员表分页列表", type = OperationLogType.PAGE)
@ApiOperation(value = "rest-api-会话成员表分页列表")
public ApiResult<List<ApiImConversationMembersQueryVo>> getApiImConversationMembersList(@Validated @RequestBody ApiImConversationMembersPageParam apiImConversationMembersPageParam, @RequestHeader String appkey, @RequestHeader String appSecret) throws Exception {
// 根据appKey从数据库查询密钥
ImApplication imApplication = imApplicationService.getOneByAppKey(appkey);
if (imApplication == null) {
return ApiResult.result(ApiCode.FAIL, null);
}
// 校验appkey 和appSecret
if (!imApplication.getAppSecret().equals(appSecret)) {
return ApiResult.result(ApiCode.FAIL, null);
}
return imConversationMembersService.getRestApiImConversationMembersList(apiImConversationMembersPageParam, imApplication);
}
// /**
// * 添加会话成员表
// */
// @PostMapping("/add")
// @OperationLog(name = "添加会话成员表", type = OperationLogType.ADD)
// @ApiOperation(value = "添加会话成员表")
// public ApiResult<Boolean> addImConversationMembers(@Validated(Add.class) @RequestBody ImConversationMembers imConversationMembers) throws Exception {
// boolean flag = imConversationMembersService.saveImConversationMembers(imConversationMembers);
// return ApiResult.result(flag);
// }
//
// /**
// * 修改会话成员表
// */
// @PostMapping("/update")
// @OperationLog(name = "修改会话成员表", type = OperationLogType.UPDATE)
// @ApiOperation(value = "修改会话成员表")
// public ApiResult<Boolean> updateImConversationMembers(@Validated(Update.class) @RequestBody ImConversationMembers imConversationMembers) throws Exception {
// boolean flag = imConversationMembersService.updateImConversationMembers(imConversationMembers);
// return ApiResult.result(flag);
// }
//
// /**
// * 删除会话成员表
// */
// @PostMapping("/delete/{id}")
// @OperationLog(name = "删除会话成员表", type = OperationLogType.DELETE)
// @ApiOperation(value = "删除会话成员表")
// public ApiResult<Boolean> deleteImConversationMembers(@PathVariable("id") Long id) throws Exception {
// boolean flag = imConversationMembersService.deleteImConversationMembers(id);
// return ApiResult.result(flag);
// }
//
// /**
// * 获取会话成员表详情
// */
// @GetMapping("/info/{id}")
// @OperationLog(name = "会话成员表详情", type = OperationLogType.INFO)
// @ApiOperation(value = "会话成员表详情")
// public ApiResult<ImConversationMembersQueryVo> getImConversationMembers(@PathVariable("id") Long id) throws Exception {
// ImConversationMembersQueryVo imConversationMembersQueryVo = imConversationMembersService.getImConversationMembersById(id);
// return ApiResult.ok(imConversationMembersQueryVo);
// }
//
}
package com.wecloud.im.controller.serverapi;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.param.add.ImMsgSendToOnlineClient;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImMessageService;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 消息存储表 控制器
*
* @author wei
* @since 2021-04-29
*/
@Slf4j
@RestController
@RequestMapping("/server/imMessage")
@Api(value = "服务端rest-API-消息", tags = {"服务端rest-API-消息"})
public class ApiImMessageController extends BaseController {
@Autowired
private ImApplicationService imApplicationService;
@Autowired
private ImMessageService imMessageService;
/**
* 向会话中在线client,下发透传消息
*/
@PostMapping("/sendToOnlineClient")
@ApiOperation(value = "向会话中在线client,下发透传消息", notes = "应用服务端向某会话中所有client下发透传消息, 不会保存进离线消息, 仅在线client能收到")
public ApiResult<Boolean> restApiImMessageSend(@RequestBody ImMsgSendToOnlineClient imMsgSendToOnlineClient, @RequestHeader String appkey, @RequestHeader String appSecret) throws Exception {
// return imMessageService.updateMsgWithdrawById(imMsgRecall);
// 根据appKey从数据库查询密钥
ImApplication imApplication = imApplicationService.getOneByAppKey(appkey);
if (imApplication == null) {
return ApiResult.result(ApiCode.FAIL, null);
}
// 校验appkey 和appSecret
if (!imApplication.getAppSecret().equals(appSecret)) {
return ApiResult.result(ApiCode.FAIL, null);
}
return imMessageService.restApiImMessageSend(imMsgSendToOnlineClient, imApplication);
}
}
package com.wecloud.im.entity;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 消息在线推送
*
* @author wei
* @since 2021-04-29
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImApiMessageOnlineSend ")
public class ImApiMessageOnlineSend extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("内容")
private String content;
@ApiModelProperty("会话id")
private Long conversationId;
}
...@@ -56,4 +56,9 @@ public class ImClient extends BaseEntity { ...@@ -56,4 +56,9 @@ public class ImClient extends BaseEntity {
@ApiModelProperty("设备推送token") @ApiModelProperty("设备推送token")
private String deviceToken; private String deviceToken;
@ApiModelProperty("头像")
private String headPortrait;
@ApiModelProperty("主昵称")
private String nickname;
} }
...@@ -48,7 +48,13 @@ public class ImConversationMembers extends BaseEntity { ...@@ -48,7 +48,13 @@ public class ImConversationMembers extends BaseEntity {
@ApiModelProperty("客户端id") @ApiModelProperty("客户端id")
private Long fkClientId; private Long fkClientId;
@ApiModelProperty("可选 自定义属性,供开发者扩展使用。")
private String attributes;
@NotNull(message = "单向删除(隐藏)会话, 0不显示, 1显示不能为空") @NotNull(message = "单向删除(隐藏)会话, 0不显示, 1显示不能为空")
@ApiModelProperty("单向删除(隐藏)会话, 0不显示, 1显示") @ApiModelProperty("单向删除(隐藏)会话, 0不显示, 1显示")
private Long displayStatus; private Long displayStatus;
@ApiModelProperty("会话中client的备注名")
private String clientRemarkName;
} }
package com.wecloud.im.executor;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.wecloud.im.ws.model.WsConstants;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 业务处理线程池
*/
public class BusinessThreadPool {
private final static ThreadFactory BUSINESS_THREAD_FACTORY = new ThreadFactoryBuilder()
.setNamePrefix("-business-").build();
/**
* 业务处理线程池
*/
public final static ExecutorService BUSINESS_TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS, WsConstants.CPU_PROCESSORS * 2,
60L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024 * 2), BUSINESS_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy());
}
...@@ -6,10 +6,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; ...@@ -6,10 +6,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.param.ImClientPageParam; import com.wecloud.im.param.ImClientPageParam;
import com.wecloud.im.param.ImClientQueryVo; import com.wecloud.im.param.ImClientQueryVo;
import com.wecloud.im.vo.GetInfoListVo;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
/** /**
* 终端表 Mapper 接口 * 终端表 Mapper 接口
...@@ -41,4 +43,6 @@ public interface ImClientMapper extends BaseMapper<ImClient> { ...@@ -41,4 +43,6 @@ public interface ImClientMapper extends BaseMapper<ImClient> {
int removeOldToken(@Param("appId") Long appId, @Param("deviceToken") String deviceToken); int removeOldToken(@Param("appId") Long appId, @Param("deviceToken") String deviceToken);
List<GetInfoListVo> getInfoList(@Param("appId") Long appId, @Param("conversationId") Long conversationId, @Param("clientIds") List<String> clientIds);
} }
...@@ -77,7 +77,7 @@ public interface ImConversationMapper extends BaseMapper<ImConversation> { ...@@ -77,7 +77,7 @@ public interface ImConversationMapper extends BaseMapper<ImConversation> {
/** /**
* 查询已经存在的会话信息 * 查询已经存在的一对一会话信息
* *
* @param clientId1 * @param clientId1
* @param clientId2 * @param clientId2
......
...@@ -4,12 +4,15 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; ...@@ -4,12 +4,15 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImConversationMembers; import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.param.ImConversationMembersPageParam; import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo; import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.vo.ImConversationMemberListVo;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
/** /**
* 会话成员表 Mapper 接口 * 会话成员表 Mapper 接口
...@@ -28,6 +31,12 @@ public interface ImConversationMembersMapper extends BaseMapper<ImConversationMe ...@@ -28,6 +31,12 @@ public interface ImConversationMembersMapper extends BaseMapper<ImConversationMe
*/ */
ImConversationMembersQueryVo getImConversationMembersById(Serializable id); ImConversationMembersQueryVo getImConversationMembersById(Serializable id);
List<ApiImConversationMembersQueryVo> getRestApiImConversationMembersList(@Param("conversationId") Long conversationId);
List<ImConversationMemberListVo> getImConversationMembersList(@Param("conversationId") Long conversationId);
/** /**
* 获取分页对象 * 获取分页对象
* *
......
...@@ -4,12 +4,14 @@ import cn.hutool.core.thread.ThreadFactoryBuilder; ...@@ -4,12 +4,14 @@ import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.wecloud.im.ws.model.WsConstants; import com.wecloud.im.ws.model.WsConstants;
import com.wecloud.im.ws.receive.ReadWsData; import com.wecloud.im.ws.receive.ReadWsData;
import com.wecloud.im.ws.service.MangerChannelService; import com.wecloud.im.ws.service.MangerChannelService;
import com.wecloud.rtc.service.RtcService;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleStateEvent; import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
...@@ -35,6 +37,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -35,6 +37,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
@Resource @Resource
private ReadWsData readWsData; private ReadWsData readWsData;
@Autowired
private RtcService rtcService;
@Resource @Resource
private MangerChannelService mangerChannelService; private MangerChannelService mangerChannelService;
...@@ -46,9 +51,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -46,9 +51,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
* io密集型任务配置尽可能多的线程数量 * io密集型任务配置尽可能多的线程数量
*/ */
private final static ExecutorService TASK_THREAD_POOL_EXECUTOR = private final static ExecutorService TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 2, WsConstants.CPU_PROCESSORS * 2, new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 5, WsConstants.CPU_PROCESSORS * 10,
30L, TimeUnit.MILLISECONDS, 10L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024 * 5), NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy()); new LinkedBlockingQueue<Runnable>(10), NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy());
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) { protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
...@@ -62,7 +67,7 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -62,7 +67,7 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
/* /*
* 在此进入耗时业务线程池, 将不再阻塞netty的I/O线程,提高网络吞吐 * 在此进入耗时业务线程池, 将不再阻塞netty的I/O线程,提高网络吞吐
*/ */
TASK_THREAD_POOL_EXECUTOR.execute(() -> BusinessThreadPool.BUSINESS_TASK_THREAD_POOL_EXECUTOR.execute(() ->
execute(ctx, data) execute(ctx, data)
); );
...@@ -148,7 +153,7 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -148,7 +153,7 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) { public void handlerAdded(ChannelHandlerContext ctx) {
String userIdByChannel = mangerChannelService.getStringInfoByChannel(ctx); String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
log.info("连接WS成功handlerAdded,uid:" + userIdByChannel + "," + ",channelId:" + ctx.channel().id().asLongText()); log.info("连接WS成功handlerAdded,uid:" + userIdByChannel + "," + ",channelId:" + ctx.channel().id().asLongText());
} }
...@@ -171,8 +176,16 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -171,8 +176,16 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
@Override @Override
public void handlerRemoved(ChannelHandlerContext ctx) { public void handlerRemoved(ChannelHandlerContext ctx) {
String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get();
String clientId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get();
String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
log.info("uid:" + userIdByChannel + "," + "handlerRemoved" + ",channelId:" + ctx.channel().id().asLongText());
// 关掉连接 // 关掉连接
mangerChannelService.offline(ctx); mangerChannelService.offline(ctx);
ctx.close();
// rtc清空缓存
rtcService.clientOffline(appKey, clientId);
} }
} }
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* 会话成员表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ApiImConversationMembersPageParam")
public class ApiImConversationMembersPageParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会话表id", required = true)
private Long conversationId;
}
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* 会话成员表 查询结果对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ApiImConversationMembersQueryVo")
public class ApiImConversationMembersQueryVo implements Serializable {
private static final long serialVersionUID = 1L;
// @ApiModelProperty("唯一id")
// private Long id;
// @ApiModelProperty("加入时间")
// private Date createTime;
@ApiModelProperty("客户端id")
private String clientId;
// @ApiModelProperty("修改时间")
// private Date updateTime;
//
// @ApiModelProperty("应用appid")
// private Long fkAppid;
// @ApiModelProperty("会话表id")
// private Long fkConversationId;
}
\ No newline at end of file
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* sign
*
* @author wei
* @since 2021-04-29
*/
@Data
@ApiModel(value = "GetClientInfoParam")
public class GetClientInfoParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("client客户端id")
private List<String> clientIds;
@ApiModelProperty("会话id")
private Long conversationId;
}
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* 会话成员表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ImConvMemeClientRemarkNameParam")
public class ImConvMemeClientRemarkNameParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会话中的client备注,展示给会话中其他client查看的", required = true)
private String clientRemarkName;
@ApiModelProperty("会话表id")
private Long conversationId;
}
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* 会话成员表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ImConversationMembersListParam")
public class ImConversationMembersListParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会话表id", required = true)
private Long conversationId;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 添加或修改推送设备信息
*
* @author wei
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImClientHeadPortraitAdd")
public class ImClientHeadPortraitAdd extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("头像,uri地址")
private String headPortrait;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 添加或修改推送设备信息
*
* @author wei
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImClientHeadPortraitAndNicknameUpdate")
public class ImClientHeadPortraitAndNicknameUpdate extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("头像,uri地址")
private String headPortrait;
@ApiModelProperty("主昵称")
private String nickname;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author wei
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImClientLeaveConversation")
public class ImClientLeaveConversation extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("会话表id")
private Long conversationId;
@ApiModelProperty("会话的创建者退出时,是否需要转移给下一个client, true为转移, false为不转移直接解散")
private Boolean transfer;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 添加或修改推送设备信息
*
* @author wei
* @since 2021-04-27
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImClientNicknameAdd")
public class ImClientNicknameAdd extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主昵称")
private String nickname;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author wei
* @since 2021年11月30日16:57:03
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImClientToConversation")
public class ImClientToConversation extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("会话表id")
private Long conversationId;
@ApiModelProperty("要操作的clientId")
private List<String> clientIds;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.HashMap;
/**
* 会话表
*
* @author wei
* @since 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImConversationAttrUpdate")
public class ImConversationAttrUpdate extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("json格式,自定义属性,供开发者扩展使用。")
private HashMap attributes;
@ApiModelProperty("会话表id")
private Long conversationId;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.HashMap;
/**
* 会话表
*
* @author wei
* @since 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImConversationMemAttrUpdate")
public class ImConversationMemAttrUpdate extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("json格式,自定义属性,供开发者扩展使用。")
private HashMap attributes;
@ApiModelProperty("会话表id")
private Long conversationId;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 会话表
*
* @author wei
* @since 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImConversationNameUpdate")
public class ImConversationNameUpdate extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("对话的名字,可为群组命名。")
private String name;
@ApiModelProperty("会话表id")
private Long conversationId;
}
package com.wecloud.im.param.add;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.HashMap;
/**
* 自定义透传内容
*
* @author wei
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImMsgSendToOnlineClient")
public class ImMsgSendToOnlineClient extends BaseEntity {
private static final long serialVersionUID = 1L;
// @ApiModelProperty(value = "自定义透传内容", required = true)
// private String content;
@ApiModelProperty(value = "自定义透传内容 ,为任意参数名称和类型的对象,供开发者扩展使用。", required = true)
private HashMap content;
@ApiModelProperty(value = "会话id", required = true)
private Long conversationId;
}
...@@ -34,7 +34,7 @@ public class PushUtils { ...@@ -34,7 +34,7 @@ public class PushUtils {
} }
public static void main(String[] args) { public static void main(String[] args) {
// TODO set your appkey and master secret here // set your appkey and master secret here
PushUtils demo = new PushUtils("your appkey", "your master secret"); PushUtils demo = new PushUtils("your appkey", "your master secret");
try { try {
...@@ -52,7 +52,7 @@ public class PushUtils { ...@@ -52,7 +52,7 @@ public class PushUtils {
String body = "今日可能下雨🌂"; String body = "今日可能下雨🌂";
demo.sendIOSUnicast(deviceTokenIOS, titleIOS, subtitle, body); demo.sendIOSUnicast(deviceTokenIOS, titleIOS, subtitle, body);
/* TODO these methods are all available, just fill in some fields and do the test /* these methods are all available, just fill in some fields and do the test
* demo.sendAndroidCustomizedcastFile(); * demo.sendAndroidCustomizedcastFile();
* demo.sendAndroidBroadcast(); * demo.sendAndroidBroadcast();
* demo.sendAndroidGroupcast(); * demo.sendAndroidGroupcast();
...@@ -76,7 +76,7 @@ public class PushUtils { ...@@ -76,7 +76,7 @@ public class PushUtils {
broadcast.setText("Android broadcast text"); broadcast.setText("Android broadcast text");
broadcast.goAppAfterOpen(); broadcast.goAppAfterOpen();
broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION); broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device. // Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc. // For how to register a test device, please see the developer doc.
broadcast.setProductionMode(); broadcast.setProductionMode();
// Set customized fields // Set customized fields
...@@ -98,7 +98,7 @@ public class PushUtils { ...@@ -98,7 +98,7 @@ public class PushUtils {
*/ */
public void sendAndroidUnicast(String deviceToken, String unicastText, String unicastTicker, String title) throws Exception { public void sendAndroidUnicast(String deviceToken, String unicastText, String unicastTicker, String title) throws Exception {
AndroidUnicast unicast = new AndroidUnicast(appkey, appMasterSecret); AndroidUnicast unicast = new AndroidUnicast(appkey, appMasterSecret);
// TODO Set your device token // Set your device token
unicast.setDeviceToken(deviceToken); unicast.setDeviceToken(deviceToken);
...@@ -108,7 +108,7 @@ public class PushUtils { ...@@ -108,7 +108,7 @@ public class PushUtils {
unicast.setText(unicastText); unicast.setText(unicastText);
unicast.goAppAfterOpen(); unicast.goAppAfterOpen();
unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION); unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device. // Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc. // For how to register a test device, please see the developer doc.
unicast.setProductionMode(); unicast.setProductionMode();
// Set customized fields // Set customized fields
...@@ -120,7 +120,7 @@ public class PushUtils { ...@@ -120,7 +120,7 @@ public class PushUtils {
public void sendAndroidGroupcast() throws Exception { public void sendAndroidGroupcast() throws Exception {
AndroidGroupcast groupcast = new AndroidGroupcast(appkey, appMasterSecret); AndroidGroupcast groupcast = new AndroidGroupcast(appkey, appMasterSecret);
/* TODO /*
* Construct the filter condition: * Construct the filter condition:
* "where": * "where":
* { * {
...@@ -150,7 +150,7 @@ public class PushUtils { ...@@ -150,7 +150,7 @@ public class PushUtils {
groupcast.goAppAfterOpen(); groupcast.goAppAfterOpen();
groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION); groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
groupcast.setChannelActivity("your channel activity"); groupcast.setChannelActivity("your channel activity");
// TODO Set 'production_mode' to 'false' if it's a test device. // Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc. // For how to register a test device, please see the developer doc.
groupcast.setProductionMode(); groupcast.setProductionMode();
//厂商通道相关参数 //厂商通道相关参数
...@@ -161,7 +161,7 @@ public class PushUtils { ...@@ -161,7 +161,7 @@ public class PushUtils {
public void sendAndroidCustomizedcast() throws Exception { public void sendAndroidCustomizedcast() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey, appMasterSecret); AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey, appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias. // Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then // And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification. // use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type"); customizedcast.setAlias("alias", "alias_type");
...@@ -170,7 +170,7 @@ public class PushUtils { ...@@ -170,7 +170,7 @@ public class PushUtils {
customizedcast.setText("Android customizedcast text"); customizedcast.setText("Android customizedcast text");
customizedcast.goAppAfterOpen(); customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION); customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device. // Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc. // For how to register a test device, please see the developer doc.
customizedcast.setProductionMode(); customizedcast.setProductionMode();
//厂商通道相关参数 //厂商通道相关参数
...@@ -181,7 +181,7 @@ public class PushUtils { ...@@ -181,7 +181,7 @@ public class PushUtils {
public void sendAndroidCustomizedcastFile() throws Exception { public void sendAndroidCustomizedcastFile() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey, appMasterSecret); AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey, appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias. // Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then // And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification. // use file_id to send customized notification.
String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb" + "\n" + "alias"); String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb" + "\n" + "alias");
...@@ -191,7 +191,7 @@ public class PushUtils { ...@@ -191,7 +191,7 @@ public class PushUtils {
customizedcast.setText("Android customizedcast text"); customizedcast.setText("Android customizedcast text");
customizedcast.goAppAfterOpen(); customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION); customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device. // Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc. // For how to register a test device, please see the developer doc.
customizedcast.setProductionMode(); customizedcast.setProductionMode();
//厂商通道相关参数 //厂商通道相关参数
...@@ -202,7 +202,7 @@ public class PushUtils { ...@@ -202,7 +202,7 @@ public class PushUtils {
public void sendAndroidFilecast() throws Exception { public void sendAndroidFilecast() throws Exception {
AndroidFilecast filecast = new AndroidFilecast(appkey, appMasterSecret); AndroidFilecast filecast = new AndroidFilecast(appkey, appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens // upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb"); String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb");
filecast.setFileId(fileId); filecast.setFileId(fileId);
filecast.setTicker("Android filecast ticker"); filecast.setTicker("Android filecast ticker");
...@@ -224,7 +224,7 @@ public class PushUtils { ...@@ -224,7 +224,7 @@ public class PushUtils {
broadcast.setAlert("今日天气", "", "今日可能下雨🌂"); broadcast.setAlert("今日天气", "", "今日可能下雨🌂");
broadcast.setBadge(0); broadcast.setBadge(0);
broadcast.setSound("default"); broadcast.setSound("default");
// TODO set 'production_mode' to 'true' if your app is under production mode // set 'production_mode' to 'true' if your app is under production mode
broadcast.setTestMode(); broadcast.setTestMode();
// Set customized fields // Set customized fields
broadcast.setCustomizedField("test", "helloworld"); broadcast.setCustomizedField("test", "helloworld");
...@@ -243,7 +243,7 @@ public class PushUtils { ...@@ -243,7 +243,7 @@ public class PushUtils {
*/ */
public void sendIOSUnicast(String deviceToken, String title, String subtitle, String body) throws Exception { public void sendIOSUnicast(String deviceToken, String title, String subtitle, String body) throws Exception {
IOSUnicast unicast = new IOSUnicast(appkey, appMasterSecret); IOSUnicast unicast = new IOSUnicast(appkey, appMasterSecret);
// TODO Set your device token // Set your device token
unicast.setDeviceToken(deviceToken); unicast.setDeviceToken(deviceToken);
//alert值设置为字符串 //alert值设置为字符串
...@@ -253,7 +253,7 @@ public class PushUtils { ...@@ -253,7 +253,7 @@ public class PushUtils {
unicast.setAlert(title, subtitle, body); unicast.setAlert(title, subtitle, body);
unicast.setBadge(0); unicast.setBadge(0);
unicast.setSound("default"); unicast.setSound("default");
// TODO set 'production_mode' to 'true' if your app is under production mode // set 'production_mode' to 'true' if your app is under production mode
unicast.setTestMode(); unicast.setTestMode();
// Set customized fields // Set customized fields
unicast.setCustomizedField("test", "helloworld"); unicast.setCustomizedField("test", "helloworld");
...@@ -262,7 +262,7 @@ public class PushUtils { ...@@ -262,7 +262,7 @@ public class PushUtils {
public void sendIOSGroupcast() throws Exception { public void sendIOSGroupcast() throws Exception {
IOSGroupcast groupcast = new IOSGroupcast(appkey, appMasterSecret); IOSGroupcast groupcast = new IOSGroupcast(appkey, appMasterSecret);
/* TODO /*
* Construct the filter condition: * Construct the filter condition:
* "where": * "where":
* { * {
...@@ -289,14 +289,14 @@ public class PushUtils { ...@@ -289,14 +289,14 @@ public class PushUtils {
groupcast.setAlert("今日天气", "subtitle", "今日可能下雨🌂"); groupcast.setAlert("今日天气", "subtitle", "今日可能下雨🌂");
groupcast.setBadge(0); groupcast.setBadge(0);
groupcast.setSound("default"); groupcast.setSound("default");
// TODO set 'production_mode' to 'true' if your app is under production mode // set 'production_mode' to 'true' if your app is under production mode
groupcast.setTestMode(); groupcast.setTestMode();
client.send(groupcast); client.send(groupcast);
} }
public void sendIOSCustomizedcast() throws Exception { public void sendIOSCustomizedcast() throws Exception {
IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey, appMasterSecret); IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey, appMasterSecret);
// TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias. // Set your alias and alias_type here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then // And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification. // use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type"); customizedcast.setAlias("alias", "alias_type");
...@@ -305,14 +305,14 @@ public class PushUtils { ...@@ -305,14 +305,14 @@ public class PushUtils {
customizedcast.setAlert("今日天气", "", "今日可能下雨🌂"); customizedcast.setAlert("今日天气", "", "今日可能下雨🌂");
customizedcast.setBadge(0); customizedcast.setBadge(0);
customizedcast.setSound("default"); customizedcast.setSound("default");
// TODO set 'production_mode' to 'true' if your app is under production mode // set 'production_mode' to 'true' if your app is under production mode
customizedcast.setTestMode(); customizedcast.setTestMode();
client.send(customizedcast); client.send(customizedcast);
} }
public void sendIOSFilecast() throws Exception { public void sendIOSFilecast() throws Exception {
IOSFilecast filecast = new IOSFilecast(appkey, appMasterSecret); IOSFilecast filecast = new IOSFilecast(appkey, appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens // upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb"); String fileId = client.uploadContents(appkey, appMasterSecret, "aa" + "\n" + "bb");
filecast.setFileId(fileId); filecast.setFileId(fileId);
//filecast.setAlert("IOS 文件播测试"); //filecast.setAlert("IOS 文件播测试");
...@@ -320,7 +320,7 @@ public class PushUtils { ...@@ -320,7 +320,7 @@ public class PushUtils {
filecast.setAlert("今日天气", "", "今日可能下雨🌂"); filecast.setAlert("今日天气", "", "今日可能下雨🌂");
filecast.setBadge(0); filecast.setBadge(0);
filecast.setSound("default"); filecast.setSound("default");
// TODO set 'production_mode' to 'true' if your app is under production mode // set 'production_mode' to 'true' if your app is under production mode
filecast.setTestMode(); filecast.setTestMode();
client.send(filecast); client.send(filecast);
} }
......
package com.wecloud.im.service; package com.wecloud.im.service;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.param.GetClientInfoParam;
import com.wecloud.im.param.ImClientPageParam; import com.wecloud.im.param.ImClientPageParam;
import com.wecloud.im.param.ImClientQueryVo; import com.wecloud.im.param.ImClientQueryVo;
import com.wecloud.im.param.add.ImClientDeviceInfoAdd; import com.wecloud.im.param.add.ImClientDeviceInfoAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAndNicknameUpdate;
import com.wecloud.im.param.add.ImClientNicknameAdd;
import com.wecloud.im.vo.GetInfoListVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.BaseService; import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import java.util.List;
/** /**
* 终端表 服务类 * 终端表 服务类
* *
...@@ -15,6 +23,23 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging; ...@@ -15,6 +23,23 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging;
*/ */
public interface ImClientService extends BaseService<ImClient> { public interface ImClientService extends BaseService<ImClient> {
boolean updateHeadPortrait(ImClientHeadPortraitAdd imClientHeadPortraitAdd) throws Exception;
boolean updateHeadAndNickname(ImClientHeadPortraitAndNicknameUpdate imClientHeadPortraitAndNicknameUpdate);
/**
* 根据ids获取Client的头像昵称
*
* @param getClientInfoParam
* @return
* @throws Exception
*/
ApiResult<List<GetInfoListVo>> getInfoList(GetClientInfoParam getClientInfoParam) throws Exception;
boolean updateNickname(ImClientNicknameAdd imClientNicknameAdd) throws Exception;
/** /**
* 保存 * 保存
* *
......
package com.wecloud.im.service; package com.wecloud.im.service;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImConversationMembers; import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.param.ApiImConversationMembersPageParam;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.param.ImConvMemeClientRemarkNameParam;
import com.wecloud.im.param.ImConversationMembersListParam;
import com.wecloud.im.param.ImConversationMembersPageParam; import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo; import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.param.add.ImConversationMemAttrUpdate;
import com.wecloud.im.vo.ImConversationMemberListVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.BaseService; import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import java.util.List;
/** /**
* 会话成员表 服务类 * 会话成员表 服务类
* *
...@@ -14,6 +24,32 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging; ...@@ -14,6 +24,32 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging;
*/ */
public interface ImConversationMembersService extends BaseService<ImConversationMembers> { public interface ImConversationMembersService extends BaseService<ImConversationMembers> {
/**
* 服务端api-会话成员表分页列表
*
* @param apiImConversationMembersPageParam
* @param imApplication
* @return
*/
ApiResult<List<ApiImConversationMembersQueryVo>> getRestApiImConversationMembersList(ApiImConversationMembersPageParam apiImConversationMembersPageParam, ImApplication imApplication);
ApiResult<Boolean> saveOrUpdateClientRemarkName(ImConvMemeClientRemarkNameParam imConvMemeClientRemarkNameParam);
/**
* 会话成员表分页列表
*
* @param imConversationMembersListParam
* @return
* @throws Exception
*/
List<ImConversationMemberListVo> getImConversationMembersList(ImConversationMembersListParam imConversationMembersListParam) throws Exception;
ApiResult<Boolean> saveOrUpdateAttr(ImConversationMemAttrUpdate imConversationMemAttrUpdate);
/** /**
* 保存 * 保存
* *
......
...@@ -4,8 +4,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; ...@@ -4,8 +4,12 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.wecloud.im.entity.ImConversation; import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.param.ImConversationPageParam; import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo; import com.wecloud.im.param.ImConversationQueryVo;
import com.wecloud.im.param.add.ImClientLeaveConversation;
import com.wecloud.im.param.add.ImClientToConversation;
import com.wecloud.im.param.add.ImConversationAttrUpdate;
import com.wecloud.im.param.add.ImConversationCreate; import com.wecloud.im.param.add.ImConversationCreate;
import com.wecloud.im.param.add.ImConversationDisplayUpdate; import com.wecloud.im.param.add.ImConversationDisplayUpdate;
import com.wecloud.im.param.add.ImConversationNameUpdate;
import com.wecloud.im.vo.ImConversationCreateVo; import com.wecloud.im.vo.ImConversationCreateVo;
import com.wecloud.im.vo.MyConversationListVo; import com.wecloud.im.vo.MyConversationListVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -40,6 +44,39 @@ public interface ImConversationService extends BaseService<ImConversation> { ...@@ -40,6 +44,39 @@ public interface ImConversationService extends BaseService<ImConversation> {
*/ */
ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) throws JsonProcessingException; ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) throws JsonProcessingException;
/**
* 将用户添加进会话
*
* @param imClientToConversation
* @return
* @throws JsonProcessingException
*/
ApiResult<Boolean> addClientToConversation(ImClientToConversation imClientToConversation);
/**
* 将client从会话移除
*
* @param imClientToConversation
* @return
*/
ApiResult<Boolean> delClientToConversation(ImClientToConversation imClientToConversation) throws Exception;
/**
* client退出会话
*/
ApiResult<Boolean> leaveConversation(ImClientLeaveConversation imClientToConversation) throws Exception;
/**
* 添加或修改会话名称
*/
ApiResult<Boolean> saveOrUpdateName(ImConversationNameUpdate imConversationNameUpdate) throws Exception;
/**
* 添加或修改会话拓展字段
*/
ApiResult<Boolean> saveOrUpdateAttr(ImConversationAttrUpdate imConversationAttrUpdate) throws Exception;
/** /**
* 修改 * 修改
* *
......
package com.wecloud.im.service; package com.wecloud.im.service;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImMessage; import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.param.ImHistoryMessagePageParam; import com.wecloud.im.param.ImHistoryMessagePageParam;
import com.wecloud.im.param.add.ImMsgRecall; import com.wecloud.im.param.add.ImMsgRecall;
import com.wecloud.im.param.add.ImMsgSendToOnlineClient;
import com.wecloud.im.param.add.ImMsgUpdate; import com.wecloud.im.param.add.ImMsgUpdate;
import com.wecloud.im.vo.ImMessageOfflineListVo; import com.wecloud.im.vo.ImMessageOfflineListVo;
import com.wecloud.im.vo.OfflineMsgDto; import com.wecloud.im.vo.OfflineMsgDto;
...@@ -22,6 +25,18 @@ public interface ImMessageService extends BaseService<ImMessage> { ...@@ -22,6 +25,18 @@ public interface ImMessageService extends BaseService<ImMessage> {
/** /**
* 下发透传消息
*
* @param imMsgSendToOnlineClient
* @return
*/
ApiResult<Boolean> restApiImMessageSend(ImMsgSendToOnlineClient imMsgSendToOnlineClient, ImApplication imApplication);
ImMessage saveImMessage(ImApplication imApplication, ImClient imClientSender, Long toConversationId, long messageId, String content);
/**
* 消息撤回 只能撤回客户端自己发送的消息 * 消息撤回 只能撤回客户端自己发送的消息
* *
* @return * @return
......
...@@ -8,11 +8,17 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; ...@@ -8,11 +8,17 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.mapper.ImClientMapper; import com.wecloud.im.mapper.ImClientMapper;
import com.wecloud.im.param.GetClientInfoParam;
import com.wecloud.im.param.ImClientPageParam; import com.wecloud.im.param.ImClientPageParam;
import com.wecloud.im.param.ImClientQueryVo; import com.wecloud.im.param.ImClientQueryVo;
import com.wecloud.im.param.add.ImClientDeviceInfoAdd; import com.wecloud.im.param.add.ImClientDeviceInfoAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAndNicknameUpdate;
import com.wecloud.im.param.add.ImClientNicknameAdd;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService; import com.wecloud.im.service.ImClientService;
import com.wecloud.im.vo.GetInfoListVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl; import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo; import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
...@@ -27,6 +33,8 @@ import org.springframework.cache.annotation.Cacheable; ...@@ -27,6 +33,8 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/** /**
* 终端表 服务实现类 * 终端表 服务实现类
* *
...@@ -43,6 +51,92 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -43,6 +51,92 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
@Autowired @Autowired
private ImApplicationService imApplicationService; private ImApplicationService imApplicationService;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateHeadPortrait(ImClientHeadPortraitAdd imClientHeadPortraitAdd) throws Exception {
ImClient curentClient = getCurentClient();
// shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid
// ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
curentClient.setHeadPortrait(imClientHeadPortraitAdd.getHeadPortrait());
imClientMapper.updateById(curentClient);
// 清除client的redis缓存
deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());
return true;
}
@Override
public boolean updateHeadAndNickname(ImClientHeadPortraitAndNicknameUpdate imClientHeadPortraitAndNicknameUpdate) {
ImClient curentClient = getCurentClient();
// shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid
// ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
curentClient.setHeadPortrait(imClientHeadPortraitAndNicknameUpdate.getHeadPortrait());
curentClient.setNickname(imClientHeadPortraitAndNicknameUpdate.getNickname());
imClientMapper.updateById(curentClient);
// 清除client的redis缓存
deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());
return true;
}
@Override
public ApiResult<List<GetInfoListVo>> getInfoList(GetClientInfoParam getClientInfoParam) throws Exception {
ImClient curentClient = getCurentClient();
// List<ImClient> imClients = this.list(new QueryWrapper<ImClient>().lambda()
// .eq(ImClient::getFkAppid, curentClient.getFkAppid())
// .in(ImClient::getClientId, getClientInfoParam.getClientId())
// );
//
// List<GetInfoListVo> getInfoListVos = new ArrayList<>();
//
// for (ImClient imClient : imClients) {
//
// GetInfoListVo getInfoListVo = new GetInfoListVo();
// getInfoListVo.setHeadPortrait(imClient.getHeadPortrait());
// getInfoListVo.setNickname(imClient.getNickname());
// getInfoListVo.setClientId(imClient.getClientId());
// getInfoListVos.add(getInfoListVo);
// }
List<GetInfoListVo> infoList = imClientMapper.getInfoList(curentClient.getFkAppid(), getClientInfoParam.getConversationId(), getClientInfoParam.getClientIds());
return ApiResult.ok(infoList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateNickname(ImClientNicknameAdd imClientNicknameAdd) throws Exception {
ImClient curentClient = getCurentClient();
// shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid
// ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
curentClient.setNickname(imClientNicknameAdd.getNickname());
imClientMapper.updateById(curentClient);
// 清除client的redis缓存
deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());
return true;
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public boolean saveImClient(ImClient imClient) throws Exception { public boolean saveImClient(ImClient imClient) throws Exception {
......
package com.wecloud.im.service.impl; package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversationMembers; import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.mapper.ImConversationMapper;
import com.wecloud.im.mapper.ImConversationMembersMapper; import com.wecloud.im.mapper.ImConversationMembersMapper;
import com.wecloud.im.param.ApiImConversationMembersPageParam;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.param.ImConvMemeClientRemarkNameParam;
import com.wecloud.im.param.ImConversationMembersListParam;
import com.wecloud.im.param.ImConversationMembersPageParam; import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo; import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.param.add.ImConversationMemAttrUpdate;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImConversationMembersService; import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImConversationService;
import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.vo.ImConversationMemberListVo;
import com.wecloud.im.ws.service.WriteDataService;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl; import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo; import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
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 java.util.List;
/** /**
* 会话成员表 服务实现类 * 会话成员表 服务实现类
* *
...@@ -26,9 +48,154 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -26,9 +48,154 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class ImConversationMembersServiceImpl extends BaseServiceImpl<ImConversationMembersMapper, ImConversationMembers> implements ImConversationMembersService { public class ImConversationMembersServiceImpl extends BaseServiceImpl<ImConversationMembersMapper, ImConversationMembers> implements ImConversationMembersService {
// private static final JsonMapper JSON_MAPPER = new JsonMapper();
@Autowired
private WriteDataService writeDataService;
@Autowired
private ImConversationMapper imConversationMapper;
@Autowired
private ImConversationMembersService imConversationMembersService;
@Autowired
private ImConversationService imConversationService;
@Autowired
private ImClientService imClientService;
@Autowired
private ImApplicationService imApplicationService;
@Autowired
private ImMessageService imMessageService;
@Autowired @Autowired
private ImConversationMembersMapper imConversationMembersMapper; private ImConversationMembersMapper imConversationMembersMapper;
@Override
public ApiResult<List<ApiImConversationMembersQueryVo>> getRestApiImConversationMembersList(ApiImConversationMembersPageParam apiImConversationMembersPageParam, ImApplication imApplication) {
List<ApiImConversationMembersQueryVo> restApiImConversationMembersList = imConversationMembersMapper.getRestApiImConversationMembersList(apiImConversationMembersPageParam.getConversationId());
return ApiResult.ok(restApiImConversationMembersList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<Boolean> saveOrUpdateClientRemarkName(ImConvMemeClientRemarkNameParam imConvMemeClientRemarkNameParam) {
// shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询application
ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
ImClient imClientSender = imClientService.getCurentClient();
// 查询该成员
ImConversationMembers imConversationMember = imConversationMembersService.getOne(
new QueryWrapper<ImConversationMembers>().lambda()
.eq(ImConversationMembers::getFkAppid, imApplication.getId())
.eq(ImConversationMembers::getFkConversationId, imConvMemeClientRemarkNameParam.getConversationId())
.eq(ImConversationMembers::getFkClientId, imClientSender.getId())
);
if (imConversationMember == null) {
return ApiResult.fail();
}
// // 查询该会话所有成员
// List<ImConversationMembers> membersList = imConversationMembersService.list(
// new QueryWrapper<ImConversationMembers>().lambda()
// .eq(ImConversationMembers::getFkAppid, imApplication.getId())
// .eq(ImConversationMembers::getFkConversationId, imConversationAttrUpdate.getConversationId())
// .notIn(ImConversationMembers::getId, imClientSender.getId())
// );
imConversationMember.setClientRemarkName(imConvMemeClientRemarkNameParam.getClientRemarkName());
boolean b = imConversationMembersService.updateById(imConversationMember);
if (b) {
//TODO ws下发群成员备注变动事件
return ApiResult.ok();
} else {
return ApiResult.fail();
}
}
@Override
public List<ImConversationMemberListVo> getImConversationMembersList(ImConversationMembersListParam imConversationMembersListParam) throws Exception {
return imConversationMembersMapper.getImConversationMembersList(imConversationMembersListParam.getConversationId());
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<Boolean> saveOrUpdateAttr(ImConversationMemAttrUpdate imConversationMemAttrUpdate) {
// shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询application
ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
ImClient imClientSender = imClientService.getCurentClient();
// 查询该成员
ImConversationMembers imConversationMember = imConversationMembersService.getOne(
new QueryWrapper<ImConversationMembers>().lambda()
.eq(ImConversationMembers::getFkAppid, imApplication.getId())
.eq(ImConversationMembers::getFkConversationId, imConversationMemAttrUpdate.getConversationId())
.eq(ImConversationMembers::getId, imClientSender.getId())
);
if (imConversationMember == null) {
return ApiResult.fail();
}
// // 查询该会话所有成员
// List<ImConversationMembers> membersList = imConversationMembersService.list(
// new QueryWrapper<ImConversationMembers>().lambda()
// .eq(ImConversationMembers::getFkAppid, imApplication.getId())
// .eq(ImConversationMembers::getFkConversationId, imConversationAttrUpdate.getConversationId())
// .notIn(ImConversationMembers::getId, imClientSender.getId())
// );
JsonMapper jsonMapper = new JsonMapper();
try {
String attributes = jsonMapper.writeValueAsString(imConversationMemAttrUpdate.getAttributes());
imConversationMember.setAttributes(attributes);
} catch (JsonProcessingException e) {
e.printStackTrace();
return ApiResult.fail();
}
boolean b = imConversationMembersService.updateById(imConversationMember);
if (b) {
//TODO ws下发群成员属性变动事件
return ApiResult.ok();
} else {
return ApiResult.fail();
}
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public boolean saveImConversationMembers(ImConversationMembers imConversationMembers) throws Exception { public boolean saveImConversationMembers(ImConversationMembers imConversationMembers) throws Exception {
......
...@@ -15,6 +15,7 @@ import com.wecloud.im.service.ImClientService; ...@@ -15,6 +15,7 @@ import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImConversationMembersService; import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImInboxService; import com.wecloud.im.service.ImInboxService;
import com.wecloud.im.service.ImMessageService; import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.ws.enums.MsgTypeEnum;
import com.wecloud.im.ws.enums.WsResponseCmdEnum; import com.wecloud.im.ws.enums.WsResponseCmdEnum;
import com.wecloud.im.ws.model.WsResponseModel; import com.wecloud.im.ws.model.WsResponseModel;
import com.wecloud.im.ws.service.WriteDataService; import com.wecloud.im.ws.service.WriteDataService;
...@@ -101,7 +102,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -101,7 +102,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
// 内容 // 内容
HashMap<String, String> stringStringHashMap = new HashMap<>(); HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put("type", "-1009"); stringStringHashMap.put("type", MsgTypeEnum.CLIENT_RECEIVED_MSG.getUriCode() + "");
stringStringHashMap.put("receiverId", curentClient.getClientId()); stringStringHashMap.put("receiverId", curentClient.getClientId());
// 推送给接收方 // 推送给接收方
...@@ -144,7 +145,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -144,7 +145,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
// 内容 // 内容
HashMap<String, String> stringStringHashMap = new HashMap<>(); HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put("type", "-1010"); stringStringHashMap.put("type", MsgTypeEnum.CLIENT_READ_MSG + "");
stringStringHashMap.put("receiverId", curentClient.getClientId()); stringStringHashMap.put("receiverId", curentClient.getClientId());
sendMsgStatus(curentClient, application, stringStringHashMap, imMsgReadStatusUpdate.getMsgIds()); sendMsgStatus(curentClient, application, stringStringHashMap, imMsgReadStatusUpdate.getMsgIds());
......
...@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.OrderItem; ...@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.json.JsonMapper;
import com.wecloud.im.entity.ImApiMessageOnlineSend;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversation; import com.wecloud.im.entity.ImConversation;
...@@ -15,6 +16,7 @@ import com.wecloud.im.entity.ImMessageOnlineSend; ...@@ -15,6 +16,7 @@ import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.mapper.ImMessageMapper; import com.wecloud.im.mapper.ImMessageMapper;
import com.wecloud.im.param.ImHistoryMessagePageParam; import com.wecloud.im.param.ImHistoryMessagePageParam;
import com.wecloud.im.param.add.ImMsgRecall; import com.wecloud.im.param.add.ImMsgRecall;
import com.wecloud.im.param.add.ImMsgSendToOnlineClient;
import com.wecloud.im.param.add.ImMsgUpdate; import com.wecloud.im.param.add.ImMsgUpdate;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService; import com.wecloud.im.service.ImClientService;
...@@ -53,6 +55,8 @@ import java.util.List; ...@@ -53,6 +55,8 @@ import java.util.List;
@Service @Service
public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMessage> implements ImMessageService { public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMessage> implements ImMessageService {
// private static final JsonMapper JSON_MAPPER = new JsonMapper();
@Autowired @Autowired
private ImMessageMapper imMessageMapper; private ImMessageMapper imMessageMapper;
...@@ -77,6 +81,86 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes ...@@ -77,6 +81,86 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ApiResult<Boolean> restApiImMessageSend(ImMsgSendToOnlineClient imMsgSendToOnlineClient, ImApplication imApplication) {
// 查询该会话所有成员
List<ImConversationMembers> membersList = imConversationMembersService.list(
new QueryWrapper<ImConversationMembers>().lambda()
.eq(ImConversationMembers::getFkConversationId, imMsgSendToOnlineClient.getConversationId())
);
if (membersList.isEmpty()) {
log.info("membersList为空,toConversationId:" + imMsgSendToOnlineClient.getConversationId());
return ApiResult.fail();
}
ImApiMessageOnlineSend imApiMessageOnlineSend = new ImApiMessageOnlineSend();
imApiMessageOnlineSend.setCreateTime(new Date());
JsonMapper jsonMapper = new JsonMapper();
try {
String attributes = jsonMapper.writeValueAsString(imMsgSendToOnlineClient.getContent());
imApiMessageOnlineSend.setContent(attributes);
} catch (JsonProcessingException e) {
e.printStackTrace();
return ApiResult.fail();
}
imApiMessageOnlineSend.setConversationId(imMsgSendToOnlineClient.getConversationId());
// 遍历发送
for (ImConversationMembers conversationMembers : membersList) {
// 查询接收方
ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getId, conversationMembers.getFkClientId()));
if (imClientReceiver == null) {
continue;
}
WsResponseModel<ImApiMessageOnlineSend> responseModel = new WsResponseModel<>();
responseModel.setCmd(WsResponseCmdEnum.REST_API_MSG.getCmdCode());
ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage());
responseModel.setData(imApiMessageOnlineSend);
responseModel.setReqId(null);
// 向接收方推送
writeDataService.write(responseModel, imApplication.getAppKey(), imClientReceiver.getClientId());
}
return null;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImMessage saveImMessage(ImApplication imApplication, ImClient imClientSender, Long toConversationId, long messageId, String content) {
ImMessage imMessage = new ImMessage();
imMessage.setId(messageId);
imMessage.setCreateTime(new Date());
imMessage.setFkAppid(imApplication.getId());
imMessage.setSender(imClientSender.getId());
imMessage.setContent(content);
imMessage.setWithdraw(false);
imMessage.setEvent(false);
imMessage.setSystem(false);
imMessage.setSendStatus(2);
imMessage.setFkConversationId(toConversationId);
this.save(imMessage);
return imMessage;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<Boolean> updateMsgWithdrawById(ImMsgRecall imMsgRecall) { public ApiResult<Boolean> updateMsgWithdrawById(ImMsgRecall imMsgRecall) {
ImClient imClientSender = imClientService.getCurentClient(); ImClient imClientSender = imClientService.getCurentClient();
......
package com.wecloud.im.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "GetInfoListVo")
public class GetInfoListVo implements Serializable {
@ApiModelProperty("会话中client的备注名")
private String clientRemarkName;
@ApiModelProperty("头像")
private String headPortrait;
@ApiModelProperty("主昵称")
private String nickname;
@ApiModelProperty("clientId")
private String clientId;
@ApiModelProperty("client自己的自定义扩展属性")
private String clientAttributes;
@ApiModelProperty("会话成员列表的自定义扩展属性")
private String memberAttributes;
}
package com.wecloud.im.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "ImConversationMemberListVo")
public class ImConversationMemberListVo implements Serializable {
@ApiModelProperty("会话中client的备注名")
private String clientRemarkName;
@ApiModelProperty("头像")
private String headPortrait;
@ApiModelProperty("主昵称")
private String nickname;
@ApiModelProperty("clientId")
private String clientId;
@ApiModelProperty("client自己的自定义扩展属性")
private String clientAttributes;
@ApiModelProperty("会话成员列表的自定义扩展属性")
private String memberAttributes;
}
package com.wecloud.im.ws.enums;
/**
* @Description ws响应类型
* @Author xxxname xxxemail.com
* @Date 2019-12-05
*/
public enum MsgTypeEnum {
// xx邀请xx加入会话 -1007
INVITE_CLIENT_JOIN_CONVERSATION(-1007),
// xx被xx移出会话 -1008
REMOVE_CLIENT_CONVERSATION(-1008),
// xx已接收某消息 -1009
CLIENT_RECEIVED_MSG(-1009),
// xx已读某条消息 -1010
CLIENT_READ_MSG(-1010),
// 你被xx拉入新会话 -1011
CLIENT_JOIN_NEW_CONVERSATION(-1011),
// 主动退出会话 -1012
LEAVE_CONVERSATION(-1012),
// 成为新群主 -1013
CONVERSATION_NEW_CREATOR(-1013),
;
private final int uriCode;
MsgTypeEnum(int uriCode) {
this.uriCode = uriCode;
}
/**
* 根据uriCode获取
*
* @param uriCode
* @return
*/
public static MsgTypeEnum getByCode(int uriCode) {
for (MsgTypeEnum wsResponsePathEnum : values()) {
if (wsResponsePathEnum.getUriCode() == uriCode) {
return wsResponsePathEnum;
}
}
return null;
}
public int getUriCode() {
return uriCode;
}
}
...@@ -8,6 +8,16 @@ package com.wecloud.im.ws.enums; ...@@ -8,6 +8,16 @@ package com.wecloud.im.ws.enums;
public enum WsResponseCmdEnum { public enum WsResponseCmdEnum {
/** /**
* 服务端下发透传消息
*/
REST_API_MSG(6),
/**
* 会话中的事件
*/
CONVERSATION_EVENT_MSG(5),
/**
* 下发在线RTC事件 * 下发在线RTC事件
*/ */
SINGLE_RTC_MSG(4), SINGLE_RTC_MSG(4),
......
...@@ -119,6 +119,11 @@ public class PushTask { ...@@ -119,6 +119,11 @@ public class PushTask {
} }
private void android(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) { private void android(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
if (imApplication.getAndroidPushChannel() == null) {
return;
}
// 安卓推送通道,友盟:1;firebase:2; 信鸽3 // 安卓推送通道,友盟:1;firebase:2; 信鸽3
if (imApplication.getAndroidPushChannel() == 1) { if (imApplication.getAndroidPushChannel() == 1) {
log.info("友盟"); log.info("友盟");
...@@ -152,6 +157,11 @@ public class PushTask { ...@@ -152,6 +157,11 @@ public class PushTask {
} }
private void ios(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) { private void ios(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
if (imApplication.getIosPushChannel() == null) {
return;
}
// ios推送通道,友盟:1;firebase:2; apns原生:3 // ios推送通道,友盟:1;firebase:2; apns原生:3
if (imApplication.getIosPushChannel() == 1) { if (imApplication.getIosPushChannel() == 1) {
log.info("友盟"); log.info("友盟");
......
...@@ -140,6 +140,8 @@ public class ImChatConcrete extends ImCmdAbstract { ...@@ -140,6 +140,8 @@ public class ImChatConcrete extends ImCmdAbstract {
long messageId = SnowflakeUtil.getId(); long messageId = SnowflakeUtil.getId();
// 入库 保存消息至消息表 // 入库 保存消息至消息表
ImMessage imMessage = saveImMessage(imApplication, imClientSender, toConversationId, messageId, content); ImMessage imMessage = saveImMessage(imApplication, imClientSender, toConversationId, messageId, content);
// 保存消息至消息表
ImMessage imMessage = imMessageService.saveImMessage(imApplication, imClientSender, toConversationId, messageId, content);
// 封装响应的实体 // 封装响应的实体
ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend(); ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();
...@@ -236,21 +238,6 @@ public class ImChatConcrete extends ImCmdAbstract { ...@@ -236,21 +238,6 @@ public class ImChatConcrete extends ImCmdAbstract {
return imClientSender; return imClientSender;
} }
private ImMessage saveImMessage(ImApplication imApplication, ImClient imClientSender, Long toConversationId, long messageId, String content) {
ImMessage imMessage = new ImMessage();
imMessage.setId(messageId);
imMessage.setCreateTime(new Date());
imMessage.setFkAppid(imApplication.getId());
imMessage.setSender(imClientSender.getId());
imMessage.setContent(content);
imMessage.setWithdraw(false);
imMessage.setEvent(false);
imMessage.setSystem(false);
imMessage.setSendStatus(2);
imMessage.setFkConversationId(toConversationId);
imMessageService.save(imMessage);
return imMessage;
}
/** /**
* 判断是否被拉黑 * 判断是否被拉黑
......
...@@ -26,5 +26,31 @@ ...@@ -26,5 +26,31 @@
<include refid="Base_Column_List"/> <include refid="Base_Column_List"/>
from im_client from im_client
</select> </select>
<select id="getInfoList" resultType="com.wecloud.im.vo.GetInfoListVo">
SELECT
im_client.client_id AS clientId,
im_client.head_portrait AS headPortrait,
im_client.nickname,
(SELECT im_conversation_members.client_remark_name FROM im_conversation_members AS im_conversation_members WHERE
im_conversation_members.fk_conversation_id = #{conversationId} AND im_conversation_members.fk_client_id =
clientId ) AS clientRemarkName ,
(SELECT im_conversation_members.attributes FROM im_conversation_members AS im_conversation_members WHERE
im_conversation_members.fk_conversation_id = #{conversationId} AND im_conversation_members.fk_client_id =
clientId ) AS memberAttributes ,
im_client.attributes AS clientAttributes
FROM
im_client AS im_client
WHERE
im_client.fk_appid = #{appId}
AND im_client.client_id IN
<foreach collection="clientIds" item="clientId" index="index" open="(" close=")" separator=",">
#{clientId}
</foreach>
</select>
</mapper> </mapper>
...@@ -92,14 +92,19 @@ ...@@ -92,14 +92,19 @@
<select id="getRepetitionConversationInfo" resultType="com.wecloud.im.entity.ImConversation"> <select id="getRepetitionConversationInfo" resultType="com.wecloud.im.entity.ImConversation">
SELECT im_conversation.*
SELECT im_conversation.*,
(SELECT COUNT(im2.id)
FROM im_conversation_members AS im2
WHERE im2.fk_conversation_id = im_conversation_members.fk_conversation_id) AS members_count
FROM im_conversation_members FROM im_conversation_members
INNER JOIN (SELECT * INNER JOIN (SELECT *
FROM im_conversation_members FROM im_conversation_members
WHERE im_conversation_members.fk_client_id = #{clientId2}) AS im_conversation_members2 WHERE im_conversation_members.fk_client_id = #{clientId2}) AS im_conversation_members2
ON im_conversation_members.fk_conversation_id = im_conversation_members2.fk_conversation_id ON im_conversation_members.fk_conversation_id = im_conversation_members2.fk_conversation_id
INNER JOIN im_conversation ON im_conversation.id = im_conversation_members.fk_conversation_id INNER JOIN im_conversation ON im_conversation.id = im_conversation_members.fk_conversation_id
WHERE im_conversation_members.fk_client_id = #{clientId1} LIMIT 1 WHERE im_conversation_members.fk_client_id = #{clientId1}
HAVING members_count = 2 LIMIT 1
</select> </select>
</mapper> </mapper>
...@@ -20,5 +20,27 @@ ...@@ -20,5 +20,27 @@
<include refid="Base_Column_List"/> <include refid="Base_Column_List"/>
from im_conversation_members from im_conversation_members
</select> </select>
<select id="getRestApiImConversationMembersList"
resultType="com.wecloud.im.param.ApiImConversationMembersQueryVo">
SELECT im_client.client_id AS clientId
FROM im_conversation_members AS imConversationMembers
INNER JOIN im_client AS im_client ON im_client.id = imConversationMembers.fk_client_id
WHERE fk_conversation_id = #{conversationId}
</select>
<select id="getImConversationMembersList" resultType="com.wecloud.im.vo.ImConversationMemberListVo">
SELECT im_client.client_id as clientId,
im_conversation_members.client_remark_name as clientRemarkName,
im_client.head_portrait as headPortrait,
im_client.nickname,
im_conversation_members.attributes AS memberAttributes,
im_client.attributes AS clientAttributes
FROM im_conversation_members AS im_conversation_members
INNER JOIN im_client AS im_client ON im_client.id = im_conversation_members.fk_client_id
WHERE im_conversation_members.fk_conversation_id = #{conversationId}
</select>
</mapper> </mapper>
...@@ -15,7 +15,7 @@ spring-boot-plus: ...@@ -15,7 +15,7 @@ spring-boot-plus:
spring: spring:
datasource: datasource:
url: jdbc:mysql://localhost:3306/wecloud_im_v1_3?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://localhost:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: root username: root
password: 123 password: 123
......
...@@ -18,16 +18,16 @@ spring-boot-plus: ...@@ -18,16 +18,16 @@ spring-boot-plus:
spring: spring:
# upay # upay
# datasource: datasource:
# url: jdbc:mysql://172.31.38.183:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://172.31.38.183:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
# username: web username: web
# password: 74DXJwJE7wYehHr5VFJbc2w8 password: 74DXJwJE7wYehHr5VFJbc2w8
# # Redis配置 # Redis配置
# redis: redis:
# database: 0 database: 0
# host: 172.31.38.183 host: 172.31.38.183
# password: qZ8yzTz8chSZE1ZbbRbK password: qZ8yzTz8chSZE1ZbbRbK
# port: 6379 port: 6379
# 飞蛙 # 飞蛙
# datasource: # datasource:
...@@ -41,20 +41,21 @@ spring: ...@@ -41,20 +41,21 @@ spring:
# port: 6379 # port: 6379
# 国内IM集成版 # 国内IM集成版
datasource: # datasource:
url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true # url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: root # username: root
password: axT8knPN5hAP # password: axT8knPN5hAP
redis: # redis:
database: 0 # database: 0
host: 127.0.0.1 # host: 127.0.0.1
password: JH86uc53r8Ca # password: JH86uc53r8Ca
port: 6379 # port: 6379
#
# cloud:
# nacos:
# discovery:
# server-addr: localhost:8848
cloud:
nacos:
discovery:
server-addr: localhost:8848
# knife4j配置 # knife4j配置
knife4j: knife4j:
enable: ${spring-boot-plus.swagger.enable} enable: ${spring-boot-plus.swagger.enable}
......
...@@ -14,41 +14,42 @@ spring-boot-plus: ...@@ -14,41 +14,42 @@ spring-boot-plus:
response-log-format: false response-log-format: false
#spring: # 海外 upay 飞蛙等 IM测试外网
# datasource:
# url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
# username: web
# password: axT8knPN5hAP
#
# # Redis配置
# redis:
# database: 0
# host: 127.0.0.1
# password: JH86uc53r8Ca
# port: 6379
# cloud:
# nacos:
# discovery:
# server-addr: localhost:8848
# 国内IM测试外网
spring: spring:
datasource: datasource:
url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: root username: web
password: temple123456 password: axT8knPN5hAP
# Redis配置 # Redis配置
redis: redis:
database: 0 database: 0
host: 127.0.0.1 host: 127.0.0.1
password: temple123456 password: JH86uc53r8Ca
port: 6379 port: 6379
cloud: cloud:
nacos: nacos:
discovery: discovery:
server-addr: localhost:8848 server-addr: localhost:8848
# 国内IM测试外网
#spring:
# datasource:
# url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
# username: root
# password: temple123456
#
# # Redis配置
# redis:
# database: 0
# host: 127.0.0.1
# password: temple123456
# port: 6379
# cloud:
# nacos:
# discovery:
# server-addr: localhost:8848
# 打印SQL语句和结果集,本地开发环境可开启,线上注释掉 # 打印SQL语句和结果集,本地开发环境可开启,线上注释掉
mybatis-plus: mybatis-plus:
configuration: configuration:
......
...@@ -199,6 +199,8 @@ spring-boot-plus: ...@@ -199,6 +199,8 @@ spring-boot-plus:
- /imApplication/** - /imApplication/**
- /signDemo/get - /signDemo/get
- /Wecloud-IM-Websocket-Docs.html - /Wecloud-IM-Websocket-Docs.html
# 服务端rest-API
- /server/**
# 多行字符串权限配置 # 多行字符串权限配置
filter-chain-definitions: | filter-chain-definitions: |
......
This source diff could not be displayed because it is too large. You can view the blob instead.
# wecloud-im 前端Websocket对接文档 # wecloud-im 前端Websocket对接文档
...@@ -28,7 +28,7 @@ http://192.168.1.89/api/doc.html#/home ...@@ -28,7 +28,7 @@ http://192.168.1.89/api/doc.html#/home
https://imapitest.wecloud.cn/api/doc.html#/home https://imapitest.wecloud.cn/api/doc.html#/home
``` ```
只包含api接口文档 只包含api接口文档 websocket对接说明在此文档中
## 适用对象 ## 适用对象
...@@ -192,7 +192,9 @@ wss://imapi.wecloud.cn/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ ...@@ -192,7 +192,9 @@ wss://imapi.wecloud.cn/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ
- 4:下发单人在线RTC事件通知 - 4:下发单人在线RTC事件通知
- 5:响应请求(用于RTC音视频通话) - 5: 会话中的事件
- 6:下发透传消息
...@@ -219,6 +221,8 @@ wss://imapi.wecloud.cn/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ ...@@ -219,6 +221,8 @@ wss://imapi.wecloud.cn/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ
- xx已接收某消息 -1009 - xx已接收某消息 -1009
- xx已读某条消息 -1010 - xx已读某条消息 -1010
- 你被xx拉入新会话 -1011 - 你被xx拉入新会话 -1011
- 主动退出会话 -1012
- 成为新群主 -1013
以上基础平台固定类型均使用负数,所有正数留给自定义扩展类型使用,0 作为「没有类型」被保留起来。 以上基础平台固定类型均使用负数,所有正数留给自定义扩展类型使用,0 作为「没有类型」被保留起来。
...@@ -414,6 +418,9 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -414,6 +418,9 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
``` ```
上面是完整的例子,如果只想简单的发送图像 URL:
必传参数示例 必传参数示例
```json ```json
{ {
...@@ -450,7 +457,7 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -450,7 +457,7 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
## 发送音频消息 ## 发送音频消息
```json ```json
...@@ -630,6 +637,22 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -630,6 +637,22 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
## 服务端下发透传消息
```json
{
"reqId":"1",
"cmd":6,
"data":{
"toConversation":1394188055950266368,
"createTime":1621240016587,
"content":"json字符串,或任意字符数据"
}
}
```
## 客户端在线接收事件类型消息 ## 客户端在线接收事件类型消息
### 事件类型type (xx表示为某客户端) ### 事件类型type (xx表示为某客户端)
...@@ -639,6 +662,223 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -639,6 +662,223 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
- xx已接收某消息 -1009 - xx已接收某消息 -1009
- xx已读某条消息 -1010 - xx已读某条消息 -1010
- 你被xx拉入新会话 -1011 - 你被xx拉入新会话 -1011
- xx主动退出会话 -1012
- xx成为新群主 -1013
- 群拓展字段变动事件 -1014
- 会话名称字段变动事件 -1015
### 下发 会话名称字段变动事件
该event事件消息类型不需要回执,该消息不会存入离线消息列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"createTime":1629086007054,
"content":{
"type":-1015,
"name":"xxxxxxx"
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
### 下发 会话拓展字段变动事件
该event事件消息类型不需要回执,该消息不会存入离线消息列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"createTime":1629086007054,
"content":{
"type":-1014,
"attributes":"xxxxxxx"
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
### 下发 xx成为新群主
"cmd":5
该event事件消息类型需要已读和已接收回执,该消息会存入离线消息列表和消息历史记录列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"msgId":1427109835333308416,
"createTime":1629086007054,
"sender":"aaaaa1",
"content":{
"type":-1013
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
**参数描述**
| 字段名 | 字段类型 | 是否可空 | 说明 |
| ------ | -------- | -------- | ----------------- |
| sender | String | 否 | 新群主的client ID |
### 下发 xx主动退出会话
"cmd":5
该event事件消息类型需要已读和已接收回执,该消息会存入离线消息列表和消息历史记录列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"msgId":1427109835333308416,
"createTime":1629086007054,
"sender":"aaaaa1",
"content":{
"type":-1012
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
**参数描述**
| 字段名 | 字段类型 | 是否可空 | 说明 |
| ------ | -------- | -------- | --------------- |
| sender | String | 否 | 退出的client ID |
### 下发 xx被xx移出会话
type为-1008
"cmd":5
该event事件消息类型需要已读和已接收回执,该消息会存入离线消息列表和消息历史记录列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"msgId":1427109835333308416,
"createTime":1629086007054,
"sender":"aaaaa1",
"content":{
"operator":"aaaaa1",
"passivityOperator":"aaaaa2",
"type":-1008
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
**参数描述**
| 字段名 | 字段类型 | 是否可空 | 说明 |
| ----------------- | -------- | -------- | ----------------- |
| operator | String | 否 | 操作的client ID |
| passivityOperator | String | 否 | 被操作的client ID |
### 下发 xx邀请xx加入会话
type为-1007
"cmd":5
该event事件消息类型需要已读和已接收回执,该消息会存入离线消息列表和消息历史记录列表
```json
{
"cmd":5,
"code":200,
"msg":"成功",
"data":{
"msgId":1427109835333308416,
"createTime":1629086007054,
"sender":"aaaaa1",
"content":{
"operator":"aaaaa1",
"passivityOperator":"aaaaa2",
"type":"-1007"
},
"event":true,
"conversationId":1427109730563788800
},
"reqId":null
}
```
**参数描述**
| 字段名 | 字段类型 | 是否可空 | 说明 |
| ------------------ | -------- | -------- | -------------- |
| operator | String | 否 | 操作的client ID |
| passivityOperator | String | 否 | 被操作的client ID |
### 服务端在线下发 某消息*已接收*状态 ### 服务端在线下发 某消息*已接收*状态
......
# wecloud-im服务端REST API对接文档 # wecloud-im服务端REST API对接文档
...@@ -24,13 +24,7 @@ ___ ...@@ -24,13 +24,7 @@ ___
https://wstest.im199.com/api/imApplication/add https://wstest.im199.com/api/imApplication/add
``` ```
___
ws连接示例
```
wss://wstest.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJjbGllbnRJZCI6ImFiY2QxIiwiaXNzIjoid2VjbG91ZF9pbSIsImFwcEtleSI6IkpLdE5IZnJWVXdzaGF4ek4iLCJleHAiOjE2MjgzMjMxNDMsImlhdCI6MTYyMzEzOTE0MywianRpIjoiNWU3NzU5ZjM2ODQ3NDFiMzg4MGEyYjkwMjQ0OWZjZmYifQ.CC-iuGjNwQLH4VxFI2wZEPuP4AGabOUOiRh9snp3IB4
```
_______ _______
...@@ -54,13 +48,6 @@ ___ ...@@ -54,13 +48,6 @@ ___
https://ws.im199.com/api/imApplication/add https://ws.im199.com/api/imApplication/add
``` ```
___
ws连接示例
```
wss://ws.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJjbGllbnRJZCI6ImFiY2QxIiwiaXNzIjoid2VjbG91ZF9pbSIsImFwcEtleSI6IkpLdE5IZnJWVXdzaGF4ek4iLCJleHAiOjE2MjgzMjMxNDMsImlhdCI6MTYyMzEzOTE0MywianRpIjoiNWU3NzU5ZjM2ODQ3NDFiMzg4MGEyYjkwMjQ0OWZjZmYifQ.CC-iuGjNwQLH4VxFI2wZEPuP4AGabOUOiRh9snp3IB4
```
_______ _______
...@@ -70,28 +57,49 @@ _______ ...@@ -70,28 +57,49 @@ _______
## 鉴权方式 ## 鉴权方式
### 方式一: ### 方式一(正在开发):
对于 POST 和 PUT 请求,请求的主体必须是 JSON 格式,而且 HTTP header 的 Content-Type 需要设置为 `application/json` 对于 POST 和 PUT 请求,请求的主体必须是 JSON 格式,而且 HTTP header 的 Content-Type 需要设置为 `application/json`
用户验证通过 HTTP header 来进行,**X-LC-Id** 标明正在运行的是哪个应用(应用的 App ID), **X-LC-Key** 用来授权鉴定 endpoint: 用户验证通过 HTTP header 来进行,**appkey** 标明正在运行的是哪个应用(应用的 App ID), **appSecret** 用来授权鉴定 endpoint:
```json **示例**: rest-api-会话成员表分页列表
curl -X PUT \
-H "X-LC-Id: {{appid}}" \ - Request URL: http://192.168.1.89:8082/api/restApi/imConversationMembers/findList
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \ - Request Method: POST
-d '{"content": "更新一篇博客的内容"}' \
https://https://ws.im199.com/api/ **请求头部**
```
appkey: D13ug9jsWbJbeVx1
appSecret: c92edcc7ba0c68b9b1da4cec6f3511876b2302faf2ab3737
``` ```
**X-LC-Key** 通常情况下是应用的 App Key
**请求body**
```
{
"conversationId": 1442742976269914112
}
```
**响应数据**
```
{"code":200,"message":"成功","data":[{"clientId":"1442742442803503105"},{"clientId":"1435497966619996162"}]}
```
### 方式二 ### 方式二(暂时没开发)
**更安全的鉴权** **更安全的鉴权**
......
本地:
String appKey = "QNtP3EjtLw26ekt0";
String appSecret = "a5e619003868258e0f7c5b5821ea00fb6b2302faf2ab3737";
--
clientA1
--
aaaaa2
--
# 国内测试外网api文档 # 国内测试外网api文档
https://imapitest.wecloud.cn/api//doc.html#/home https://imapitest.wecloud.cn/api//doc.html#/home
...@@ -294,4 +305,18 @@ channelId_ababab1:{ ...@@ -294,4 +305,18 @@ channelId_ababab1:{
token = null token = null
} }
2021年11月05日 >> 2021年11月05日 >>
\ No newline at end of file
1. 增加客户端api: 查询会话成员列表, 字段: client id ,client头像, client的拓展字段,
在该会话的会话成员拓展字段,在该会话的昵称
5. 增加客户端api: 添加或修改client的主昵称
6. 获取token接口 要返回在im系统中的头像和昵称
2.增加客户端api: 添加或修改 client的拓展字段
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment