Java版 WebSocket实现消息推送
使用Java实现WebSocket一对一 ,一对多消息推送 亲测有效!!!!!!!
一. 准备工具
前端:一张HTML页面
后端: SpringBoot
管理工具: Maven
这三个都是Java开发的必备技能,不多做解释了, 直接发车
二. 项目准备工作
- 后端创建SpringBoot工程,过程略…
- 前端创建HTML页面二张
现在本人前端开发多用Vue,但是都是用的原生的JavaScript,所以用什么框架无所谓…
- 前端书写代码
这里主要实现功能,就不写样式什么的了,但是原理一致
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
let webSocket = null;
if ('WebSocket' in window){
webSocket = new WebSocket('ws://localhost:8080/webSocket');
}else{
alert('该浏览器不支持')
}
webSocket.onopen = function (event){
console.log('建立连接')
}
webSocket.onclose = function (event){
console.log('关闭连接')
}
webSocket.onmessage = function (event){
console.log('收到消息:'+event.data)
}
webSocket.onerror = function (event){
console.log('websocket发生错误');
}
window.onbeforeunload = function (){
webSocket.close();
}
</script>
</html>
- 接下来书写后端Java代码
引入WebSocket的依赖,这里给予SpringBoot,所以直接引入SpringBoot-Start的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
书写配置类,其实就是实例化一个Bean
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
一般的请求都会写到Controller里面,咱们的WebSocket写到Service方便多次调用
一对一还是一对多,方法的区别在这里,接下来先说群发消息的那种(就是所有加入到WebSocket的用户都会收到该消息)
@Component
@ServerEndpoint("/webSocket")
public class WebSocketService {
private Session session;
private static CopyOnWriteArraySet<WebSocketService> websockets = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
websockets.add(this);
System.err.println("【建立连接】 用户为:" + this.session);
System.err.println("【建立连接】 总数为:" + websockets.size());
}
@OnClose
public void onClose() {
websockets.remove(this);
System.err.println("【连接断开】 用户为:" + this.session);
System.err.println("【连接断开】 总数为:" + websockets.size());
}
@OnMessage
public void onMessage(String message) {
System.err.println("【收到客户端发的消息】:" + message);
}
public void sendMessage(String message) {
for (WebSocketService websocket : websockets) {
System.err.println("广播消息 【给用户】 :" + websocket + "发送消息" + "【" + message + "】");
try {
websocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.getMessage();
}
}
}
}
为了方便测试,在写一个接口,用来发送消息
@RestController
@RequestMapping("/hello")
public class Controller {
@Autowired
private WebSocketService webSocketService;
@GetMapping("h1")
public void h1() {
webSocketService.sendMessage("您有新的消息");
}
}
接下来就是测试
后端SpringBoot项目启动…
两张页面分别去访问,我直接用两个浏览器方便看清
当页面进去的时候,打开F12可以看到建立连接,则证明与后端WebSocket连接成功
接下来用PostMan等等接口测试工具或者浏览器url都行,去请求刚才写的接口,也就是localhost:8080/hello/h1
请求一次则页面会提示收到消息 就成功了
接下来很多人就会问一对一怎么发,我不想群发
那么接下来就改造一下WebSocketService就好了,跟上步伐 冲冲冲
思路: 看黑板!!!!!!!!!
实际上对于刚才所有的Session都是用的Set存储的,我这里可以使用一个Map存储,将Session作为Value,而key就用用户的唯一标识,比如用户ID等等…
接下来,换曲:
<script>
let webSocket = null;
if ('WebSocket' in window){
webSocket = new WebSocket('ws://localhost:8080/webSocket/2');
}else{
alert('该浏览器不支持')
}
webSocket.onopen = function (event){
console.log('建立连接')
}
webSocket.onclose = function (event){
console.log('关闭连接')
}
webSocket.onmessage = function (event){
console.log('收到消息:'+event.data)
}
webSocket.onerror = function (event){
console.log('websocket发生错误');
}
window.onbeforeunload = function (){
webSocket.close();
}
</script>
@Component
@ServerEndpoint("/webSocket/{id}")
public class WebSocketService {
private Session session;
private static ConcurrentHashMap<Long, WebSocketService> websockets = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(@PathParam("id") Long id, Session session) {
this.session = session;
websockets.put(id, this);
System.err.println("【建立连接】 用户为:" + this.session);
System.err.println("【建立连接】 用户Id为:" + id);
System.err.println("【建立连接】 总数为:" + websockets.size());
}
public void sendMessage(String message, Long userId) {
if (userId == null) {
Iterator<Map.Entry<Long, WebSocketService>> iterator = websockets.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Long, WebSocketService> entry = iterator.next();
WebSocketService webSocket = entry.getValue();
System.err.println("广播消息 【给用户】 :" + webSocket + "发送消息" + "【" + message + "】");
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} else {
Iterator<Map.Entry<Long, WebSocketService>> iterator2 = websockets.entrySet().iterator();
while (iterator2.hasNext()) {
Map.Entry<Long, WebSocketService> entry = iterator2.next();
WebSocketService webSocket = entry.getValue();
Long key = entry.getKey();
if (userId == key) {
System.err.println("广播消息 【给用户】 :" + key + "发送消息" + "【" + message + "】");
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return;
}
}
}
|