美文网首页JavaSpring-BootSpring WebSocket
Spring WebSocket初探2 (Spring WebS

Spring WebSocket初探2 (Spring WebS

作者: Devid | 来源:发表于2015-11-18 17:15 被阅读10385次

    See more: Spring WebSocket reference
    整个例子属于WiseMenuFrameWork的一部分,可以将整个项目Clone下来,如果朋友们有需求,我可以整理一个独立的demo出来。

    接上一篇:Spring WebSocket初探1 (Spring WebSocket入门教程)

    WebSocket前端准备

    前端我们需要用到两个js文件:
    sockjs.jsstomp.js

    • SockJS
      SockJS 是一个浏览器上运行的 JavaScript 库,如果浏览器不支持 WebSocket,该库可以模拟对 WebSocket 的支持,实现浏览器和 Web 服务器之间低延迟、全双工、跨域的通讯通道。
    • Stomp
      Stomp 提供了客户端和代理之间进行广泛消息传输的框架。Stomp 是一个非常简单而且易用的通讯协议实现,尽管代理端的编写可能非常复杂,但是编写一个 Stomp 客户端却是很简单的事情,另外你可以使用 Telnet 来与你的 Stomp 代理进行交互。

    发送公告功能

    html代码

    <div>    
        <div>        
            <button id="connect" onclick="connect();">Connect</button> 
           <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>    
        </div>    
        <div id="conversationDiv">        
            <p>            
                <label>notice content?</label>        
            </p>        
            <p>            
                  <textarea id="name" rows="5"></textarea>        
            </p>        
            <button id="sendName" onclick="sendName();">Send</button>        
            <p id="response"></p>    
        </div>
    </div>
    

    javascript代码

    <script src="/js/sockjs-0.3.4.min.js"></script>
    <script src="/js/stomp.min.js"></script>
    <script>    
        var stompClient = null;    
        function setConnected(connected) {        
            document.getElementById('connect').disabled = connected;        
            document.getElementById('disconnect').disabled = !connected;        
            document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';        
            document.getElementById('response').innerHTML = '';    
        }    
        // 开启socket连接
        function connect() {        
            var socket = new SockJS('/socket');        
            stompClient = Stomp.over(socket);        
            stompClient.connect({}, function (frame) {            
                 setConnected(true);            
            });    
        }    
        // 断开socket连接
        function disconnect() {        
            if (stompClient != null) {            
                stompClient.disconnect();        
            }        
            setConnected(false);        
            console.log("Disconnected");    
        }    
        // 向‘/app/change-notice’服务端发送消息
        function sendName() {        
            var value = document.getElementById('name').value;            
            stompClient.send("/app/change-notice", {}, value);    
        }    
        connect();
    </script>
    

    相关说明:
    关于JavaScript实现WebSocket的功能很简单,基本分以下几步:

    开启Socket

    1. var socket = new SockJS('/socket'); 先构建一个SockJS对象
    2. stompClient = Stomp.over(socket); 用Stomp将SockJS进行协议封装
    3. stompClient.connect() 与服务端进行连接,同时有一个回调函数,处理连接成功后的操作信息。

    发送消息

    stompClient.send("/app/change-notice", {}, value);

    页面预览:

    Paste_Image.png

    修改公告功能


    当我们发送公告后,将上图的公告信息在不刷新页面的情况下,使用WebSocket将其改变。发送公告的前端代码已经完成,现在我们来写另一个客户端,用来接收第一个页面发送的公告,展示在上图红框中。
    功能比较简单,所以下面只给出部分js代码:

    var noticeSocket = function () {    
      var s = new SockJS('/socket');    
      var stompClient = Stomp.over(s);    
      stompClient.connect({}, function () {         
        console.log('notice socket connected!');
        stompClient.subscribe('/topic/notice', function (data) {            
          $('.message span.content').html(data.body);        
        });    
     });
    };
    

    相关说明:
    这里与发送公告代码不同的是,在stompClient建立连接成功之后,我们要监听服务端发送过来的信息,接收到之后,改变页面上公告的内容,所以用到了stompClient.subscribe()
    这个subscribe()方法功能就是定义一个订阅地址,用来接收服务端的信息(在服务端代码中,我们在@SendTo中指定了这个订阅地址“/topic/notice”),当收到消息后,在回调函数中处理业务逻辑。

    至此,所有的功能开发完毕!

    效果演示

    首先我们发布一条公告:


    然后我们切到另一个页面,发现内容已变:

    相关文章

      网友评论

      • 花荣贤弟:您好,请问有没有研究过stomp的ack机制,在client消费subscribe这条消息后,如何提醒服务器客户端已经消费?
      • 25079c021976:你好,websockt连接之后会断掉。错误码是1006,请问一下是什么问题呢?
      • 蜻蜓队长_前来觐见:当前端send消息为空的时候后端会报错。
        蜻蜓队长_前来觐见:请问怎么添加空字符串的处理
      • b9d6a9716034:不错不错,收藏了。

        推荐下,分库分表中间件 Sharding-JDBC 源码解析 17 篇:http://t.cn/R0UfGFT


      • d53b94c2c297:扩容缩容,高可用问题如何解决呢
      • 92f31811f2bc:定时任务中得不到simmessagingtemplate,怎么解决
      • 6de1769b01d4:大佬,能不能贴一下“公告页面”的代码 :disappointed_relieved: 我是自学的,不太明白。。。
        可以讲一下它的原理吗?求解 :pray:
      • bulbuls:如果消息来源于第三方怎么办呢? 后台程序中产生了消息怎么推送到客户端?
      • 388b34fc0f12: Incompatibile SockJS! Main site uses: "1.1.1", the iframe: "1.0.0".

        这个问题楼主有解决吗?

        github上他们说貌似是sockjs本身有问题。要禁止使用默认cdn依赖库就能解决问题?不知道楼主怎么解决的。
      • e552d312c71a:楼主有简易的聊天室案例吗
      • HJ_风:当我配置为:// 开启Socket链接
        function connect() {
        // ws://localhost:8080/websocket/start/add
        var url = 'ws://localhost:8080/websocket/start/add';
        var socket = new SockJS(url);
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // 订阅Socket消息
        stompClient.subscribe('/topic/showResult', function(calResult){
        showResult(JSON.parse(calResult.body).result);
        });
        });
        }这个时
        又出现错误为:
        XMLHttpRequest cannot load ws://localhost:8080/websocket/start/add/info. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
        这是为什么呢?
        388b34fc0f12:@0b71340e50ac 看样子是跨域访问的问题http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#websocket-server-allowed-origins
      • HJ_风:按照你的“var socket = new SockJS('/socket');”这种配置方式,我的是// 开启Socket链接
        function connect() {
        // ws://localhost:8080/websocket/start/add
        var url = '/add';
        var socket = new SockJS(url);
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // 订阅Socket消息
        stompClient.subscribe('/topic/showResult', function(calResult){
        showResult(JSON.parse(calResult.body).result);
        });
        });
        }
        但是后来得到的响应是GET http://localhost:8080/add/info 404 (Not Found),请教下这个是为什么呢?需要配置服务端的请求地址么?服务端的地址不是ws://协议吗?非常感谢回复!
        388b34fc0f12:@0b71340e50ac servlet requestmapping配置问题吧,servlet找不到这个路径就会报这个错。
        我加了个/*的路径映射就没这个问题了。
      • 08ce6595ae2e:还有后续么? 看完了我越发迷惑啊,这还是websocket么, 如果一个客户端连接过来,我要记录客户端id, 等到特定事件发生后,我去通知该客户端, 这种要如何做?
      • 没事找抽:我遇到了发送中文报错的问题,英文和数字都没有问题。
        org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Invalid UTF-8 start byte 0xae
        at [Source: [B@684aaa68; line: 1, column: 3]; nested exception is com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 start byte 0xae
        at [Source: [B@684aaa68; line: 1, column: 3]
        Devid:@没事找抽 "Could not read JSON: Invalid UTF-8 start byte 0xae",不规范的utf-8字节,“oxae”是个什么鬼,查一下。参考:http://stackoverflow.com/questions/13830346/jackson-json-parser-invalid-utf-8-start-byte
      • fa58400b6330:我把您的依赖改成compile("org.springframework.boot:spring-boot-starter-websocket"),可以吗。
        HJ_风:@2233我 当我配置为:// 开启Socket链接
        function connect() {
        // ws://localhost:8080/websocket/start/add
        var url = 'ws://localhost:8080/websocket/start/add';
        var socket = new SockJS(url);
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // 订阅Socket消息
        stompClient.subscribe('/topic/showResult', function(calResult){
        showResult(JSON.parse(calResult.body).result);
        });
        });
        }这个时
        又出现错误为:
        XMLHttpRequest cannot load ws://localhost:8080/websocket/start/add/info. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
        这是为什么呢?
        HJ_风:@2233我 按照你的“var socket = new SockJS('/socket');”这种配置方式,我的是// 开启Socket链接
        function connect() {
        // ws://localhost:8080/websocket/start/add
        var url = '/add';
        var socket = new SockJS(url);
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // 订阅Socket消息
        stompClient.subscribe('/topic/showResult', function(calResult){
        showResult(JSON.parse(calResult.body).result);
        });
        });
        }
        但是后来得到的响应是GET http://localhost:8080/add/info 404 (Not Found),请教下这个是为什么呢?需要配置服务端的请求地址么?服务端的地址不是ws://协议吗?非常感谢回复!
        Devid:@小北不想风 参考这里https://spring.io/guides/gs/spring-boot/,里面的**Build With Gradle**
      • fa58400b6330:index()
        指定了一个页面,用来实现WebSocket客户端发送公告功能,使用的是@RequestMapping,所以接收的是http请求,进行页面跳转。

        我要是不指定页面该怎么去更改。。。测试下功能就行。我按照你的方法写好后加载不出html页面,希望您能帮我解决下
        Devid:@小北不想风 web项目没有相应怎么行呢:sweat:
        fa58400b6330:这样只能显示return中的字符串,依旧加载不出web页 :dizzy_face:
        Devid:@小北不想风 加@ResponseBody注解
      • fa58400b6330:多谢您的回复
      • fa58400b6330:你好,我用的是gradle,按你的方法配置了下,出现了如下错误,新手不太了解,希望能帮帮我
        Exception in thread "main" java.lang.IllegalStateException: Tomcat connector in failed state
        at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:157)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:288)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:141)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
        at org.springframework.boot.SpringApplication$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
        at com.freedom.orion.OrionApplication.main(OrionApplication.groovy:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
        fa58400b6330:@Devid 谢谢 :blush:
        Devid:@小北不想风 应该是端口号被占用了,上面没有提示端口号信息吗?参考http://stackoverflow.com/questions/20735205/launching-spring-application-address-already-in-use
      • 2d36dc0d77f2:能分享一个独立的Demo么? 谢谢!
        2d36dc0d77f2:@Devid 嗯,谢谢。刚从象牙塔出来的菜鸟 :smile:
        Devid:@张小豆Shawn 没有独立demo。websocket在项目中的应用其实也仅限于模块化,结合spring mvc
      • 雨中的漫步者:加油!有没有关于黑客攻防技术?

      本文标题:Spring WebSocket初探2 (Spring WebS

      本文链接:https://www.haomeiwen.com/subject/gxklhttx.html