- 浏览: 194784 次
- 性别:
- 来自: 南京
文章分类
最新评论
一、简介
WebSocket协议为web应用程序定义了一种全新的重要能力:在客户端和服务器端之间可以进行全双工的双向通信。简短来说,Websocket协议是先用http做初始化的握手,之后利用http向服务器发送一个协议升级(或者协议变化)的请求,如果服务器同意会返回一个101的状态码。如果这个握手成功,http请求升级后对应的底层的tcp socket会一直保持着打开状态,服务端和客户端就都可以利用它来发送消息。
二、后备选项
做WebSocket应用的一个重要挑战就是要考虑不支持WebSocket的浏览器,如IE从IE10开始才支持(具体的浏览器支持情况可以查看http://caniuse.com/websockets)。后备选项指的就是当需要时能够通过其他方式来模拟Websocket API从而在不支持Websocket的浏览器中利用Websocket的功能。
Spring FrameWork基于SockJs protocal对此提供的透明的支持,可以通过配置而不用修改应用程序代码。SockJs的具体内容可以参考https://github.com/sockjs/sockjs-protocol。
三、Websocket中的子协议
Websocket定义了消息的架构,但是没有规定具体的协议。而直接用TPCP把字节流转换成消息流是极其笨重的,而且不像应用层协议的HTTP,对于一个到来的信息,在WebSocket协议中是没有足够的信息来使framework或者容器知道如何去路由它,以及如何处理它。因此Websocket对于应用程序而言太低层太琐碎,就像现在大多数web应用都会采用一种web 框架,而不是直接用servlet api。
基于这个原因,Websocket RFC定义了子协议。在握手过程中,服务端和客户端可以利用请求头中的 Sec-WebSocket-Protocol来协定一个高层次的应用级别的子协议。虽然子协议不是必须的,但是即便不用,你的应用程序也需要定义一种客户端和服务端都能识别的消息格式。
在Spring Framework中提供了STOMP-一种简单的面向文本的消息协议。虽然STOMP是面向文本的,但是消息内容不仅仅局限于文本,也可以是二进制类型。STOMP的具体内容可以参考http://stomp.github.io/stomp-specification-1.2.html。
四、什么时候要用Websocket
web应用中最适合采用Websocket的是服务端和客户端以高频率低延时交换信息的场合。例如金融、股票、游戏等,这些都是对延时非常敏感,而且交换信息的频率很高的行业。
五、示例
本示例没有用maven,采用xml的配置形式
1.web.xml
和普通的spring mvc没有区别,作用
a.定义了一个servlet拦截器,以及Mapping规则
b.引入spring-context配置文件
c.添加log4j配置文件
2.DispatcherServlet Context配置文件,作用
a.激活注解配置功能
b.配置资源文件路径
c.配置视图层技术
d.引入具体组件配置文档
e.配置websocket相关内容
关键点:
a.头部引入了「xmlns:websocket=“http://www.springframework.org/schema/websocket”」,websocket对应的命名空间
b.「<websocket:message-broker application-destination-prefix=“/app”>」标明以app开头的请求将被认为是websocket请求
c.「<websocket:stomp-endpoint path=“/websocket”>」注册一个websocket的endpoint,并采用stomp作为子协议,这个endpoint会在websocket handshake时用到(js中初始化websocket)
d.「<websocket:sockjs />」表示启用sockjs备用选项,以便在不支持websocket的浏览器端正常模拟出websocket的效果
e.「<websocket:simple-broker prefix="/topic, /queue" />」标明broker采用SimpleBroker,并定义broker请求对应的地址是topic和queue
3.组件配置文档,主要作用
a.配置默认页面路径
b.配置组件扫描路径
具体文件
4.代码
a.controller 接受用户请求,包括http请求和websocket请求
b.service 模拟逻辑处理,处理完成后发送消息给broker
c.html代码
d.js代码
关键点
a.「var socket = new SockJS(‘/SpringWebsocket/websocket’);」初始化一个SockJs对象,其中SpringWebsocket是自己的工程名,websocket是在Servlet-context.xml中配置的websocket的endpoint
b.「stompClient.send("/app/hello", {}, JSON.stringify({'name': $(“#name”).val()}));」发送消息到websocket,对应的方法是controller中的@MessageMapping(“/hello”)注解方法,注意多了个app前缀,是在Servlet-context.xml中配置的application-destination-prefix
c.「stompClient.subscribe(‘/topic/greetings’, function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});」表示从broker中订阅/topic/greetings,当有消息发送到/topic/greetings时,客户端就可以收到通知,并获取消息的内容。
最终的工程目录:
工程的具体代码请参考附件
WebSocket协议为web应用程序定义了一种全新的重要能力:在客户端和服务器端之间可以进行全双工的双向通信。简短来说,Websocket协议是先用http做初始化的握手,之后利用http向服务器发送一个协议升级(或者协议变化)的请求,如果服务器同意会返回一个101的状态码。如果这个握手成功,http请求升级后对应的底层的tcp socket会一直保持着打开状态,服务端和客户端就都可以利用它来发送消息。
二、后备选项
做WebSocket应用的一个重要挑战就是要考虑不支持WebSocket的浏览器,如IE从IE10开始才支持(具体的浏览器支持情况可以查看http://caniuse.com/websockets)。后备选项指的就是当需要时能够通过其他方式来模拟Websocket API从而在不支持Websocket的浏览器中利用Websocket的功能。
Spring FrameWork基于SockJs protocal对此提供的透明的支持,可以通过配置而不用修改应用程序代码。SockJs的具体内容可以参考https://github.com/sockjs/sockjs-protocol。
三、Websocket中的子协议
Websocket定义了消息的架构,但是没有规定具体的协议。而直接用TPCP把字节流转换成消息流是极其笨重的,而且不像应用层协议的HTTP,对于一个到来的信息,在WebSocket协议中是没有足够的信息来使framework或者容器知道如何去路由它,以及如何处理它。因此Websocket对于应用程序而言太低层太琐碎,就像现在大多数web应用都会采用一种web 框架,而不是直接用servlet api。
基于这个原因,Websocket RFC定义了子协议。在握手过程中,服务端和客户端可以利用请求头中的 Sec-WebSocket-Protocol来协定一个高层次的应用级别的子协议。虽然子协议不是必须的,但是即便不用,你的应用程序也需要定义一种客户端和服务端都能识别的消息格式。
在Spring Framework中提供了STOMP-一种简单的面向文本的消息协议。虽然STOMP是面向文本的,但是消息内容不仅仅局限于文本,也可以是二进制类型。STOMP的具体内容可以参考http://stomp.github.io/stomp-specification-1.2.html。
四、什么时候要用Websocket
web应用中最适合采用Websocket的是服务端和客户端以高频率低延时交换信息的场合。例如金融、股票、游戏等,这些都是对延时非常敏感,而且交换信息的频率很高的行业。
五、示例
本示例没有用maven,采用xml的配置形式
1.web.xml
和普通的spring mvc没有区别,作用
a.定义了一个servlet拦截器,以及Mapping规则
b.引入spring-context配置文件
c.添加log4j配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>SpringTest</display-name> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/resources/log4j/log4j.properties</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- Disables Servlet Container welcome file handling. Needed for compatibility with Servlet 3.0 and Tomcat 7.0 --> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
2.DispatcherServlet Context配置文件,作用
a.激活注解配置功能
b.配置资源文件路径
c.配置视图层技术
d.引入具体组件配置文档
e.配置websocket相关内容
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:websocket="http://www.springframework.org/schema/websocket" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd "> <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --> <!-- Enables the Spring MVC @Controller programming model --> <mvc:annotation-driven/> <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory --> <mvc:resources mapping="/resources/**" location="/resources/" /> <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> <!-- <bean --> <!-- class="org.springframework.web.servlet.view.InternalResourceViewResolver"> --> <!-- <property name="prefix" value="/WEB-INF/views/" /> --> <!-- <property name="suffix" value=".jsp" /> --> <!-- </bean> --> <bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".html" /> <!-- Template cache is true by default. Set to false if you want --> <!-- templates to be automatically updated when modified. --> <property name="cacheable" value="false" /> </bean> <!-- SpringTemplateEngine automatically applies SpringStandardDialect and --> <!-- enables Spring's own MessageSource message resolution mechanisms. --> <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver" /> </bean> <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /> </bean> <!-- Imports user-defined @Controller beans that process client requests --> <import resource="controllers.xml" /> <!-- Enable STOMP over WebSocket --> <websocket:message-broker application-destination-prefix="/app"> <websocket:stomp-endpoint path="/websocket"> <websocket:sockjs /> </websocket:stomp-endpoint> <websocket:simple-broker prefix="/topic, /queue" /> </websocket:message-broker> </beans>
关键点:
a.头部引入了「xmlns:websocket=“http://www.springframework.org/schema/websocket”」,websocket对应的命名空间
b.「<websocket:message-broker application-destination-prefix=“/app”>」标明以app开头的请求将被认为是websocket请求
c.「<websocket:stomp-endpoint path=“/websocket”>」注册一个websocket的endpoint,并采用stomp作为子协议,这个endpoint会在websocket handshake时用到(js中初始化websocket)
d.「<websocket:sockjs />」表示启用sockjs备用选项,以便在不支持websocket的浏览器端正常模拟出websocket的效果
e.「<websocket:simple-broker prefix="/topic, /queue" />」标明broker采用SimpleBroker,并定义broker请求对应的地址是topic和queue
3.组件配置文档,主要作用
a.配置默认页面路径
b.配置组件扫描路径
具体文件
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- Maps '/' requests to the 'home' view --> <mvc:view-controller path="/" view-name="views/index.html"/> <context:component-scan base-package="test.spring.socket"/> </beans>
4.代码
a.controller 接受用户请求,包括http请求和websocket请求
package test.spring.socket; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import test.spring.socket.service.GreetingService; @Controller public class GreetingController { private static final Log logger = LogFactory.getLog(GreetingController.class); @Autowired private GreetingService service; @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { service.greeting(); return new Greeting("Hello, " + message.getName() + "!"); } @RequestMapping("/index") public String hello() { logger.info("start to maping request hell"); return "socket/index"; } }
b.service 模拟逻辑处理,处理完成后发送消息给broker
/** * */ package test.spring.socket.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import test.spring.socket.Greeting; /** * @author dwxx-chengaofeng * */ @Service public class GreetingService { @Autowired private SimpMessagingTemplate template; public void greeting() throws InterruptedException { for (int i = 0; i < 10; i++) { Thread.sleep(1000); // simulated delay template.convertAndSend("/topic/greetings", new Greeting("the number is" + i)); } } }
c.html代码
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Hello WebSocket</title> <link th:href="@{/resources/socket/css/main.css}" rel="stylesheet"> <script type="text/javascript" th:src="@{/resources/js/jquery-2.0.3.js}"></script> <script type="text/javascript" th:src="@{/resources/socket/js/sockjs.js}"></script> <script type="text/javascript" th:src="@{/resources/socket/js/stomp.js}"></script> <script type="text/javascript" th:src="@{/resources/socket/js/app.js}"></script> </head> <body> <noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript> <div id="main-content" class="container"> <div class="row"> <div class="col-md-6"> <form class="form-inline"> <div class="form-group"> <label for="connect">WebSocket connection:</label> <button id="connect" class="btn btn-default" type="submit">Connect</button> <button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect </button> </div> </form> </div> <div class="col-md-6"> <form class="form-inline"> <div class="form-group"> <label for="name">What is your name?</label> <input type="text" id="name" class="form-control" placeholder="Your name here..."> </div> <button id="send" class="btn btn-default" type="submit">Send</button> </form> </div> </div> <div class="row"> <div class="col-md-12"> <table id="conversation" class="table table-striped"> <thead> <tr> <th>Greetings</th> </tr> </thead> <tbody id="greetings"> </tbody> </table> </div> </div> </form> </div> </body> </html>
d.js代码
var stompClient = null; function setConnected(connected) { $("#connect").prop("disabled", connected); $("#disconnect").prop("disabled", !connected); if (connected) { $("#conversation").show(); } else { $("#conversation").hide(); } $("#greetings").html(""); } function connect() { var socket = new SockJS('/SpringWebsocket/websocket'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/topic/greetings', function (greeting) { showGreeting(JSON.parse(greeting.body).content); }); }); } function disconnect() { if (stompClient != null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); } function sendName() { stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()})); } function showGreeting(message) { $("#greetings").append("<tr><td>" + message + "</td></tr>"); } $(function () { $("form").on('submit', function (e) { e.preventDefault(); }); $( "#connect" ).click(function() { connect(); }); $( "#disconnect" ).click(function() { disconnect(); }); $( "#send" ).click(function() { sendName(); }); });
关键点
a.「var socket = new SockJS(‘/SpringWebsocket/websocket’);」初始化一个SockJs对象,其中SpringWebsocket是自己的工程名,websocket是在Servlet-context.xml中配置的websocket的endpoint
b.「stompClient.send("/app/hello", {}, JSON.stringify({'name': $(“#name”).val()}));」发送消息到websocket,对应的方法是controller中的@MessageMapping(“/hello”)注解方法,注意多了个app前缀,是在Servlet-context.xml中配置的application-destination-prefix
c.「stompClient.subscribe(‘/topic/greetings’, function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});」表示从broker中订阅/topic/greetings,当有消息发送到/topic/greetings时,客户端就可以收到通知,并获取消息的内容。
最终的工程目录:
工程的具体代码请参考附件
发表评论
-
spring-session-redis 实现原理
2019-03-20 19:24 16941.实现原理 1.1 得益于HttpSession和HttpS ... -
spring-security
2018-01-08 09:05 0FilterSecurityInterceptor是一个fil ... -
Spring cloud config利用gitlab webhook自动刷新
2017-02-10 20:14 27一、简介 Spring Cloud Config 提供serv ... -
Spring @ConfigurationProperties
2017-02-10 20:27 8151.配置文件类 package chengf.spring ... -
Spring 利用@Value注入properties文件属性
2017-01-21 09:05 1438本编文章是对Spring利用@Value来直接注入proper ... -
Spring ws 小示例
2016-12-10 15:43 4274一、简介 Spring Web Service 致力于开发 ... -
Spring+Schedule(定时任务)小示例
2016-11-18 17:21 1408本篇文章简单介绍一个Spring的schedule小例子。此定 ... -
Spring+thymeleaf小示例
2016-11-18 14:01 1047之前一篇文章写了个简单的Spring mvc例子,界面表示层用 ... -
SpringMVC小示例
2016-11-16 20:23 689***因为在内网环境下, ...
相关推荐
本项目结合这三个技术,构建了一个整合的示例,旨在展示如何在SpringBoot应用中实现安全的、基于WebSocket的实时通信。 首先,SpringBoot是由Pivotal团队提供的一个简化Spring应用初始搭建以及开发过程的框架。它...
在本示例中,我们将探讨如何使用Spring框架的版本4结合WebSocket、Socket、STOMP协议以及Jetty服务器来构建一个实时通信的应用。WebSocket是一种在浏览器和服务器之间建立长连接的协议,极大地提高了数据传输效率,...
这本学习笔记应该详细介绍了如何在 Spring 应用中集成 Spring MVC 和 WebSocket,包括设置项目结构、配置 Spring 容器、编写 WebSocket 处理端点类、实现客户端连接及消息交互的示例代码,并可能涉及到如何在 Spring...
// Vue前端连接WebSocket示例代码 var socket = new SockJS('/websocket'); var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log('Connected: ' + frame); stompClient...
1. **Spring Boot集成WebSocket**:Spring Boot提供了Spring WebSocket模块,可以方便地集成WebSocket功能。通过配置`WebSocketConfig`类,我们可以定义WebSocket的端点(如`/websocket`),并在该端点上处理连接...
在本文中,我们将深入探讨如何使用Spring Boot和WebSocket技术创建一个简单的前后端交互示例。Spring Boot是Java领域中广泛使用的微服务框架,它简化了Spring应用的初始设置和配置。而WebSocket则是一种在客户端和...
本项目是一个基于Spring Boot的WebSocket广播式通信的示例。"广播式"意味着当服务器接收到一条消息时,会将这条消息广播给所有已连接的客户端,而不仅仅是单个客户端。这样的设计适用于需要同步更新所有用户状态的...
在本示例"spring + websocket demo"中,我们看到的是一个基于Spring框架实现WebSocket功能的简单示例。以下是这个压缩包中包含的关键知识点: 1. **Spring WebSocket配置**: - `SpringWebSocketConfig.java`是...
总的来说,这个"Springboot+Websocket示例"展示了如何使用Spring Boot和WebSocket创建一个简单的实时通信应用。它帮助开发者理解WebSocket的基本用法以及如何在Spring Boot环境中集成WebSocket,从而实现高效、实时...
总的来说,这个"srpingboot+websocket+stomp代码示例"提供了一个完整的WebSocket实时通信系统模型,通过学习和理解这个示例,开发者可以快速掌握在SpringBoot应用中使用WebSocket和STOMP进行实时数据交换的技巧,为...
在Spring Boot应用中整合ActiveMQ和WebSocket,可以创建一个实时通信系统,使后端服务能够高效地推送消息到前端客户端。...如果需要实现WebSocket部分,可以参考Spring官方文档和相关示例代码进行开发。
总结来说,这个DEMO提供了一个基于MyEclipse、Spring、WebSocket和SockJS的实时通信示例,展示了如何在非Maven项目中构建和部署WebSocket应用程序,以及如何处理浏览器兼容性问题。对于初学者,这是一个很好的学习...
【标题】"SpringBoot+websocket广播式应用"指的是在Java开发环境中,利用Spring Boot框架集成WebSocket技术来构建实时通信的应用。Spring Boot简化了Spring应用程序的初始设置和配置,使其易于快速开发独立的、生产...
在本文中,我们将深入探讨如何使用Spring Boot和WebSocket技术构建一个简易的聊天室。Spring Boot是Java领域中广泛使用的框架,它简化了Spring应用程序的初始设置和配置。WebSocket则是一种在客户端和服务器之间建立...
标题"Spring4+Hibernate4+HTML5WebSocket简单应用示例"指出,这个示例项目是关于如何在Java后端环境中整合Spring 4、Hibernate 4框架,并利用HTML5的WebSocket技术来实现实时通信。Spring是企业级Java应用的主流框架...
标题"springboot+shiro+websocket+swagger"表明这是一个关于将这四个技术整合到一起的应用示例或教程。下面我们将逐一深入探讨这些技术以及它们的整合方式。 首先,SpringBoot是基于Spring的轻量级框架,它引入了...
这个"Spring+WebSocket+SockJS简单DEMO"项目就是结合这些技术创建一个实时通信的示例。 首先,让我们深入了解一下Spring框架中的WebSocket支持。Spring框架从4.0版本开始引入了WebSocket支持,通过`@MessageMapping...
在你提供的压缩包文件"springWebsockeForTomcatLog-master"中,可能包含了实现这个功能的示例代码,包括Spring配置、WebSocket端点、客户端连接逻辑等。这些代码可以帮助我们更好地理解和实践Spring+WebSocket的消息...