spring4 使用websocket
要了解的内容:
sockjs,对于低版本的ie等不支持websocket的浏览器,采用js模拟websocket对象的办法来实现兼容(其实也有轮询的情况)。sockjs地址 https://github.com/sockjs/sockjs-client
stomp 协议,一种格式比较简单且被广泛支持的通信协议,spring4提供了以stomp协议为基础的websocket通信实现。
------------------------------------------------------------------------------------------
然后,重点来了,spring实现websocket的大概原理是什么样子的呢?spring 的websocket实现,实际上是一个简易版的消息队列(而且是主题-订阅模式的),对于要发给具体用户的消息,spring的实现是创建了一个跟用户名相关的主题,实际上如果同一用户登录多个客户端,每个客户端都会收到消息,因此可以看出来,spring的websocket实现是基于广播模式的,要实现真正的单客户端用户区分(单用户多端登录只有一个收到消息),只能依赖于session(相当于一个终端一个主题了)。消息的具体处理过程如何,先上一图:
客户端发送消息,服务端接收后先判断该消息是否需要经过后台程序处理,也就是是否是application消息(图中的/app分支),如果是,则根据消息的url路径转到controller中相关的处理方法进行处理,处理完毕后发送到具体的主题或者队列;如果不是application消息,则直接发送到相关主题或者队列,然后经过处理发送给客户端。
因此在使用的时候,有了一开始的客户端注册到指定url,这个所谓的注册到执行url的过程,实际就是客户端跟服务端建立websocket连接的过程,连接建立之后,要发送或者接收什么消息都通过这一个websocket通信连接来完成,而不是每一个主题建立一个连接,这样可以节省开销。其中服务端代码.withSockJS()的作用是声明我们想要使用 SockJS 功能,如果WebSocket不可用的话,会使用 SockJS。
@Configuration
@EnableWebSocketMessageBroker //在 WebSocket 上启用 STOMP
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//webServer就是websocket的端点,客户端需要注册这个端点进行链接,
registry.addEndpoint("/webServer").setAllowedOrigins("*").withSockJS();
} @Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// registry.setPathMatcher(new AntPathMatcher("."));//可以已“.”来分割路径,看看类级别的@messageMapping和方法级别的@messageMapping registry.enableSimpleBroker("/topic","/user");
registry.setUserDestinationPrefix("/user/");
registry.setApplicationDestinationPrefixes("/app");//走@messageMapping
} @Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return true;
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration webSocketTransportRegistration) {
}
@Override
public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
// TODO Auto-generated method stub
}
@Override
public void addArgumentResolvers(List<org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver> list) {
}
@Override
public void addReturnValueHandlers(List<org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler> list) {
}
}
@EnableWebSocketMessageBroker 的作用是在WebSocket 上启用 STOMP,registerStompEndpoints方法的作用是websocket建立连接用的(也就是所谓的注册到指定的url),configureMessageBroker方法作用是配置一个简单的消息代理。如果补充在,默认情况下会自动配置一个简单的内存消息队列,用来处理“/topic”为前缀的消息,但经过重载后,消息队列将会处理前缀为“/topic”、“/user”的消息,并会将“/app”的消息转给controller处理。
@RequestMapping("/myws")
@Controller
public class WebSocketController {
@Resource
private SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/hello")
// @SendTo("/topic/hello")//会把方法的返回值广播到指定主题(“主题”这个词并不合适)
public void toTopic(SocketMessageVo msg , String name) {
System.out.println(msg.getName()+","+msg.getMsg());
this.simpMessagingTemplate.convertAndSend("/topic/hello",msg.getName()+","+msg.getMsg());
// return "消息内容:"+ msg.getName()+"--"+msg.getMsg();
} @MessageMapping("/message")
// @SendToUser("/message")//把返回值发到指定队列(“队列”实际不是队列,而是跟上面“主题”类似的东西,只是spring在SendTo的基础上加了用户的内容而已)
public void toUser(SocketMessageVo msg ) {
System.out.println(msg.getName()+","+msg.getMsg());
this.simpMessagingTemplate.convertAndSendToUser("123","/message",msg.getName()+msg.getMsg());
} @RequestMapping("/sendMsg")
public void sendMsg(HttpSession session){
System.out.println("测试发送消息:随机消息" +session.getId());
this.simpMessagingTemplate.convertAndSendToUser("123","/message","后台具体用户消息");
}
}
WebSocketConfig 中配置setApplicationDestinationPrefixes()的消息会被转发到WebSocketController 中 @MessageMapping 相应方法进行处理。@SendTo("/topic/hello") 会把方法的返回值序列化为json串,然后发送到指定的主题,不用此注解,使用 simpMessagingTemplate.convertAndSend 效果相同;若为 @SendToUser("/message") 则为发送到指定的用户队列(实际队列名字为/user/用户名/原队列名),不用此注解,使用 simpMessagingTemplate.convertAndSendToUser() 效果相同;
后台主动往前端推送消息,直接调用 simpMessagingTemplate.convertAndSendToUser() 跟 simpMessagingTemplate.convertAndSend() 即可将消息发往队列或者主题。
前端代码:
//建立websocket连接
function openWs(){
websocket = new SockJS("http://localhost:8080/autotest" + "/webServer"); var stompClient = Stomp.over(websocket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/hello', function(data) { //订阅消息
console.log("收到topic消息:"+data.body);//body中为具体消息内容
});
stompClient.subscribe('/user/' + 123 + '/message', function(message){
console.log("收到session消息:"+message.body);//body中为具体消息内容
});
}); document.getElementById("sendws").onclick = function() {
stompClient.send("/app/message", {}, JSON.stringify({
name: "nane",
msg: "发送的消息aaa"
}));
}
}
//关闭连接
function wsClose() {
websocket.close();
}
代码完成后运行效果如下:
可以看到连接建立握手的过程,以及订阅成功后的消息打印,<<<为从服务端接收到的消息,>>>为往服务端发的消息。
--------------------------------------------------------------------------------
最后,websocket 跟轮询,长连接相比有啥优势,参见:https://www.zhihu.com/question/20215561
这里有一点不明,websocket跟长连接都是每个客户端跟服务端建立了一个连接,为什么说长连接对服务端资源消耗严重,而不提websocket对服务端的消耗呢?是websocket协议更底层,只在物理链路上有个连接,并没有实际消耗jvm的资源?有知道的大神请留言指教。
spring4 使用websocket的更多相关文章
- spring4使用websocket
看到spring4的介绍上说已经支持websocket了,尝试了一下之后各种坑,不如servlet简单,写篇文章来讲解一下自己遇到的坑. 环境:tomcat8+spring4.1.6+jdk8+ngi ...
- tomcat支持的websocket服务
首发:个人博客 在tomcat7之后的版本,写个websocket服务程序非常容易——如以下代码所示,当客户端建立了一个连接并发送了一些什么内容到服务器,服务器将每隔两秒返回一个字符串“world”. ...
- web即时通讯2--基于Spring websocket达到web聊天室
如本文所用,Spring4和websocket要构建web聊天室,根据框架SpringMVC+Spring+Hibernate的Maven项目,后台使用spring websocket进行消息转发和聊 ...
- spring4+websocket+nginx详细配置
实现的版本jdk1.7.0_25, tomcat7.0.47.0, Tengine/2.1.1 (nginx/1.6.2), servlet3.0, spring4.2.2 使用maven导入版本3. ...
- spring4 security 4 +websocket 实现单点登录
测试地址:http://sms.reyo.cn/ 帐号:aa 密码:123456 先看一下效果图: spring4 security 4 实现单点登录,而websocket 实现单点的下线通知
- spring4.0之九:websocket简单应用
Spring 4.0的一个最大更新是增加了websocket的支持.websocket提供了一个在web应用中的高效.双向的通讯,需要考虑到客户端(浏览器)和服务器之间的高频和低延时消息交换.一般的应 ...
- spring WebSocket详解
场景 websocket是Html5新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决http请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天.股票交易.游戏 ...
- spring+websocket整合
java-websocket的搭建非常之容易,没用框架的童鞋可以在这里下载撸主亲自调教好的java-websocket程序: Apach Tomcat 8.0.3+MyEclipse+maven+JD ...
- Spring4新特性简述
Spring是一个java世界中极其流行 的开源框架.Spring的初衷是降低企业级开发的复杂性,并试图通过POJO对象实现之前EJB这类重型框架才能实现的功能.Spring不仅仅对服务 端开发有用, ...
随机推荐
- c# ftp创建文件(非上传文件)
c# ftp创建文件(非上传文件) 一.奇葩的故事: 今天项目中遇到这么个奇葩的问题,ftp文件传输完成后要在ftp目录下另一个文件夹下创建对应的空文件,听说是为了文件的完整性,既然这么说,那么就必 ...
- java 学习第零篇JDK安装和记事本编辑JAVA(2)
上面说了如何安装JDK那么这把就是来说怎么用记事本编写java 桌面上新建一个记事本 之后编写: public class a{ public static void main(String [ ...
- UIViewController+MJPopupViewController
1.MJPopupBackgroundView 1.1 MJPopupBackgroundView.h // // MJPopupBackgroundView.h // watched // // C ...
- Ubuntu 如何为 XMind 添加快速启动方式和图标
目录 Ubuntu 如何为 XMind 添加快速启动方式和图标 Ubuntu 如何为 XMind 添加快速启动方式和图标 按照教程Ubuntu16.04LTS安装XMind8并创建运行图标进行Xmin ...
- Serialization之BinaryFormatter
前言 BinaryFormatter序列化二进制序列化使用二进制编码来生成精简的序列化,以用于存储或基于套接字的网络流等. 内容 下面通过一个小小的例子来给大家说明什么是BinaryFormatter ...
- [翻译]CURAND Libaray--Host API--(2)
Translated by xingoo 如果有错误请联系:xinghl90@gmail.com 2.3 返回值 所有的CURAND host端的函数返回值都是curandStatus_t.如果调用没 ...
- 基本css拼图形
关闭按钮: <em class="close"></em> .close { width: 16px; height: 16px; text-align: ...
- 2019年GPLT L2-3 深入虎穴 比赛题解 中国高校计算机大赛-团体程序设计天梯赛题解
著名的王牌间谍 007 需要执行一次任务,获取敌方的机密情报.已知情报藏在一个地下迷宫里,迷宫只有一个入口,里面有很多条通路,每条路通向一扇门.每一扇门背后或者是一个房间,或者又有很多条路,同样是每条 ...
- 浅谈 关于ARC循环引用得问题
这段时间在研究关于ARC得循环引用导致变量不能释放,在此先介绍一本书英文书: <Pro Multithreading and Memory Management for iOS and OS X ...
- 牛客国庆集训day5 G 贵族用户 (模拟)
链接:https://www.nowcoder.com/acm/contest/205/G来源:牛客网 题目描述 终于活成了自己讨厌的样子. 充钱能让你变得更强. 在暖婊这个游戏里面,如果你充了x元钱 ...