当前位置: 首页 > article >正文

java配置webSocket、前端使用uniapp连接

一、这个管理系统是基于若依框架,配置webSocKet的maven依赖

<!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

二、配置类配置webSocket的端点和相关的参数

1、WebSocketConfig - webSocket配置类

注意:ws://yourdomain:port/ws/order?token=yourTokenValue。
可以使用cpolar 工具把IP地址解析成可访问的域名。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate WebSocketHandler webSocketHandler;/*** 注册websocket的端点* 客户端连接格式: ws://yourdomain:port/ws/order?token=yourTokenValue* token参数必须提供,系统会通过token从Redis获取对应的openId用于用户识别* @param registry WebSocketHandlerRegistry*/@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(webSocketHandler, "/ws/order").setAllowedOrigins("*"); // 允许跨域访问}/*** 配置WebSocket服务器的参数* 包括:连接超时时间、心跳超时时间、最大消息大小等* @return ServletServerContainerFactoryBean*/@Beanpublic ServletServerContainerFactoryBean createWebSocketContainer() {ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();// 设置异步发送超时时间为25秒container.setAsyncSendTimeout(25000L);// 设置最大会话空闲时间为60秒container.setMaxSessionIdleTimeout(60000L);// 设置最大文本消息缓冲区大小为8KBcontainer.setMaxTextMessageBufferSize(8192);// 设置最大二进制消息缓冲区大小为8KBcontainer.setMaxBinaryMessageBufferSize(8192);return container;}
}

2、WebSocketHandler - webSocket处理器
 

