基于WebSocket的web端IM即时通讯应用的开发

栏目: 后端 · 发布时间: 6年前

内容简介:功能列表:1、Web端的IM应用2、支持上线、下线、实时在线提醒

功能列表:

1、Web端的IM应用

2、支持上线、下线、实时在线提醒

3、单聊、群聊的建立

4、普通文字、表情、图片的传输(子定义富文本)

5、单人的顶级提醒,多对话的窗口的提醒

6、调用图灵机器人的自动回复演示

核心技术列表

1、websocket、sockjs、stomp

2、前端展示涉及的jquery、vue、elementUI、jquerybase64js

3、后端springboot、jsoup、spring-security、spring-websocket

成果展示:

基于WebSocket的web端IM即时通讯应用的开发

基于WebSocket的web端IM即时通讯应用的开发

基于WebSocket的web端IM即时通讯应用的开发

基于WebSocket的web端IM即时通讯应用的开发

技术实现说明:

Websocket部分

web端的IM应用,要想实现两个客户端的通信,必然要通过服务器进行信息的转发。例如A要和B通信,则应该是A先把信息发送给IM应用服务器,服务器根据A信息中携带的接收者将它再转发给B,同样B到A也是这种模式。

而要实现web端的实时通讯,websocket也是其中最好的方式,其他的协议如长轮询、短轮询、iframe数据、htmlfile等。

在实际开发中,我们通常使用的是一些别人写好的实时通讯的库,比如socket.io、sockjs(我们本次使用了他,类似jquery,对其他即时通讯技术做了封装),他们的原理就是将上面(还有一些其他的如基于Flash的push)的一些技术进行了在客户端和服务端的封装,然后给开发者一个统一调用的接口。这个接口在支持websocket的环境下使用websocket,在不支持它的时候启用上面所讲的一些hack技术。

WebSocket是HTML5的一种新通信协议(ws协议),是一个消息架构,不强制使用任何特定的消息协议,它依赖于应用层解释消息的含义;与处在应用层的HTTP不同,WebSocket处在TCP上非常薄的一层,会将字节流转换为文本/二进制消息,因此,对于实际应用来说,WebSocket的通信形式层级过低,因此,可以在 WebSocket 之上使用 STOMP协议,来为浏览器 和 server间的 通信增加适当的消息语义。

STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议。 同 HTTP 在 TCP 套接字上添加请求-响应模型层一样,STOMP 在 WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;

STOMP 源码http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js,有兴趣的可以看一下能大致了解其原理和用法。

本例程序核心代码:

<!--TO 创建socket连接 并订阅相关频道-->
var socket = new SockJS('/im-websocket');
stompClient = Stomp.over(socket);
//设置stomp 控制台日志为不输出
stompClient.debug=null;
stompClient.connect({}, function (frame) {
       // 相当于连接 ws://localhost:8080/gs-guide-websocket/041/hk5tax0r/websocket hk5tax0r就是sessionid
    console.log("正在连接",socket._transport.url);
    //订阅通用私聊频道 群组也通过这里实现
    stompClient.subscribe('/user/topic/private', function (greeting) {
        
    }
   );
    //订阅用户上线下线的公共频道
    stompClient.subscribe('/topic/userlist', function (greeting) {
        
    });
},function errorCallBack (error) {
    // 连接失败时(服务器响应 ERROR 帧)的回调方法
 
});

数据发送如下:

//第一个参数对应controller的 @MessageMapping注解 /app为后台定义的通用前缀

//第三个参数为内容字符串

stompClient.send("/app/private", {}, JSON.stringify(message));//发送服务器

对应服务端部分

#WebSocketConfig
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

  public List<User> onlineUser=new ArrayList<User>();
  @Autowired
  private SimpMessagingTemplate template;
  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setUserDestinationPrefix("/user");
    config.setApplicationDestinationPrefixes("/app");
    config.setCacheLimit(1048576);//大小 1M
  }
  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    //注册的websocket接入点,前端链接的就是它
    registry.addEndpoint("/im-websocket").withSockJS();
  }

  @Override
  public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
    //设置 文件缓冲 大小 1M
//如不设置文件稍微大一点就报错了
    registration.setMessageSizeLimit(1048576);
    registration.setSendBufferSizeLimit(1048576);
    registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
      @Override
      public WebSocketHandler decorate(final WebSocketHandler handler) {
        return new WebSocketHandlerDecorator(handler) {
          @Override
          public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
            ******
          }

          @Override
          public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
            throws Exception {
      *****
          }
        };
      }
    });
    super.configureWebSocketTransport(registration);
  }
}


#contoller
@MessageMapping("/private")
public void privatechat(ImMessage message) throws Exception {
*****
template.convertAndSendToUser(message.getReceiver(),"/topic/private",message);
////发送其订阅的频道
///浏览器客户端,订阅了’/user/topic/private这条路径,
}

其中@MessageMapping("bar") //@MessageMapping接收客户端消息

另外@SendTo("/topic/brocast") //@SendTo广播消息出去

@SendToUser("/topic/greetings")//发送对应人。

这两个注解可以用template.convertAndSendTo、template.convertAndSendToUser在代码实现。

Spring-security部分

做了简单的登录验证,登录成功即在系统存有sessionid。结合上面的订阅,实际链接的后台地址会附加上sessionid,也就是httprequest中的登录授权信息即javax.security.Principal会被绑定到websocket的session中。即可以实现与指定登录人的双向链接。

