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

SpringCloud+Vue实现大文件分片下载(支持开始、暂停、继续、取消)

1. 实现效果

http://localhost:8089/#/demo

开始下载
暂停

所有代码已提交至
https://github.com/SJshenjian/cloud.git与
https://github.com/SJshenjian/cloud-web.git中,欢迎star

2. 后端核心代码

@FeignClient(value = "download", contextId = "download")
@Component
@RequestMapping("/download")
public interface DownloadClient {@GetMapping("/download")@Operation(summary = "大文件下载", tags = "通用服务", security = {@SecurityRequirement(name = "token")})ResponseEntity<Object> downloadFile(@RequestHeader HttpHeaders headers, @RequestParam String fileId);
}@RestController
public class DownloadController implements DownloadClient {private final DownloadService downloadService;public DownloadController(DownloadService downloadService) {this.downloadService = downloadService;}@Overridepublic ResponseEntity<Object> downloadFile(@RequestHeader HttpHeaders headers, @RequestParam String fileId) {return downloadService.downloadFile(headers, fileId);}
}public interface DownloadService {/*** 分片下载大文件** @param headers* @param fileId* @return*/ResponseEntity<Object> downloadFile(@RequestHeader HttpHeaders headers, @RequestParam String fileId);
}@Slf4j
@Service
public class DownloadServiceImpl implements DownloadService {@Overridepublic ResponseEntity<Object> downloadFile(HttpHeaders headers, String fileId) {Path filePath = Paths.get("/home/sfxs/files/" + fileId);File file = filePath.toFile();long fileLength = file.length();// 解析 Range 头List<HttpRange> ranges = headers.getRange();if (ranges.isEmpty()) {// 计算分片 MD5String fileMD5;try {fileMD5 = Md5Utils.calculateMD5(Files.readAllBytes(filePath));} catch (Exception e) {log.error("Failed to calculate MD5 for file {}", fileId, e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}return ResponseEntity.ok().header("Content-Disposition", "attachment; filename=" + file.getName()).contentLength(fileLength).header("File-MD5", fileMD5) // 添加 MD5 响应头.body(new FileSystemResource(file));}// 处理 Range 请求HttpRange range = ranges.get(0);long start = range.getRangeStart(fileLength);long end = range.getRangeEnd(fileLength);long rangeLength = end - start + 1;log.info("start: {}, end: {}", start, end);try (RandomAccessFile raf = new RandomAccessFile(file, "r");FileChannel channel = raf.getChannel()) {ByteBuffer buffer = ByteBuffer.allocate((int) rangeLength);channel.position(start);channel.read(buffer);buffer.flip();return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).header("Content-Range", "bytes " + start + "-" + end + "/" + fileLength).header("Accept-Ranges", "bytes").contentLength(rangeLength).body(buffer.array());} catch (Exception e) {log.error("Failed to process range request for file {}", fileId, e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}// 这种方式会导致原始文件大小为0
//        return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
//                .header("Content-Range", "bytes " + start + "-" + end + "/" + fileLength)
//                .header("Accept-Ranges", "bytes")
//                .contentLength(rangeLength)
//                .body(new ResourceRegion(new FileSystemResource(file), start, rangeLength));// 计算当前分片的MD5, 排查用
//        byte[] chunkData;
//        try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
//            raf.seek(start);
//            chunkData = new byte[(int) rangeLength];
//            raf.read(chunkData);
//            bytesToHex(chunkData);
//            String md5 = DigestUtils.md5DigestAsHex(chunkData);
//            return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
//                    .header("Content-Range", "bytes " + start + "-" + end + "/" + fileLength)
//                    .header("Accept-Ranges", "bytes")
//                    .header("File-MD5", md5)  // 添加MD5校验头
//                    .contentLength(rangeLength)
//                    .body(new ResourceRegion(new FileSystemResource(file), start, rangeLength));
//        } catch (FileNotFoundException e) {
//            throw new RuntimeException(e);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }}
}

3. 后端超时及自定义头配置

# application.yml
spring:cloud:openfeign:client:config:default:connectTimeout: 5000      # 5秒连接超时readTimeout: 30000         # 30秒读取超时download: # 下载服务专用配置connectTimeout: 30000   # 连接超时30秒readTimeout: 3600000   # 读取超时60分钟(1小时)
@Slf4j
@Component
public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {// 允许跨域response.setHeader("Access-Control-Allow-Origin", "*");// 允许自定义请求头token(允许head跨域) 新增File-MD5response.setHeader("Access-Control-Allow-Headers", "Authorization, Role, Accept, Origin, X-Requested-With, Content-Type, Last-Modified, File-MD5");response.setHeader("Content-type", "application/json;charset=UTF-8");response.getWriter().print(JSON.toJSONString(ResponseVo.message(ResponseCode.UN_AUTHORIZED)));}
}

3. 统一返回放开

放开FileSystemResource与ResourceRegion的返回拦截

@RestControllerAdvice
@Slf4j
public class UnitedResponseAdvice implements ResponseBodyAdvice<Object> {@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body != null && !(body instanceof ResponseVo) && !(body instanceof byte[]) && !(body instanceof FileSystemResource) && !(body instanceof ResourceRegion)) {// 放行Swagger相关if (body instanceof TreeMap && ((TreeMap)body).containsKey("oauth2RedirectUrl")) {return body;}// 解决string返回异常if (body instanceof String) {return JSON.toJSONString(ResponseVo.message(ResponseCode.SUCCESS.val(), ResponseCode.SUCCESS.des(), body));}return ResponseVo.message(ResponseCode.SUCCESS.val(), ResponseCode.SUCCESS.des(), body);}if (body == null) {return JSON.toJSONString(ResponseVo.message(ResponseCode.SUCCESS.val(), ResponseCode.SUCCESS.des(), ""));}return body;}
}

4. 前端Vue组件编写

<template><div class="download-container"><el-button-group><el-button@click="startDownload":disabled="isDownloading"type="primary"icon="el-icon-download">开始下载</el-button><el-button@click="pauseDownload":disabled="!isDownloading || isPaused"icon="el-icon-video-pause">暂停</el-button><el-button@click="resumeDownload":disabled="!isPaused"icon="el-icon-caret-right">继续</el-button><el-button@click="cancelDownload":disabled="!isDownloading"type="danger"icon="el-icon-close">取消</el-button></el-button-group><el-progress:percentage="progressPercent":status="progressStatus":stroke-width="16"class="progress-bar"/><div class="download-info"><span v-if="speed">下载速度: {{ speed }} MB/s</span><span>已下载: {{ formatFileSize(downloadedSize) }} / {{ formatFileSize(totalSize) }}</span></div></div>
</template><script>
import baseUrl from "../../util/baseUrl";
import store from "../../store";
import {md5} from "js-md5";export default {name: "DownloadFile",props: {fileId: {type: String,required: true}},data() {return {chunkSize: 5 * 1024 * 1024, // 5MB 分片maxRetries: 3,isDownloading: false,isPaused: false,progressPercent: 0,progressStatus: '',speed: '',downloadedSize: 0,totalSize: 0,controller: null,retryCount: 0,chunks: [],downloadStartTime: null,fileName: '',serverFileMD5: '' // 存储服务器提供的文件 MD5}},computed: {fileUrl() {return `${baseUrl.apiUrl}/download/download?fileId=${this.fileId}`;},estimatedTime() {if (!this.speed || this.speed <= 0) return '--';const remaining = (this.totalSize - this.downloadedSize) / (this.speed * 1024 * 1024);return remaining > 3600? `${Math.floor(remaining / 3600)}小时${Math.floor((remaining % 3600) / 60)}分钟`: `${Math.floor(remaining / 60)}分钟${Math.floor(remaining % 60)}`;}},methods: {formatFileSize(bytes) {if (bytes === 0) return '0 Bytes';const k = 1024;const sizes = ['Bytes', 'KB', 'MB', 'GB'];const i = Math.floor(Math.log(bytes) / Math.log(k));return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];},async calculateMD5(data) {try {return md5(data); // Compute MD5 hash} catch (error) {console.error('MD5 error:', error);throw error;}},async startDownload() {if (this.isDownloading) return;try {this.resetState();this.isDownloading = true;this.downloadStartTime = Date.now();this.controller = new AbortController();// 获取文件元数据await this.fetchFileMetadata();// 恢复进度或开始新下载await this.downloadChunks();} catch (err) {this.handleError(err);}},async fetchFileMetadata() {const headRes = await fetch(this.fileUrl, {method: 'HEAD',headers: {Authorization: store.getters.token,'Cache-Control': 'no-cache'}});if (!headRes.ok) {throw new Error(`获取文件信息失败: ${headRes.statusText}`);}this.totalSize = parseInt(headRes.headers.get('Content-Length')) || 0;const contentDisposition = headRes.headers.get('Content-Disposition');this.fileName = contentDisposition? contentDisposition.split('filename=')[1].replace(/"/g, ''): this.fileId;this.serverFileMD5 = headRes.headers.get('File-MD5') || ''; // 获取服务器提供的 MD5if (!this.serverFileMD5) {console.warn('服务器未提供文件 MD5,无法进行完整性验证');}// 恢复进度const savedProgress = localStorage.getItem(this.getStorageKey());if (savedProgress) {const progressData = JSON.parse(savedProgress);this.downloadedSize = progressData.downloaded;this.progressPercent = Math.round((this.downloadedSize / this.totalSize) * 100);}},getStorageKey() {return `download-${btoa(this.fileUrl)}`;},async downloadChunks() {while (this.downloadedSize < this.totalSize && !this.isPaused) {const start = this.downloadedSize;const end = Math.min(start + this.chunkSize - 1, this.totalSize - 1);try {const chunkBlob = await this.downloadChunk(start, end);const customBlob = {blob: chunkBlob,start: start,end: end};this.chunks.push(customBlob);this.retryCount = 0;} catch (err) {if (err.name === 'AbortError') return;if (this.retryCount++ < this.maxRetries) {await new Promise(resolve => setTimeout(resolve, 1000 * this.retryCount));continue;}throw err;}}if (this.downloadedSize >= this.totalSize) {await this.completeDownload();}},async downloadChunk(start, end) {const startTime = Date.now();// 禁用缓存const response = await fetch(this.fileUrl, {headers: {Range: `bytes=${start}-${end}`,Authorization: store.getters.token,'Cache-Control': 'no-cache'},signal: this.controller.signal // 添加时间戳参数以避免浏览器缓存});if (!response.ok) {throw new Error(`下载失败: ${response.statusText}`);}// 方法1:直接使用 arrayBuffer() 方法(最简单)const contentRange = response.headers.get('Content-Range');console.log('Content-Range:', contentRange);  // 确保它匹配你请求的范围const arrayBuffer = await response.arrayBuffer();// 排查用户端与服务端的MD5校验// const chunk_md5 = response.headers.get('File-MD5')// const real_md5 = await this.calculateMD5(arrayBuffer)// console.log(arrayBuffer)// if (chunk_md5 !== real_md5) {//   console.error("MD5不一致:", chunk_md5, real_md5)//   console.log("HEX" + utils.toHex(arrayBuffer))// } else {//   console.error("MD5一致:", chunk_md5, real_md5)//   console.log("HEX" + utils.toHex(arrayBuffer))// }// 更新进度this.updateProgress(start, arrayBuffer.byteLength, startTime);return arrayBuffer;// const reader = response.body.getReader();// let receivedLength = 0;// const chunks = [];//// while (true) {//   const { done, value } = await reader.read();//   if (done) break;////   chunks.push(value);//   receivedLength += value.length;////   // 更新进度//   this.updateProgress(start, receivedLength, startTime);// }// return chunks;},updateProgress(start, receivedLength, startTime) {this.downloadedSize = start + receivedLength;this.progressPercent = Math.round((this.downloadedSize / this.totalSize) * 100);// 计算下载速度const timeElapsed = (Date.now() - startTime) / 1000;this.speed = (receivedLength / 1024 / 1024 / timeElapsed).toFixed(2);// 保存进度localStorage.setItem(this.getStorageKey(),JSON.stringify({downloaded: this.downloadedSize,chunks: this.chunks.length}));},pauseDownload() {this.isPaused = true;this.controller.abort();this.progressStatus = 'warning';this.$message.warning('下载已暂停');},resumeDownload() {this.isPaused = false;this.progressStatus = '';this.controller = new AbortController();this.downloadChunks();this.$message.success('继续下载');},cancelDownload() {this.controller.abort();this.resetState();localStorage.removeItem(this.getStorageKey());this.$message.info('下载已取消');},async completeDownload() {try {this.progressStatus = 'success';await this.saveFile();this.$message.success('下载完成');} catch (err) {this.handleError(err);} finally {this.cleanup();}},async saveFile() {// 1. 排序分片const sortedChunks = this.chunks.sort((a, b) => a.start - b.start);const fullBlob = new Blob(sortedChunks.map(c => c.blob), { type: 'application/zip' });// 计算下载文件的 MD5let arrayBuffer;if (this.serverFileMD5) {arrayBuffer = await fullBlob.arrayBuffer();const downloadedMD5 = await this.calculateMD5(arrayBuffer);if (downloadedMD5 !== this.serverFileMD5) {this.progressStatus = 'exception';this.$message.error('文件校验失败:MD5 不匹配,文件可能已损坏');throw new Error('MD5 verification failed');}}// 检查 ZIP 文件头const uint8Array = new Uint8Array(arrayBuffer);const zipHeader = uint8Array.slice(0, 4);if (zipHeader[0] !== 80 || zipHeader[1] !== 75 || zipHeader[2] !== 3 || zipHeader[3] !== 4) {this.progressStatus = 'exception';this.$message.error('无效的 ZIP 文件:文件头错误');throw new Error('Invalid ZIP file header');}// 创建下载链接const url = URL.createObjectURL(fullBlob);const a = document.createElement('a');a.href = url;a.download = this.fileName;a.style.display = 'none';// 触发下载document.body.appendChild(a);a.click();// 延迟清理await new Promise(resolve => setTimeout(resolve, 100));document.body.removeChild(a);URL.revokeObjectURL(url);},resetState() {this.isDownloading = false;this.isPaused = false;this.progressPercent = 0;this.progressStatus = '';this.speed = '';this.downloadedSize = 0;this.retryCount = 0;this.chunks = [];this.controller = null;this.serverFileMD5 = '';},cleanup() {this.isDownloading = false;localStorage.removeItem(this.getStorageKey());},handleError(err) {console.error('下载错误:', err);this.progressStatus = 'exception';this.$message.error(`下载失败: ${err.message}`);this.cleanup();}},beforeUnmount() {if (this.controller) {this.controller.abort();}}
}
</script><style scoped>
.download-container {max-width: 800px;margin: 20px auto;padding: 20px;border: 1px solid #ebeef5;border-radius: 4px;background-color: #f5f7fa;
}.el-button-group {margin-bottom: 15px;
}.progress-bar {margin: 20px 0;
}.download-info {display: flex;justify-content: space-between;margin-top: 10px;color: #606266;font-size: 14px;
}.download-info span {padding: 0 5px;
}
</style>

相关文章:

SpringCloud+Vue实现大文件分片下载(支持开始、暂停、继续、取消)

1. 实现效果 http://localhost:8089/#/demo 所有代码已提交至 https://github.com/SJshenjian/cloud.git与 https://github.com/SJshenjian/cloud-web.git中&#xff0c;欢迎star 2. 后端核心代码 FeignClient(value "download", contextId "download"…...

RK3576 Android 14.0 SDK开发指南(第一集)

RK3576 Android 14.0 SDK代码编译 SDK下载到本地后大概70多个G 下载后要做个校验 解压后内核源码 kernel代码路径说明 Android14支持6.1 版本的kernel&#xff0c;kernel源码在工程中kernel-6.1目录下 Lunch项说明 一键编译命令 ./build.sh -UKAupSoc RK3576 SDK默认没有开…...

【C/C++】现代C++线程池:从入门到生产级实现

文章目录 现代C线程池&#xff1a;从入门到生产级实现&#x1f9e0; What Is a Thread Pool?&#x1f9e9; Why Use a Thread Pool?&#x1f530; Part 1: Basic Thread Pool (Beginner)&#x1f527; Minimal Working Code:✅ Usage: &#x1f9d1;‍&#x1f52c; Part 2: …...

后期:daplink

问题描述: 问题一:总工程,USB插入能识别到dap,但有个黄色的感叹号!现在连感叹号都没有了。 重点跟踪了枚举的几个函数,差异点就是有个工厂描述符没有枚举到。 问题二: 下载后,目标板,没有自动复位。 问题三:未移植daplink的时候,虚拟串口是收发正常,貌似没有映射到…...

Android SharedPreferences:从零到一的全面解析与实战指南

简介 SharedPreferences是Android平台提供的一种轻量级键值对存储方案,虽然看似简单,但在实际开发中却蕴含着丰富的技术细节和最佳实践。本文将从基本概念出发,深入分析其源码实现原理,探讨企业级开发中的应用技巧,并提供完整的代码示例,帮助开发者全面掌握这一重要数据…...

推扫式高光谱相机VIX-N230重磅发布——开启精准成像新时代

随着各行业对高光谱成像技术需求的持续增长&#xff0c;市场对于高分辨率、高灵敏度以及快速成像的高光谱相机的需求愈发迫切。中达瑞和凭借多年的行业经验和技术积累&#xff0c;敏锐捕捉到这一市场趋势&#xff0c;正式推出全新一代推扫式可见光近红外高光谱相机——VIX-N230…...

实现rpc通信机制(待定)

一、概述 &#xff08;1&#xff09;rpc&#xff08;remote procedure call, 远程接口调用&#xff09;,就像在本地调用函数一样&#xff0c;是应用组成服务内部分布式的基础功能。应用场景是在内网中的计算&#xff0c;比如&#xff1a;(a) 为上传的一张图片加水印、&#xf…...

STM32--串口函数

USART_GetFlagStatus() 用于获取某个串口的寄存器中的某个标志位的状态&#xff0c;和中断无关。 USART_ClearFlag() 用于清楚串口寄存器中的标志位的状态&#xff0c;和中断无关。 USART_ITConfig() 使能或禁用指定的 USART 中断。 USART_ITConfig(USART1, USART_IT_TXE, …...

Linux跨网络通信中IP与MAC的作用

是的&#xff0c;MAC地址和IP地址分别属于OSI模型的不同层次&#xff0c;并在数据封装过程中被添加到不同的位置&#xff1a; 1. MAC地址&#xff08;数据链路层&#xff09; 作用层级&#xff1a;数据链路层&#xff08;第二层&#xff09;。封装位置&#xff1a;添加到数据链…...

Facebook隐私保护的成与败:一场对用户信任的考验

引言 在这个信息爆炸的时代&#xff0c;Facebook作为全球最大的社交网络平台之一&#xff0c;其隐私保护政策和实践一直是公众关注的焦点。随着数据泄露事件的频发&#xff0c;Facebook在隐私保护方面的成与败&#xff0c;不仅关系到其自身的声誉&#xff0c;更是对用户信任的…...

面试算法刷题3(核心+acm)

102. 二叉树的层序遍历 递归法 核心代码模式 不断递归根节点&#xff0c;根据深度来判断加在哪一层上。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(in…...

[Java] idea的调试介绍

1. 什么是调试&#xff1f; 调试就是帮助我们去寻找代码中的bug&#xff0c;优化代码的过程。调试对于程序员来说非常重要&#xff0c;能帮助我们更容易去找到代码中的错误&#xff0c;去修复。 2. idea集成开发环境的调试 下面我就介绍下idea集成开发环境下的调试&#xff…...

winrm ‘Protocol‘ object has no attribute ‘run_ps‘

在使用 winrm 库时遇到错误 ‘Protocol’ object has no attribute ‘run_ps’ 通常意味着你正在尝试使用一个不存在的属性或方法。在 Python 中使用 winrm 库时&#xff0c;正确的调用方式应该使用 client 对象来运行 PowerShell 命令&#xff0c;而不是直接在 Protocol 对象上…...

WHAT - CSS 中的 min-width

文章目录 基本语法常见取值使用场景举例min-width: 0为什么 min-width: 0 重要&#xff1f;场景演示提示 注意事项 在 WHAT - CSS 中的 width 中我们已经详细介绍过 width。那为什么 CSS 还要提供一个 min-width&#xff1f; 阅读本文前可先阅读 MDN - min-width。 min-width…...

测试W5500的第2步_使用ioLibrary库创建TCP客户端

ioLibrary库下载地址&#xff1a;文件下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples 源文件下载地址:https://gitee.com/wiznet-hk 没有注册的&#xff0c;只能复制粘贴了。 本文介绍了如何初始化STM32的硬件资源&#xff0c;配置W5500的网络参数&#xff…...

深度学习中的正则化方法与卷积神经网络基础

笔记 1 正则化方法 1.1 什么是正则化 防止模型过拟合(训练集效果好, 测试集效果差), 提高模型泛化能力 一种防止过拟合, 提高模型泛化能力的策略 L1正则: 需要通过手动写代码实现 L2正则: SGD(weight_decay) dropout BN 1.2 Dropout正则化 让神经元以p概率随机死亡, 每…...

pg_dump

以下是 PostgreSQL 中 pg_dump 命令的 核心参数 及 使用示例 的详细说明&#xff1a; 一、核心参数分类及说明 pg_dump 主要用于备份单个数据库&#xff0c;支持多种格式和灵活的控制选项。以下是其关键参数分类&#xff1a; 1. 连接参数 参数说明-h, --hostHOST数据库服务器…...

css使用clip-path属性切割显示可见内容

1. 需求 想要实现一个渐变的箭头Dom&#xff0c;不想使用svg、canvas去画&#xff0c;可以考虑使用css的clip-path属性切割显示内容。 2. 实现 <div class"arrow">箭头 </div>.arrow{width: 200px;height: 60px;background-image: linear-gradient(45…...

系统设计——项目设计经验总结1

摘要 在系统设计的时候&#xff0c;注意域的区分&#xff0c;功能区分、类的区分、方法区分范围和定义。在系统设计的时候的&#xff0c;需要思考类、方法在什么情况下会涉及到修改&#xff0c;遵循记住&#xff1a;一个类应该只有一个原因被修改&#xff01; 当不满足&#x…...

如何在WordPress网站上添加即时聊天功能

在 WordPress 网站上添加即时聊天功能既简单又有益。近年来&#xff0c;即时聊天已经有了长足的发展&#xff0c;融入了强大的交流和自动化功能&#xff0c;类似于流行的人工智能聊天机器人。无论您是想提高销售转化率还是将人工智能整合到客户服务流程中&#xff0c;在 WordPr…...

[luogu12542] [APIO2025] 排列游戏 - 交互 - 博弈 - 分类讨论 - 构造

传送门&#xff1a;https://www.luogu.com.cn/problem/P12542 题目大意&#xff1a;给定一个长为 n n n 的排列和一张 m m m 个点 e e e 条边的简单连通图。每次你可以在图上每个点设置一个 0 ∼ n − 1 0\sim n-1 0∼n−1、两两不同的权值发给交互库&#xff0c;交互库会…...

图像处理基础知识

OpenCV计算机视觉开发实践&#xff1a;基于Qt C - 商品搜索 - 京东 信息是自然界物质运动总体的一个重要方面&#xff0c;人们认识世界和改造世界就是要获得各种各样的图像信息&#xff0c;这些信息是人类获得外界信息的主要来源。大约有70%的信息是通过人眼获得的。近代科学研…...

使用MybatisPlus实现sql日志打印优化

背景&#xff1a; 在排查无忧行后台服务日志时&#xff0c;一个请求可能会包含多个执行的sql&#xff0c;经常会遇到SQL语句与对应参数不连续显示&#xff0c;或者参数较多需要逐个匹配的情况。这种情况下&#xff0c;如果需要还原完整SQL语句就会比较耗时。因此&#xff0c;我…...

HarmonyOS5云服务技术分享--ArkTS开发Node环境

✨ 你好呀&#xff0c;开发者小伙伴们&#xff01;今天我们来聊聊如何在HarmonyOS&#xff08;ArkTS API 9及以上&#xff09;中玩转云函数&#xff0c;特别是结合Node.js和HTTP触发器的开发技巧。文章会手把手带你从零开始&#xff0c;用最接地气的方式探索这个功能&#xff0…...

水利数据采集MCU水资源的智能守护者

水利数据采集仪MCU&#xff0c;堪称水资源的智能守护者&#xff0c;其重要性不言而喻。在水利工程建设和水资源管理领域&#xff0c;MCU数据采集仪扮演着不可或缺的角色。它通过高精度的传感器和先进的微控制器技术&#xff0c;实时监测和采集水流量、水位、水质等关键数据&…...

深度学习之用CelebA_Spoof数据集搭建一个活体检测-用MNN来推理时候如何利用Conan对软件包进行管理

我为什么用Conan 前面的文章&#xff1a;深度学习之用CelebA_Spoof数据集搭建一个活体检测-训练好的模型用MNN来推理有提到怎么使用MNN对训练好的模型进行推理&#xff0c;里面并没有提到我是怎么编译和进行代码依赖包的管理的详细步骤&#xff0c;在这里我是用的是Conan:一个…...

深入解剖 G1 收集器的分区模型与调优策略

JVM 垃圾收集系列之三 | 高并发低延迟系统的首选 GC 解法&#xff01; 一、为什么我们需要 G1 垃圾收集器&#xff1f; 在传统 GC&#xff08;如 CMS&#xff09;中&#xff0c;我们常常面临的问题是&#xff1a; GC 停顿不可预测&#xff08;Stop-The-World&#xff09;内存…...

兰亭妙微・UI/UX 设计・全链路开发

【遇见专业设计&#xff0c;共筑卓越产品】 在数字化浪潮中&#xff0c;界面是产品与用户对话的第一窗口。 兰亭妙微&#xff08;蓝蓝设计&#xff09;&#xff0c;自 2008 年深耕 UI/UX 领域&#xff0c;以清华团队为核心&#xff0c;16 年专注软件与互联网产品的界面设计开…...

Babylon.js学习之路《六、材质与纹理:为模型赋予真实的表面效果》

文章目录 1. 引言&#xff1a;材质与纹理的重要性1.1 材质与纹理的核心作用 2. 基础材质&#xff1a;StandardMaterial2.1 材质属性详解2.2 实战&#xff1a;创建金属材质 3. 纹理贴图&#xff1a;从基础到高级3.1 基础纹理映射3.2 多纹理混合技术 4. 高级材质&#xff1a;PBRM…...

飞致云旗下开源项目GitHub Star总数突破150,000个

2025年5月19日&#xff0c;中国领先的开源软件提供商飞致云宣布&#xff0c;其旗下开源项目在代码托管平台GitHub上所获得的Star总数已经超过150,000个。基于在开源领域的长期耕耘和探索&#xff0c;飞致云的开源势能不断增强&#xff0c;获得第一个五万GitHub Star用时89个月&…...

萌新联赛第(三)场

C题 这道题用暴力去写想都不要想&#xff0c;一定超时&#xff0c;于是我们需要优化&#xff0c;下面是思路过程&#xff1a; 如图&#xff0c;本题只需找到x的因数个数和(n-x)的因数个数&#xff0c;这两个相乘&#xff0c;得到的就是对于这个x来说组合的个数&#xff0c;且x…...

cplex12.9 安装教程以及下载

cplex 感觉不是很好找&#xff0c;尤其是教育版&#xff0c;我这里提供一个版本&#xff0c;在下面的图可以看到&#xff0c;不仅可以配置matlab&#xff0c;也可以配置vs,现在拿vs2017来测试一下&#xff0c;具体文件的文件有需要的可以复制下面的链接获取 我用网盘分享了「c…...

Pycharm-jupyternotebook不渲染

解决方案&#xff1a; https://youtrack.jetbrains.com/issue/PY-54244 import plotly.io as pio pio.renderers.default "vscode"...

layui 介绍

layui&#xff08;谐音&#xff1a;类 UI) 是一套开源的 Web UI 解决方案&#xff0c;采用自身经典的模块化规范&#xff0c;并遵循原生 HTML/CSS/JS 的开发方式&#xff0c;极易上手&#xff0c;拿来即用。其风格简约轻盈&#xff0c;而组件优雅丰盈&#xff0c;从源代码到使用…...

大数据相关操作

大数据相关操作 一、环境配置 1、修改主机名 #修改主机名 hostnamectl set-hostname master2、固定IP地址 # 进入修改 sudo vim /etc/netplan/01-network-manager-all.yaml# 修改配置文件 # Let NetworkManager manage all devices on this system network:version: 2rend…...

谷歌宣布推出 Android 的新安全功能,以防止诈骗和盗窃

在上周二的 Android Show 上&#xff0c;也就是Google I/O 开发者大会之前&#xff0c;谷歌宣布了 Android 的全新安全和隐私功能。这些新功能包括对通话、屏幕共享、消息、设备访问和系统级权限的全新保护。谷歌希望通过这些功能保护用户免遭诈骗&#xff0c;在设备被盗或被攻…...

WSL虚拟机整体迁移教程(如何将WSL从C盘迁移到其他盘)

文章目录 WSL虚拟机迁移教程一、查看当前主机的子系统二、导出 WSL 子系统三、将打包好的文件发送给另一个人四、在另一台机器导入并恢复子系统五、附加命令六、注意事项和导出文件信息6.1 注意事项6.2 导出文件信息使用 wsl --export 命令导出整个 WSL 子系统时&#xff0c;它…...

汽车区域电子电气架构(Zonal E/E)的统一

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 钝感力的“钝”&#xff0c;不是木讷、迟钝&#xff0c;而是直面困境的韧劲和耐力&#xff0c;是面对外界…...

开源一个记账软件,支持docker一键部署

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 开源一个记账软件&#xff0c;支持docker一键部署 项目简介功能特性技术栈快速开始环境要求运行步…...

新能源汽车焊接智能节气阀

在新能源汽车产业迅猛发展的浪潮中&#xff0c;制造工艺的优劣直接关系到车辆的性能、安全与市场竞争力。焊接&#xff0c;作为新能源汽车生产流程里的关键一环&#xff0c;无论是构建车身框架&#xff0c;还是连接电池模组&#xff0c;其质量的好坏都起着决定性作用。而在焊接…...

React 第四十四节Router中 usefetcher的使用详解及注意事项

前言 useFetcher 是 React Router 中一个强大的钩子&#xff0c;用于在不触发页面导航的情况下执行数据加载&#xff08;GET&#xff09;或提交&#xff08;POST&#xff09;。 一、useFetcher 应用场景&#xff1a; 1、后台数据预加载&#xff08;如鼠标悬停时加载数据&…...

33、魔法防御术——React 19 安全攻防实战

一、奥术护盾&#xff08;基础防御&#xff09; 1. 敏感数据加密术 // cryptoUtils.js - 数据加密工具export const encrypt (data) > {// 实际项目应使用Web Crypto API或crypto-jsreturn btoa(encodeURIComponent(data));};​export const decrypt (data) > {try {…...

NVM 安装与配置指南

简介 Node Version Manager&#xff08;NVM&#xff09;是一个常用的 Node.js 版本管理工具&#xff0c;可用于在开发过程中方便地切换不同版本的 Node.js。通过 NVM&#xff0c;用户可以根据项目需求选择不同的 Node.js 版本&#xff0c;而无需手动安装和卸载多个版本的 Node…...

SpringMVC04所有注解按照使用位置划分| 按照使用层级划分(业务层、视图层、控制层)

目录 一、所有注解按照使用位置划分&#xff08;类、方法、参数&#xff09; 1. 类级别注解 2. 方法级别注解 3. 参数级别注解 4. 字段/返回值注解 二、按照使用层级划分&#xff08;业务层、视图层、控制层&#xff09; 1、控制层&#xff08;Controller Layer&#x…...

【数据库】-1 mysql 的安装

文章目录 1、mysql数据库1.1 mysql数据库的简要介绍 2、mysql数据库的安装2.1 centos安装2.2 ubuntu安装 1、mysql数据库 1.1 mysql数据库的简要介绍 MySQL是一种开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典MySQL AB公司开发&#xff0c;目前…...

MySQL与Redis一致性问题分析

一、一致性问题概述 1.1 什么是一致性问题&#xff1f; 在数据库-缓存架构中&#xff0c;当MySQL中的数据&#xff08;最新值&#xff09;与Redis缓存中的数据&#xff08;缓存旧值&#xff09;出现差异时&#xff0c;由于程序总是优先读取Redis缓存&#xff0c;就会导致应用…...

Xshell传输文件

新建文件 点击新建 完善主机地址 然后输入我们的远端服务器的SSH协议 一般的是这样的ssh -p 44562 rootregion-1.autodl.com 由于Xshell比较特殊我们输入ssh rootregion-1.autodl.com 44562这样的形式 然后输入服务器的密码即可...

怎样用 esProc 为大主子表关联提速

类似订单和明细表这样的主子表关联比较常见&#xff0c;在 SQL 中&#xff0c;这种关联用 JOIN 实现&#xff0c;在两个表都很大的情况下&#xff0c;常常出现计算速度非常慢的现象。 如果预先将主子表都按照主键有序存储&#xff0c;就可以使用归并算法实现关联。这种算法只需…...

打卡day31

文件的规范拆分和写法 知识点回顾 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 作业&#xff1a;尝试针对之前的心脏病项目&#xff0c;准备拆分的项目文件&#xff0c;思考下哪些部分可以未来复用。 导入依赖库 # 忽视警告 import warnings warn…...

编译原理的部分概念

解释程序&#xff1a;边解释边执行&#xff1a;不断读取源程序的语句&#xff0c;解释语句&#xff0c;读取此语句需要的数据&#xff0c;根据执行结果读取下一条语句&#xff0c;继续解释执行&#xff0c;直到返回结果。 编译程序&#xff1a;将源程序完整地转换成机器语言程…...