• agent page


    本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自行查阅相关知识。
    本篇的项目主要是一个学习Spring websocket和STOMP的项目,基于Spring4.0之上。因为Spring4.0之上才支持Websocket。例子比较的简单,但是总体实现了

    1. 浏览器 和服务器可以正常建立websocket服务
    2. 浏览器可以像服务器订阅并发送消息
    3. 浏览器可以接收到服务器推送过来的消息,即浏览器订阅的消息

    一.简单介绍Websocket和STOMP

    1.websocket介绍

    websocket协议是html5的一种新的协议,提供了通过套接字实现全双工通信的功能,【全双工:意味着服务器可以发送消息给浏览器,浏览器也可以发送消息给服务器】并能够实现web浏览器和服务器之间的异步通信。

    它和http通信机制对比如下图:

    这里写图片描述

    • http每次发送请求都需要和服务器建立一次连接, 是一种无状态的协议。
    • websocket只要第一个建立成功,浏览器就可以服务器进行通信,是一种有状态的协议。
    • websocket协议的请求报文和响应报文和http也是有区别的,这里不做介绍!

    2.STOMP介绍

    什么是 STOMP呢? http是在TCP套接字之上添加了请求-响应模型! STOMP是在WebSocket之上提供了一个基于帧的线路格式层,用于定义消息的语义。 STOMP帧由命令、一个或多个头信息以及负载所组成!举例发送数据的一个STOMP帧:
    SEND
    destination:/app/marco
    content-length:20
    
    {"message":"hello"}
    
    • 这里STOMP的命令是SEND,后面接发送的目标地址,消息内容长度,然后是一个空行,最后是发送内容,这个里面是一个JSON消息。
    • 这里需要注意的是destination,目标地址,消息会发送到这个目的地,这个目的地有服务端组件来进行处理。
    • Spring使用STOMP需要进行配置,并且Spring为STOMP消息提供了基于SpringMVC的编程模型!

    二.搭建项目【项目的源码 springwebscoket demo

    下面进入实战演练:

    1、添加依赖

    <!-- 添加Spring依赖 -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aspects</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <!--spring单元测试依赖 -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>${spring.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- spring webmvc相关jar -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
        </dependency>
    
        <!--Spring websocket start-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-websocket</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-messaging</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <!--Spring websocket end-->
    
        <!-- For SockJS -->
        <!-- http://jira.codehaus.org/browse/JACKSON-884 -->
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>${jackson.version}</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-core</artifactId>
          <version>${jackson.version}</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-annotations</artifactId>
          <version>${jackson.version}</version>
        </dependency>
    

    2、添加配置文件

    1.web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
      <display-name>spring-webscoket</display-name>
      <!-- 读取spring配置文件 -->
    
    
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>classpath*:application*.xml</param-value>
    	</context-param>
    
    
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<!-- Spring字符集过滤器 -->
    	<filter>
    		<filter-name>SpringEncodingFilter</filter-name>
    		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    		<init-param>
    			<param-name>encoding</param-name>
    			<param-value>UTF-8</param-value>
    		</init-param>
    		<init-param>
    			<param-name>forceEncoding</param-name>
    			<param-value>true</param-value>
    		</init-param>
    		<async-supported>true</async-supported>
    	</filter>
    	<filter-mapping>
    		<filter-name>SpringEncodingFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    
    
    	<!-- springMVC核心配置 -->
    	<servlet>
    		<servlet-name>dispatcherServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<!--spingMVC的配置路径 -->
    			<param-value>classpath:spring-mvc.xml</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    		<async-supported>true</async-supported>
    	</servlet>
    	<!-- 拦截设置 -->
    	<servlet-mapping>
    		<servlet-name>dispatcherServlet</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    	
      
      <welcome-file-list>
      	<welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
    </web-app>
    
    

    需要注意:< async-supported>true< /async-supported>,在filter和Servlet中都需要添加!

    2.spring-mvc.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:p="http://www.springframework.org/schema/p"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:mvc="http://www.springframework.org/schema/mvc"
      xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
         
        <!-- 扫描controller(controller层注入) -->
       <context:component-scan base-package="com.dufy"/>
    
         <mvc:annotation-driven />
    
        <!-- 当在web.xml 中   DispatcherServlet使用 <url-pattern>/</url-pattern> 映射时,能映射静态资源 -->
        <mvc:default-servlet-handler />  
    	<!-- 静态资源映射 -->
        <mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
       
    
       <!-- 对模型视图添加前后缀 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
        </bean>
          
    
    </beans>
    
    3.applicationContext.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    ">
    
    	<!-- Spring WebSocketSession管理容器 -->
    	<bean id="webSocketSessionManager" class="com.dufy.webscocket.session.data.DefaultWebSocketSessionManager" />
    
    	<!-- websocket握手拦截器 -->
    	<bean id="handshakeInterceptor" class="com.dufy.webscocket.interceptor.ChatHandInteceptor" />
    
    	<!-- WebSocket相关监听器 -->
    	<bean id="sessionConnectedListener" class="com.dufy.webscocket.listener.SessionConnectedListener" />
    	<bean id="sessionDisConnectedListener" class="com.dufy.webscocket.listener.SessionClosedListener" />
    	<bean id="sessionSubscribeListener" class="com.dufy.webscocket.listener.SessionSubscribeListener" />
    
    </beans>
    

    3、添加代码

    1.后台代码目录
    ![这里写图片描述](http://img.blog.csdn.net/20170813111044867?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDY0ODU1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    2.前台代码
    (1)建立websocket的jsp页面: ``` <%@ page contentType="text/html;charset=UTF-8" language="java" %> <% String path = request.getContextPath(); String basePath = request.getServerName() + ":" + request.getServerPort(); String finalPath = "http://" + basePath + path; out.print("finalPath = " + finalPath); %>
    <script src="${pageContext.request.contextPath}/recourse/jquery-1.7.2.min.js"></script>
    <script src="${pageContext.request.contextPath}/recourse/stomp.js"></script>
    <script src="${pageContext.request.contextPath}/recourse/sockjs.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function(){
            connect();
            //checkoutUserlist();
        });
    
        var projectName = "springwebscoket";
        var baseUrl= getBaseUrl();
        var stompClient = null;
        console.log("baseUrl = " + baseUrl);
        //this line.
        function connect() {
            console.log('Connected: ----------------------------------');
            var userid = document.getElementById('name').value;
    
            var socket = new SockJS(baseUrl + projectName +"/chat");
            console.log("=-="+ socket);
            stompClient = Stomp.over(socket);
    
            stompClient.connect({}, function(frame) {
                setConnected(true);
                console.log('Connected: ' + frame);
    
                stompClient.ws.onclose = function (CloseEvent){
                    console.log("ERROR","weboscket close code is " + CloseEvent.code);
                    setConnected(false);
                };
    
                //系统订阅消息
                stompClient.subscribe('/user/queue/system/newMsg', function (greeting) {
                    console.log("------ue/system/newMsg-----------");
                    console.log(greeting);
                    showGreeting(JSON.parse(greeting.body).content);
                });
    
                //新消息订阅
                stompClient.subscribe('/user/queue/chat/newMsg', function (greeting) {
                    console.log("/chat/newMsg" + greeting);
                    $("#showMessage").append("<p>"+JSON.parse(greeting.body).message+"</p>")
                    //showGreeting(JSON.parse(greeting.body).content);
                });
    
                //访客消息响应订阅
                stompClient.subscribe('/user/queue/chat/msgResponse', function (greeting) {
                    alert("收到信息");
                });
    
                //关闭订阅消息
                stompClient.subscribe('/user/queue/system/close', function (greeting) {
                    var retCode = JSON.parse(greeting.body).retCode;
                    if(retCode == "000000"){
                        _evaluate.open();
                        disconnect();
                    }
                });
    
    
            },function(error){
                var msg = "会话建立失败,请稍候重试!";
                alert(msg);
                setConnected(false);
    
            });
        }
    
    
    
        function sendName() {
            var name = document.getElementById('name').value;
            stompClient.send("/app/sendMessage", {}, JSON.stringify({ 'name': name }));
        }
    
        function disconnect() {
            if (stompClient != null) {
                stompClient.disconnect();
            }
            setConnected(false);
            console.log("Disconnected");
        }
    
    
        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 = '';
        }
    
        function showGreeting(message) {
            var response = document.getElementById('response');
            var p = document.createElement('p');
            p.style.wordWrap = 'break-word';
            p.appendChild(document.createTextNode(message));
            response.appendChild(p);
        }
    
    
        /**
         * 获取baseUrl
         * @returns {string}
         */
        function getBaseUrl(){
            var url= window.location.href;
            var num = url.indexOf(projectName);
            var baseUrlStr = url.substring(0,num);
            return baseUrlStr;
        }
    </script>
    

    Welcome

    ${name }

    访问此页面

    <div id="showMessage">
    
    </div>
    
    (2)服务器推送消息的页面:
    
    

    <%@ page contentType="text/html; charset=utf-8"%>
    <!doctype html>

    agent page


    
    <h4>4、项目演示</h4>
    (1).启动项目,我项目 不是的Application context 为 /springwebscoket ,端口9091,启动成功访问:http://localhost:9081/springwebscoket/,显示如下页面:
    ![这里写图片描述](http://img.blog.csdn.net/20170813112346425?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDY0ODU1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    
    (2).点击访客登录,进行登录,登录成功!创建websocket成功!如图:
    ![这里写图片描述](http://img.blog.csdn.net/20170813112452311?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDY0ODU1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    
    
    (3).创建成功,发送消息到服务器,如图:
    ![这里写图片描述](http://img.blog.csdn.net/20170813112531961?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDY0ODU1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    
    (4).创建成功,接收服务器发来的消息,如图:
    ![这里写图片描述](http://img.blog.csdn.net/20170813112602144?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDY0ODU1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    
    
    <h3>三.总结</h3>
    上面的项目里面的代码没有具体进行讲解,因为项目中可以运行起来,并且里面的逻辑也比较简单,如有不懂的地方可以直接对项目进行debug调试,一步步看,一步步学习,建议学习之前,要对websocket和STOMP有了解!
    <font color='red'>如果您对项目中有不懂的地方,欢迎加入我的QQ群:600756207,和我进行沟通!共同成长!</font>
    
    <h3>四.参考</h3>
    <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html">官方文档</a>
    
    
    ----------
    
    
    
    <font size=4 color=blue>欢迎访问我的csdn博客,我们一同成长!</font>
    
    "<font size=5>**不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!**</font>"
    
    <font size=4 color=red> 博客首页</font>:<a href="http://blog.csdn.net/u010648555" target="_blank">http://blog.csdn.net/u010648555</a>
  • 相关阅读:
    bzoj 2138: stone
    LOJ #6062. 「2017 山东一轮集训 Day2」Pair
    bzoj 5341: [Ctsc2018]暴力写挂
    UOJ #356. 【JOI2017春季合宿】Port Facility
    UOJ #357. 【JOI2017春季合宿】Sparklers
    UOJ #349. 【WC2018】即时战略
    bzoj 3600: 没有人的算术
    Codeforces 960G. Bandit Blues
    codeforces524E
    codeforces193B
  • 原文地址:https://www.cnblogs.com/aflyun/p/7352830.html
Copyright © 2020-2023  润新知