十次方社交项目-im即时消息通讯3

一、即时通讯的业务场景和需求

即时通信(Instant Messaging,简称IM)是一个允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流。 即时通讯技术应用于需要实时收发消息的业务场景。

现在各种各样的即时通讯软件也层出不穷:

  • 客服系统

   招商银行客服中心

  • 直播互动

   image

  • 社交APP

   image

  • 智能硬件,物联网

   image

二、系统设计

1. 技术选型

  • 环信im云
  • 前端框架 vue

2. 架构设计

 前端页面使用十次方用户微服务认证用户身份,使用环信im云进行即时消息通信。

  image

三、环境和工具

  • nodejs
  • npm
  • 前端框架 vue
  • 开发工具 vscode

四、十次方即时通讯功能

1. 用户微服务实现

 1) 创建tensquare_user子模块

  创建Maven工程

 2) 在pom.xml中添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>tensquare_parent</artifactId>
        <groupId>com.tensquare</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tesquare_user</artifactId>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.tensquare</groupId>
            <artifactId>tensquare_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatisplus-spring-boot-starter</artifactId>
            <version>${mybatisplus-spring-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
    </dependencies>

</project>
View Code

 3) 编写application.yml配置文件

server:
  port: 9008
spring:
  application:
    name: tensquare-user
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.240.134:3306/tensquare_user?characterEncoding=utf-8
    username: root
    password: root
mybatis-plus:
  type-aliases-package: com.tensquare.user.pojo
  global-config:
    id-type: 1
    db-column-underline: false
    refresh-mapper: true
    configuration:
      map-underscore-to-camel-case: true
      cache-enabled: true              #配置的缓存的全局开关
      lazyLoadingEnable: true           #延时加载的开关,开启延时加载,否则按需加载属性
      multipleResultSetsEnabled: true  #允许单语句返回多结果集
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #打印sql语句,调试用
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka/
  instance:
    prefer-ip-address: true
View Code

 4)编写MyBatis配置Bean

package com.tensquare.user.config;

import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public PaginationInterceptor createPaginationInterceptor(){
        return new PaginationInterceptor();
    }
}

 5) 编写引导类

package com.tensquare.user;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@MapperScan("com.tensquare.user.dao")
@EnableEurekaClient
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class);
    }
}

 6) 编写pojo

package com.tensquare.user.pojo;

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;

@TableName("tb_user")
@Data
public class User implements Serializable {

    @TableId(type = IdType.INPUT)
    private String id;
    private String mobile;
    private String password;
    private String nickname;
    private String sex;
    private Date birthday;
    private String avatar;
    private String email;
    private Date regdate;
    private Date updatedate;
    private Date lastdate;
    private Long online;
    private String interest;
    private String personality;
    private Integer fanscount;
    private Integer followcount;
}

 7) 编写dao

package com.tensquare.user.dao;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.tensquare.user.pojo.User;

public interface UserDao extends BaseMapper<User> {
}

 8) 编写service

package com.tensquare.user.service;

import com.tensquare.user.dao.UserDao;
import com.tensquare.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User login(User user) {
        return userDao.selectOne(user);
    }
}

 9) 编写controller

package com.tensquare.user.controller;

import com.tensquare.entity.Result;
import com.tensquare.entity.StatusCode;
import com.tensquare.user.pojo.User;
import com.tensquare.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("user")
@CrossOrigin
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "login",method = RequestMethod.POST)
    public Result login(@RequestBody User user){
        User result = userService.login(user);
        if(result != null){
            return  new Result(true, StatusCode.OK,"登录成功",result);
        }
        return  new Result(false, StatusCode.ERROR,"登录失败");
    }
}

2. 即时通讯前端准备

 访问环信IM开发文档--> Web客户端 --> SDK集成介绍 --》Web IM 集成介绍

 或者直接访问http://docs-im.easemob.com/im/web/intro/integration

 2.1 按照文档,使用git下载集成案例:

$ git clone https://github.com/easemob/webim.git

 2.2 复制案例中的\webim\sdk目录下的所有js文件到项目resources\static\js中

 2.3 复制webim\simpleDemo中的资料到resources\static中

  f28e0d1c49272b7c50c73084e67bba6b_1564476315662

 测试demo.html,确认即时通讯的用户登录,发文本消息,效果如下

  b404542bf108ee8e56ac05f15e71da1b_1564476721670

3. 发送和接收消息

 复制Spring-websocket项目中的chatroom.jsp改造为chatroom.html,根据demo.html案例实现用户注册和登录和即时消息功能。最终效果:

