本篇主要讲解如何使用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页面:
```

<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 }

访问此页面

Connect
ConnectAny
Disconnect
you can send message to WebSocketMessageController[ @MessageMapping("/sendMessage") ]
Send

<div id="showMessage">

</div>

Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能的更多相关文章

  1. Spring学习(十一)-----Spring使用@Required注解依赖检查

    Spring学习(九)-----Spring依赖检查 bean 配置文件用于确定的特定类型(基本,集合或对象)的所有属性被设置.在大多数情况下,你只需要确保特定属性已经设置但不是所有属性.. 对于这种 ...

  2. Spring学习(六)-----Spring使用@Autowired注解自动装配

    Spring使用@Autowired注解自动装配 在上一篇 Spring学习(三)-----Spring自动装配Beans示例中,它会匹配当前Spring容器任何bean的属性自动装配.在大多数情况下 ...

  3. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  4. aop学习总结二------使用cglib动态代理简单实现aop功能

    aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...

  5. spring学习(三) ———— spring事务操作

    前面一篇博文讲解了什么是AOP.学会了写AOP的实现,但是并没有实际运用起来,这一篇博文就算是对AOP技术应用的进阶把,重点是事务的处理. --wh 一.jdbcTemplate 什么是JdbcTem ...

  6. spring学习12 -Spring 框架模块以及面试常见问题注解等

    以下为spring常见面试问题: 1.Spring 框架中都用到了哪些设计模式? Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的: 代理模式—在AOP和remoting中被用的比较 ...

  7. Spring学习【Spring概述】

    从本文開始,我们就要一起学习Spring框架,首先不得不说Spring框架是一个优秀的开源框架. 当中採用IoC原理实现的基于Java Beans的配置管理和AOP的思想都是非常值得学习与使用的.以下 ...

  8. Spring boot 基于Spring MVC的Web应用和REST服务开发

    Spring Boot利用JavaConfig配置模式以及"约定优于配置"理念,极大简化了基于Spring MVC的Web应用和REST服务开发. Servlet: package ...

  9. Spring学习笔记—Spring之旅

    1.Spring简介     Spring是一个开源框架,最早由Rod Johnson创建,并在<Expert One-on-One:J2EE Design and Development> ...

随机推荐

  1. hdu3081 Marriage Match II(二分+并查集+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...

  2. jmeter系列------参数关联

    接口请求中的一个变量需要用上一个接口道服务器返回响应的动态值(上个请求). 遇到这样的情况,我们就需要用到关联 例如用户A发表了一个一条微信朋友圈,用户B想对这条朋友圈进行评论,就需要先获取到这个朋友 ...

  3. Selenium+IDEA+Maven+TestNG环境搭建

    第一 安装java环境. 1. 下载并安装Jdk1.7或Jdk1.8 http://www.oracle.com/technetwork/java/javase/downloads/index.htm ...

  4. C++内存布局详解

    一个由C/C++编译的程序除了存放函数二进制代码的程序代码段(code段)外,数据占用的内存大致分为以下几个部分: 1.栈区(stack) 存放局部变量.函数参数.返回数据.返回地址等.系统自动分配释 ...

  5. Java 得到磁盘以及内存信息

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt217 1.得到磁盘信息 File[] files = File. listR ...

  6. Windbg DUMP

    Windbg DUMP分析(原创汇总) 1. 引入篇 1.1 下载安装 1.2 调试器 1.3 操作界面2. 命令篇 2.1 按照来源划分 2.1.1 基本命令 2.1.2 元命令 2.1.3 扩展命 ...

  7. 第二次项目冲刺(Beta阶段)5.24

    1.提供当天站立式会议照片一张 会议内容: ①检查前一天的任务情况. ②制定新一轮的任务计划. 2.每个人的工作 (1)工作安排 队员 今日进展 明日安排 王婧 #63Web输出以文件名为标题 #63 ...

  8. 联想G50-70安装SSD及WIN10教程

    借着双11的东风,果断入手SSD120G和4G内存条1枚.经过近一周的安装与试运行,笔者实现了SSD+HDD双硬盘+WIN10系统.目前运行体验非常好,开机时间9秒,软件运行也非常流畅.在折腾的过程中 ...

  9. 201521123104 《Java程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 1. List中指定元素的删除(题目4-1) 1.1 实验总结 这道题的关键是如何删除元素.一 ...

  10. 201521123060 《Java程序设计》第3周学习总结

    1. 本周学习总结 2. 书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; p ...