Spring Boot 系列 - WebSocket 简单使用
在实现消息推送的项目中往往需要WebSocket,以下简单讲解在Spring boot 中使用 WebSocket。
1、pom.xml 中引入 spring-boot-starter-websocket
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、往spring容器中注入 ServerEndpointExporter
package com.sam.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket配置
* <p>
* 自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
* 要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
*
* @author sam
* @since 2017/9/13
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、Endpoint 具体实现
package com.sam.websocket;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* ServerEndpoint
* <p>
* 使用springboot的唯一区别是要@Component声明下,而使用独立容器是由容器自己管理websocket的,但在springboot中连容器都是spring管理的。
* <p>
* 虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
*
* @author sam
* @since 2017/9/13
*/
@ServerEndpoint("/ws/chatRoom/{userName}") //WebSocket客户端建立连接的地址
@Component
public class ChatRoomServerEndpoint {
/**
* 存活的session集合(使用线程安全的map保存)
*/
private static Map<String, Session> livingSessions = new ConcurrentHashMap<>();
/**
* 建立连接的回调方法
*
* @param session 与客户端的WebSocket连接会话
* @param userName 用户名,WebSocket支持路径参数
*/
@OnOpen
public void onOpen(Session session, @PathParam("userName") String userName) {
livingSessions.put(session.getId(), session);
sendMessageToAll(userName + " 加入聊天室");
}
/**
* 收到客户端消息的回调方法
*
* @param message 客户端传过来的消息
* @param session 对应的session
*/
@OnMessage
public void onMessage(String message, Session session, @PathParam("userName") String userName) {
sendMessageToAll(userName + " : " + message);
}
/**
* 发生错误的回调方法
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 关闭连接的回调方法
*/
@OnClose
public void onClose(Session session, @PathParam("userName") String userName) {
livingSessions.remove(session.getId());
sendMessageToAll(userName + " 退出聊天室");
}
/**
* 单独发送消息
*
* @param session
* @param message
*/
public void sendMessage(Session session, String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 群发消息
*
* @param message
*/
public void sendMessageToAll(String message) {
livingSessions.forEach((sessionId, session) -> {
sendMessage(session, message);
});
}
}
4、前端页面实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
</head>
<body>
<h1>聊天室</h1>
<textarea id="chat_content" readonly="readonly" cols="100" rows="9">
</textarea>
<br>
用户:<input type="text" id="user_name" value="" name="userName"/>
<button id="btn_join">加入聊天室</button>
<button id="btn_exit">退出聊天室</button>
<br>
消息:<input type="text" id="send_text" value="" name="sendText"/>
<button id="btn_send">发送</button>
</body>
</html>
<script>
$(function () {
var prefixUrl = 'ws://127.0.0.1:8080/ws/chatRoom/';
var ws;//WebSocket连接对象
//判断当前浏览器是否支持WebSocket
if (!('WebSocket' in window)) {
alert('Not support websocket');
}
$('#btn_join').click(function () {
var userName = $('#user_name').val();
//创建WebSocket连接对象
ws = new WebSocket(prefixUrl + userName);
//连接成功建立的回调方法
ws.onopen = function (event) {
console.log('建立连接')
}
//接收到消息的回调方法
ws.onmessage = function (event) {
console.log('接收到内容:' + event.data)
$('#chat_content').append(event.data + '\n')
}
//连接发生错误的回调方法
ws.onerror = function (event) {
console.log('发生错误')
}
//连接关闭的回调方法
ws.onclose = function (event) {
console.log('关闭连接')
}
})
//发送消息
function sendMessage(message) {
ws.send(message);
}
//关闭连接
function closeWebSocket() {
ws.close();
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
wx.close();
}
//发送消息
$('#btn_send').click(function () {
sendMessage($('#send_text').val())
})
//点击退出聊天室
$('#btn_exit').click(function () {
closeWebSocket();
})
})
</script>
以上为完整demo内容。
推荐: 阿里技术-小马哥讲解WebSocket
Spring Boot 系列 - WebSocket 简单使用的更多相关文章
- 【websocket】spring boot 集成 websocket 的四种方式
集成 websocket 的四种方案 1. 原生注解 pom.xml <dependency> <groupId>org.springframework.boot</gr ...
- 国内最全的Spring Boot系列之二
历史文章 <国内最全的Spring Boot系列之一> 视频&交流平台 SpringBoot视频:http://t.cn/R3QepWG Spring Cloud视频:http:/ ...
- Spring Boot 系列教程19-后台验证-Hibernate Validation
后台验证 开发项目过程中,后台在很多地方需要进行校验操作,比如:前台表单提交,调用系统接口,数据传输等.而现在多数项目都采用MVC分层式设计,每层都需要进行相应地校验. 针对这个问题, JCP 出台一 ...
- Spring Boot 系列教程18-itext导出pdf下载
Java操作pdf框架 iText是一个能够快速产生PDF文件的java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好 ...
- Spring Boot 系列教程15-页面国际化
internationalization(i18n) 国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式. 它要求从产品中抽离所有地域语言,国家/地区和 ...
- Spring Boot 系列教程12-EasyPoi导出Excel下载
Java操作excel框架 Java Excel俗称jxl,可以读取Excel文件的内容.创建新的Excel文件.更新已经存在的Excel文件,现在基本没有更新了 http://jxl.sourcef ...
- Spring Boot 系列教程11-html页面解析-jsoup
需求 需要对一个页面进行数据抓取,并导出doc文档 html解析器 jsoup 可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操 ...
- Spring Boot 系列教程10-freemarker导出word下载
freemarker FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页.电子邮件.配置文件.源代码等)的通用工具. 它不是面向最终用户的,而是一个 ...
- Spring Boot 系列教程9-swagger-前后端分离后的标准
前后端分离的必要 现在的趋势发展,需要把前后端开发和部署做到真正的分离 做前端的谁也不想用Maven或者Gradle作为构建工具 做后端的谁也不想要用Grunt或者Gulp作为构建工具 前后端需要通过 ...
随机推荐
- Java:ConcurrentHashMap是弱一致的
本文将用到Java内存模型的happens-before偏序关系(下文将简称为hb)以及ConcurrentHashMap的底层模型相关的知识.happens-before相关内容参见:JLS §17 ...
- etcd 增减节点
一.查看集群节点 etcdctl --endpoint=https://10.2.0.6:2379 --ca-file=/etc/etcd/ca.pem --cert-file=/etc/etcd/c ...
- Linux学习---指针运算、修饰符(const、volatile、typedef)及、运算符(++、--、+、-)
const:常量.只读[不能变] char *p; const char *p; [T] 字符串内容可以为“hello world”或“aaa”,但只读(不可修改) char const *p; ch ...
- Notes : <Hands-on ML with Sklearn & TF> Chapter 7
.caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...
- DOM函数和jQuery函数的覆盖与执行顺序
<script type="text/javascript"> window.onload = function () { alert(); } window.onlo ...
- html或者jsp页面刷新问题
setTimeout(function(){window.location.reload();//刷新当前页面.},2000) window.location.reload();//刷新当前页面.pa ...
- IDEA的Database管理台如何显示
1.找出database的显示view 2.点击设置数据库,下载驱动文件,直接点击下载就行了,用什么数据库就下什么 3.填写服务器地址和用户名密码,点击测试,成功就表示连上了 4.一些常用按钮 5.目 ...
- Stacking Plates(存档待续.....(没有写思路和程序))
问题描述 盘子装运公司是一家网络零售商,顾名思义,是一家只销售盘子的公司.该公司销售的盘子由不计其数的生产厂商提供,品种是全宇宙最多的,为此公司的员工倍感自豪. 在最近的一次成本分析中,公司员工发现, ...
- ElasticSearch是如何实现分布式的?
面试题 es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)? 面试官心理分析 在搜索这块,lucene 是最流行的搜索库.几年前业内一般都问,你了解 lucene 吗?你知道倒排索引的原理 ...
- BATJ等公司必问的8道Java经典面试题,你都会了吗?
1.谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗? 考点分析: 对于这类笼统的问题,你需要尽量表现出自己的思维深入并系统化,Java 知识理解得也比较全面,一定要避免让面试官 ...