页面展示部分

页面展示核心应用vue,vue不好实现的地方使用的是jquery。样式采用的elmentUI。

在开发这个im应用测试案例的时候。实现了一些前端效果。核心有用的列到下面,各位也许在后面的学习中能够用到。

1.vue兼容性的问题

因为本来不是webpack开发模式,属于直接引入js的普通HTML开发,如需要解决vue兼容性问题,可以引入

https://cdn.bootcss.com/babel... 以解决。

2、vue用法(v-model、@click、v-html、v-forv-if,v-bind)的应用,指令、过滤器、全局方法、watch的使用。其中指令用来实现div的默认焦点。全局方法用来代替过滤器,实现实时的消息内容base64解码。

3、利用vue核心数据的双向绑定,不刷新显示更新。但数据设计为多层的json数组数据,当底层数据变化,vue不能自动检测到变化。需要进行手动检测。

代码-this.$forceUpdate();

4、关于图片消息的用法

用图片上传按钮上,存在透明的fileinput文件,每次上传完,通过onchange方法,先检测文件大小、类型后,通过fileReader预览。这其中涉及富文本框焦点的问题、和base64转码的问题。另外当上传失败通过.val('')清空file,这样才能重新选择文件上传并成功触发onchange事件(值得了解,试验了半天才行)

var filec=$("#file"+index);
if (filec&&filec.length>0) {
    var fileList = filec[0].files;
    if(!/image\/\w+/.test(fileList[0].type))            //判断获取的是否为图片文件
    {
        this.$message.error('请确保文件为图像文件');
        //清空input 可以再次上传并触发onchange
        filec.val('')
        return false;
    }
    if(fileList[0].size>1048576){
        this.$message.error('请确保图片不大于1M');
        //清空input 可以再次上传并触发onchange
        filec.val('')
        return false;
    }
    fileReader.onload = function (e) {
        // 获取文件的base64编码
        var base64 = e.target.result
        var image = new Image();
        image.src = base64;
        image.onload = function() {
            //文件像素过大,调整为稍小的
            var newW="";var newH="";
            if(this.width>this.height&&this.width>200){
                newW=200;
                newH=200/this.width*this.height;
            }
            if(this.width<=this.height&&this.height>200){
                newH=200;
                newW=200/this.height*this.width;
            }
            var h = '<img src=' + base64 + ' width='+newW+' height='+newH+'>';
            _insertimg(h, index)//插入到富文本对应的位置
        };
    }
    fileReader.readAsDataURL(fileList[0]);

5、关于富文本在指定焦点位置插入数据的问题,后续可以考虑baidueditor等成熟产品。

当前富文本主要利用了html5的属性contenteditable解决的

具体可以查看_insertimg方法

6、在实现上述富文本的时候,类似插入表情、选择图片的时候,只要点击屏幕,则当前页面焦点即转移,影响实际插入的位置。所以需要设置这些按钮点击的时候屏蔽默认效果。

一个是按钮的@click.prvent。另外可以通过下面的方法解决

document.addEventListener("mousedown", function(e){
  if(e.target.id=="emoijT"){
        e.preventDefault()
    }
}, false);

7、因为当前发送的消息是带html标签的富文本信息,为避免传输的问题,将内容进行base64转码,消息被接收后再转码回来。

var stompClient = null;

//防止乱码

$.base64.utf8encode = true;

$.base64.btoa(thisMessage);//使用插件base64编码

//解码 $.base64.atob(c, true);

8、当前案例不仅实现了多对话窗口,隐藏的对话提醒。也实现了当前人的浏览器标题提醒。

var pageMessage = {
    time: 0,
    title: document.title,
    timer: null,
    // 显示新消息提示
    show: function () {
        var title = pageMessage.title.replace("【   】", "").replace("【新消息】", "");
        // 定时器,设置消息切换频率闪烁效果就此产生
        pageMessage.timer = setTimeout(function () {
            pageMessage.time++;
            pageMessage.show();
            if (pageMessage.time % 2 == 0) {
                document.title = "【新消息】" + title
            }
            else {
                document.title = "【   】" + title
            }
            ;
        }, 600);
        return [pageMessage.timer, pageMessage.title];
    },
    // 取消新消息提示 v
    clear: function () {
        clearTimeout(pageMessage.timer);
        document.title = pageMessage.title;
    }
};

9、关于机器人自动对话,目前使用jsoup调用的远程接口,由其返回答案。虽然是免费接口,但是一天不能调用多次。

String url = "http://www.tuling123.com/openapi/api";
//请填写自己的key
String userid="454995";
String post = "{\"key\": \"646d321c227045a69253fd07d8703840\",\"info\": \""+message.getContent()+"\",\"userid\":\""+userid+"\"}";
String body = Jsoup.connect(url).method(Connection.Method.POST)
        .requestBody(post)
        .header("Content-Type", "application/json; charset=utf-8")
        .ignoreContentType(true).execute().body();

以上所述就是小编给大家介绍的《基于WebSocket的web端IM即时通讯应用的开发》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Seasoned Schemer

The Seasoned Schemer

Daniel P. Friedman、Matthias Felleisen / The MIT Press / 1995-12-21 / USD 38.00

drawings by Duane Bibbyforeword and afterword by Guy L. Steele Jr.The notion that "thinking about computing is one of the most exciting things the human mind can do" sets both The Little Schemer (form......一起来看看 《The Seasoned Schemer》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换