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>

属性配置

工具类

为了减少代码量,此处就不集成 RedisMysql 之类的存储化依赖…

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">聊&nbsp;&nbsp;天&nbsp;&nbsp;室&nbsp;</label><textarea id="message_content" readonly="readonly" cols="57" rows="10"> </textarea> <br/> <label for="in_user_name">用户姓名 &nbsp;</label><input id="in_user_name" value=""/>
<button id="btn_join">加入聊天室</button>
<button id="btn_exit">离开聊天室</button> <br/><br/> <label for="in_room_msg">群发消息 &nbsp;</label><input id="in_room_msg" value=""/>
<button id="btn_send_all">发送消息</button> <br/><br/><br/> 好友聊天
<br/>
<label for="in_sender">发送者 &nbsp;</label><input id="in_sender" value=""/><br/>
<label for="in_receive">接受者 &nbsp;</label><input id="in_receive" value=""/><br/>
<label for="in_point_message">消息体 &nbsp;</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 方法,为了更好的演示效果这里打开了俩浏览器窗口做的测试…

测试结果

打造属于你的聊天室(WebSocket)的更多相关文章

  1. JAVA-Socket通信 打造属于自己的聊天室(服务端)

    我们每天都在使用着微信.QQ等聊天软件,但不知你是否有想过这些聊天软件是如何实现的?是否想过要制作一个属于自己的聊天室? 本篇博客将带你打造一个简单的属于自己的聊天室,将cmd作为聊天窗口,可通过内网 ...

  2. 用NodeJS打造多人在线聊天室(NodeJS & SocketIO & Express & EJS & MongoDB & Gulp)

    项目背景 这个项目主要是为了玩玩NodeJS,项目的方向大概是做出类似QQ的在线聊天系统.想要在线体验可以点击在线演示. 项目使用PM2进行部署和管理,功能在不断的迭代开发中.如果你觉得这个项目比较有 ...

  3. WebSocket聊天室demo

    根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using ...

  4. 分享基于 websocket 网页端聊天室

    博客地址:https://ainyi.com/67 有一个月没有写博客了,也是因为年前需求多.回家过春节的原因,现在返回北京的第二天,想想,应该也要分享技术专题的博客了!! 主题 基于 websock ...

  5. 基于 OpenResty 实现一个 WS 聊天室

    基于 OpenResty 实现一个 WS 聊天室 WebSocket WebSocket 协议分析 WebSocket 协议解决了浏览器和服务器之间的全双工通信问题.在WebSocket出现之前,浏览 ...

  6. FastAPI(56)- 使用 Websocket 打造一个迷你聊天室

    背景 在实际项目中,可能会通过前端框架使用 WebSocket 和后端进行通信 这里就来详细讲解下 FastAPI 是如何操作 WebSocket 的 模拟 WebSocket 客户端 #!usr/b ...

  7. 使用socket.io打造公共聊天室

    最近的计算机网络课上老师开始讲socket,tcp相关的知识,当时脑袋里就蹦出一个想法,那就是打造一个聊天室.实现方式也挺多的,常见的可以用C++或者Java进行socket编程来构建这么一个聊天室. ...

  8. nodejs+mongoose+websocket搭建xxx聊天室

    简介 本文是由nodejs+mongoose+websocket打造的一个即时聊天系统:本来打算开发一个类似于网页QQ类似功能的聊天系统,但是目前只是开发了一个模块功能 --- 类似群聊的,即一对多的 ...

  9. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

随机推荐

  1. Java实现 删数字

    删数字 时间限制: 1 Sec 内存限制: 128 MB 题目描述 奶牛在数学课上学习了整除的概念.农夫Farmer John为了考验它的数学水平,于是在白纸上写了正整数T.由于农夫不喜欢数字0,所以 ...

  2. Java实现 LeetCode 68 文本左右对齐

    68. 文本左右对齐 给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本. 你应该使用"贪心算法"来放置 ...

  3. Java实现蓝桥杯正则问题

    题目描述 考虑一种简单的正则表达式: 只由 x ( ) | 组成的正则表达式. 小明想求出这个正则表达式能接受的最长字符串的长度. 例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是 ...

  4. java实现字符串比较

    标题:字符串比较 我们需要一个新的字符串比较函数compare(s1, s2). 对这个函数要求是: 1. 它返回一个整数,表示比较的结果. 2. 结果为正值,则前一个串大,为负值,后一个串大,否则, ...

  5. java实现第七届蓝桥杯打靶

    打靶 题目描述 小明参加X星球的打靶比赛. 比赛使用电子感应计分系统.其中有一局,小明得了96分. 这局小明共打了6发子弹,没有脱靶. 但望远镜看过去,只有3个弹孔. 显然,有些子弹准确地穿过了前边的 ...

  6. PAT 统计同成绩学生

    本题要求读入 N 名学生的成绩,将获得某一给定分数的学生人数输出. 输入格式: 输入在第 1 行给出不超过 105 的正整数 N,即学生总人数.随后一行给出 N 名学生的百分制整数成绩,中间以空格分隔 ...

  7. 【华为云技术分享】数据库开发:MySQL Seconds_Behind_Master简要分析

    [摘要]对于mysql主备实例,seconds_behind_master是衡量master与slave之间延时的一个重要参数.通过在slave上执行"show slave status;& ...

  8. git新手入门问题总结

    git新手入门问题总结 前言 本人为2019年6月份刚刚毕业,大三暑假中旬来到上海,实习时间大致为十个月,在这十个月里面学到了许多关于git使用方面的知识 经常会逛开源中国水水动态,看看技术帖子学习知 ...

  9. CentOS 7设置静态IP并修改DNS

    1. 设置静态IP 首先需要确定网线插在服务器的哪一个网络接口上,接口旁边一般都有写.我这边是插在1号接口上的. 然后修改网络配置文件,文件位于 /etc/sysconfig/network-scri ...

  10. 线上服务的FGC问题排查,看这篇就够了!

    线上服务的GC问题,是Java程序非常典型的一类问题,非常考验工程师排查问题的能力.同时,几乎是面试必考题,但是能真正答好此题的人并不多,要么原理没吃透,要么缺乏实战经验. 过去半年时间里,我们的广告 ...