<!DOCTYPE HTML>
<html>
  <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="edge" />
      <title>聊天室</title>
      <script src="js/jquery-1.12.3.min.js"></script>
      <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
      <style>
        body{
            margin-top:5px;
        }
      </style>
      <script type="text/javascript" src="WebIMConfig.js"></script>
      <script type="text/javascript" src="js/EMedia_x1v1.js"></script>
      <script type="text/javascript" src="js/webimSDK3.0.4.js"></script>
  </head>
  <body>
    <div class="container">
        <div class="row">
            <div class="col-md-3">
            <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">登录和注册</h3>
                  </div>
                <div class="panel-body">
                    <input type="text" class="form-control"  id="userId"  placeholder="用户id"/><br>
                    <button id="reg" type="button" class="btn btn-primary">注册</button>
                    <button id="login" type="button" class="btn btn-primary">登录</button>
                </div>
                  </div>
                </div>
                <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">消息接收者</h3>
                  </div>
                  <div class="panel-body">
                    <div class="list-group">
                        <input type="text" class="form-control"  id="toUserId"  placeholder="接收消息用户id"/><br>
                    </div>
                  </div>
                </div>
                <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">群发系统广播</h3>
                  </div>
                  <div class="panel-body">
                    <input type="text" class="form-control"  id="msg" /><br>
                    <button id="broadcast" type="button" class="btn btn-primary">发送</button>
                  </div>
                </div>
            </div>
              <div class="col-md-9">
                  <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title" id="talktitle"></h3>
                  </div>
                  <div class="panel-body">
                    <div class="well" id="log-container" style="height:400px;overflow-y:scroll">
                    
                    </div>
                        <input type="text" id="myinfo" class="form-control col-md-12" /> <br>
                        <button id="send" type="button" class="btn btn-primary">发送</button>
                    </div>
                </div>
              </div>
        </div>
    </div>

    <script>
        //创建连接
        var conn = {};
        console.log(WebIM, window.WebIM);
        WebIM.config = config;
        conn = WebIM.conn = new WebIM.default.connection({
            appKey: WebIM.config.appkey,
            isHttpDNS: WebIM.config.isHttpDNS,
            isMultiLoginSessions: WebIM.config.isMultiLoginSessions,
            host: WebIM.config.Host,
            https: WebIM.config.https,
            url: WebIM.config.xmppURL,
            apiUrl: WebIM.config.apiURL,
            isAutoLogin: false,
            heartBeatWait: WebIM.config.heartBeatWait,
            autoReconnectNumMax: WebIM.config.autoReconnectNumMax,
            autoReconnectInterval: WebIM.config.autoReconnectInterval,
            isStropheLog: WebIM.config.isStropheLog,
            delivery: WebIM.config.delivery
        })

        //回调方法
        conn.listen({
            onOpened: function (message) {          //连接成功回调
                var myDate = new Date().toLocaleString();
                console.log("%c [opened] 连接已成功建立", "color: green");
                console.log(myDate);
                // rek();
                // alert(myDate + "登陆成功")
            },
            onClosed: function (message) {
                console.log("onclose:" + message);
                console.log(error);
            },         //连接关闭回调
            onTextMessage: function (message) {
                console.log('onTextMessage: ', message);
                $("#log-container").append("<div class='bg-info'><label class='text-danger'>接收到id为"+message.from+"的消息:</label><div class='text-success'>"+message.data+"</div></div><br>");
                alert("end");
            }
        });

        var userId;
        var nickname;
        var password;
        //注册
        //本案例使用用户id即可完成注册和登录
        document.getElementById("reg").onclick = function () {
            userId = document.getElementById("userId").value;
            //设置Ajax 是同步的,需要先获取用户数据再注册
            $.ajaxSettings.async = false
            $.get("/user/"+userId,function (data) {
                nickname = data.data.nickname;
                password = data.data.password;
            });
            alert(nickname);
            alert(password);
            var option = {
                username: userId,
                nickname: nickname,
                password: password,
                appKey: WebIM.config.appkey,
                success: function () {
                    console.log('注册成功');
                },
                error: function () {
                    console.log('注册失败');
                },
                apiUrl: WebIM.config.apiURL
            };
            conn.signup(option);
        };

        //登录
        document.getElementById("login").onclick = function () {
            userId = document.getElementById("userId").value;
            $.ajaxSettings.async = false
            $.get("/user/"+userId,function (data) {
                password = data.data.password;
            });
            var options= {
                user: userId,
                pwd: password,
                appKey: WebIM.config.appkey,
                apiUrl: WebIM.config.apiURL
            };
            conn.open(options);
            console.log(options);
        };

        //文本消息
        var conf = WebIM.config
        WebIM.config = conf
        WebIM.message = WebIM.default.message
        WebIM.utils = WebIM.default.utils
        WebIM.debug = WebIM.default.debug
        WebIM.statusCode = WebIM.default.statusCode

        var myDate = new Date().toLocaleString();
        document.getElementById('send').onclick = function () {
            var tname = document.getElementById('toUserId').value;
            var tmsg = document.getElementById("myinfo").value;
            var id = conn.getUniqueId();    //生成本地消息id
            var msg = new WebIM.default.message('txt',id);//
            msg.set({
                msg: tmsg,    //消息内容
                to: tname,
                ext:{
                    'time': myDate
                },
                // 接收消息对象(用户id)
                success: function (id,serverMsgId) {
                    console.log('send private text success');
                    msgText = msg.body.msg;
                },
                fail: function (e) {
                    console.log('send private text error');
                }
            });
            msg.body.chatType = 'singleChat';
            conn.send(msg.body);
            //在聊天信息显示页面展示聊天数据
            $("#log-container").append("<div class='bg-info'><label class='text-danger'>发送给id为"+tname+"" +
                    "消息:</label><div class='text-success'>"+tmsg+"</div></div><br>");
            console.log(msg);
        };
    </script>
  </body>
</html>
View Code

 

posted on 2025-12-04 03:51  花溪月影  阅读(1)  评论(0)    收藏  举报