场景

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


CIM

Gitee地址:

cim: 【专注10年,从未刷星】(http://farsunset.com)。CIM是一套基于netty框架下的推送系统,或许有一些企业有着自己一套即时通讯系统的需求,那么CIM为您提供了一个解决方案,目前CIM支持websocket,android,ios,桌面应用,系统应用等多端接入支持,可应用于移动应用,物联网,智能家居,嵌入式开发,桌面应用,WEB应用以及后台系统之间的即时消服务。

CIM项目是基于mina或者netty框架下的推送系统,我们平常使用第三方的推送SDK,如极光推送,百度推送,小米推送,以及腾讯信鸽等来支撑自己的移动端的业务,或许有一些用户自己实现即时通讯系统的需求,那么CIM为您提供了一个解决方案或者思路,目前CIM支持 websocket,android,ios,桌面应用,系统应用等多端接入支持,目前CIM服务端使用springboot搭建仅仅拥有消息推送的功能,关于数据缓存与持久化都需要使用者自己开发,但是配备了比较完整的使用文档。最后希望CIM能为您带来一些价值。

将上面的cim代码拉取到本地,代码结构如下

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端

目录说明
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打开并运行其服务端代码

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_02

打开浏览器访问

 http://localhost:8088/console/session/list

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_spring boot_03

默认是8080端口,这里将其修改过

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_vue.js_04

为了测试其推送效果,使用AndroidStudio打开其Android的示例代码

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_05

找到包路径下的app下的Constant中的服务器IP地址设置,将地址修改为上面启动的服务端的ip地址。其他端口号保持不变

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_vue.js_06

然后运行APP

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_07

连接成功之后会跳转到登录页面,输入登录账号之后点击登录

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_08

登录成功,然后回到后台服务端页面中

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_vue.js_09

刷新页面,会发现在线用户列表中已经显示,点击发送消息

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_10

输入消息内容,点击发送

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_11

则会在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>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

然后按照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>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.

注意这里不用引入sdk的依赖,下面直接将sdk的源码集成进来

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_spring boot_12

在ruoyi-common的包下直接新建cim.sdk.server目录,然后将CIM下的

cim-server-sdk下的cim-server-sdk-netty下的src下的包路径下的代码复制过来

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_13

复制到对应的上面新建的包路径下

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_ci_14

将其复制过来之后,原有代码的引入路径会报错。将sdk.server下的每个代码中的引入路径全部删掉重新导入。

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_15

然后找到resources下的i18n下的message.properties国家化文件。将CIM自带的的国际化的字段信息复制到若依下面

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_16

接下来就是转移配置文件中的一些配置

打开若依的application.yml

首先是添加host配置

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_17

若依默认是不带host配置的

然后再添加cim所需要的配置

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_18

这里就需要把cim在properties中的配置改为yml中的配置了

下面就是将cim的服务端的代码集成到若依这套架构中

在若依的ruoyi-admin下的com.ruoyi下新建cim包以及config包,config包下主要是放置用来配置项目启动后

启动websocket服务的配置类,然后在cim包下放置cim服务端的代码

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_spring boot_19

然后将其复制过来之后,每个目录下引用的路径要修改。依次将每个打开,将错误的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);
 }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

然后将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());
 }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

然后就是生成前端代码。这里使用若依自带的代码生成工具

首先在数据库中设计一个表,表结构和CIM的sdk的CIMSession一样

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_20

表结构的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;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

然后使用若依的代码生成工具,生成代码,这主要取前端代码和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>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.

然后将请求的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
    })
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

然后运行前端和后端项目,并且使用其app的demo,连接后台后,在新版的在线用户中,就可以看到app端连接的用户了

 

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_ci_21

点击后面的发送消息按钮

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_spring boot_22

点击发送

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_后端_23

就会在app端收到推送,然后使用其示例代码中的cim-client-web中的index.html登录之后,就会在在线用户列表中看到

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_服务端_24

然后给web端发送消息

若依集成CIM(即时推送系统)实现将服务端修改为SpringBoot+Vue前后端分离版_vue.js_25