@Component
@Slf4j
public class WebSocketHandler extends TextWebSocketHandler {@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 用线程安全的集合来管理所有连接的 WebSocket 会话private static final Set<WebSocketSession> sessions = new CopyOnWriteArraySet<>();// 使用ConcurrentHashMap来存储openId到session的映射关系private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();// 使用ConcurrentHashMap来存储session到openId的映射关系(反向映射)private static final Map<WebSocketSession, String> sessionUsers = new ConcurrentHashMap<>();// 记录每个session最后一次活跃时间private static final Map<String, Long> sessionLastActiveTime = new ConcurrentHashMap<>();// 心跳检查的定时任务执行器private final ScheduledExecutorService heartbeatScheduler = Executors.newSingleThreadScheduledExecutor();// 心跳超时时间,单位毫秒private static final long HEARTBEAT_TIMEOUT = 50000L; // 50秒// 用于解析JSON的对象映射器private static final ObjectMapper objectMapper = new ObjectMapper();/*** 构造方法,启动心跳检测任务*/public WebSocketHandler() {// 每15秒检查一次心跳heartbeatScheduler.scheduleAtFixedRate(this::checkHeartbeats, 15, 15, TimeUnit.SECONDS);}/*** 心跳检查方法,清理那些超时的连接*/private void checkHeartbeats() {long currentTime = System.currentTimeMillis();for (Map.Entry<String, Long> entry : sessionLastActiveTime.entrySet()) {String openId = entry.getKey();long lastActive = entry.getValue();// 如果超过超时时间没有活动,则关闭会话if (currentTime - lastActive > HEARTBEAT_TIMEOUT) {WebSocketSession session = userSessions.get(openId);if (session != null && session.isOpen()) {try {log.warn("会话心跳超时,主动断开连接 - openId: {}, 上次活跃: {}ms前", openId, currentTime - lastActive);session.close(CloseStatus.NORMAL);} catch (IOException e) {log.error("关闭超时WebSocket会话异常 - openId: {}, 错误: {}", openId, e.getMessage());} finally {// 确保从会话映射中移除sessions.remove(session);sessionUsers.remove(session);userSessions.remove(openId);sessionLastActiveTime.remove(openId);}} else {// 会话已关闭或不存在,直接清理userSessions.remove(openId);sessionLastActiveTime.remove(openId);}}}}/*** 新客户端连接时,加入到 sessions 集合中* @param session 会话*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);// 从URL中获取token参数,格式应为 /ws/order?token=xxxString token = extractToken(session);if (token != null) {// 从Redis中获取对应的openIdString openId = getOpenIdFromToken(token);if (openId != null) {userSessions.put(openId, session);sessionUsers.put(session, openId);sessionLastActiveTime.put(openId, System.currentTimeMillis()); // 记录初始活跃时间log.info("WebSocket连接已建立 - token: {}, openId: {}, 当前连接数: {}", token, openId, sessions.size());} else {log.warn("找不到token对应的openId,token可能已过期 - token: {}", token);// 可以选择关闭这个无效的连接session.close(CloseStatus.NOT_ACCEPTABLE);}} else {log.warn("WebSocket连接未提供token参数,无法识别用户");// 可以选择关闭这个无效的连接session.close(CloseStatus.NOT_ACCEPTABLE);}}/*** 客户端断开连接时,从 sessions 集合中移除* @param session 会话* @param status*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);// 从用户会话映射中也移除String openId = sessionUsers.remove(session);if (openId != null) {userSessions.remove(openId);sessionLastActiveTime.remove(openId);log.info("WebSocket连接已关闭 - openId: {}, 状态: {}", openId, status);}}/*** 处理收到的文本消息* 对于心跳消息进行特殊处理*/@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String openId = sessionUsers.get(session);String payload = message.getPayload();try {// 尝试解析为JSONJsonNode jsonNode = objectMapper.readTree(payload);// 检查是否是心跳消息if (jsonNode.has("type") && "ping".equals(jsonNode.get("type").asText())) {// 更新最后活跃时间if (openId != null) {sessionLastActiveTime.put(openId, System.currentTimeMillis());}// 发送pong响应session.sendMessage(new TextMessage("{\"type\":\"pong\",\"time\":" + System.currentTimeMillis() + "}"));return;}} catch (Exception e) {// 不是JSON格式的消息,忽略错误继续处理}// 更新最后活跃时间if (openId != null) {sessionLastActiveTime.put(openId, System.currentTimeMillis());}log.debug("收到消息 - openId: {}, 内容: {}", openId, payload);// 在这里可以添加其他消息处理逻辑}/*** 从WebSocketSession中提取token* @param session WebSocket会话* @return token,如果不存在则返回null*/private String extractToken(WebSocketSession session) {String query = session.getUri().getQuery();if (query != null && query.contains("token=")) {String[] params = query.split("&");for (String param : params) {String[] keyValue = param.split("=");if (keyValue.length == 2 && "token".equals(keyValue[0])) {log.info("WebSocket连接已获取token - token: {}", keyValue[1]);return keyValue[1];}}}return null;}/*** 从token获取对应的openId* @param token 用户token* @return openId,如果token无效则返回null*/private String getOpenIdFromToken(String token) {if (token == null || token.isEmpty()) {return null;}try {// 从Redis中获取token对应的openIdreturn stringRedisTemplate.opsForValue().get(WECHAT_KEY + token);} catch (Exception e) {log.error("从Redis获取token信息异常 - token: {}, 错误: {}", token, e.getMessage());return null;}}/*** 发送支付成功的通知给所有连接的客户端* @param message 消息体*/public void sendPaymentSuccessNotification(String message) {for (WebSocketSession session : sessions) {try {// 通过 WebSocket 向每个客户端发送消息session.sendMessage(new TextMessage(message));} catch (IOException e) {log.error("发送支付成功通知失败", e);}}}/*** 向指定用户发送消息* @param openId 用户的openId* @param message 消息内容* @return 是否发送成功*/public boolean sendMessageToUser(String openId, String message) {WebSocketSession session = userSessions.get(openId);if (session != null && session.isOpen()) {try {session.sendMessage(new TextMessage(message));log.info("消息已发送给用户 - openId: {}", openId);return true;} catch (IOException e) {log.error("发送消息给用户失败 - openId: {}", openId, e);return false;}} else {log.info("用户未通过WebSocket连接 - openId: {}", openId);return false;}}/*** 向所有用户发送心跳检测消息*/public void sendHeartbeat() {String heartbeatMsg = "{\"type\":\"heartbeat\",\"time\":" + System.currentTimeMillis() + "}";for (WebSocketSession session : sessions) {if (session.isOpen()) {try {session.sendMessage(new TextMessage(heartbeatMsg));} catch (IOException e) {log.error("发送心跳消息失败", e);}}}}
}

