场景

若依前后端分离版本地搭建开发环境并运行项目的教程:

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


posted on 2024-03-07 16:11  霸道流氓  阅读(283)  评论(0编辑  收藏  举报