我带着小程序和Springboot后端终于战胜了WebSocket!!!胜利( •̀ ω •́ )y
WebSocket项目笔记
1. What is WebSocket?
(以下内容来源于百度百科)
- WebSocket是一种在单个TCP连接上进行全双工通信的协议
- WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
- 在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
- 背景:
- 推送技术的演进发展:轮询 ---> Comet ---> WebSocket
握手协议:
2. Let's try!
因为项目要求,我的小程序需要与后端服务器进行长连接,以传送数据。所以我需要在我配置好的Springboot框架中添加WebSocket。十分庆幸的是,Springboot已经集成好了WebSocket了。所以过程并不复杂。看了很多博客,内容都大同小异。
我有点懵,因为我发现大家都在说的是,客户端与服务器建立连接的过程的实现。所以有几个问题:
- 既然是服务器主动发送消息,那么服务器到底 “到底什么时候发送消息呢?怎么发送?”
- 如何传参数,传的参数如何接收与使用。
- 我只需要针对某个客户端发消息,在同时有多个socket连接的时候我怎么标识该客户端?
大概就有这些。下面我们在配置过程中将问题逐个击破!
- 开发环境:Springboot 1.5.19 Java1.8
- 配置pom文件
<!-- 引入 websocket 依赖类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 配置Springboot开启WebSocket支持
package com.cuc.happyseat.config.websocket; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; /**
* 开启WebSocket支持
*/
@Configuration
public class WebSocketConfig { @Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
} }
- WebSocket服务类编写
这里对照下面的代码看:
- 第20行,@ServerEndpoint("/websocket/{userID}"),括号中的内容就是客户端请求Socket连接时的访问路径,userID是我要求客户端传来的参数,我这里算是为了标识该客户端吧。
- 第28行,在该类中添加属性 userID,并添加对应的getUserID()方法。
- 第46行,在onOpen()方法即建立连接的时候就接收参数userID,需要标识@PathParam("userID") 。接收参数后直接赋值给属性userID。
- 第140-157行,是针对特定客户端发送消息。服务器和客户端在建立连接成功后就生成了一个WebSocket对象,并存在集合中,对象里特有的属性是我们设置的userID。所以通过唯一的userID就能标识服务器与该客户端建立的那个连接啦!这样要求发送消息时,传入userID与消息,服务器在自己的WebSocket连接集合中遍历找到对应客户端的连接,就可以直接发消息过去啦~~
package com.cuc.happyseat.websocket; import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; /*@ServerEndpoint注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint("/websocket/{userID}")
@Component
public class WebSocketServer { //每个客户端都会有相应的session,服务端可以发送相关消息
private Session session; //接收userID
private Integer userID; //J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接
private static CopyOnWriteArraySet<WebSocketServer> copyOnWriteArraySet = new CopyOnWriteArraySet<WebSocketServer>(); public Integer getUserID() {
return userID;
} /**
* @Name:onOpen
* @Description:打开连接。进入页面后会自动发请求到此进行连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:@PathParam("userID") Integer userID
* @Return:
*/
@OnOpen
public void onOpen(Session session, @PathParam("userID") Integer userID) {
this.session = session;
this.userID = userID;
System.out.println(this.session.getId());
//System.out.println("userID:" + userID);
copyOnWriteArraySet.add(this);
System.out.println("websocket有新的连接, 总数:"+ copyOnWriteArraySet.size()); } /**
* @Name:onClose
* @Description:用户关闭页面,即关闭连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnClose
public void onClose() {
copyOnWriteArraySet.remove(this);
System.out.println("websocket连接断开, 总数:"+ copyOnWriteArraySet.size());
} /**
* @Name:onMessage
* @Description:测试客户端发送消息,测试是否联通
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnMessage
public void onMessage(String message) {
System.out.println("websocket收到客户端发来的消息:"+message);
} /**
* @Name:onError
* @Description:出现错误
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误:" + error.getMessage() + "; sessionId:" + session.getId());
error.printStackTrace();
} public void sendMessage(Object object){
//遍历客户端
for (WebSocketServer webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + object.toString());
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendObject(object) ;
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* @Name:sendMessage
* @Description:用于发送给客户端消息(群发)
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
public void sendMessage(String message) {
//遍历客户端
for (WebSocketServer webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + message);
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* @throws Exception
* @Name:sendMessage
* @Description:用于发送给指定客户端消息
* @Author:mYunYu
* @Create Date:14:47 2018/11/15
* @Parameters:
* @Return:
*/
public void sendMessage(Integer userID, String message) throws Exception {
Session session = null;
WebSocketServer tempWebSocket = null;
for (WebSocketServer webSocket : copyOnWriteArraySet) {
if (webSocket.getUserID() == userID) {
tempWebSocket = webSocket;
session = webSocket.session;
break;
}
}
if (session != null) {
//服务器主动推送
tempWebSocket.session.getBasicRemote().sendText(message); } else {
System.out.println("没有找到你指定ID的会话:{}"+ "; userId:" + userID);
}
} }
- Controller类的编写。
- 我在看博客的时候,发现有的博主写了Controller类,有的没写,我就有点疑惑了。后来,咳咳,发现特地写了一个Controller类只是为了测试。。
- 一般在实际项目中,在确保建立连接过程没有问题的情况下,我们就直接在一些写好的接口中写 WebSocketServer.sendMessage(param, message)语句就行了。
- 也因此,你写的位置就决定了你什么时候给你的客户端发消息,这样也就实现了主动推送消息的功能咯~
- 前提是:在你的Controller类里,以@Resource的方式注入WebSocket,而不是@Autowired方式哦(⊙o⊙)。
@Resource
WebSocketServer webSocket;
@Autowired
UserService userService;
调用示例:
if(userID>0) {
boolean location = userService.getLocation(userID);
if(location==false) {//验证用户当前不在馆内
boolean i = userService.modifyLocation(userID, true);
if(i==true) {
modelMap.put("successEnter", true);
//发消息给客户端
webSocket.sendMessage(userID, "success");
}
}else {
modelMap.put("successEnter", false);
//发消息给客户端
webSocket.sendMessage(userID, "fail");
}
}else {
modelMap.put("successEnter", false);
//发消息给客户端
webSocket.sendMessage(userID, "fail");
}
- 前端测试
因为我只写后端,前端部分小姐姐说看微信的官方文档就可以啦~ 链接:在此!微信封装好了吧,好像不难。
3. Problems
- 前期我看很多博客,的确产生很多问题,想不通,主要就是上面几个问题。然后我写了让前端先连WebSocket试了一下,想自己了解一下连接过程(也就是在控制台输出的文件中查),后来就慢慢通了。可以说是一帆风顺了??
- 不过我确保我没问题不算,得前端说了算对吧。所以,,我背了锅
我带着小程序和Springboot后端终于战胜了WebSocket!!!胜利( •̀ ω •́ )y的更多相关文章
- 微信小程序开发(后端Java)
微信使用的开发语言和文件很「特殊」. 小程序所使用的程序文件类型大致分为以下几种: ①WXML(WeiXin Mark Language,微信标记语言) ②WXSS(WeiXin Style Shee ...
- 【好好编程-技术博客】微信小程序开发中前后端的交互
微信小程序开发中前后端的交互 微信小程序的开发有点类似与普通网页的开发,但是也不尽然相同.小程序的主要开发语言是JavaScript,开发同普通的网页开发有很大的相似性,对于前端开发者而言,从网页开发 ...
- 记录一次用宝塔部署微信小程序Node.js后端接口代码的详细过程
一直忙着写毕设,上一次写博客还是元旦,大半年过去了.... 后面会不断分享各种新项目的源码与技术.欢迎关注一起学习哈! 记录一次部署微信小程序Node.js后端接口代码的详细过程,使用宝塔来部署. 我 ...
- 【node+小程序+web端】简单的websocket通讯
[node+小程序+web端]简单的websocket通讯 websoket是用来做什么的? 聊天室 消息列表 拼多多 即时通讯,推送, 实时交互 websoket是什么 websocket是一个全新 ...
- 微信小程序项目总结-记账小程序(包括后端)
一.小程序部分 这是理财系统的前端,江苏海洋大学微信小程序比赛,最后获得了一等奖 GitHub:https://github.com/GeorgeLeoo/finance 1. 项目描述 (1). 此 ...
- 微信小程序支付+php后端
最近在做自有项目后端用的是thinkphp5.1框架,闲话不说直接上代码 小程序代码 wxpay: function(e){ let thisid = e.currentTarget.dataset. ...
- 关于微信小程序登录,后端如何生成3rd_session?(后端为c#)
各位大神,请教一个问题,现在是小程序端调用wx.login后,将code传入后端接口,后端发起微信服务器request获取openid和session_key,后端再自定义生成一个登录状态:3rd_s ...
- 微信小程序支付C#后端源码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...
- 「小程序JAVA实战」小程序的springboot后台拦截器(61)
转自:https://idig8.com/2018/09/24/xiaochengxujavashizhanxiaochengxudespringboothoutailanjieqi60/ 之前咱们把 ...
随机推荐
- 设计模式之外观模式——Java语言描述
外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.它想现有的系统添加了一个接口,以隐藏系统的复杂性 介绍 意图 为子系统中的一组接口提供了一个一致的界面,外观模式定义了一个高层接 ...
- vue slot+传参
插槽分为默认插槽和具名插槽: 默认插槽: //父组件<div> <h3>父组件</h3> <testChild> <div>默认插槽< ...
- Asp.NetCore轻松学-配置服务 apollo 部署实践
前言 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置 ...
- Java关于数字工具类~持续汇总~
/** * 01 * 描述:求int数组中最大值 * [时间 2019年3月5日下午3:21:36 作者 陶攀峰] */ public static int test01(int[]sz) { int ...
- 2、自动化运维之SaltStack远程执行详解
SaltStack远程执行详解 ●目标(Targeting) ●模块(Module) ●返回(Returnners) 混合模式-C 选项 主机名设置参照: redis-node1-redis03-id ...
- hbase coprocessor 二级索引
Coprocessor方式二级索引 1. Coprocessor提供了一种机制可以让开发者直接在RegionServer上运行自定义代码来管理数据.通常我们使用get或者scan来从Hbase中获取数 ...
- Windows Server 2016-命令行批量导出AD用户列表信息
本章节为大家带来如何通过Powershell或ldifde命令行方式导出域用户列表信息,方便大家日常运维工作中使用. Powershell方式导出现有Staff目录下所有用户信息列表: Get-ADU ...
- windows之自动化在虚拟机部署操作系统并自带python环境
(1)使用详情: **************************** * 操作说明 * **************************** 1.修改Config文件夹中的Se ...
- 阿里巴巴excel工具easyexcel 助你快速简单避免OOM
Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有 ...
- 实战经验|大神战队都在i春秋教你打CTF
全国大学生信息安全竞赛创新实践能力赛旨在培养.选拔.推荐优秀信息安全专业人才创造条件,促进高等学校信息安全专业课程体系.教学内容和方法的改革,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学 ...
- 微信小程序开发(后端Java)