Commit 125c76ce by hewei

Merge branch 'feature-1.4-upay-group' into '1.4'

Feature 1.4 upay group

See merge request !7
parents c8eba5d3 f49133f4
# 四恩慈善 - 后端项目 # 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);
/** /**
* 获取分页对象 * 获取分页对象
* *
......
package com.wecloud.im.netty.core; package com.wecloud.im.netty.core;
import cn.hutool.core.thread.ThreadFactoryBuilder; import com.wecloud.im.executor.BusinessThreadPool;
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 com.wecloud.rtc.service.RtcService;
...@@ -15,11 +14,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -15,11 +14,6 @@ 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;
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;
/** /**
* @Description app端 长连接事件处理 * @Description app端 长连接事件处理
...@@ -43,17 +37,6 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -43,17 +37,6 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
@Resource @Resource
private MangerChannelService mangerChannelService; private MangerChannelService mangerChannelService;
private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
.setNamePrefix("WS-business-").build();
/**
* 耗时核心业务处理线程池
* 属于io密集型业务
* io密集型任务配置尽可能多的线程数量
*/
private final static ExecutorService TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 5, WsConstants.CPU_PROCESSORS * 10,
10L, TimeUnit.MILLISECONDS,
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) {
...@@ -67,7 +50,7 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -67,7 +50,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)
); );
......
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("友盟");
......
...@@ -32,7 +32,7 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -32,7 +32,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
* <p> * <p>
* 由于来自远程端调用下发数据 如果是群聊1000人群则调用1000次 为不要占用太多资源 需要排队下发 * 由于来自远程端调用下发数据 如果是群聊1000人群则调用1000次 为不要占用太多资源 需要排队下发
* 经过并发测试 200并发1000人群消息 需要调用200x1000=20w次 考虑单机cpu性能还要顾及本机api业务 设置阻塞队列 * 经过并发测试 200并发1000人群消息 需要调用200x1000=20w次 考虑单机cpu性能还要顾及本机api业务 设置阻塞队列
* 为避免过多占用本地io线程导致response慢,设置LinkedBlockingQueue数量多可以避免抢占,TODO (队列数量需要测试调试到最优数量 ) * 为避免过多占用本地io线程导致response慢,设置LinkedBlockingQueue数量多可以避免抢占, (队列数量需要测试调试到最优数量 )
* 最大线程数量不要设置太多 数量、优先级一定要比本地io线程低级 * 最大线程数量不要设置太多 数量、优先级一定要比本地io线程低级
* *
* *
...@@ -108,8 +108,8 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -108,8 +108,8 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// //
// //
// /** // /**
// * TODO 待完成: 根据ACK回执 以及线程等待超时机制来判断客户端是否离线和超时; // * 待完成: 根据ACK回执 以及线程等待超时机制来判断客户端是否离线和超时;
// * TODO 待完成: 发送后阻塞当前子线程2秒后获取ack回执 如客户端发起ack回执则需要主动唤醒当前子线程 立马唤醒当前子线程, 判断如果已回执则返回发送成功, 如果未回执则判断客户端是否断线或发送错误 // * 待完成: 发送后阻塞当前子线程2秒后获取ack回执 如客户端发起ack回执则需要主动唤醒当前子线程 立马唤醒当前子线程, 判断如果已回执则返回发送成功, 如果未回执则判断客户端是否断线或发送错误
// * // *
// * @param msg // * @param msg
// * @param userId // * @param userId
......
package com.wecloud.im.ws.service.impl; package com.wecloud.im.ws.service.impl;
import cn.hutool.core.thread.ThreadFactoryBuilder;
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.ws.model.WsResponseModel; import com.wecloud.im.ws.model.WsResponseModel;
import com.wecloud.im.ws.model.WsConstants;
import com.wecloud.im.ws.model.request.ReceiveModel; import com.wecloud.im.ws.model.request.ReceiveModel;
import com.wecloud.im.ws.service.MangerChannelService; import com.wecloud.im.ws.service.MangerChannelService;
import com.wecloud.im.ws.service.WriteDataService; import com.wecloud.im.ws.service.WriteDataService;
...@@ -14,11 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -14,11 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashMap; import java.util.HashMap;
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;
/** /**
* @Description 下发数据 * @Description 下发数据
...@@ -28,17 +21,17 @@ import java.util.concurrent.TimeUnit; ...@@ -28,17 +21,17 @@ import java.util.concurrent.TimeUnit;
@Component @Component
public class WriteDataServiceImpl implements WriteDataService { public class WriteDataServiceImpl implements WriteDataService {
private final static ThreadFactory WRITE_NAMED_THREAD_FACTORY = new ThreadFactoryBuilder() // private final static ThreadFactory WRITE_NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
.setNamePrefix("ws-WRITE-").build(); // .setNamePrefix("ws-WRITE-").build();
/** // /**
* 耗时核心业务处理线程池 // * 耗时核心业务处理线程池
* 属于io密集型业务 // * 属于io密集型业务
* io密集型任务配置尽可能多的线程数量 // * io密集型任务配置尽可能多的线程数量
*/ // */
private final static ExecutorService WRITE_TASK_THREAD_POOL_EXECUTOR = // private final static ExecutorService WRITE_TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 2, WsConstants.CPU_PROCESSORS * 3, // new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 2, WsConstants.CPU_PROCESSORS * 3,
1L, TimeUnit.MILLISECONDS, // 1L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), WRITE_NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy()); // new LinkedBlockingQueue<Runnable>(), WRITE_NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy());
@Autowired @Autowired
private MangerChannelService mangerChannelService; private MangerChannelService mangerChannelService;
...@@ -74,8 +67,8 @@ public class WriteDataServiceImpl implements WriteDataService { ...@@ -74,8 +67,8 @@ public class WriteDataServiceImpl implements WriteDataService {
@Override @Override
public void write(WsResponseModel responseModel, String toAppKey, String toClientId) { public void write(WsResponseModel responseModel, String toAppKey, String toClientId) {
WRITE_TASK_THREAD_POOL_EXECUTOR.execute( // WRITE_TASK_THREAD_POOL_EXECUTOR.execute(
() -> { // () -> {
JsonMapper jsonMapper = new JsonMapper(); JsonMapper jsonMapper = new JsonMapper();
String json = null; String json = null;
...@@ -88,9 +81,9 @@ public class WriteDataServiceImpl implements WriteDataService { ...@@ -88,9 +81,9 @@ public class WriteDataServiceImpl implements WriteDataService {
mangerChannelService.writeData(json, toAppKey, toClientId); mangerChannelService.writeData(json, toAppKey, toClientId);
} }
); // );
} //}
} }
...@@ -137,7 +137,7 @@ public class ImChatConcrete extends ImCmdAbstract { ...@@ -137,7 +137,7 @@ public class ImChatConcrete extends ImCmdAbstract {
// 生成消息id // 生成消息id
long messageId = SnowflakeUtil.getId(); long messageId = SnowflakeUtil.getId();
// 保存消息至消息表 // 保存消息至消息表
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();
...@@ -210,21 +210,6 @@ public class ImChatConcrete extends ImCmdAbstract { ...@@ -210,21 +210,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;
}
private boolean black(ReceiveModel receiveModel, String appKey, String clientUniId, ImClient imClientSender, List<ImConversationMembers> membersList) { private boolean black(ReceiveModel receiveModel, String appKey, String clientUniId, ImClient imClientSender, List<ImConversationMembers> membersList) {
// 判断是否被拉黑 // 判断是否被拉黑
......
...@@ -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对接文档
...@@ -180,7 +180,9 @@ wss://ws.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWI ...@@ -180,7 +180,9 @@ wss://ws.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWI
- 4:下发单人在线RTC事件通知 - 4:下发单人在线RTC事件通知
- 5:响应请求(用于RTC音视频通话) - 5: 会话中的事件
- 6:下发透传消息
...@@ -207,6 +209,8 @@ wss://ws.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWI ...@@ -207,6 +209,8 @@ wss://ws.im199.com/ws?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWI
- xx已接收某消息 -1009 - xx已接收某消息 -1009
- xx已读某条消息 -1010 - xx已读某条消息 -1010
- 你被xx拉入新会话 -1011 - 你被xx拉入新会话 -1011
- 主动退出会话 -1012
- 成为新群主 -1013
以上基础平台固定类型均使用负数,所有正数留给自定义扩展类型使用,0 作为「没有类型」被保留起来。 以上基础平台固定类型均使用负数,所有正数留给自定义扩展类型使用,0 作为「没有类型」被保留起来。
...@@ -397,6 +401,8 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -397,6 +401,8 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
} }
``` ```
上面是完整的例子,如果只想简单的发送图像 URL: 上面是完整的例子,如果只想简单的发送图像 URL:
```json ```json
...@@ -440,6 +446,22 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -440,6 +446,22 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响
## 服务端下发透传消息
```json
{
"reqId":"1",
"cmd":6,
"data":{
"toConversation":1394188055950266368,
"createTime":1621240016587,
"content":"json字符串,或任意字符数据"
}
}
```
## 客户端在线接收事件类型消息 ## 客户端在线接收事件类型消息
### 事件类型type (xx表示为某客户端) ### 事件类型type (xx表示为某客户端)
...@@ -449,6 +471,223 @@ websocket是异步的 有可能你很快速的发送了几条消息,服务器响 ...@@ -449,6 +471,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"}]}
```
### 方式二 ### 方式二(暂时没开发)
**更安全的鉴权** **更安全的鉴权**
......
...@@ -306,3 +306,18 @@ imapitest.wecloud.cn ...@@ -306,3 +306,18 @@ imapitest.wecloud.cn
web示例: web示例:
imwebtest.wecloud.cn imwebtest.wecloud.cn
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