SpringBoot 是为了简化 Spring 应用的创建、运行、调试、部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程
Webscoket 对浏览器有一定的要求,所以使用之前要考虑兼容性的问题….
Webscoket
WebSocket 是 HTML5 新增的一种在单个 TCP 连接上进行全双工通讯的协议,与 HTTP 协议没有太大关系….
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 WebSocket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage() 事件来接收服务器返回的数据..
长连接
与 AJAX 轮训的方式差不多,但长连接不像 AJAX 轮训一样,而是采用的阻塞模型(一直打电话,没收到就不挂电话);客户端发起连接后,如果没消息,就一直不返回 Response 给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
在没有 WebSocket 之前,大家常用的手段应该就是轮训了,比如每隔几秒发起一次请求,但这样带来的就是高性能开销,都知道一次 HTTP 响应是需要经过三次握手和四次挥手,远不如 TCP 长连接来的划算
WebSocket 事件
WebSocket 事件
本章目标
利用 Spring Boot 与 WebSocke 打造 一对一 和 一对多 的在线聊天….
导入依赖
依赖 spring-boot-starter-websocket…
1 2 3 4 5 6 7 8 9 10
|
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies>
|
属性配置
工具类
为了减少代码量,此处就不集成 Redis、Mysql 之类的存储化依赖…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
package com.battcn.utils;
import javax.websocket.RemoteEndpoint; import javax.websocket.Session; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap;
/** * @author Levin * @since 2018/6/26 0026 */ public final class WebSocketUtils {
/** * 模拟存储 websocket session 使用 */ public static final Map<String, Session> LIVING_SESSIONS_CACHE = new ConcurrentHashMap<>();
public static void sendMessageAll(String message) { LIVING_SESSIONS_CACHE.forEach((sessionId, session) -> sendMessage(session, message)); }
/** * 发送给指定用户消息 * * @param session 用户 session * @param message 发送内容 */ public static void sendMessage(Session session, String message) { if (session == null) { return; } final RemoteEndpoint.Basic basic = session.getBasicRemote(); if (basic == null) { return; } try { basic.sendText(message); } catch (IOException e) { e.printStackTrace(); } } }
|
服务端点
@ServerEndpoint 中的内容就是 WebSocket 协议的地址,其实仔细看会发现与 @RequestMapping 也是异曲同工的…
- HTTP 协议:
http://localhost:8080/path
- WebSocket 协议:
ws://localhost:8080/path
@OnOpen、@OnMessage、@OnClose、@OnError 注解与 WebSocket 中监听事件是相对应的…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
package com.battcn.websocket;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController;
import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException;
import static com.battcn.utils.WebSocketUtils.LIVING_SESSIONS_CACHE; import static com.battcn.utils.WebSocketUtils.sendMessage; import static com.battcn.utils.WebSocketUtils.sendMessageAll;
/** * 聊天室 * * @author Levin * @since 2018/6/26 0026 */ @RestController @ServerEndpoint("/chat-room/{username}") public class ChatRoomServerEndpoint {
private static final Logger log = LoggerFactory.getLogger(ChatRoomServerEndpoint.class);
@OnOpen public void openSession(@PathParam("username") String username, Session session) { LIVING_SESSIONS_CACHE.put(username, session); String message = "欢迎用户[" + username + "] 来到聊天室!"; log.info(message); sendMessageAll(message);
}
@OnMessage public void onMessage(@PathParam("username") String username, String message) { log.info(message); sendMessageAll("用户[" + username + "] : " + message); }
@OnClose public void onClose(@PathParam("username") String username, Session session) { //当前的Session 移除 LIVING_SESSIONS_CACHE.remove(username); //并且通知其他人当前用户已经离开聊天室了 sendMessageAll("用户[" + username + "] 已经离开聊天室了!"); try { session.close(); } catch (IOException e) { e.printStackTrace(); } }
@OnError public void onError(Session session, Throwable throwable) { try { session.close(); } catch (IOException e) { e.printStackTrace(); } throwable.printStackTrace(); }
@GetMapping("/chat-room/{sender}/to/{receive}") public void onMessage(@PathVariable("sender") String sender, @PathVariable("receive") String receive, String message) { sendMessage(LIVING_SESSIONS_CACHE.get(receive), "[" + sender + "]" + "-> [" + receive + "] : " + message); }
}
|
聊天室 HTML
onopen 建立 WebSocket 连接时触发。
message 客户端监听服务端事件,当服务端向客户端推送消息时会被监听到。
error WebSocket 发生错误时触发。
close 关闭 WebSocket 连接时触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>battcn websocket</title> <script src="jquery-3.2.1.min.js" ></script> </head> <body>
<label for="message_content">聊 天 室 </label><textarea id="message_content" readonly="readonly" cols="57" rows="10">
</textarea>
<br/>
<label for="in_user_name">用户姓名 </label><input id="in_user_name" value=""/> <button id="btn_join">加入聊天室</button> <button id="btn_exit">离开聊天室</button>
<br/><br/>
<label for="in_room_msg">群发消息 </label><input id="in_room_msg" value=""/> <button id="btn_send_all">发送消息</button>
<br/><br/><br/>
好友聊天 <br/> <label for="in_sender">发送者 </label><input id="in_sender" value=""/><br/> <label for="in_receive">接受者 </label><input id="in_receive" value=""/><br/> <label for="in_point_message">消息体 </label><input id="in_point_message" value=""/><button id="btn_send_point">发送消息</button>
</body>
<script type="text/javascript"> $(document).ready(function(){ var urlPrefix ='ws://localhost:8080/chat-room/'; var ws = null; $('#btn_join').click(function(){ var username = $('#in_user_name').val(); var url = urlPrefix + username; ws = new WebSocket(url); ws.onopen = function () { console.log("建立 websocket 连接..."); }; ws.onmessage = function(event){ //服务端发送的消息 $('#message_content').append(event.data+'\n'); }; ws.onclose = function(){ $('#message_content').append('用户['+username+'] 已经离开聊天室!'); console.log("关闭 websocket 连接..."); } }); //客户端发送消息到服务器 $('#btn_send_all').click(function(){ var msg = $('#in_room_msg').val(); if(ws){ ws.send(msg); } }); // 退出聊天室 $('#btn_exit').click(function(){ if(ws){ ws.close(); } });
$("#btn_send_point").click(function() { var sender = $("#in_sender").val(); var receive = $("#in_receive").val(); var message = $("#in_point_message").val(); $.get("/chat-room/"+sender+"/to/"+receive+"?message="+message,function() { alert("发送成功...") }) })
}) </script>
</html>
|
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
package com.battcn;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/** * @author Levin */ @EnableWebSocket @SpringBootApplication public class Chapter24Application {
public static void main(String[] args) { SpringApplication.run(Chapter24Application.class, args);
}
@Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
|
测试
启动 Chapter24Application.java 中的 main 方法,为了更好的演示效果这里打开了俩浏览器窗口做的测试…
测试结果
- JAVA-Socket通信 打造属于自己的聊天室(服务端)
我们每天都在使用着微信.QQ等聊天软件,但不知你是否有想过这些聊天软件是如何实现的?是否想过要制作一个属于自己的聊天室? 本篇博客将带你打造一个简单的属于自己的聊天室,将cmd作为聊天窗口,可通过内网 ...
- 用NodeJS打造多人在线聊天室(NodeJS & SocketIO & Express & EJS & MongoDB & Gulp)
项目背景 这个项目主要是为了玩玩NodeJS,项目的方向大概是做出类似QQ的在线聊天系统.想要在线体验可以点击在线演示. 项目使用PM2进行部署和管理,功能在不断的迭代开发中.如果你觉得这个项目比较有 ...
- WebSocket聊天室demo
根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using ...
- 分享基于 websocket 网页端聊天室
博客地址:https://ainyi.com/67 有一个月没有写博客了,也是因为年前需求多.回家过春节的原因,现在返回北京的第二天,想想,应该也要分享技术专题的博客了!! 主题 基于 websock ...
- 基于 OpenResty 实现一个 WS 聊天室
基于 OpenResty 实现一个 WS 聊天室 WebSocket WebSocket 协议分析 WebSocket 协议解决了浏览器和服务器之间的全双工通信问题.在WebSocket出现之前,浏览 ...
- FastAPI(56)- 使用 Websocket 打造一个迷你聊天室
背景 在实际项目中,可能会通过前端框架使用 WebSocket 和后端进行通信 这里就来详细讲解下 FastAPI 是如何操作 WebSocket 的 模拟 WebSocket 客户端 #!usr/b ...
- 使用socket.io打造公共聊天室
最近的计算机网络课上老师开始讲socket,tcp相关的知识,当时脑袋里就蹦出一个想法,那就是打造一个聊天室.实现方式也挺多的,常见的可以用C++或者Java进行socket编程来构建这么一个聊天室. ...
- nodejs+mongoose+websocket搭建xxx聊天室
简介 本文是由nodejs+mongoose+websocket打造的一个即时聊天系统:本来打算开发一个类似于网页QQ类似功能的聊天系统,但是目前只是开发了一个模块功能 --- 类似群聊的,即一对多的 ...
- 利用socket.io+nodejs打造简单聊天室
代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...
随机推荐
- Java实现 蓝桥杯 算法提高 成绩排序
试题 算法提高 成绩排序 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 给出n个学生的成绩,将这些学生按成绩排序, 排序规则,优先考虑数学成绩,高的在前:数学相同,英语高的在前:数 ...
- Java实现复数运算
1 问题描述 编程实现两个复数的运算.设有两个复数 和 ,则他们的运算公式为: 要求:(1)定义一个结构体类型来描述复数. (2)复数之间的加法.减法.乘法和除法分别用不用的函数来实现. (3)必须使 ...
- CVE-2020-0796漏洞复现(RCE)
0x01 漏洞简介 2020年3月10日,微软在其官方SRC发布了CVE-2020-0796的安全公告(ADV200005,MicrosoftGuidance for Disabling SMBv3 ...
- 1.keras-构建基本简单网络实现线性回归
构建基本简单网络实现线性回归 1.创建数据绘制散点图 import keras import numpy as np import matplotlib.pyplot as plt from kera ...
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。
使用mybatis逆向工程的时候,delete方法的使用姿势不对,导致表被清空了,在生产上一刷新后发现表里没数据了,一股凉意从脚板心直冲天灵盖. 于是开发了一个拦截器,并写下这篇文章记录并分享. 这锅 ...
- 如何将自己在github写的android library开源,让大家依赖使用
编写library并上传至github后,让别人可以通过gradle的方式添加依赖 http://www.jianshu.com/p/9aedfd749cec
- Uber基于Apache Hudi构建PB级数据湖实践
1. 引言 从确保准确预计到达时间到预测最佳交通路线,在Uber平台上提供安全.无缝的运输和交付体验需要可靠.高性能的大规模数据存储和分析.2016年,Uber开发了增量处理框架Apache Hudi ...
- Java 切割字符串的几种方式
按效率排: 1.StringTokenizer切割 是java.util中的一个类,包含的api有: StringTokenizer的方法请参考上一篇. 其中,countTokens为length:n ...
- EIGRP-10-弥散更新算法-计算距离,报告距离,可行距离和可行性条件
对于某个目的网络,EIGRP持续关注它的各种距离参数.EIGRP使用复合度量参数,不过为了简化,这里使用一个没有单位的数值.同样出于简化,这里的EIGRP路由器都不使用水平分割.
- 有没有人想和我一起编写 Clear Writer 的?
合作内容 程序编写 了解 JS.HTML.CSS 等基础前端技能,了解 Electron 开发. 翻译 熟练运用一门外语(中文英文除外),书面表达过关. 报酬 在 Github 上本项目里面的 REA ...