注意:这里发送消息给指定用户需要前端传递token,获取存储在redis中的openId(微信小程序用户标识)

3、发送消息我定义了一个定时器发送消息和心跳测试

3.1、根据自己业务封装的消息体
 

@ApiModel(value = "MessageVo",discriminator = "websocket的消息体")
public class MessageVo {@ApiModelProperty(value = "消息标题",dataType = "string")private String title;@ApiModelProperty(value = "消息内容",dataType = "string")private String content;@ApiModelProperty(value = "车牌号码",dataType = "string")private String plateNumber;@ApiModelProperty(value = "订单编号",dataType = "string")private String orderNumber;@ApiModelProperty(value = "创建时间",dataType = "date")private Date createTime;}
/*** 定时发送提醒消息给待过磅状态的用户* 每1分钟执行一次,提醒用户进行过磅操作*/public void sendWeighingReminder() {log.info("开始执行待过磅用户提醒任务");try {// 查询所有待过磅的订单WeighingRecords pendingQuery = new WeighingRecords();pendingQuery.setStatus(0L); // 待过磅List<WeighingRecords> pendingWeighingOrders = weighingRecordsMapper.selectWeighingRecordsList(pendingQuery);// 如果没有待过磅订单,直接返回if (pendingWeighingOrders == null || pendingWeighingOrders.isEmpty()) {log.info("没有查询到待过磅订单,跳过发送提醒");return;}log.info("查询到 {} 条待过磅订单,开始发送提醒", pendingWeighingOrders.size());int successCount = 0;// 遍历所有待过磅订单,发送提醒消息for (WeighingRecords order : pendingWeighingOrders) {// 检查是否有有效的openIdString openId = order.getOpenId();if (openId == null || openId.trim().isEmpty()) {log.warn("订单 {} 缺少有效的openId,无法发送提醒", order.getOrderNumber());continue;}// 创建消息体MessageVo messageVo = new MessageVo();messageVo.setTitle("过磅提醒");messageVo.setContent("您有一条待过磅的订单,请及时前往过磅点进行过磅操作。");messageVo.setOrderNumber(order.getOrderNumber());messageVo.setPlateNumber(order.getPlateNumber()); // 设置车牌号messageVo.setCreateTime(DateUtils.getNowDate());try {// 转换为JSON字符串String messageJson = objectMapper.writeValueAsString(messageVo);// 直接使用openId发送消息(WebSocketHandler内部会通过openId查找对应的会话)boolean sent = webSocketHandler.sendMessageToUser(openId, messageJson);if (sent) {successCount++;log.info("成功向用户 {} 发送过磅提醒消息,订单号: {}", openId, order.getOrderNumber());} else {log.info("用户 {} 未连接WebSocket,无法发送过磅提醒消息,订单号: {}", openId, order.getOrderNumber());}} catch (JsonProcessingException e) {log.error("消息序列化异常,订单号: {}, 错误: {}", order.getOrderNumber(), e.getMessage());} catch (Exception e) {log.error("发送消息异常,订单号: {}, 错误: {}", order.getOrderNumber(), e.getMessage());}}log.info("过磅提醒任务完成,共尝试: {} 条,成功: {} 条", pendingWeighingOrders.size(), successCount);} catch (Exception e) {log.error("过磅提醒任务异常: {}", e.getMessage(), e);}}/*** 定期发送心跳消息,保持WebSocket连接活跃* 每25秒执行一次,低于WebSocketConfig中设置的60秒超时时间*/public void sendHeartbeat() {log.debug("开始执行WebSocket心跳任务");try {webSocketHandler.sendHeartbeat();log.debug("WebSocket心跳消息发送完成");} catch (Exception e) {log.error("WebSocket心跳任务异常: {}", e.getMessage(), e);}}

4、由于这个管理系统是基于若依所以需要配置鉴权,否则会被拦截
这个是部分配置代码

@Beanprotected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{return httpSecurity// CSRF禁用,因为不使用session.csrf(csrf -> csrf.disable())// 禁用HTTP响应标头.headers((headersCustomizer) -> {headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());})// 认证失败处理类.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))// 基于token,所以不需要session.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))// 注解标记允许匿名访问的url.authorizeHttpRequests((requests) -> {permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());// 对于登录login 注册register 验证码captchaImage 允许匿名访问requests.antMatchers("/login", "/register", "/captchaImage","/weiXin/login","/weiXin/returnNotify","/ws/**").permitAll()
..........}

注意:端点配置的是“/ws/order",所以在这了配置为”/ws/**“

三、小程序端的部分代码配置

注意:需要在路径上面传递token,为了后端获取openId向指定用户发送消息

这个是小程序的webSocket的地址示例:“wss://5aa7e45c.r11.cpolar.top/ws/order?token=${this.token}”

相关文章:

java配置webSocket、前端使用uniapp连接

一、这个管理系统是基于若依框架&#xff0c;配置webSocKet的maven依赖 <!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency> 二、配…...

interface接口和defer场景分析

接口 接口这里主要两点&#xff1a; 设计业务结构时采用依赖倒转&#xff1a;业务层向下依赖抽象层&#xff0c;实现层向上依赖抽象层。 相比于之前&#xff1a; 之后&#xff1a; 注意struct中嵌套interface和不嵌套interface的区别&#xff1a; type Myinterface interfac…...

02、基础入门-Spring生态圈

02、基础入门-Spring生态圈 # Spring生态圈概述 **Spring生态圈**是基于Spring框架的一系列开源项目和工具的集合&#xff0c;涵盖了各种领域&#xff0c;包括Web开发、数据访问、集成、测试、安全等。 ## 主要组成部分 1. **Spring Framework**&#xff1a;是整个生态圈的核心…...

前后端交互中的绝对路径和相对路径

前端 <form action"hello" method"post"> 1. 不加斜杠 &#xff08;相对路径&#xff0c;如 action"hello"&#xff09; 解析规则&#xff1a;基于当前页面的 URL 路径部分 进行拼接。 假设当前页面 URL 是 http://域名:端口/应用上下文…...

从零开始学习three.js(18):一文详解three.js中的着色器Shader

在WebGL和Three.js的3D图形渲染中&#xff0c;着色器&#xff08;Shader&#xff09; 是实现复杂视觉效果的核心工具。通过编写自定义的着色器代码&#xff0c;开发者可以直接操作GPU&#xff0c;实现从基础颜色渲染到动态光照、粒子效果等高级图形技术。本文将深入解析Three.j…...

调用百度云API机器翻译

新建Python文件&#xff0c;叫 text_translator.py 输入 import requests import jsonAPI_KEY "glYiYVF2dSc7EQ8n78VDRCpa" # 替换为自己的API Key SECRET_KEY "kUlhze8OQZ7xbVRp" # 替换为自己的Secret Keydef main():# 选择翻译方向while True:di…...

大模型训练计算显存占用

在大模型训练过程中&#xff0c;GPU显存中需要存储多种类型的数据&#xff0c;这些数据的合理管理直接影响训练效率和模型规模。需要放入GPU的关键数据类型如下&#xff1a; 注意&#xff1a; 在计算大模型训练占用的显存时&#xff0c;一般只计算 模型参数、梯度、优化器 的显…...

uni-app学习笔记六-vue3响应式基础

一.使用ref定义响应式变量 在组合式 API 中&#xff0c;推荐使用 ref() 函数来声明响应式状态&#xff0c;ref() 接收参数&#xff0c;并将其包裹在一个带有 .value 属性的 ref 对象中返回 示例代码&#xff1a; <template> <view>{{ num1 }}</view><vi…...

亚远景-ASPICE与ISO 21434在汽车电子系统开发中的应用案例

在汽车电子系统开发中&#xff0c;ASPICE&#xff08;Automotive Software Process Improvement and Capacity Determination&#xff09;与ISO 21434&#xff08;Road vehicles — Cybersecurity engineering&#xff09;是两个关键标准&#xff0c;分别从软件开发流程和网络安…...

『已解决』Python virtualenv_ error_ unrecognized arguments_--wheel-bundle

📣读完这篇文章里你能收获到 🐍 了解 virtualenv 参数错误的原因及解决方案📦 学习如何正确配置 Python 虚拟环境文章目录 前言一、问题描述1.1 错误现象1.2 影响范围二、问题分析2.1 根本原因三、解决方案3.1 兼容处理3.2 完整解决方案四、总结前言 本文详细介绍了在 D…...

详细介绍一下Python连接MySQL数据库的完整步骤

以下是 Python 连接 MySQL 数据库的完整步骤&#xff0c;包含环境准备、连接建立、数据操作、错误处理和性能优化等内容&#xff1a; 一、环境准备 安装 MySQL 服务器 Windows/macOS&#xff1a;下载安装包 MySQL Installer Linux&#xff1a; bash Ubuntu/Debian sudo apt-…...

【Unity 2023 新版InputSystem系统】新版InputSystem 如何进行人物移动(包括配置、代码详细实现过程)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、InputSystem配置二、GameInput 游戏输入脚本1.实现思路2.完整代码三、Player 游戏人物移动脚本1.实现思路2.完整代码四、场景脚本设置1.组件设置五、问题解决1.人物一直下落2.人物跳跃时,…...

单片机-STM32部分:13-1、编码器

飞书文档https://x509p6c8to.feishu.cn/wiki/BpEywhaX9iqbiLkdqdAcmDnwnab EC旋转编码器 在产品开发过程中&#xff0c;需要位置闭环的的产品&#xff0c;类似电机类产品来说&#xff0c;编码器至关重要&#xff0c;它不仅可以使我们对带年纪进行精确的速度闭环&#xff0c;位…...

机器学习第十二讲:特征选择 → 选最重要的考试科目做录取判断

机器学习第十二讲&#xff1a;特征选择 → 选最重要的考试科目做录取判断 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1a;超详细手把手指南 一、学…...

关于我在使用stream().toList()遇到的问题

关于我在使用stream().toList()遇到的问题 问题描述 在测试以上程序的时候抛出了空指针异常 于是我以为是我数据库中存在null字段&#xff0c;但查看后发现并不存在为null的数据 问题排查 起初我以为问题出现在sort排序方法这&#xff0c;事实也确实是&#xff0c;当我把s…...

javascript 编程基础(2)javascript与Node.js

文章目录 一、Node.js 与 JavaScript1、基本概念1.1、JavaScript&#xff1a;动态脚本语言1.2、Node.js&#xff1a;JavaScript 运行时环境 2、核心区别3、执行环境差异3.1、浏览器中的JavaScript3.2、Node.js中的JavaScript 4、共同点5、为什么需要Node.js&#xff1f; 一、No…...

Spring Boot 集成 druid,实现 SQL 监控

文章目录 背景Druid 简介监控统计 StateFilter其它 Filter详细步骤第 1 步:添加依赖第 2 步:添加数据源配置【通用部分】第 3 步:添加监控配置【关键部分】第 3 步:访问 druid 页面参考背景 😂 在 Code Review 过程中发现,经常有开发会忘记给表加索引。这就导致,生产运…...

多卡跑ollama run deepseek-r1

# 设置环境变量并启动模型 export CUDA_VISIBLE_DEVICES0,1,2,3 export OLLAMA_SCHED_SPREAD1 # 启用多卡负载均衡 ollama run deepseek-r1:32b 若 deepseek-r1:32b 的显存需求未超过单卡容量&#xff08;如单卡 24GB&#xff09;&#xff0c;Ollama 不会自动启用多卡 在run…...

HTML向四周扩散背景

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>扩散背景效果</title><style>body {…...

基于Java在高德地图面查询检索中使用WGS84坐标的一种方法-以某商场的POI数据检索为例

前言 随着移动互联网的飞速发展&#xff0c;基于位置的服务&#xff08;LBS&#xff09;需求日益增长&#xff0c;越来越多的应用需要从地图中检索特定区域内的地理信息&#xff0c;例如商业场所、公共服务设施等。商场作为城市商业活动的重要载体&#xff0c;其周边的地理信息…...

使用 Terraform 创建 Azure Databricks

使用 Terraform 创建 Azure Databricks Terraform 是一种基础设施即代码(IaC)工具,允许用户通过声明式配置文件来管理和部署云资源。Azure Databricks 是一个基于 Apache Spark 的分析平台,专为数据工程和数据科学设计。通过 Terraform,可以自动化 Azure Databricks 的创…...

本地部署dify+ragflow+deepseek ,结合小模型实现故障预测,并结合本地知识库和大模型给出维修建议

1.准备工作 使用ollama 拉取deepseek-r1:7b 官网下载ollama ollama run deepseek-r1:7b ollama list Ragflow专注于构建基于检索增强生成&#xff08;RAG&#xff09;的工作流&#xff0c;强调模块化和轻量化&#xff0c;适合处理复杂文档格式和需要高精度检索的场景。Dify…...

SECERN AI提出3D生成方法SVAD!单张图像合成超逼真3D Avatar!

SECERN AI提出的3D生成方法SVAD通过视频扩散生成合成训练数据&#xff0c;利用身份保留和图像恢复模块对其进行增强&#xff0c;并利用这些经过优化的数据来训练3DGS虚拟形象。SVAD在新的姿态和视角下保持身份一致性和精细细节方面优于现有最先进&#xff08;SOTA&#xff09;的…...

深入探索:Core Web Vitals 进阶优化与新兴指标

一、INP&#xff08;Interaction to Next Paint&#xff09;深度解析 INP 与 FID 的核心差异 • 响应范围&#xff1a;FID仅测量首次输入延迟&#xff0c;而INP跟踪页面生命周期中所有关键交互 • 测量维度&#xff1a;INP综合考虑输入延迟、处理时间和下一帧渲染时间 • 评…...

c/c++的opencv开闭操作

OpenCV 中的形态学开运算与闭运算 (C) 在计算机视觉和图像处理领域&#xff0c;形态学操作是用于分析和处理图像形状的一系列非线性操作。OpenCV 作为一个强大的开源计算机视觉库&#xff0c;提供了丰富的形态学转换函数。其中&#xff0c;“开运算”&#xff08;Opening&…...

【物联网】 ubantu20.04 搭建L2TP服务器

部署篇 序言 为了是两个客户端在同一个网络内&#xff0c;需要找一台服务器&#xff0c;搭建一个L2TP服务器&#xff0c;通过L2TP使两个客户端在同一个网络内,为什么要搭建&#xff0c;主要是解决例如员工出差后&#xff0c;还需要连接公司内网资源的问题&#xff0c;本文主要…...

winrar 工具测试 下载 与安装

https://zhuanlan.zhihu.com/p/680852417 https://www.angusj.com/resourcehacker/#download 点击String Table&#xff0c;在展开列表中找到80:2052展开&#xff0c;删除1277行。点击右上方编译按钮&#xff0c;并保存。...

PLC组网的方法、要点及实施全解析

一、PLC组网方法 1.1 基于以太网的组网 - 适用场景&#xff1a;适用于数据传输量大、通信距离长、对实时性要求相对不苛刻的场景&#xff0c;如大型工厂的车间级数据交互、跨区域设备协同控制 。 - 实现方式&#xff1a;利用工业以太网交换机&#xff0c;将支持以太网接口的…...

网络安全深度解析:21种常见网站漏洞及防御指南

一、高危漏洞TOP 10 1. SQL注入(SQLi) 原理:通过构造恶意SQL语句突破系统过滤机制 典型场景: - 联合查询注入: union select 1,version(),3--+ - 布尔盲注:and (select substr(user(),1,1)=r) - 时间盲注:;if(now()=sysdate(),sleep(5),0)/ 防御方案: - 严格参数化查…...

【FAQ】HarmonyOS SDK 闭源开放能力 —Vision Kit (3)

1.问题描述&#xff1a; 通过CardRecognition识别身份证拍照拿到的照片地址&#xff0c;使用该方法获取不到图片文件&#xff0c;请问如何解决&#xff1f; 解决方案&#xff1a; //卡证识别实现页&#xff0c;文件名为CardDemoPage&#xff0c;需被引入至入口页 import { …...