Websocket升级版

之前写过一个关于websocket的博客,是看书时候做的一个demo。但是纸上得来终觉浅,这次实战后实打实的踩了不少坑,写个博客记录总结。

1.安装postman

websocket接口调试,需要8.5以及以上版本的postman

先把以前的卸载,直接exe安装就好

点击这个连接可以下载,或者去官网下载

https://download.csdn.net/download/qq_35653822/88419296

2.postman调试方法

2.1参考这个博客的postman调试方法

Postman进行Websocket接口测试_postman websocket-CSDN博客

2.2请求路径

不是http开头  而是ws开头

如 ws://127.0.0.1:9999/test/3

2.3测试方式

websocket接口和普通接口不同,需要先建立连接,再发送消息

建立连接时候这个url可以是pathvariable那种

如 /test/{id}

3.上代码

3.1controller层

1.@ServerEndpoint
这个注解算是websocket中极其重要的一个注解了
这里边要配置上前后端建立连接的url,后端返回前端内容的解析器。我这写了两个分别对应字符串和指定实体的解析器。以及websocket对应的config文件

2. @OnOpen  @OnMessage

@OnOpen 前后端建立连接时走的方法,也就是postman点击connect按钮时候会走的方法

@OnMessage 前端给后端发送消息时走的方法,也就是postman点击send的时候会走的方法

3.session.getBasicRemote().sendObject();

后端给前端发送消息,此处根据类型不同,走不同的解析器。也就是@ServerEndpoint中的

encoders

4.注入bean

根据idea提示,需要用set方法注入 

package websocket;import com.fasterxml.jackson.databind.ObjectMapper;
import com.valley.common.result.Result;
import com.valley.system.enums.LinkType;
import com.valley.system.pojo.bo.ConnectResultBO;
import com.valley.system.pojo.form.SourceForm;
import com.valley.system.service.SysDataSourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;import javax.websocket.EncodeException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.security.Principal;/*** @Description: websocket  url中得sourceId是为了指定websocket得连接*/@ServerEndpoint(value = "/linkTest/{sourceId}", encoders = {ServerEncoder.class,StringEncoder.class},configurator = WebSocketConfig.class)
@Component
@Slf4j
public class WebSocketController {private static SysDataSourceService sysDataSourceService;@Autowiredpublic void setDeviceListenerService(SysDataSourceService sysDataSourceService) {WebSocketController.sysDataSourceService = sysDataSourceService;}/*** 实现服务器主动推送*/public void sendMessage(String message, Session session) throws IOException {session.getBasicRemote().sendText(message);}/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sourceId") String sourceId) throws EncodeException, IOException {log.info("连接成功,sourceId:{}", sourceId);session.getBasicRemote().sendObject(sourceId);}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) throws Exception {log.info("【websocket消息】收到客户端发来的消息:{}", message);// 创建ObjectMapper对象ObjectMapper objectMapper = new ObjectMapper();// 将JSON字符串解析为JSON对象SourceForm sourceForm = objectMapper.readValue(message, SourceForm.class);//根据type判断是否是心跳连接if(LinkType.HEARTBEAT.equals(sourceForm.getLinkType())){//前端约定返回“pong”session.getBasicRemote().sendObject("pong");return;}ConnectResultBO bo = sysDataSourceService.linkTest(sourceForm);try {Result<ConnectResultBO> result = Result.success(bo);session.getBasicRemote().sendObject(result);//session.getBasicRemote().sendText(message.toString());} catch (IOException e) {e.printStackTrace();}}}

3.2config层

1.需要配置在controller层的@ServerEndpoint中

@ServerEndpoint(value = "/api/v1/source/linkTest/{sourceId}", encoders = {ServerEncoder.class,StringEncoder.class},configurator = WebSocketConfig.class)

2. @Configuration修饰

因为要返回其他的bean

3.websocket的token上传返回

需要取header中的 Sec-WebSocket-Protocol 属性,并且返回给前端的时候也要在header中携带

package websocket;import cn.hutool.core.lang.Assert;
import com.valley.system.config.Constant;
import jodd.util.StringUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Collections;
import java.util.List;
import java.util.Map;/*** @Description: websocket配置*/
@Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator{@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}/*** 建立握手时,连接前的操作*/@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {// 这个userProperties 可以通过 session.getUserProperties()获取//获取请求头String token = request.getHeaders().get("Sec-WebSocket-Protocol").get(0);Assert.notNull(token,"token不可为空");//todo 之后需要对token进行解析校验//OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);//前端会把空格传成&nbsp//token = token.replace(Constant.NBSP," ");//当Sec-WebSocket-Protocol请求头不为空时,需要返回给前端相同的响应response.getHeaders().put("Sec-WebSocket-Protocol", Collections.singletonList(token));super.modifyHandshake(sec, request, response);}/*** 初始化端点对象,也就是被@ServerEndpoint所标注的对象*/@Overridepublic <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {return super.getEndpointInstance(clazz);}
}

3.3解析器

1.如果不配置,在调用

session.getBasicRemote().sendObject(sourceId);

返回方法的时候会报此类型解析器不存在的错误

2.解析器写完之后要加到controller层的@ServerEndpoint中

@ServerEndpoint(value = "/api/v1/source/linkTest/{sourceId}", encoders = {ServerEncoder.class,StringEncoder.class},configurator = WebSocketConfig.class)

3.3.1实体解析器

package websocket;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.valley.common.result.Result;
import com.valley.system.pojo.bo.ConnectResultBO;import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;/*** @Description: websocket发送给前端 泛型中Result<ConnectResultBO>是要发送的类型*/
public class ServerEncoder implements Encoder.Text<Result<ConnectResultBO>> {@Overridepublic void destroy() {// TODO Auto-generated method stub// 这里不重要}@Overridepublic void init(EndpointConfig arg0) {// TODO Auto-generated method stub// 这里也不重要}@Overridepublic String encode(Result<ConnectResultBO> responseMessage) {try {JsonMapper jsonMapper = new JsonMapper();return jsonMapper.writeValueAsString(responseMessage);} catch (JsonProcessingException e) {e.printStackTrace();return null;}}
}

