`

Spring4+WebSocket小示例

阅读更多
一、简介
    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时,客户端就可以收到通知,并获取消息的内容。
最终的工程目录:



工程的具体代码请参考附件
  • 大小: 28.7 KB
分享到:
评论

相关推荐

    SpringBoot+SpringSecurity+WebSocket

    本项目结合这三个技术,构建了一个整合的示例,旨在展示如何在SpringBoot应用中实现安全的、基于WebSocket的实时通信。 首先,SpringBoot是由Pivotal团队提供的一个简化Spring应用初始搭建以及开发过程的框架。它...

    Spring4+WebSocket+Socket+STOMP+Jetty构建示例

    在本示例中,我们将探讨如何使用Spring框架的版本4结合WebSocket、Socket、STOMP协议以及Jetty服务器来构建一个实时通信的应用。WebSocket是一种在浏览器和服务器之间建立长连接的协议,极大地提高了数据传输效率,...

    spring+springMVC+WebSocket 的学习笔记

    这本学习笔记应该详细介绍了如何在 Spring 应用中集成 Spring MVC 和 WebSocket,包括设置项目结构、配置 Spring 容器、编写 WebSocket 处理端点类、实现客户端连接及消息交互的示例代码,并可能涉及到如何在 Spring...

    spring boot+vue+websocket带token身份认证推送消息实现

    // Vue前端连接WebSocket示例代码 var socket = new SockJS('/websocket'); var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log('Connected: ' + frame); stompClient...

    Spring Boot 整合 Netty + WebSocket 实时消息推送

    1. **Spring Boot集成WebSocket**:Spring Boot提供了Spring WebSocket模块,可以方便地集成WebSocket功能。通过配置`WebSocketConfig`类,我们可以定义WebSocket的端点(如`/websocket`),并在该端点上处理连接...

    spring boot+websocket前后端简单demo

    在本文中,我们将深入探讨如何使用Spring Boot和WebSocket技术创建一个简单的前后端交互示例。Spring Boot是Java领域中广泛使用的微服务框架,它简化了Spring应用的初始设置和配置。而WebSocket则是一种在客户端和...

    Spring Boot + WebSocket + 广播式

    本项目是一个基于Spring Boot的WebSocket广播式通信的示例。"广播式"意味着当服务器接收到一条消息时,会将这条消息广播给所有已连接的客户端,而不仅仅是单个客户端。这样的设计适用于需要同步更新所有用户状态的...

    spring + websocket demo

    在本示例"spring + websocket demo"中,我们看到的是一个基于Spring框架实现WebSocket功能的简单示例。以下是这个压缩包中包含的关键知识点: 1. **Spring WebSocket配置**: - `SpringWebSocketConfig.java`是...

    Springboot+Websocket示例

    总的来说,这个"Springboot+Websocket示例"展示了如何使用Spring Boot和WebSocket创建一个简单的实时通信应用。它帮助开发者理解WebSocket的基本用法以及如何在Spring Boot环境中集成WebSocket,从而实现高效、实时...

    srpingboot+websocket+stomp代码示例.rar

    总的来说,这个"srpingboot+websocket+stomp代码示例"提供了一个完整的WebSocket实时通信系统模型,通过学习和理解这个示例,开发者可以快速掌握在SpringBoot应用中使用WebSocket和STOMP进行实时数据交换的技巧,为...

    SpringBoot整合ActiveMQ+websocket.docx

    在Spring Boot应用中整合ActiveMQ和WebSocket,可以创建一个实时通信系统,使后端服务能够高效地推送消息到前端客户端。...如果需要实现WebSocket部分,可以参考Spring官方文档和相关示例代码进行开发。

    myeclipse+spring+websocket+sockjs(非maven项目)

    总结来说,这个DEMO提供了一个基于MyEclipse、Spring、WebSocket和SockJS的实时通信示例,展示了如何在非Maven项目中构建和部署WebSocket应用程序,以及如何处理浏览器兼容性问题。对于初学者,这是一个很好的学习...

    springboot+websocket+idea.zip

    【标题】"SpringBoot+websocket广播式应用"指的是在Java开发环境中,利用Spring Boot框架集成WebSocket技术来构建实时通信的应用。Spring Boot简化了Spring应用程序的初始设置和配置,使其易于快速开发独立的、生产...

    使用Spring Boot + WebSocket 构建的一个简易聊天室

    在本文中,我们将深入探讨如何使用Spring Boot和WebSocket技术构建一个简易的聊天室。Spring Boot是Java领域中广泛使用的框架,它简化了Spring应用程序的初始设置和配置。WebSocket则是一种在客户端和服务器之间建立...

    Spring4+Hibernate4+HTML5WebSocket简单应用示例

    标题"Spring4+Hibernate4+HTML5WebSocket简单应用示例"指出,这个示例项目是关于如何在Java后端环境中整合Spring 4、Hibernate 4框架,并利用HTML5的WebSocket技术来实现实时通信。Spring是企业级Java应用的主流框架...

    springboot+shiro+websocket+swagger

    标题"springboot+shiro+websocket+swagger"表明这是一个关于将这四个技术整合到一起的应用示例或教程。下面我们将逐一深入探讨这些技术以及它们的整合方式。 首先,SpringBoot是基于Spring的轻量级框架,它引入了...

    Spring+WebSocket+SockJS简单DEMO

    这个"Spring+WebSocket+SockJS简单DEMO"项目就是结合这些技术创建一个实时通信的示例。 首先,让我们深入了解一下Spring框架中的WebSocket支持。Spring框架从4.0版本开始引入了WebSocket支持,通过`@MessageMapping...

    Spring+Websocket实现消息的推送

    在你提供的压缩包文件"springWebsockeForTomcatLog-master"中,可能包含了实现这个功能的示例代码,包括Spring配置、WebSocket端点、客户端连接逻辑等。这些代码可以帮助我们更好地理解和实践Spring+WebSocket的消息...

Global site tag (gtag.js) - Google Analytics