场景
若依前后端分离版本地搭建开发环境并运行项目的教程:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662
CIM
Gitee地址:
https://gitee.com/farsunset/cim
CIM项目是基于mina或者netty框架下的推送系统,我们平常使用第三方的推送SDK,如极光推送,百度推送,小米推送,以及腾讯信鸽等来支撑自己的移动端的业务,或许有一些用户自己实现即时通讯系统的需求,那么CIM为您提供了一个解决方案或者思路,目前CIM支持 websocket,android,ios,桌面应用,系统应用等多端接入支持,目前CIM服务端使用springboot搭建仅仅拥有消息推送的功能,关于数据缓存与持久化都需要使用者自己开发,但是配备了比较完整的使用文档。最后希望CIM能为您带来一些价值。
将上面的cim代码拉取到本地,代码结构如下
目录说明
1.cim-use-examples是各个客户端使用示例
2.cim-client-sdk 是各个客户端的SDK源码
3.cim-server-sdk 是服务端SDK源码,分为 mina和netty 两个版本,二者任选其一
4.cim-boot-server是springboot服务端工程源码,使用Idea工具开发
其中所有的sdk均为IntelliJ IDEA工程,Maven打包成jar导出引入到对应的客户端或服务端工程
然后我们使用IDEA打开并运行其服务端代码
打开浏览器访问
http://localhost:8088/console/session/list
默认是8080端口,这里将其修改过
为了测试其推送效果,使用AndroidStudio打开其Android的示例代码
找到包路径下的app下的Constant中的服务器IP地址设置,将地址修改为上面启动的服务端的ip地址。其他端口号保持不变
然后运行APP
连接成功之后会跳转到登录页面,输入登录账号之后点击登录
登录成功,然后回到后台服务端页面中
刷新页面,会发现在线用户列表中已经显示,点击发送消息
输入消息内容,点击发送
则会在app中收到消息推送。
以上是CIM自带服务端的推送效果,但是器服务端不是前后端分离版的,现在讲怎样
在SpringBoot+Vue前后端分离版的架构中集成CIM的服务端
首先按照上面一开始的博客将前后端分离的架构搭建好
然后找到若依的common模块的pom.xml中引入项目所需的依赖,首先添加properties
<properties>
<java.version>1.8</java.version>
<netty.version>4.1.35.Final</netty.version>
<mina.version>2.1.3</mina.version>
<protobuf.version>3.11.1</protobuf.version>
</properties>
然后按照cim服务端的依赖添加坐标
<!--- ##################使用mina版本SDK时的配置 start ##################-->
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>${mina.version}</version>
</dependency>
<!--- ##################使用mina版本SDK时的配置 end ##################-->
<!--- ##################使用netty本SDK时的配置 start ##################-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
</dependency>
<!--- ##################使用netty本SDK时的配置 end ##################-->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>cn.teaey.apns4j</groupId>
<artifactId>apns4j</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
注意这里不用引入sdk的依赖,下面直接将sdk的源码集成进来
在ruoyi-common的包下直接新建cim.sdk.server目录,然后将CIM下的
cim-server-sdk下的cim-server-sdk-netty下的src下的包路径下的代码复制过来
复制到对应的上面新建的包路径下
将其复制过来之后,原有代码的引入路径会报错。将sdk.server下的每个代码中的引入路径全部删掉重新导入。
然后找到resources下的i18n下的message.properties国家化文件。将CIM自带的的国际化的字段信息复制到若依下面
接下来就是转移配置文件中的一些配置
打开若依的application.yml
首先是添加host配置
若依默认是不带host配置的
然后再添加cim所需要的配置
这里就需要把cim在properties中的配置改为yml中的配置了
下面就是将cim的服务端的代码集成到若依这套架构中
在若依的ruoyi-admin下的com.ruoyi下新建cim包以及config包,config包下主要是放置用来配置项目启动后
启动websocket服务的配置类,然后在cim包下放置cim服务端的代码
然后将其复制过来之后,每个目录下引用的路径要修改。依次将每个打开,将错误的import删掉,重新导入。
然后修改sessionController,这个是显示在线用户的列表的接口,将其修改为前端请求数据的接口
@RestController
@RequestMapping("/system/onlineUser")
public class SessionController {
@Resource
private CIMSessionService cimSessionService;
/**
* 查询在线用户列表
*/
@GetMapping("/list")
public AjaxResult list()
{
List<CIMSession> list = cimSessionService.list();
return AjaxResult.success(list);
}
}
然后将api.controller下的MessageController中的接口修改
@RestController
@RequestMapping("/api/message")
public class MessageController {
@Resource
private DefaultMessagePusher defaultMessagePusher;
@PostMapping(value = "/send")
public ResponseEntity<Long> send(@RequestBody Message message) {
message.setId(System.currentTimeMillis());
defaultMessagePusher.push(message);
return ResponseEntity.ok(message.getId());
}
}
然后就是生成前端代码。这里使用若依自带的代码生成工具
首先在数据库中设计一个表,表结构和CIM的sdk的CIMSession一样
表结构的sql如下
DROP TABLE IF EXISTS `cim_online_user`;
CREATE TABLE `cim_online_user` (
`id` int(50) NOT NULL COMMENT '数据库主键Id',
`account` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'session绑定的用户账号',
`nid` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'session在本台服务器上的ID',
`deviceId` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端ID (设备号码+应用包名),ios为deviceToken',
`host` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'session绑定的服务器IP',
`channel` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '终端设备类型',
`deviceModel` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '终端设备型号',
`clientVersion` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '终端应用版本',
`systemVersion` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '终端系统版本',
`bindTime` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
`longitude` double(100, 0) NULL DEFAULT NULL COMMENT '经度',
`latitude` double(100, 0) NULL DEFAULT NULL COMMENT '纬度',
`location` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '位置',
`apns` int(10) NULL DEFAULT NULL COMMENT 'APNs推送状态',
`state` int(10) NULL DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '在线用户' ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
然后使用若依的代码生成工具,生成代码,这主要取前端代码和sql文件
然后替换为前端代码后,将其页面代码修改为请求后台接口获取
<template>
<div class="app-container">
<el-table
v-loading="loading"
:data="onlineUserList"
@selection-change="handleSelectionChange"
>
<el-table-column label="账号" align="center" prop="account" />
<el-table-column label="设备ID" align="center" prop="nid" />
<el-table-column
label="客户端ID"
align="center"
prop="deviceId"
width="400"
/>
<el-table-column label="服务器IP" align="center" prop="host" />
<el-table-column
label="终端设备类型"
align="center"
prop="channel"
width="100"
/>
<el-table-column
label="终端设备型号"
align="center"
prop="deviceModel"
width="100"
/>
<el-table-column
label="终端应用版本"
align="center"
prop="clientVersion"
width="100"
/>
<el-table-column
label="终端系统版本"
align="center"
prop="systemVersion"
width="100"
/>
<el-table-column
label="登录时间"
align="center"
prop="bindTime"
width="180"
:formatter="dateFormat"
/>
<el-table-column label="位置" align="center" prop="location" />
<el-table-column label="状态" align="center" prop="state" />
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="sendMessage(scope.row)"
>发送消息</el-button
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 发送消息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="接收账号" prop="account">
<el-input v-model="form.account" readonly="true" />
</el-form-item>
<el-form-item label="消息内容" prop="nid">
<el-input
v-model="form.content"
type="textarea"
placeholder="请输入内容"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listOnlineUser, doSendMessage } from "@/api/system/onlineUser";
import moment from "moment";
export default {
name: "OnlineUser",
components: {},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 在线用户表格数据
onlineUserList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
account: null,
host: null,
},
// 表单参数
form: {},
// 表单校验
rules: {},
};
},
created() {
this.getList();
},
methods: {
//时间格式化
dateFormat: function (row, column) {
debugger;
var date = row[column.property];
if (date == undefined) {
return "";
}
return moment(date).format("YYYY-MM-DD HH:mm:ss");
},
/** 查询在线用户列表 */
getList() {
this.loading = true;
listOnlineUser().then((response) => {
debugger;
this.onlineUserList = response.data;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
account: null,
host: null,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 发送消息按钮操作 */
sendMessage(row) {
this.reset();
this.open = true;
this.title = "发送消息";
this.form.account = row.account;
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate((valid) => {
if (valid) {
debugger;
doSendMessage(this.form).then((response) => {
this.msgSuccess("发送成功");
this.open = false;
});
}
});
},
},
};
</script>
然后将请求的js的代码修改为
import request from '@/utils/request'
// 查询在线用户列表
export function listOnlineUser() {
return request({
url: '/system/onlineUser/list',
method: 'get',
})
}
// 发送消息
export function doSendMessage(data) {
var message = {};
message.content = data.content;
message.action = 2;
message.sender = 'system';
message.receiver = data.account;
message.format = '0';
debugger
return request({
url: '/api/message/send',
method: 'post',
data: message
})
}
然后运行前端和后端项目,并且使用其app的demo,连接后台后,在新版的在线用户中,就可以看到app端连接的用户了
点击后面的发送消息按钮
点击发送
就会在app端收到推送,然后使用其示例代码中的cim-client-web中的index.html登录之后,就会在在线用户列表中看到
然后给web端发送消息
示例代码下载
https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/15727997