 3.3.2字符串解析器

现在复盘来看,我这个解析器写的完全没必要,如果要发送字符串  把

session.getBasicRemote().sendObject

改为

session.getBasicRemote().sendText

就行了

public class StringEncoder implements Encoder.Text<String>{@Overridepublic String encode(String s){return s;}@Overridepublic void init(EndpointConfig endpointConfig) {}@Overridepublic void destroy() {}
}

4.security权限过滤

这块踩了很久的坑,我们项目是开源项目改的,然后自己拆成了好几个微服务。我开始的时候只专注去改auth项目中的,不管是忽略路径permitall,还是加切面,还是加filter。都不生效。

最后,在公共项目common中找到一个关于security的配置,改了permitall,才生效

但是还要注意哈,既然在这里把权限放开了,那在config中,就得把权限校验加上

此处放开是因为,上边说过前端只能把token放到header的Sec-WebSocket-Protocol属性中,而不能像平时一样放到Authorization属性中。

 5.插曲

在进行实体转换的时候,前端多给我传了参数,引起了报错

objectMapper.readValue(message, SourceForm.class);

为了让代码健壮一点,给实体加了个注解

@JsonIgnoreProperties(ignoreUnknown = true)

Unrecognized field , not marked as ignorable解决办法-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/133466.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【智能家居项目】裸机版本——认识esp8266 | 网络子系统

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《智能家居项目》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 如上图整个智能家居程序总体框架图&#xff0c;还剩下网络子系统没有实现&#xff0c;以及最终…

工业环网交换机运行原理

在智能制造领域&#xff0c;工业环网交换机是一种必不可少的网络设备。该技术通过将各种工业设备、传感器和机器人连接到同一网络中&#xff0c;实现了高效的数据传输和快速的信息交流。在本文中&#xff0c;我们将讨论工业环网交换机的运行原理&#xff0c;以帮助您更好地了解…

pdf怎么压缩?pdf文件缩小的方法在这里

PDF文件由于其跨平台、可打印性强等特点&#xff0c;成为了我们日常工作中经常使用的一种文件格式。然而&#xff0c;这种格式的文件有时候会因为过于庞大而给我们的存储和传输带来困扰&#xff0c;其实&#xff0c;这种情况只需要通过一些工具对PDF文件进行压缩&#xff0c;即…

Spring6 - ioc

文章目录 IoC容器IoC容器在Spring的实现基于XML管理Bean获取bean**①方式一&#xff1a;根据id获取**②方式二&#xff1a;根据类型获取③方式三&#xff1a;根据id和类型④扩展知识 依赖注入之setter注入依赖注入之构造器注入特殊值处理为对象类型属性赋值为数组类型属性赋值为…

Zookeeper分布式一致性协议ZAB源码剖析

文章目录 1、ZAB协议介绍2、消息广播 1、ZAB协议介绍 ZAB 协议全称&#xff1a;Zookeeper Atomic Broadcast&#xff08;Zookeeper 原子广播协议&#xff09;。 Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面&#xff0c;Zookeeper 并…

Docker的私有仓库部署——Harbor

Harbor 简介 一、什么是Harbor Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c; 其目标是帮助用户迅速搭建一个企业级的 Docker Registry 服务。 Harbor以 Docker 公司开源的 Registry 为基础&#xff0c; 提供了图形管理 UI 、基于角色的访问控制(Role…

git介绍和安装、(git,github,gitlab,gitee介绍)、git工作流程、git常用命令、git忽略文件

1 git介绍和安装 2 git&#xff0c;github&#xff0c;gitlab&#xff0c;gitee介绍 3 git工作流程 4 git常用命令 5 git忽略文件 1 git介绍和安装 首页功能写完了---》正常应该提交到版本仓库---》大家都能看到这个---》 运维应该把现在这个项目部署到测试环境中---》测试…

Java使用opencv实现人脸识别、人脸比对

1. opencv概述 OpenCV是一个开源的计算机视觉库&#xff0c;它提供了一系列丰富的图像处理和计算机视觉算法&#xff0c;包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网&#xff1a;https://opencv.org/ opencv官网文档&#xff1a;https://docs.opencv.or…

剧院建筑三维可视化综合管控平台提高安全管理效率

随着数字孪生技术的高速发展&#xff0c;智慧楼宇也被提上日程&#xff0c;以往楼宇管理存在着设备故障排查困难、能源浪费与管理不足、安全性和风险高等问题&#xff0c;而智慧楼宇数字孪生可视化中控平台&#xff0c;打造智慧楼宇管理一张图&#xff0c;实现了智慧建筑和楼宇…

vite项目运行后只显示主机地址

在vite.config.js中配置 server: {host: 0.0.0.0,port:8087}

[网鼎杯 2018]Comment git泄露 / 恢复 二次注入 .DS_Store bash_history文件查看

首先我们看到账号密码有提示了 我们bp爆破一下 我首先对数字爆破 因为全字符的话太多了 爆出来了哦 所以账号密码也出来了 zhangwei zhangwei666 没有什么用啊 扫一下吧 有git git泄露 那泄露看看 真有 <?php include "mysql.php"; session_start(); if(…

在React中,什么是props(属性)?如何向组件传递props?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…