Commit 90b07d5d by giaogiao

消息在线发送和接收;

消息保存收件箱;
创建聊天会话;
添加会话成员;
parent 4095b386
...@@ -44,6 +44,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; ...@@ -44,6 +44,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = {"io.geekidea.springbootplus", "com.wecloud", "com.wecloud.im", "com.wecloud.im.config"}) @SpringBootApplication(scanBasePackages = {"io.geekidea.springbootplus", "com.wecloud", "com.wecloud.im", "com.wecloud.im.config"})
public class SpringBootPlusApplication { public class SpringBootPlusApplication {
public static void main(String[] args) { public static void main(String[] args) {
// 启动spring-boot-plus // 启动spring-boot-plus
ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args); ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args);
......
...@@ -3,6 +3,7 @@ package io.geekidea.springbootplus.test; ...@@ -3,6 +3,7 @@ package io.geekidea.springbootplus.test;
import cn.hutool.core.lang.Snowflake; import cn.hutool.core.lang.Snowflake;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.tillo.app_ws.utils.RSAGenerator; import com.wecloud.im.tillo.app_ws.utils.RSAGenerator;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -17,7 +18,13 @@ import java.util.Date; ...@@ -17,7 +18,13 @@ import java.util.Date;
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest @SpringBootTest
public class AppKeyTest { public class ImApplicationTest {
@Autowired
private ImConversationMembersService imConversationMembersService;
@Autowired
private ImApplicationService imApplicationService;
public static void main(String[] args) { public static void main(String[] args) {
String appKey = RSAGenerator.getAppKey(); //定义变量接收 String appKey = RSAGenerator.getAppKey(); //定义变量接收
...@@ -26,15 +33,10 @@ public class AppKeyTest { ...@@ -26,15 +33,10 @@ public class AppKeyTest {
int i = 1; int i = 1;
} }
@Autowired
private ImApplicationService imApplicationService;
@Test @Test
public void add() { public void add() {
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10; i++) {
addDb(i); addDb(i);
} }
} }
...@@ -53,5 +55,4 @@ public class AppKeyTest { ...@@ -53,5 +55,4 @@ public class AppKeyTest {
imApplicationService.save(imApplication); imApplicationService.save(imApplication);
} }
} }
package io.geekidea.springbootplus.test;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImConversationService;
import io.geekidea.springbootplus.framework.shiro.util.SnowflakeUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Date;
/**
* imConversation 单元测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ImConversationMembersTest {
@Autowired
private ImConversationMembersService imConversationMembersService;
@Autowired
private ImConversationService imConversationService;
@Test
public void addConversation() {
long creator = 1390920735408656384L;
long user2 = 1390921236443435008L;
long appid = 1387022761016299520L;
Long imConversationId = SnowflakeUtil.getId();
// 创建会话
ImConversation imConversation = new ImConversation();
imConversation.setId(imConversationId);
imConversation.setCreateTime(new Date());
imConversation.setLastMessage(null);
imConversation.setFkAppid(appid);
imConversation.setCreator(creator);
imConversation.setName("");
imConversation.setAttributes("");
imConversation.setSystem(false);
imConversationService.save(imConversation);
// 将自己添加到会话
Long imConversationMembersId = SnowflakeUtil.getId();
ImConversationMembers imConversationMembers = new ImConversationMembers();
imConversationMembers.setId(imConversationMembersId);
imConversationMembers.setCreateTime(new Date());
// imConversationMembers.setUpdateTime(new Date());
imConversationMembers.setFkAppid(appid);
imConversationMembers.setFkConversationId(imConversationId);
imConversationMembers.setFkClientId(creator);
imConversationMembersService.save(imConversationMembers);
// 将他人添加到会话
Long imConversationMembersId2 = SnowflakeUtil.getId();
ImConversationMembers imConversationMembers2 = new ImConversationMembers();
imConversationMembers2.setId(imConversationMembersId2);
imConversationMembers2.setCreateTime(new Date());
imConversationMembers2.setFkAppid(appid);
imConversationMembers2.setFkConversationId(imConversationId);
imConversationMembers2.setFkClientId(user2);
imConversationMembersService.save(imConversationMembers2);
}
}
package io.geekidea.springbootplus.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel;
public class JsonTest {
public static void main(String[] args) throws JsonProcessingException {
// jsonTest();
}
private static void jsonTest() throws JsonProcessingException {
String data = "{\n" +
"\"reqId\":\"123123\",\n" +
"\"cmd\":1,\n" +
"\"data\":{\n" +
" \"type\":-1,\n" +
" \"text\":\"这是一个纯文本消息\",\n" +
" \"attrs\":{\n" +
" \"a\":\"attrs是用来存储用户自定义的一些键值对\"}}\n" +
"}\n";
// json转换成对象
JsonMapper jsonMapper = new JsonMapper();
ReceiveModel receiveModel = jsonMapper.readValue(data, ReceiveModel.class);
// data对象转换成json
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(receiveModel.getData());
}
}
...@@ -31,38 +31,48 @@ public class LoginTest { ...@@ -31,38 +31,48 @@ public class LoginTest {
@Autowired @Autowired
private StringRedisTemplate redisTemplate; private StringRedisTemplate redisTemplate;
@Autowired @Autowired
private ImApplicationService imApplicationService; private ImApplicationService imApplicationService;
@Autowired @Autowired
private ImClientService imClientService; private ImClientService imClientService;
/**
* 根据客户方生成签名字符串 验证通过则下发token
*
* @param timestemp
* @param clientId
* @param appKey
* @param sign
* @return
* @throws Exception
*/
private String getToken(String timestemp, String clientId, String appKey, String sign) throws Exception { private String getToken(String timestemp, String clientId, String appKey, String sign) throws Exception {
String token = null; // 根据appKey从数据库查询密钥
// 从数据库查询密钥
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOne(
new QueryWrapper<ImApplication>().lambda().eq(ImApplication::getAppKey, appKey) new QueryWrapper<ImApplication>().lambda().eq(ImApplication::getAppKey, appKey)
); );
// 验证签名 // 生成以数据库为准的签名
String mySign = new MD5().digestHex(timestemp + clientId + imApplication.getAppKey() + imApplication.getAppSecret()); String mySign = new MD5().digestHex(timestemp + clientId + imApplication.getAppKey() + imApplication.getAppSecret());
// 验证签名
if (mySign.equals(sign)) { if (mySign.equals(sign)) {
System.out.println("一致" + mySign); System.out.println("一致" + mySign);
// return null;
} else { } else {
System.out.println("不一致" + mySign); System.out.println("不一致" + mySign);
return null;
} }
// 判断client是否存在 // 判断client是否存在
ImClient byid = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient client = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId()) .eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getClientId, clientId)); .eq(ImClient::getClientId, clientId));
if (byid == null) { if (client == null) {
System.out.println("不存在"); System.out.println("不存在");
ImClient imClient = new ImClient(); ImClient imClient = new ImClient();
...@@ -75,8 +85,10 @@ public class LoginTest { ...@@ -75,8 +85,10 @@ public class LoginTest {
System.out.println("存在"); System.out.println("存在");
} }
String generateToken = JwtUtil.generateToken(clientId, imApplication.getAppSecret(), Duration.ofDays(100)); // 生成token
String generateToken = JwtUtil.generateToken(clientId, appKey, imApplication.getAppSecret(), Duration.ofDays(100));
// 保存redis
redisTemplate.opsForValue().set("client:" + imApplication.getAppKey() + ":" + clientId, generateToken); redisTemplate.opsForValue().set("client:" + imApplication.getAppKey() + ":" + clientId, generateToken);
return generateToken; return generateToken;
} }
...@@ -84,10 +96,10 @@ public class LoginTest { ...@@ -84,10 +96,10 @@ public class LoginTest {
@Test @Test
public void test() throws Exception { public void test() throws Exception {
// 时间戳 // 时间戳
String timestemp = "1619574452548"; String timestemp = "1620456403794";
String clientId = "c1"; String clientId = "hahah_30";
String appKey = "elLwpel1gWCHDqZy"; String appKey = "elLwpel1gWCHDqZy";
String sign = "b240f069db255eaa0ab4677016c86f71"; String sign = "9db5c1383829d346adba48182fd8f503";
String token = getToken(timestemp, clientId, appKey, sign); String token = getToken(timestemp, clientId, appKey, sign);
System.out.println("token:" + token); System.out.println("token:" + token);
} }
......
...@@ -9,7 +9,7 @@ import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel; ...@@ -9,7 +9,7 @@ import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel;
import java.util.Date; import java.util.Date;
/** /**
* 生成测试appkey与appSecret对,并存入数据库 * 客户方签名字符串生成 单元测试
*/ */
//@RunWith(SpringJUnit4ClassRunner.class) //@RunWith(SpringJUnit4ClassRunner.class)
//@SpringBootTest //@SpringBootTest
...@@ -21,14 +21,14 @@ public class SignTest { ...@@ -21,14 +21,14 @@ public class SignTest {
/** /**
* 获取sign,客户端sdk得到sign之后就可以进行登录 和开启websocket * 获取sign,客户端sdk得到sign之后就可以进行登录 和开启websocket
* <p> * <p>
* sign = MD5{ clientId + AppKey + appSecret} * sign = MD5{ clientId + appKey + appSecret}
* *
* @param AppKey * @param appKey
* @param appSecret * @param appSecret
*/ */
private static void getSign(String timestemp, String clientId, String AppKey, String appSecret) { private static void getSign(String timestemp, String clientId, String appKey, String appSecret) {
String sign = new MD5().digestHex(timestemp + clientId + AppKey + appSecret); String sign = new MD5().digestHex(timestemp + clientId + appKey + appSecret);
System.out.println("timestemp:" + timestemp); System.out.println("timestemp:" + timestemp);
System.out.println("sign:" + sign); System.out.println("sign:" + sign);
...@@ -36,12 +36,12 @@ public class SignTest { ...@@ -36,12 +36,12 @@ public class SignTest {
} }
public static void main(String[] args) throws JsonProcessingException { public static void main(String[] args) throws JsonProcessingException {
String clientId = "c1"; String clientId = "hahah_30";
String appKey = "elLwpel1gWCHDqZy"; String appKey = "elLwpel1gWCHDqZy";
String appSecret = "68809bb5a9077a83631aeb0b17b5965d6b2302faf2ab3737"; String appSecret = "68809bb5a9077a83631aeb0b17b5965d6b2302faf2ab3737";
String timestemp = String.valueOf(new Date().getTime()); String timestemp = String.valueOf(new Date().getTime());
getSign(timestemp, clientId, appKey, appSecret); getSign(timestemp, clientId, appKey, appSecret);
jsonTest(); // jsonTest();
} }
private static void jsonTest() throws JsonProcessingException { private static void jsonTest() throws JsonProcessingException {
...@@ -52,7 +52,7 @@ public class SignTest { ...@@ -52,7 +52,7 @@ public class SignTest {
" \"type\":-1,\n" + " \"type\":-1,\n" +
" \"text\":\"这是一个纯文本消息\",\n" + " \"text\":\"这是一个纯文本消息\",\n" +
" \"attrs\":{\n" + " \"attrs\":{\n" +
" \"a\":\"attrs 是用来存储用户自定义的一些键值对\"}}\n" + " \"a\":\"attrs是用来存储用户自定义的一些键值对\"}}\n" +
"}\n"; "}\n";
// json转换成对象 // json转换成对象
......
package com.wecloud.im.controller;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo;
import com.wecloud.im.service.ImConversationService;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.core.validator.groups.Add;
import io.geekidea.springbootplus.framework.core.validator.groups.Update;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RestController;
/**
* 会话表 控制器
*
* @author wei
* @since 2021-05-07
*/
@Slf4j
@RestController
@RequestMapping("/imConversation")
@Api(value = "会话表API", tags = {"会话表"})
public class ImConversationController extends BaseController {
@Autowired
private ImConversationService imConversationService;
/**
* 添加会话表
*/
@PostMapping("/add")
@OperationLog(name = "添加会话表", type = OperationLogType.ADD)
@ApiOperation(value = "添加会话表")
public ApiResult<Boolean> addImConversation(@Validated(Add.class) @RequestBody ImConversation imConversation) throws Exception {
boolean flag = imConversationService.saveImConversation(imConversation);
return ApiResult.result(flag);
}
/**
* 修改会话表
*/
@PostMapping("/update")
@OperationLog(name = "修改会话表", type = OperationLogType.UPDATE)
@ApiOperation(value = "修改会话表")
public ApiResult<Boolean> updateImConversation(@Validated(Update.class) @RequestBody ImConversation imConversation) throws Exception {
boolean flag = imConversationService.updateImConversation(imConversation);
return ApiResult.result(flag);
}
/**
* 删除会话表
*/
@PostMapping("/delete/{id}")
@OperationLog(name = "删除会话表", type = OperationLogType.DELETE)
@ApiOperation(value = "删除会话表")
public ApiResult<Boolean> deleteImConversation(@PathVariable("id") Long id) throws Exception {
boolean flag = imConversationService.deleteImConversation(id);
return ApiResult.result(flag);
}
/**
* 获取会话表详情
*/
@GetMapping("/info/{id}")
@OperationLog(name = "会话表详情", type = OperationLogType.INFO)
@ApiOperation(value = "会话表详情")
public ApiResult<ImConversationQueryVo> getImConversation(@PathVariable("id") Long id) throws Exception {
ImConversationQueryVo imConversationQueryVo = imConversationService.getImConversationById(id);
return ApiResult.ok(imConversationQueryVo);
}
/**
* 会话表分页列表
*/
@PostMapping("/getPageList")
@OperationLog(name = "会话表分页列表", type = OperationLogType.PAGE)
@ApiOperation(value = "会话表分页列表")
public ApiResult<Paging<ImConversationQueryVo>> getImConversationPageList(@Validated @RequestBody ImConversationPageParam imConversationPageParam) throws Exception {
Paging<ImConversationQueryVo> paging = imConversationService.getImConversationPageList(imConversationPageParam);
return ApiResult.ok(paging);
}
}
package com.wecloud.im.controller;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.service.ImConversationMembersService;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.core.validator.groups.Add;
import io.geekidea.springbootplus.framework.core.validator.groups.Update;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RestController;
/**
* 会话成员表 控制器
*
* @author wei
* @since 2021-05-07
*/
@Slf4j
@RestController
@RequestMapping("/imConversationMembers")
@Api(value = "会话成员表API", tags = {"会话成员表"})
public class ImConversationMembersController extends BaseController {
@Autowired
private ImConversationMembersService imConversationMembersService;
/**
* 添加会话成员表
*/
@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);
}
/**
* 会话成员表分页列表
*/
@PostMapping("/getPageList")
@OperationLog(name = "会话成员表分页列表", type = OperationLogType.PAGE)
@ApiOperation(value = "会话成员表分页列表")
public ApiResult<Paging<ImConversationMembersQueryVo>> getImConversationMembersPageList(@Validated @RequestBody ImConversationMembersPageParam imConversationMembersPageParam) throws Exception {
Paging<ImConversationMembersQueryVo> paging = imConversationMembersService.getImConversationMembersPageList(imConversationMembersPageParam);
return ApiResult.ok(paging);
}
}
package com.wecloud.im.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
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 javax.validation.constraints.NotNull;
import java.util.Date;
/**
* 会话表
*
* @author wei
* @since 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImConversation对象")
public class ImConversation extends BaseEntity {
private static final long serialVersionUID = 1L;
@NotNull(message = "会话id不能为空")
@ApiModelProperty("会话id")
@TableId(value = "id", type = IdType.INPUT)
private Long id;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
@ApiModelProperty("对话中最后一条消息的发送或接收时间")
private Date lastMessage;
@NotNull(message = "应用appid不能为空")
@ApiModelProperty("应用appid")
private Long fkAppid;
@NotNull(message = "创建者客户端id不能为空")
@ApiModelProperty("创建者客户端id")
private Long creator;
@ApiModelProperty("可选 对话的名字,可为群组命名。")
private String name;
@ApiModelProperty("可选 自定义属性,供开发者扩展使用。")
private String attributes;
@ApiModelProperty("可选 对话类型标志,是否是系统对话,后面会说明。")
private Boolean system;
}
package com.wecloud.im.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
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 javax.validation.constraints.NotNull;
import java.util.Date;
/**
* 会话成员表
*
* @author wei
* @since 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImConversationMembers对象")
public class ImConversationMembers extends BaseEntity {
private static final long serialVersionUID = 1L;
@NotNull(message = "唯一id不能为空")
@ApiModelProperty("唯一id")
@TableId(value = "id", type = IdType.INPUT)
private Long id;
@ApiModelProperty("加入时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
@NotNull(message = "应用appid不能为空")
@ApiModelProperty("应用appid")
private Long fkAppid;
@NotNull(message = "会话表id不能为空")
@ApiModelProperty("会话表id")
private Long fkConversationId;
@NotNull(message = "客户端id不能为空")
@ApiModelProperty("客户端id")
private Long fkClientId;
}
package com.wecloud.im.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
/**
* 会话表 Mapper 接口
*
* @author wei
* @since 2021-05-07
*/
@Repository
public interface ImConversationMapper extends BaseMapper<ImConversation> {
/**
* 根据ID获取查询对象
*
* @param id
* @return
*/
ImConversationQueryVo getImConversationById(Serializable id);
/**
* 获取分页对象
*
* @param page
* @param imConversationPageParam
* @return
*/
IPage<ImConversationQueryVo> getImConversationPageList(@Param("page") Page page, @Param("param") ImConversationPageParam imConversationPageParam);
}
package com.wecloud.im.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
/**
* 会话成员表 Mapper 接口
*
* @author wei
* @since 2021-05-07
*/
@Repository
public interface ImConversationMembersMapper extends BaseMapper<ImConversationMembers> {
/**
* 根据ID获取查询对象
*
* @param id
* @return
*/
ImConversationMembersQueryVo getImConversationMembersById(Serializable id);
/**
* 获取分页对象
*
* @param page
* @param imConversationMembersPageParam
* @return
*/
IPage<ImConversationMembersQueryVo> getImConversationMembersPageList(@Param("page") Page page, @Param("param") ImConversationMembersPageParam imConversationMembersPageParam);
}
package com.wecloud.im.param;
import io.geekidea.springbootplus.framework.core.pagination.BasePageOrderParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <pre>
* 会话成员表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "会话成员表分页参数")
public class ImConversationMembersPageParam extends BasePageOrderParam {
private static final long serialVersionUID = 1L;
}
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;
import java.util.Date;
/**
* <pre>
* 会话成员表 查询结果对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ImConversationMembersQueryVo对象")
public class ImConversationMembersQueryVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("唯一id")
private Long id;
@ApiModelProperty("加入时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
@ApiModelProperty("应用appid")
private Long fkAppid;
@ApiModelProperty("会话表id")
private Long fkConversationId;
@ApiModelProperty("客户端id")
private Long fkClientId;
}
\ No newline at end of file
package com.wecloud.im.param;
import io.geekidea.springbootplus.framework.core.pagination.BasePageOrderParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <pre>
* 会话表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "会话表分页参数")
public class ImConversationPageParam extends BasePageOrderParam {
private static final long serialVersionUID = 1L;
}
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;
import java.util.Date;
/**
* <pre>
* 会话表 查询结果对象
* </pre>
*
* @author wei
* @date 2021-05-07
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ImConversationQueryVo对象")
public class ImConversationQueryVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("会话id")
private Long id;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
@ApiModelProperty("对话中最后一条消息的发送或接收时间")
private Date lastMessage;
@ApiModelProperty("应用appid")
private Long fkAppid;
@ApiModelProperty("创建者客户端id")
private Long creator;
@ApiModelProperty("可选 对话的名字,可为群组命名。")
private String name;
@ApiModelProperty("可选 自定义属性,供开发者扩展使用。")
private String attributes;
@ApiModelProperty("可选 对话类型标志,是否是系统对话,后面会说明。")
private Boolean system;
}
\ No newline at end of file
package com.wecloud.im.service;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
/**
* 会话成员表 服务类
*
* @author wei
* @since 2021-05-07
*/
public interface ImConversationMembersService extends BaseService<ImConversationMembers> {
/**
* 保存
*
* @param imConversationMembers
* @return
* @throws Exception
*/
boolean saveImConversationMembers(ImConversationMembers imConversationMembers) throws Exception;
/**
* 修改
*
* @param imConversationMembers
* @return
* @throws Exception
*/
boolean updateImConversationMembers(ImConversationMembers imConversationMembers) throws Exception;
/**
* 删除
*
* @param id
* @return
* @throws Exception
*/
boolean deleteImConversationMembers(Long id) throws Exception;
/**
* 根据ID获取查询对象
*
* @param id
* @return
* @throws Exception
*/
ImConversationMembersQueryVo getImConversationMembersById(Long id) throws Exception;
/**
* 获取分页对象
*
* @param imConversationMembersPageParam
* @return
* @throws Exception
*/
Paging<ImConversationMembersQueryVo> getImConversationMembersPageList(ImConversationMembersPageParam imConversationMembersPageParam) throws Exception;
}
package com.wecloud.im.service;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo;
import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
/**
* 会话表 服务类
*
* @author wei
* @since 2021-05-07
*/
public interface ImConversationService extends BaseService<ImConversation> {
/**
* 保存
*
* @param imConversation
* @return
* @throws Exception
*/
boolean saveImConversation(ImConversation imConversation) throws Exception;
/**
* 修改
*
* @param imConversation
* @return
* @throws Exception
*/
boolean updateImConversation(ImConversation imConversation) throws Exception;
/**
* 删除
*
* @param id
* @return
* @throws Exception
*/
boolean deleteImConversation(Long id) throws Exception;
/**
* 根据ID获取查询对象
*
* @param id
* @return
* @throws Exception
*/
ImConversationQueryVo getImConversationById(Long id) throws Exception;
/**
* 获取分页对象
*
* @param imConversationPageParam
* @return
* @throws Exception
*/
Paging<ImConversationQueryVo> getImConversationPageList(ImConversationPageParam imConversationPageParam) throws Exception;
}
package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.mapper.ImConversationMembersMapper;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.service.ImConversationMembersService;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 会话成员表 服务实现类
*
* @author wei
* @since 2021-05-07
*/
@Slf4j
@Service
public class ImConversationMembersServiceImpl extends BaseServiceImpl<ImConversationMembersMapper, ImConversationMembers> implements ImConversationMembersService {
@Autowired
private ImConversationMembersMapper imConversationMembersMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveImConversationMembers(ImConversationMembers imConversationMembers) throws Exception {
return super.save(imConversationMembers);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateImConversationMembers(ImConversationMembers imConversationMembers) throws Exception {
return super.updateById(imConversationMembers);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean deleteImConversationMembers(Long id) throws Exception {
return super.removeById(id);
}
@Override
public ImConversationMembersQueryVo getImConversationMembersById(Long id) throws Exception {
return imConversationMembersMapper.getImConversationMembersById(id);
}
@Override
public Paging<ImConversationMembersQueryVo> getImConversationMembersPageList(ImConversationMembersPageParam imConversationMembersPageParam) throws Exception {
Page<ImConversationMembersQueryVo> page = new PageInfo<>(imConversationMembersPageParam, OrderItem.desc(getLambdaColumn(ImConversationMembers::getCreateTime)));
IPage<ImConversationMembersQueryVo> iPage = imConversationMembersMapper.getImConversationMembersPageList(page, imConversationMembersPageParam);
return new Paging<ImConversationMembersQueryVo>(iPage);
}
}
package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.mapper.ImConversationMapper;
import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo;
import com.wecloud.im.service.ImConversationService;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 会话表 服务实现类
*
* @author wei
* @since 2021-05-07
*/
@Slf4j
@Service
public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMapper, ImConversation> implements ImConversationService {
@Autowired
private ImConversationMapper imConversationMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveImConversation(ImConversation imConversation) throws Exception {
return super.save(imConversation);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateImConversation(ImConversation imConversation) throws Exception {
return super.updateById(imConversation);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean deleteImConversation(Long id) throws Exception {
return super.removeById(id);
}
@Override
public ImConversationQueryVo getImConversationById(Long id) throws Exception {
return imConversationMapper.getImConversationById(id);
}
@Override
public Paging<ImConversationQueryVo> getImConversationPageList(ImConversationPageParam imConversationPageParam) throws Exception {
Page<ImConversationQueryVo> page = new PageInfo<>(imConversationPageParam, OrderItem.desc(getLambdaColumn(ImConversation::getCreateTime)));
IPage<ImConversationQueryVo> iPage = imConversationMapper.getImConversationPageList(page, imConversationPageParam);
return new Paging<ImConversationQueryVo>(iPage);
}
}
...@@ -28,12 +28,11 @@ import java.util.concurrent.TimeUnit; ...@@ -28,12 +28,11 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Resource @Resource
private ReadWsData readWsData; private ReadWsData readWsData;
@Resource @Resource
private MangerChannelService appUserChannelsService; private MangerChannelService mangerChannelService;
private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder() private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
.setNamePrefix("business-").build(); .setNamePrefix("business-").build();
...@@ -50,7 +49,6 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { ...@@ -50,7 +49,6 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) { protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
String data = msg.text(); String data = msg.text();
try { try {
if (data.isEmpty()) { if (data.isEmpty()) {
return; return;
...@@ -88,6 +86,7 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { ...@@ -88,6 +86,7 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
*/ */
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.debug("检测到异常exceptionCaught", cause);
// //排除当客户端意外关闭的情况,不是发送指定指令通知服务器退出,就会产生此错误。 // //排除当客户端意外关闭的情况,不是发送指定指令通知服务器退出,就会产生此错误。
// if (ctx.channel().isActive()) { // if (ctx.channel().isActive()) {
...@@ -98,9 +97,8 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { ...@@ -98,9 +97,8 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) { public void handlerAdded(ChannelHandlerContext ctx) {
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx); String userIdByChannel = mangerChannelService.getUserIdByChannel(ctx);
// log.debug("uid:" + userIdByChannel + ",app端连接WS成功" + ",channelId:" + ctx.channel().id().asLongText());
// log.debug("uid:" + userIdByChannel + ",app端连接WS成功" + ",channelId:" + ctx.channel().id().asLongText());
log.debug("连接WS成功handlerAdded"); log.debug("连接WS成功handlerAdded");
} }
...@@ -113,13 +111,11 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { ...@@ -113,13 +111,11 @@ public class WsHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
*/ */
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) { public void channelInactive(ChannelHandlerContext ctx) {
log.debug("连接WS成功channelInactive"); log.debug("客户端不活跃channelInactive");
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx); // Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx);
// log.debug("uid:" + userIdByChannel + "," + "不活跃" + ",channelId:" + ctx.channel().id().asLongText()); // log.debug("uid:" + userIdByChannel + "," + "不活跃" + ",channelId:" + ctx.channel().id().asLongText());
// // mangerChannelService.remove(ctx);
// appUserChannelsService.remove(ctx);
} }
/** /**
......
...@@ -43,17 +43,17 @@ public interface MangerChannelService { ...@@ -43,17 +43,17 @@ public interface MangerChannelService {
/** /**
* 根据userID获取channel * 根据userID获取channel
* @param userId *
* @return * @return
*/ */
NioSocketChannel get(String userId); NioSocketChannel get(String appKey, String clientId);
/** /**
* userID绑定channel * userID绑定channel
* @param userId *
* @param channel * @param channel
*/ */
void put(String userId, NioSocketChannel channel); void put(String appKey, String clientId, NioSocketChannel channel);
/** /**
* 移除channel * 移除channel
...@@ -67,7 +67,7 @@ public interface MangerChannelService { ...@@ -67,7 +67,7 @@ public interface MangerChannelService {
* @param channelHandlerContext * @param channelHandlerContext
* @return * @return
*/ */
Long getUserIdByChannel(ChannelHandlerContext channelHandlerContext); String getUserIdByChannel(ChannelHandlerContext channelHandlerContext);
/** /**
* 下发数据 * 下发数据
......
...@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit; ...@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit;
*/ */
@Component @Component
@Slf4j @Slf4j
public class AppUserChannelsServiceImpl implements MangerChannelService { public class MangerChannelServiceImpl implements MangerChannelService {
private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder() private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
.setNamePrefix("rpcWrite-").build(); .setNamePrefix("rpcWrite-").build();
...@@ -59,18 +59,18 @@ public class AppUserChannelsServiceImpl implements MangerChannelService { ...@@ -59,18 +59,18 @@ public class AppUserChannelsServiceImpl implements MangerChannelService {
@Override @Override
public NioSocketChannel get(String userId) { public NioSocketChannel get(String appKey, String clientId) {
return MangerChannelService.CHANNEL_MAP.get(userId); return MangerChannelService.CHANNEL_MAP.get(appKey + clientId);
} }
@Override @Override
public void put(String userId, NioSocketChannel channel) { public void put(String appKey, String clientId, NioSocketChannel channel) {
// AppHashValueModel appHashValueModel = new AppHashValueModel(); // AppHashValueModel appHashValueModel = new AppHashValueModel();
// appHashValueModel.setOnlineStatus(UserCache.ONLINE); // appHashValueModel.setOnlineStatus(UserCache.ONLINE);
userCache.online(userId); // userCache.online(userId);
MangerChannelService.CHANNEL_MAP.put(userId, channel); MangerChannelService.CHANNEL_MAP.put(appKey + clientId, channel);
} }
...@@ -97,9 +97,9 @@ public class AppUserChannelsServiceImpl implements MangerChannelService { ...@@ -97,9 +97,9 @@ public class AppUserChannelsServiceImpl implements MangerChannelService {
} }
@Override @Override
public Long getUserIdByChannel(ChannelHandlerContext channelHandlerContext) { public String getUserIdByChannel(ChannelHandlerContext channelHandlerContext) {
// return channelHandlerContext.channel().attr(MangerChannelService.USER_ID).get(); return channelHandlerContext.channel().attr(MangerChannelService.CLIENT_ID).get();
return 1L; // return 1L;
} }
// @Override // @Override
...@@ -282,10 +282,9 @@ public class AppUserChannelsServiceImpl implements MangerChannelService { ...@@ -282,10 +282,9 @@ public class AppUserChannelsServiceImpl implements MangerChannelService {
@Override @Override
public boolean writeData(String msg, String toAppKey, String toClientId) { public boolean writeData(String msg, String toAppKey, String toClientId) {
NioSocketChannel nioSocketChannel = get(toAppKey, toClientId);
NioSocketChannel nioSocketChannel = get(String.valueOf(toAppKey + toClientId));
if (null == nioSocketChannel) { if (null == nioSocketChannel) {
userCache.offline(String.valueOf(toAppKey + toClientId)); // userCache.offline(toAppKey + toClientId);
log.debug("writeData连接为空:" + toAppKey + toClientId + "," + msg); log.debug("writeData连接为空:" + toAppKey + toClientId + "," + msg);
return false; return false;
} }
......
...@@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSON; ...@@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.wecloud.im.tillo.app_ws.model.ResponseModel; import com.wecloud.im.tillo.app_ws.model.ResponseModel;
import com.wecloud.im.tillo.app_ws.model.ResultStatus; import com.wecloud.im.tillo.app_ws.model.ResultStatus;
import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel; import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel;
import com.wecloud.im.tillo.app_ws.service.MangerChannelService;
import com.wecloud.im.tillo.app_ws.service.WriteDataService; import com.wecloud.im.tillo.app_ws.service.WriteDataService;
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;
...@@ -19,8 +17,8 @@ import java.util.HashMap; ...@@ -19,8 +17,8 @@ import java.util.HashMap;
@Component @Component
public class WriteDataServiceImpl implements WriteDataService { public class WriteDataServiceImpl implements WriteDataService {
@Autowired // @Autowired
private MangerChannelService mangerChannelService; // private MangerChannelService mangerChannelService;
@Override @Override
public void successAndData(ReceiveModel requestModel, Object data, Long userId, String language) { public void successAndData(ReceiveModel requestModel, Object data, Long userId, String language) {
......
package com.wecloud.im.tillo.app_ws.strategy.concrete; package com.wecloud.im.tillo.app_ws.strategy.concrete;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.entity.ImInbox; import com.wecloud.im.entity.ImInbox;
import com.wecloud.im.entity.ImMessage; import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService;
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.tillo.app_ws.annotation.ReceiveTypeAnnotation; import com.wecloud.im.tillo.app_ws.annotation.ReceiveTypeAnnotation;
...@@ -15,12 +18,15 @@ import com.wecloud.im.tillo.app_ws.enums.WsRequestCmdEnum; ...@@ -15,12 +18,15 @@ import com.wecloud.im.tillo.app_ws.enums.WsRequestCmdEnum;
import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel; import com.wecloud.im.tillo.app_ws.model.request.ReceiveModel;
import com.wecloud.im.tillo.app_ws.service.MangerChannelService; import com.wecloud.im.tillo.app_ws.service.MangerChannelService;
import com.wecloud.im.tillo.app_ws.strategy.AbstractReceiveStrategy; import com.wecloud.im.tillo.app_ws.strategy.AbstractReceiveStrategy;
import io.geekidea.springbootplus.framework.shiro.util.SnowflakeUtil;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
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 javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import java.util.List;
/** /**
* @Description 处理app单聊消息 * @Description 处理app单聊消息
...@@ -39,20 +45,36 @@ public class SingleConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -39,20 +45,36 @@ public class SingleConcreteReceiveStrategy extends AbstractReceiveStrategy {
@Autowired @Autowired
private ImApplicationService imApplicationService; private ImApplicationService imApplicationService;
@Resource
private MangerChannelService mangerChannelService;
@Autowired
private ImConversationMembersService imConversationMembersService;
@Autowired
private ImClientService imClientService;
@Override @Override
public void process(ReceiveModel requestModel, String language, ChannelHandlerContext ctx, String data) { public void process(ReceiveModel requestModel, String language, ChannelHandlerContext ctx, String data) {
String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get(); String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get();
String clientId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get(); String clientUniId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get();
// 查询imApplication
ImApplication imApplication = imApplicationService.getOne(new QueryWrapper<ImApplication>().lambda() ImApplication imApplication = imApplicationService.getOne(new QueryWrapper<ImApplication>().lambda()
.eq(ImApplication::getAppKey, appKey)); .eq(ImApplication::getAppKey, appKey));
// 查询发送者client
ImClient imClientSender = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getClientId, clientUniId));
JsonMapper jsonMapper = new JsonMapper(); JsonMapper jsonMapper = new JsonMapper();
Long toConversationId = Long.valueOf(requestModel.getData().get("toConversation").toString());
long messageId = SnowflakeUtil.getId();
String content = null; String content = null;
Long toConversation = Long.valueOf(requestModel.getData().get("toConversation").toString());
long messageId = new Snowflake(1L, 1L).nextId();
long imInboxId = new Snowflake(1L, 1L).nextId();
try { try {
content = jsonMapper.writeValueAsString(requestModel.getData()); content = jsonMapper.writeValueAsString(requestModel.getData());
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
...@@ -66,29 +88,54 @@ public class SingleConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -66,29 +88,54 @@ public class SingleConcreteReceiveStrategy extends AbstractReceiveStrategy {
// imMessage.setWithdrawTime(new Date()); // imMessage.setWithdrawTime(new Date());
// imMessage.setUpdateDate(new Date()); // imMessage.setUpdateDate(new Date());
imMessage.setFkAppid(imApplication.getId()); imMessage.setFkAppid(imApplication.getId());
imMessage.setSender(0L); imMessage.setSender(imClientSender.getId());
imMessage.setContent(content); imMessage.setContent(content);
imMessage.setWithdraw(false); imMessage.setWithdraw(false);
imMessage.setEvent(false); imMessage.setEvent(false);
imMessage.setSystem(false); imMessage.setSystem(false);
// imMessage.setAt(""); // imMessage.setAt("");
imMessage.setSendStatus(0); imMessage.setSendStatus(0);
imMessage.setFkConversationId(toConversation); imMessage.setFkConversationId(toConversationId);
imMessageService.save(imMessage); imMessageService.save(imMessage);
// 向接收方推送 // 查询该会话所有成员
// ChannelFuture channelFuture = ctx.writeAndFlush(new TextWebSocketFrame(data)); List<ImConversationMembers> membersList = imConversationMembersService.list(
ImInbox imInbox = new ImInbox(); new QueryWrapper<ImConversationMembers>().lambda()
imInbox.setId(imInboxId); .eq(ImConversationMembers::getFkConversationId, toConversationId)
imInbox.setCreateTime(new Date()); );
// imInbox.setUpdateTime(new Date());
// imInbox.setReceiverDate(new Date());
imInbox.setFkAppid(123L);
imInbox.setReceiver(12L);
imInbox.setFkMsgId(messageId);
imInbox.setReadMsg(0);
imInbox.setFkConversationId(toConversation);
imInboxService.save(imInbox);
if (membersList.isEmpty()) {
log.error("membersList为空");
return;
}
for (ImConversationMembers conversationMembers : membersList) {
// 排除发送者
if (conversationMembers.getFkClientId().equals(imClientSender.getId())) {
continue;
}
// 保存收件箱
long imInboxId = SnowflakeUtil.getId();
ImInbox imInbox = new ImInbox();
imInbox.setId(imInboxId);
imInbox.setCreateTime(new Date());
imInbox.setFkAppid(imApplication.getId());
imInbox.setReceiver(conversationMembers.getId());
imInbox.setFkMsgId(messageId);
imInbox.setReadMsg(0);
imInbox.setFkConversationId(toConversationId);
imInboxService.save(imInbox);
// 接收方
ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getId, conversationMembers.getFkClientId()));
// 向接收方推送
String imClientRecerverUniId = imClientReceiver.getClientId();
mangerChannelService.writeData(content, appKey, imClientRecerverUniId);
}
} }
} }
...@@ -11,6 +11,7 @@ import com.wecloud.im.tillo.app_ws.WsHandler; ...@@ -11,6 +11,7 @@ import com.wecloud.im.tillo.app_ws.WsHandler;
import com.wecloud.im.tillo.app_ws.model.WsConstants; import com.wecloud.im.tillo.app_ws.model.WsConstants;
import com.wecloud.im.tillo.app_ws.service.MangerChannelService; import com.wecloud.im.tillo.app_ws.service.MangerChannelService;
import com.wecloud.im.tillo.app_ws.utils.FullHttpRequestUtils; import com.wecloud.im.tillo.app_ws.utils.FullHttpRequestUtils;
import io.geekidea.springbootplus.config.constant.CommonConstant;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
...@@ -22,6 +23,7 @@ import org.springframework.data.redis.core.StringRedisTemplate; ...@@ -22,6 +23,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.Map; import java.util.Map;
...@@ -80,7 +82,6 @@ public class NettyApiRequest { ...@@ -80,7 +82,6 @@ public class NettyApiRequest {
} }
} }
/** /**
* 初始化websocket * 初始化websocket
*/ */
...@@ -92,10 +93,10 @@ public class NettyApiRequest { ...@@ -92,10 +93,10 @@ public class NettyApiRequest {
DecodedJWT jwtInfo = JwtUtil.getJwtInfo(token); DecodedJWT jwtInfo = JwtUtil.getJwtInfo(token);
String payload = jwtInfo.getPayload(); String payload = jwtInfo.getPayload();
Base64.Decoder decoder = Base64.getDecoder(); Base64.Decoder decoder = Base64.getDecoder();
payload = new String(decoder.decode(payload), "UTF-8"); payload = new String(decoder.decode(payload), StandardCharsets.UTF_8);
JSONObject jsonObject = JSONObject.parseObject(payload); JSONObject jsonObject = JSONObject.parseObject(payload);
String appKey = (String) jsonObject.get("appKey"); String appKey = (String) jsonObject.get("appKey");
String clientId = (String) jsonObject.get("username"); String clientId = (String) jsonObject.get(CommonConstant.CLIENT_ID);
// 验签token // 验签token
ImApplication imApplication = imApplicationService.getOne(new QueryWrapper<ImApplication>().lambda() ImApplication imApplication = imApplicationService.getOne(new QueryWrapper<ImApplication>().lambda()
...@@ -126,7 +127,7 @@ public class NettyApiRequest { ...@@ -126,7 +127,7 @@ public class NettyApiRequest {
ctx.pipeline().addLast("appImHandler", appImHandler); ctx.pipeline().addLast("appImHandler", appImHandler);
// 保存用户上下文对象 // 保存用户上下文对象
appUserChannelsService.put((appKey + clientId), (NioSocketChannel) ctx.channel()); appUserChannelsService.put(appKey, clientId, (NioSocketChannel) ctx.channel());
//移除当前api处理handler, 不再参与长连接处理 //移除当前api处理handler, 不再参与长连接处理
ctx.pipeline().remove("SingleHttpRequestHandler"); ctx.pipeline().remove("SingleHttpRequestHandler");
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wecloud.im.mapper.ImConversationMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, create_time, update_time, last_message, fk_appid, creator, name, attributes, system
</sql>
<select id="getImConversationById" resultType="com.wecloud.im.param.ImConversationQueryVo">
select
<include refid="Base_Column_List"/>
from im_conversation where id = #{id}
</select>
<select id="getImConversationPageList" parameterType="com.wecloud.im.param.ImConversationPageParam"
resultType="com.wecloud.im.param.ImConversationQueryVo">
select
<include refid="Base_Column_List"/>
from im_conversation
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wecloud.im.mapper.ImConversationMembersMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, create_time, update_time, fk_appid, fk_conversation_id, fk_client_id
</sql>
<select id="getImConversationMembersById" resultType="com.wecloud.im.param.ImConversationMembersQueryVo">
select
<include refid="Base_Column_List"/>
from im_conversation_members where id = #{id}
</select>
<select id="getImConversationMembersPageList" parameterType="com.wecloud.im.param.ImConversationMembersPageParam"
resultType="com.wecloud.im.param.ImConversationMembersQueryVo">
select
<include refid="Base_Column_List"/>
from im_conversation_members
</select>
</mapper>
...@@ -73,7 +73,7 @@ public interface CommonConstant { ...@@ -73,7 +73,7 @@ public interface CommonConstant {
/** /**
* JWT用户名 * JWT用户名
*/ */
String JWT_USERNAME = "username"; String CLIENT_ID = "clientId";
/** /**
* JWT刷新新token响应状态码 * JWT刷新新token响应状态码
......
...@@ -22,7 +22,6 @@ import io.geekidea.springbootplus.config.properties.JwtProperties; ...@@ -22,7 +22,6 @@ import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.framework.shiro.cache.SysLoginRedisService; import io.geekidea.springbootplus.framework.shiro.cache.SysLoginRedisService;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken; import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService; import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService;
import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.vo.JwtTokenRedisVo; import io.geekidea.springbootplus.framework.shiro.vo.JwtTokenRedisVo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -36,7 +35,6 @@ import org.springframework.data.redis.core.RedisTemplate; ...@@ -36,7 +35,6 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Date; import java.util.Date;
/** /**
...@@ -98,16 +96,16 @@ public class ShiroLoginServiceImpl implements ShiroLoginService { ...@@ -98,16 +96,16 @@ public class ShiroLoginServiceImpl implements ShiroLoginService {
String salt = jwtToken.getSalt(); String salt = jwtToken.getSalt();
Long expireSecond = jwtProperties.getExpireSecond(); Long expireSecond = jwtProperties.getExpireSecond();
// 生成新token字符串 // 生成新token字符串
String newToken = JwtUtil.generateToken(username, salt, Duration.ofSeconds(expireSecond)); // String newToken = JwtUtil.generateToken(username, salt, Duration.ofSeconds(expireSecond));
// 生成新JwtToken对象 // 生成新JwtToken对象
JwtToken newJwtToken = JwtToken.build(newToken, username, jwtToken.getUserId(), salt, expireSecond, jwtToken.getType(), null); // JwtToken newJwtToken = JwtToken.build(newToken, username, jwtToken.getUserId(), salt, expireSecond, jwtToken.getType(), null);
// 更新redis缓存 // // 更新redis缓存
sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken); // sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken);
log.debug("刷新token成功,原token:{},新token:{}", token, newToken); // log.debug("刷新token成功,原token:{},新token:{}", token, newToken);
// 设置响应头 // // 设置响应头
// 刷新token // // 刷新token
httpServletResponse.setStatus(CommonConstant.JWT_REFRESH_TOKEN_CODE); // httpServletResponse.setStatus(CommonConstant.JWT_REFRESH_TOKEN_CODE);
httpServletResponse.setHeader(JwtTokenUtil.getTokenName(), newToken); // httpServletResponse.setHeader(JwtTokenUtil.getTokenName(), newToken);
} }
@Override @Override
......
...@@ -54,23 +54,23 @@ public class JwtUtil { ...@@ -54,23 +54,23 @@ public class JwtUtil {
/** /**
* 生成JWT Token * 生成JWT Token
* *
* @param username 用户名 * @param clientId 用户名
* @param salt 盐值 * @param salt 盐值
* @param expireDuration 过期时间和单位 * @param expireDuration 过期时间和单位
* @return token * @return token
*/ */
public static String generateToken(String username, String salt, Duration expireDuration) { public static String generateToken(String clientId, String appKey, String salt, Duration expireDuration) {
try { try {
if (StringUtils.isBlank(username)) { if (StringUtils.isBlank(clientId)) {
log.error("username不能为空"); log.error("username不能为空");
return null; return null;
} }
log.debug("username:{}", username); log.debug("clientId:{}", clientId);
// 如果盐值为空,则使用默认值:666666 // // 如果盐值为空,则使用默认值:666666
if (StringUtils.isBlank(salt)) { // if (StringUtils.isBlank(salt)) {
salt = jwtProperties.getSecret(); // salt = jwtProperties.getSecret();
} // }
log.debug("salt:{}", salt); log.debug("salt:{}", salt);
// 过期时间,单位:秒 // 过期时间,单位:秒
...@@ -88,7 +88,7 @@ public class JwtUtil { ...@@ -88,7 +88,7 @@ public class JwtUtil {
// 生成token // 生成token
Algorithm algorithm = Algorithm.HMAC256(salt); Algorithm algorithm = Algorithm.HMAC256(salt);
String token = JWT.create() String token = JWT.create()
.withClaim(CommonConstant.JWT_USERNAME, username) .withClaim(CommonConstant.CLIENT_ID, clientId)
// jwt唯一id // jwt唯一id
.withJWTId(UUIDUtil.getUuid()) .withJWTId(UUIDUtil.getUuid())
// 签发人 // 签发人
...@@ -97,8 +97,8 @@ public class JwtUtil { ...@@ -97,8 +97,8 @@ public class JwtUtil {
.withSubject(jwtProperties.getSubject()) .withSubject(jwtProperties.getSubject())
// 签发的目标 // 签发的目标
.withAudience(jwtProperties.getAudience()) .withAudience(jwtProperties.getAudience())
.withClaim("test1","ddddddd") // .withClaim("test1","ddddddd")
.withClaim("appKey","elLwpel1gWCHDqZy") .withClaim("appKey", appKey)
// 签名时间 // 签名时间
.withIssuedAt(new Date()) .withIssuedAt(new Date())
// token过期时间 // token过期时间
...@@ -164,7 +164,7 @@ public class JwtUtil { ...@@ -164,7 +164,7 @@ public class JwtUtil {
if (decodedJwt == null) { if (decodedJwt == null) {
return null; return null;
} }
String username = decodedJwt.getClaim(CommonConstant.JWT_USERNAME).asString(); String username = decodedJwt.getClaim(CommonConstant.CLIENT_ID).asString();
return username; return username;
} }
......
package io.geekidea.springbootplus.framework.shiro.util;
import cn.hutool.core.lang.Snowflake;
public class SnowflakeUtil {
public static Long getId() {
return new Snowflake(1L, 1L).nextId();
}
}
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