- 浏览: 189411 次
- 性别:
- 来自: 南京
文章分类
最新评论
一、简介
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 15631.实现原理 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 7801.配置文件类 package chengf.spring ... -
Spring 利用@Value注入properties文件属性
2017-01-21 09:05 1399本编文章是对Spring利用@Value来直接注入proper ... -
Spring ws 小示例
2016-12-10 15:43 4239一、简介 Spring Web Service 致力于开发 ... -
Spring+Schedule(定时任务)小示例
2016-11-18 17:21 1367本篇文章简单介绍一个Spring的schedule小例子。此定 ... -
Spring+thymeleaf小示例
2016-11-18 14:01 1007之前一篇文章写了个简单的Spring mvc例子,界面表示层用 ... -
SpringMVC小示例
2016-11-16 20:23 651***因为在内网环境下, ...
相关推荐
NULL 博文链接:https://hbxflihua.iteye.com/blog/2436818
1、基于Spring Boot 实现的WebSocket实时数据通信Demo 2、结合Netty实现多客户端之间进行网络通信 3、在Web端建立多客户端之间的通信机制
spring websocket实现前后端通信 示例内容:用户登陆之后往设置session设置登陆名,之后跳转到发送消息页面,加载页面时创建websocket连接,这时,springmvc拦截器拦截到websocket请求,把session中登陆名保存到...
NULL 博文链接:https://quarterlifeforjava.iteye.com/blog/2163576
spring-boot-websocket-client 代码示例
完整的springMVC+Spring webSocket示例
主要介绍了Spring整合websocket整合应用示例(下)的相关资料,需要的朋友可以参考下
以下教程是小编在参与开发公司的一个crm系统,整理些相关资料,在该系统中有很多消息推送功能,在其中用到了websocket技术。下面小编整理分享到脚本之家平台供大家参考
这是一个简单的Websocket示例工程(Spring Boot工程),演示了简单的Websocket使用方法。
UserApplication 模拟WebSocket服务 PtGateClientTests 模拟WebSocket请求服务 http可以通过网页模拟 (开启鉴权之后需要postman在header中添加token才能通过鉴权) 导入之后 maven跑完即可完整运行
用最新的springboot方式结合highcharts实现简单的实时在线统计报表示例, 可以参考代码在项目中使用.
在Spring Boot中使用WebSocket的Demo项目,这个示例包括简单模式,STOMP模式消息,处理对方不在线情况,分布式WebSocket等。 技术依赖 Spring Boot :项目基础架构 thymeleaf :用于thymeleaf测试页面模板 MyBatis ...
这是一个使用 Spring WebSocket 4.0.0 RELEASE 的 WebSocket 服务器的小示例和演示。 建造 构建示例需要安装 Maven。 输出是一个 Web 档案,可以通过运行以下命令获得: mvn clean package 安装 安装应用程序的最...
本篇文章主要介绍了java WebSocket的实现以及Spring WebSocket,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
Java两种方式(原生注解和Spring封装)实现的WebSocket通信的示例源代码
Spring-Boot-Jetty-WebSocket-示例 这是如何使用Spring Boot配置Jetty WebSocket的基本示例。 有关更多信息,请阅读我的博客文章-
java及html源码 博文链接:https://wallimn.iteye.com/blog/2425666