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

如何在React中集成 PDF.js?构建支持打印下载的PDF阅读器详解

本文深入解析基于 React 和 PDF.js 构建 PDF 查看器的实现方案,该组件支持 PDF 渲染、图片打印和下载功能,并包含完整的加载状态与错误处理机制。

完整代码在最后

一个PDF 文件:

https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf

效果展示:

在这里插入图片描述

安装 PDF.js

要使用 pdf.js,你可以通过 npm 安装它。以下是安装和配置 pdf.js 的详细步骤:

1. 安装 pdfjs-dist

pdf.js 的官方 npm 包名为 pdfjs-dist。可以通过以下命令安装:

npm install pdfjs-dist
  • pdfjs-dist 是 PDF.js 的分发版本,包含了核心功能和 Worker 文件。
  • 安装完成后,你可以在项目中直接引入并使用。

2. 设置 Worker 文件路径

PDF.js 需要一个 Worker 文件来处理 PDF 渲染任务。默认情况下,Worker 文件路径需要手动设置。

方法 1:使用 CDN

如果你不想将 Worker 文件打包到项目中,可以直接使用 CDN 提供的 Worker 文件:

import { GlobalWorkerOptions } from 'pdfjs-dist';// 设置 Worker 文件路径
GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';
方法 2:本地 Worker 文件

如果你希望将 Worker 文件打包到项目中,可以这样做:

  1. 在代码中引入 Worker 文件:

    import { GlobalWorkerOptions, getDocument } from 'pdfjs-dist';
    import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';// 设置 Worker 文件路径
    GlobalWorkerOptions.workerSrc = pdfjsWorker;
    
  2. 这种方式适合离线环境或需要完全控制依赖的情况。

技术架构解析

1. 核心依赖
  • PDF.js:Mozilla 开源的 PDF 解析库,支持 Web 端 PDF 渲染
  • React Hooks:使用 useState 管理状态,useEffect 处理副作用,useRef 操作 DOM
  • Ant Design:采用 Button 组件构建操作界面

pdf.js 官网:https://mozilla.github.io/pdf.js/

2. 初始化配置

通过配置 Worker 文件实现 PDF 解析的 Web Worker 并行处理,避免阻塞主线程。

GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';

核心功能实现

1. PDF 渲染流程

这段代码的核心功能是加载一个 PDF 文件,并将其第一页渲染到 <canvas> 元素中。

// 加载 PDF 并渲染到 canvasuseEffect(() => {const abortController = new AbortController();if (!pdfUrl) return;setIsLoading(true);setError(null);getDocument({url: pdfUrl,cMapUrl: '/cmaps/', // 引入字体映射文件cMapPacked: true, // 启用字体映射文件}).promise.then((pdf) => {if (abortController.signal.aborted) return;console.log('PDF loaded');// 获取第一页pdf.getPage(1).then((page) => {if (abortController.signal.aborted) {page.cleanup();return;}console.log('Page 1 loaded');const scale = 1.5;const viewport = page.getViewport({ scale });if (!canvasRef.current) {throw new Error('Canvas element not found');}const canvas = canvasRef.current;const context = canvas.getContext('2d');// 清除之前的画布内容context?.clearRect(0, 0, canvas.width, canvas.height);canvas.height = viewport.height;canvas.width = viewport.width;console.log('Canvas尺寸设置:', canvas.width, 'x', canvas.height);// 渲染 PDF 页面到 canvasconst renderContext: any = {canvasContext: context,viewport: viewport,};const renderTask = page.render(renderContext);renderTask.promise.then(() => {console.log('页面渲染完成');setIsLoading(false);}).catch((renderError) => {if (!abortController.signal.aborted) {setError('页面渲染失败: ' + renderError.message);}});});}).catch((error) => {if (!abortController.signal.aborted) {setError('PDF加载失败: ' + error.message);console.error('Error loading PDF:', error);}}).finally(() => {if (!abortController.signal.aborted) {setIsLoading(false);}});return () => {abortController.abort();const canvas = canvasRef.current;if (canvas) {const context = canvas.getContext('2d');context?.clearRect(0, 0, canvas.width, canvas.height);}};}, [pdfUrl]);
  • 初始化加载状态:设置加载提示和清理错误信息。
  • 加载 PDF 文件:使用 getDocument 加载 PDF,并获取第一页。
  • 计算视口与画布尺寸:根据缩放比例调整 <canvas> 的大小。
  • 渲染 PDF 页面:将 PDF 页面绘制到 <canvas> 上。
  • 错误处理与清理:捕获加载和渲染中的错误,并在组件卸载时清理资源。

以下是核心实现原理与技术要点的详细解读:

1. useEffect 的作用
useEffect(() => {// ...
}, [pdfUrl]);
  • useEffect 是 React 的生命周期钩子,用于处理副作用(如数据加载、DOM 操作等)。
  • 这里的依赖项 [pdfUrl] 表示当 pdfUrl 发生变化时,这个 useEffect 会重新执行。
  • 如果 pdfUrl 为空或未改变,则不会触发新的加载。
2. 创建 AbortController
const abortController = new AbortController();
  • AbortController 是一个浏览器内置的 API,用于取消异步操作(如网络请求)。
  • 在这里,我们用它来确保在组件卸载或重新加载时,可以中断正在进行的 PDF 加载任务,避免内存泄漏或不必要的资源消耗。
3. 检查 pdfUrl 是否有效
if (!pdfUrl) return;
  • 如果 pdfUrl 为空,则直接退出函数,避免无效操作。

4. 设置加载状态
setIsLoading(true);
setError(null);
  • isLoading 设置为 true,表示开始加载 PDF。
  • 清空之前的错误信息(如果有)。
5. 加载 PDF 文件
getDocument(pdfUrl).promise.then((pdf) => { ... }).catch((error) => { ... }).finally(() => { ... });
  • getDocument 是 PDF.js 提供的方法,用于加载 PDF 文件。
  • 它返回一个 Promise,成功时会返回一个 pdf 对象,失败时会抛出错误。
关键点:
  • abortController.signal.aborted

    if (abortController.signal.aborted) return;
    
    • 如果组件已经被卸载或取消了加载任务,则直接退出,避免继续执行无意义的操作。
  • pdf.getPage(1)

    pdf.getPage(1).then((page) => { ... });
    
    • getPage(1) 获取 PDF 的第一页(索引从 1 开始)。

6. 计算视口与画布尺寸
const scale = 1.5;
const viewport = page.getViewport({ scale });if (!canvasRef.current) {throw new Error('Canvas element not found');
}
const canvas = canvasRef.current;
const context = canvas.getContext('2d');// 清除之前的画布内容
context?.clearRect(0, 0, canvas.width, canvas.height);canvas.height = viewport.height;
canvas.width = viewport.width;
console.log('Canvas尺寸设置:', canvas.width, 'x', canvas.height);
关键点:
  1. scale

    • scale=1.5 表示将 PDF 页面放大 1.5 倍进行渲染。
    • 可以根据需求调整缩放比例。
  2. getViewport

    • getViewport({ scale }) 根据缩放比例计算页面的视口尺寸(宽度和高度)。
  3. 清空画布

    • 使用 context.clearRect 清除之前的内容,确保每次渲染都是干净的。
  4. 设置画布尺寸

    • <canvas> 的宽高设置为视口的宽高,以匹配 PDF 页面的比例。
7. 渲染 PDF 页面到 Canvas
const renderContext: any = {canvasContext: context,viewport: viewport,
};const renderTask = page.render(renderContext);renderTask.promise.then(() => {console.log('页面渲染完成');setIsLoading(false);}).catch((renderError) => {if (!abortController.signal.aborted) {setError('页面渲染失败: ' + renderError.message);}});
关键点:
  1. renderContext

    • 包含两个主要属性:

      • canvasContext:指向 <canvas> 的 2D 上下文。
      • viewport:定义了渲染区域的尺寸和比例。
  2. page.render

    • 调用 page.render 方法将 PDF 页面渲染到 <canvas> 上。
    • 返回一个 renderTask 对象,包含一个 promise,用于监听渲染完成或失败的状态。
  3. 渲染完成后的回调

    • 当渲染成功时,将 isLoading 设置为 false,隐藏加载提示。
    • 如果渲染失败,则记录错误信息。
8. 错误处理
.catch((error) => {if (!abortController.signal.aborted) {setError('PDF加载失败: ' + error.message);console.error('Error loading PDF:', error);}
})
.finally(() => {if (!abortController.signal.aborted) {setIsLoading(false);}
});
关键点:
  1. 捕获加载错误

    • 如果 PDF 加载失败(如 URL 错误或网络问题),则设置错误信息并打印日志。
  2. finally

    • 无论成功还是失败,都会执行 finally 块。
    • 确保即使发生错误,isLoading 也会被重置为 false,避免加载状态卡住。
9. 清理逻辑
return () => {abortController.abort();const canvas = canvasRef.current;if (canvas) {const context = canvas.getContext('2d');context?.clearRect(0, 0, canvas.width, canvas.height);}
};
关键点:
  1. 取消加载任务

    • abortController.abort() 中断正在进行的 PDF 加载任务,避免资源浪费。
  2. 清理画布

    • 在组件卸载时清除 <canvas> 的内容,确保没有残留的绘制数据。

2. 打印功能实现

效果展示:

在这里插入图片描述

 // 打印 PDF 页面const handlePrint = () => {const canvas = canvasRef.current;if (canvas) {// 创建隐藏的iframeconst iframe = document.createElement('iframe');iframe.style.display = 'none';document.body.appendChild(iframe);// 将canvas内容转换为图片const imgData = canvas.toDataURL('image/png');const printDocument = iframe.contentWindow?.document;if (printDocument) {printDocument.open();printDocument.write(`<html><head><title>Print</title></head><body style="margin: 0;"><img src="${imgData}" style="width: 100%; height: auto;" /></body></html>`);printDocument.close();// 延迟执行打印以确保内容加载setTimeout(() => {iframe.contentWindow?.print();document.body.removeChild(iframe);}, 500);}}};
  • 获取 <canvas> 内容:将画布内容转换为 Base64 编码的图片数据。
  • 创建隐藏的 <iframe> :提供一个独立的文档环境,用于打印特定内容。
  • <iframe> 中写入 HTML:将图片嵌入到 <iframe> 的文档中。
  • 触发打印:延迟调用浏览器的打印功能,并在完成后清理 <iframe>
1. 函数定义
const handlePrint = () => { ... }
  • 这是一个 React 组件中的方法,用于处理 PDF 页面的打印操作。
  • 当用户点击“打印”按钮时,会调用这个函数。

2. 获取 <canvas> 元素
const canvas = canvasRef.current;
if (canvas) { ... }
  • 使用 canvasRef.current 获取当前组件中引用的 <canvas> 元素。
  • 如果 <canvas> 存在,则继续执行打印逻辑;否则直接退出。
3. 创建隐藏的 <iframe>
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
关键点:
  1. 为什么使用 <iframe>

    • 浏览器的打印功能通常会打印整个页面的内容。为了只打印特定内容(如 <canvas> 的内容),我们将其封装到一个隐藏的 <iframe> 中。
    • <iframe> 是一个独立的文档环境,不会影响主页面的内容。
  2. 隐藏 <iframe>

    • 设置 iframe.style.display = 'none' 将其隐藏,避免用户看到额外的 UI 元素。
  3. 添加到 DOM

    • 使用 document.body.appendChild(iframe)<iframe> 添加到页面的 DOM 树中。
4. <canvas> 内容转换为图片
const imgData = canvas.toDataURL('image/png');
关键点:
  1. toDataURL 方法

    • <canvas> 提供了 toDataURL 方法,可以将画布内容转换为 Base64 编码的图片数据。
    • 参数 'image/png' 指定输出的图片格式为 PNG。
  2. Base64 图片数据

    • imgData 是一个字符串,包含图片的 Base64 编码。例如:

      data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
      
5. <iframe> 中写入 HTML 内容
const printDocument = iframe.contentWindow?.document;
if (printDocument) {printDocument.open();printDocument.write(`<html><head><title>Print</title></head><body style="margin: 0;"><img src="${imgData}" style="width: 100%; height: auto;" /></body></html>`);printDocument.close();
}
关键点:
  1. 获取 <iframe> 的文档对象

    • iframe.contentWindow?.document 获取 <iframe>document 对象。
    • 使用可选链操作符 ?. 确保 contentWindow 存在。
  2. 写入 HTML 内容

    • 调用 printDocument.open() 打开文档流。

    • 使用 printDocument.write() 向文档中写入 HTML 内容。

    • 写入的内容包括:

      • 一个 <img> 标签,其 src 属性设置为 Base64 图片数据。
      • 样式设置为 width: 100%height: auto,确保图片自适应打印区域。
    • 调用 printDocument.close() 关闭文档流。


6. 延迟执行打印
setTimeout(() => {iframe.contentWindow?.print();document.body.removeChild(iframe);
}, 500);
关键点:
  1. 延迟执行

    • 使用 setTimeout 延迟 500 毫秒后再执行打印操作。
    • 这是为了确保 <iframe> 中的内容已经完全加载,避免打印时出现空白或不完整的情况。
  2. 触发打印

    • 调用 iframe.contentWindow?.print() 触发浏览器的打印对话框。
    • 用户可以选择打印机或保存为 PDF。
  3. 清理 <iframe>

    • 打印完成后,使用 document.body.removeChild(iframe) 从 DOM 中移除 <iframe>,释放资源。

3. 下载功能实现

<canvas> 中的内容转换为图片,并提供下载功能。用户点击“下载”按钮后,会触发这个函数,将画布内容保存为 PNG 文件。

效果展示:

在这里插入图片描述

// 下载 PDF 页面const handleDownload = () => {const canvas = canvasRef.current;if (canvas) {const imgData = canvas.toDataURL('image/png');const fileName = pdfUrl.split('/').pop()?.replace(/\.pdf$/i, '') || 'download';const link = document.createElement('a');link.download = `${fileName}.png`;link.href = imgData;document.body.appendChild(link);link.click();document.body.removeChild(link);}}
  • 获取 <canvas> 内容:将画布内容转换为 Base64 编码的图片数据。
  • 生成文件名:根据 pdfUrl 提取文件名,并移除 .pdf 后缀。
  • 创建下载链接:动态生成一个 <a> 元素,并设置其 hrefdownload 属性。
  • 触发下载:通过模拟点击事件触发浏览器的下载功能,并在完成后清理 DOM。
1. 函数定义
const handleDownload = () => { ... }
  • 这是一个 React 组件中的方法,用于处理 PDF 页面的下载操作。
  • 当用户点击“下载”按钮时,会调用这个函数。
2. 获取 <canvas> 元素
const canvas = canvasRef.current;
if (canvas) { ... }
  • 使用 canvasRef.current 获取当前组件中引用的 <canvas> 元素。
  • 如果 <canvas> 存在,则继续执行下载逻辑;否则直接退出。
3. <canvas> 内容转换为图片
const imgData = canvas.toDataURL('image/png');
关键点:
  1. toDataURL 方法

    • <canvas> 提供了 toDataURL 方法,可以将画布内容转换为 Base64 编码的图片数据。
    • 参数 'image/png' 指定输出的图片格式为 PNG。
  2. Base64 图片数据

    • imgData 是一个字符串,包含图片的 Base64 编码。例如:

      data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
      
4. 生成文件名
const fileName = pdfUrl.split('/').pop()?.replace(/.pdf$/i, '') || 'download';
关键点:
  1. 提取文件名

    • pdfUrl.split('/')pdfUrl/ 分隔成数组。
    • .pop() 获取数组的最后一个元素,通常是文件名(如 example.pdf)。
  2. 移除 .pdf 后缀

    • .replace(/.pdf$/i, '') 使用正则表达式将文件名中的 .pdf 后缀替换为空字符串。

    • /.pdf$/i 的含义:

      • . 匹配点号(. 是特殊字符,需要用反斜杠转义)。
      • pdf 匹配字符串 “pdf”。
      • $ 表示匹配字符串的结尾。
      • i 表示忽略大小写。
  3. 默认文件名

    • 如果 pdfUrl 为空或无法提取文件名,则使用默认值 'download'
5. 创建下载链接
const link = document.createElement('a');
link.download = `${fileName}.png`;
link.href = imgData;
关键点:
  1. 创建 <a> 元素

    • document.createElement('a') 创建一个 HTML 锚点(<a>)元素。
    • 这个元素用于模拟下载行为。
  2. 设置下载属性

    • link.download = ${fileName}.png` 设置下载文件的名称。
    • 例如,如果 fileNameexample,则下载的文件名为 example.png
  3. 设置链接地址

    • link.href = imgData 将 Base64 图片数据赋值给 href 属性。
    • 浏览器会将其识别为一个可下载的资源。
6. 触发下载
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
关键点:
  1. 添加到 DOM

    • 使用 document.body.appendChild(link)<a> 元素临时添加到页面的 DOM 树中。
    • 这是为了确保浏览器能够识别并触发下载行为。
  2. 触发点击事件

    • 调用 link.click() 模拟用户点击下载链接。
    • 浏览器会自动开始下载文件。
  3. 清理 DOM

    • 使用 document.body.removeChild(link) 从 DOM 中移除 <a> 元素。
    • 避免页面上留下多余的元素。

总结

本文实现的 PDF 查看器具有以下特点:

特性实现方案优势
按需加载首屏仅加载第一页快速呈现
打印/下载Canvas 转图片方案跨浏览器兼容性好
错误恢复状态隔离 + 错误边界增强组件健壮性
内存安全AbortController + 清理函数防止内存泄漏

该方案为基本的 PDF 预览需求提供了可靠实现,开发者可根据具体业务场景进行扩展优化。对于需要完整 PDF 功能(如文本选择、表单填写等)的场景,建议结合 PDF.js 的完整功能 API 进行深度定制。


完整代码:

import React, { useEffect, useRef, useState } from 'react';
import { getDocument } from 'pdfjs-dist';
import { GlobalWorkerOptions } from 'pdfjs-dist';
import { Button } from 'antd';// 设置 Worker 文件路径
GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';// 为 pdfUrl 参数添加 string 类型注解,解决隐式 any 类型问题
const PDFViewer = ({ pdfUrl }: { pdfUrl: string }) => {const canvasRef = useRef<HTMLCanvasElement>(null);const [isLoading, setIsLoading] = useState(true);const [error, setError] = useState<string | null>(null);// 打印 PDF 页面const handlePrint = () => {const canvas = canvasRef.current;if (canvas) {// 创建隐藏的iframeconst iframe = document.createElement('iframe');iframe.style.display = 'none';document.body.appendChild(iframe);// 将canvas内容转换为图片const imgData = canvas.toDataURL('image/png');const printDocument = iframe.contentWindow?.document;if (printDocument) {printDocument.open();printDocument.write(`<html><head><title>Print</title></head><body style="margin: 0;"><img src="${imgData}" style="width: 100%; height: auto;" /></body></html>`);printDocument.close();// 延迟执行打印以确保内容加载setTimeout(() => {iframe.contentWindow?.print();document.body.removeChild(iframe);}, 500);}}};// 下载 PDF 页面const handleDownload = () => {const canvas = canvasRef.current;if (canvas) {const imgData = canvas.toDataURL('image/png');const fileName = pdfUrl.split('/').pop()?.replace(/\.pdf$/i, '') || 'download';const link = document.createElement('a');link.download = `${fileName}.png`;link.href = imgData;document.body.appendChild(link);link.click();document.body.removeChild(link);}}// 加载 PDF 并渲染到 canvasuseEffect(() => {const abortController = new AbortController();if (!pdfUrl) return;setIsLoading(true);setError(null);getDocument(pdfUrl).promise.then((pdf) => {if (abortController.signal.aborted) return;console.log('PDF loaded');// 获取第一页pdf.getPage(1).then((page) => {if (abortController.signal.aborted) {page.cleanup();return;}console.log('Page 1 loaded');const scale = 1.5;const viewport = page.getViewport({ scale });if (!canvasRef.current) {throw new Error('Canvas element not found');}const canvas = canvasRef.current;const context = canvas.getContext('2d');// 清除之前的画布内容context?.clearRect(0, 0, canvas.width, canvas.height);canvas.height = viewport.height;canvas.width = viewport.width;console.log('Canvas尺寸设置:', canvas.width, 'x', canvas.height);// 渲染 PDF 页面到 canvasconst renderContext: any = {canvasContext: context,viewport: viewport,};const renderTask = page.render(renderContext);renderTask.promise.then(() => {console.log('页面渲染完成');setIsLoading(false);}).catch((renderError) => {if (!abortController.signal.aborted) {setError('页面渲染失败: ' + renderError.message);}});});}).catch((error) => {if (!abortController.signal.aborted) {setError('PDF加载失败: ' + error.message);console.error('Error loading PDF:', error);}}).finally(() => {if (!abortController.signal.aborted) {setIsLoading(false);}});return () => {abortController.abort();const canvas = canvasRef.current;if (canvas) {const context = canvas.getContext('2d');context?.clearRect(0, 0, canvas.width, canvas.height);}};}, [pdfUrl]);return (<div style={{ position: 'relative', width: '100%' }}><Button onClick={handlePrint}>打印</Button><Button onClick={handleDownload}>下载</Button>{isLoading && <div>加载中...</div>}{error && <div style={{ color: 'red' }}>{error}</div>}<div id="printPdfButton"></div><canvaskey={pdfUrl}ref={canvasRef}style={{ width: '100%', height: 'auto' }}/></div>);
};export default PDFViewer;

使用此组件:

import React from "react";
import "./index.less";
import PDFViewer from "./PDFViewer";const ImgePage = () => {return (<divstyle={{ height: "80vh", border: "1px solid #ddd", position: "relative" }}><PDFViewerpdfUrl={"https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf"}/></div>);
};export default ImgePage;

相关文章:

如何在React中集成 PDF.js?构建支持打印下载的PDF阅读器详解

本文深入解析基于 React 和 PDF.js 构建 PDF 查看器的实现方案&#xff0c;该组件支持 PDF 渲染、图片打印和下载功能&#xff0c;并包含完整的加载状态与错误处理机制。 完整代码在最后 一个PDF 文件&#xff1a; https://mozilla.github.io/pdf.js/web/compressed.tracemo…...

【完美解决】VSCode连接HPC节点,已配置密钥却还是提示需要输入密码

目录 问题描述软件版本原因分析错误逻辑链 解决方案总结 问题描述 本人在使用 ​​VSCode Remote-SSH 插件​​连接超算集群节点时&#xff0c;遇到以下问题&#xff1a;已正确配置 SSH 密钥&#xff0c;且 VSCode 能识别密钥文件&#xff08;如图1&#xff09;&#xff0c;但在…...

智能DNS解析:解决高防IP地区访问异常的实战指南

摘要&#xff1a;针对高防IP在部分地区无法访问的问题&#xff0c;本文设计基于智能DNS的流量调度方案&#xff0c;提供GeoDNS配置与故障切换代码示例。 一、问题背景 运营商误拦截或线路波动可能导致高防IP在福建、江苏等地访问异常。传统切换方案成本高&#xff0c;智能DNS可…...

【JSON2WEB】16 login.html 登录密码加密传输

【JSON2WEB】系列目录 【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSO…...

ruby超高级语法

以下是 Ruby 中一些 极度硬核 的语法和底层特性&#xff0c;涉及元编程的深渊、虚拟机原理、语法黑魔法等&#xff0c;适用于追求极限的 Ruby 开发者&#xff1a; 高级语法一 一、语法核弹级操作 1. 动态修改继承链 class A; def foo; "A"; end end class B; def …...

第十二天 - Flask/Django基础 - REST API开发 - 练习:运维管理后台API

从零开始用Flask/Django构建运维管理后台API&#xff08;实战指南&#xff09; 前言&#xff1a;为什么选择Python Web框架&#xff1f; 在运维自动化领域&#xff0c;构建管理后台是每个运维工程师的必修课。本文将通过Flask和Django两个主流框架&#xff0c;手把手教你构建…...

Docker 容器内运行程序的性能开销

在 Docker 容器内运行程序通常会有一定的性能开销&#xff0c;但具体损失多少取决于多个因素。以下是详细分析&#xff1a; 1. CPU 性能 理论开销&#xff1a;容器直接共享宿主机的内核&#xff0c;CPU 调度由宿主机管理&#xff0c;因此 CPU 运算性能几乎与原生环境一致&…...

从递归入手一维动态规划

从递归入手一维动态规划 1. 509. 斐波那契数 1.1 思路 递归 F(i) F(i-1) F(i-2) 每个点都往下展开两个分支&#xff0c;时间复杂度为 O(2n) 。 在上图中我们可以看到 F(6) F(5) F(4)。 计算 F(6) 的时候已经展开计算过 F(5)了。而在计算 F(7)的时候&#xff0c;还需要…...

【2025年认证杯数学中国数学建模网络挑战赛】A题解题思路与模型代码

【2025年认证杯数学建模挑战赛】A题 该题为典型的空间几何建模轨道动力学建模预测问题。 ⚙ 问题一&#xff1a;利用多个天文台的同步观测&#xff0c;确定小行星与地球的相对距离 问题分析 已知若干地面天文台的观测数据&#xff1a;方位角 (Azimuth) 和 高度角 (Altitude)&…...

蓝桥杯备赛 Day16 单调数据结构

单调栈和单调队列能够动态的维护&#xff0c;还需用1-2两个数组在循环时从单调栈和单调队列中记录答案 单调栈 要点 1.时刻保持内部元素具有单调性质的栈(先进后出),核心是:入栈时逐个删除所有"更差的点",一般可分为单调递减栈、单调递增栈、单调不减栈、单调不增…...

轻量级爬虫框架Feapder入门:快速搭建企业级数据管道

一、目标与前置知识 1. 目标概述 本教程的主要目标是&#xff1a; 介绍轻量级爬虫框架 Feapder 的基本使用方式。快速搭建一个采集豆瓣电影数据的爬虫&#xff0c;通过电影名称查找对应的电影详情页并提取相关信息&#xff08;电影名称、导演、演员、剧情简介、评分&#xf…...

golang gmp模型分析

思维导图&#xff1a; 1. 发展过程 思维导图&#xff1a; 在单机时代是没有多线程、多进程、协程这些概念的。早期的操作系统都是顺序执行 单进程的缺点有&#xff1a; 单一执行流程、计算机只能一个任务一个任务进行处理进程阻塞所带来的CPU时间的浪费 处于对CPU资源的利用&…...

深入理解Java Optional:告别NullPointerException的优雅方式

大家好&#xff01;今天我们来聊聊Java 8引入的一个超实用类 - Optional。不是那个让你重启电脑的CtrlAltDel哦&#xff01;&#x1f604; 这是一个能让我们优雅处理null值的工具类&#xff0c;彻底告别烦人的NullPointerException&#xff01; 一、为什么需要Optional&#x…...

【算法竞赛】树上最长公共路径前缀(蓝桥杯2024真题·团建·超详细解析)

目录 一、题目 二、思路 1. 问题转化&#xff1a;同步DFS走树 2. 优化&#xff1a;同步DFS匹配 3. 状态设计&#xff1a;dfs参数含义 4. 匹配过程&#xff1a;用 map 建立权值索引 5. 终止条件&#xff1a;无法匹配则更新答案 6. 总结 三、完整代码 四、知识点总…...

【windows10】基于SSH反向隧道公网ip端口实现远程桌面

【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 ‌Windows 10远程桌面协议的简称是RDP&#xff08;Remote Desktop Protocol&#xff09;‌。 RDP是一种网络协议&#xff0c;允许用户远程访问和操作另一台计算机。 远程桌面功…...

Python----概率论与统计(贝叶斯,朴素贝叶斯 )

一、贝叶斯 1.1、贝叶斯定理 贝叶斯定理&#xff08;Bayes Theorem&#xff09;也称贝叶斯公式&#xff0c;是关于随机事件的条件概率的定理 贝叶斯的的作用&#xff1a;根据已知的概率来更新事件的概率。 1.2、定理内容 提示&#xff1a; 贝叶斯定理是“由果溯因”的推断&…...

NO.88十六届蓝桥杯备战|动态规划-多重背包|摆花(C++)

多重背包 多重背包问题有两种解法&#xff1a; 按照背包问题的常规分析⽅式&#xff0c;仿照完全背包&#xff0c;第三维枚举使⽤的个数&#xff1b;利⽤⼆进制可以表⽰⼀定范围内整数的性质&#xff0c;转化成01 背包问题。 ⼩建议&#xff1a;并不是所有的多重背包问题都能…...

vue项目打包里面pubilc里的 tinymce里的js文件问题

以下是解决 Vue 项目打包后 public/tinymce 中 JS 文件路径问题的完整方案&#xff1a; 问题原因 当使用 public 目录存放静态资源时&#xff0c;Vue CLI 默认会将 public 下的文件 直接复制到打包目录的根路径&#xff0c;但以下操作可能导致路径错误&#xff1a; 开发环境使…...

Python星球日记 - 第18天:小游戏开发(猜数字游戏)

🌟引言: 上一篇:Python星球日记 - 第17天:数据可视化 名人说:路漫漫其修远兮,吾将上下而求索。(屈原《离骚》) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、游戏概述与原理1. 游戏基本规则2. 编程知识点3.猜数字游戏流程图二、游戏逻辑设计…...

爬虫抓包工具和PyExeJs模块

我们在处理一些网站的时候, 会遇到一些屏蔽F12, 以及只要按出浏览器的开发者工具就会关闭甚至死机的现象. 在遇到这类网站的时候. 我们可以使用抓包工具把页面上屏蔽开发者工具的代码给干掉. Fiddler和Charles 这两款工具是非常优秀的抓包工具. 他们可以监听到我们计算机上所…...

无人机击落技术难点与要点分析!

一、技术难点 1. 目标探测与识别 小型化和低空飞行&#xff1a;现代无人机体积小、飞行高度低&#xff08;尤其在城市或复杂地形中&#xff09;&#xff0c;雷达和光学传感器难以有效探测。 隐身技术&#xff1a;部分高端无人机采用吸波材料或低可探测设计&#xff0c;进…...

2025年Java无服务器架构实战:AWS Lambda与Spring Cloud Function深度整合

摘要 &#x1f4dd; 本文深入探讨如何在2025年Java生态中实现AWS Lambda与Spring Cloud Function的无缝整合。我们将从基础概念讲起&#xff0c;逐步深入到实际部署、性能优化和最佳实践&#xff0c;通过详实的代码示例展示如何构建高效、可扩展的无服务器Java应用。 目录 &a…...

LeetCode 题目 「二叉树的右视图」 中,如何从「中间存储」到「一步到位」实现代码的优化?

背景简介 在 LeetCode 的经典题目 「二叉树的右视图」 中&#xff0c;我们需要返回从右侧看一棵二叉树时所能看到的节点集合。每一层我们只能看到最右边的那个节点。 最初&#xff0c;我采用了一个常规思路&#xff1a;层序遍历 每层单独保存节点值 最后提取每层最后一个节…...

8.第二阶段x64游戏实战-string类

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;7.第二阶段x64游戏实战-分析人物属性 string类是字符串类&#xff0c;在计算机中…...

Go语言sync.Mutex包源码解读

互斥锁sync.Mutex是在并发程序中对共享资源进行访问控制的主要手段&#xff0c;对此Go语言提供了非常简单易用的机制。sync.Mutex为结构体类型&#xff0c;对外暴露Lock()、Unlock()、TryLock()三种方法&#xff0c;分别用于阻塞加锁、解锁、非阻塞加锁操作&#xff08;加锁失败…...

C++实现文件断点续传:原理剖析与实战指南

文件传输示意图 一、断点续传的核心价值 1.1 大文件传输的痛点分析 网络闪断导致重复传输&#xff1a;平均重试3-5次。 传输进度不可回溯&#xff1a;用户无法查看历史进度。 带宽利用率低下&#xff1a;每次中断需从头开始。 1.2 断点续传技术优势 指标传统传输断点续传…...

MySQL中FIND_IN_SET函数与INSTR函数用法解析

一、功能定义与语法 1、FIND_IN_SET函数 语法&#xff1a;FIND_IN_SET(str, strlist) 功能&#xff1a;在逗号分隔的字符串列表&#xff08;strlist&#xff09;中查找精确匹配的子字符串&#xff08;str&#xff09;&#xff0c;并返回其位置&#xff08;从1开始&#xff09…...

Python贝叶斯回归、强化学习分析医疗健康数据拟合截断删失数据与参数估计3实例

全文链接&#xff1a;https://tecdat.cn/?p41391 在当今数据驱动的时代&#xff0c;数据科学家面临着处理各种复杂数据和构建有效模型的挑战。本专题合集聚焦于有序分类变量处理、截断与删失数据回归分析以及强化学习模型拟合等多个重要且具有挑战性的数据分析场景&#xff0c…...

Git 协同开发的常用操作

1. 单仓库&#xff08;多分支开发&#xff09; 从远程拉取代码 git clone https://gitee.com/...查看当前分支 git branch -- *master创建并切换到你的开发分支&#xff08;my-dev&#xff09; git checkout -b my-dev查看当前分支 git branch -- marster -- *my-dev提交代…...

微信小程序 -- 原生封装table

文章目录 table.wxmltable.wxss注意 table.js注意 结果数据结构 最近菜鸟做微信小程序的一个查询功能&#xff0c;需要展示excel里面的数据&#xff0c;但是菜鸟找了一圈&#xff0c;也没发现什么组件库有table&#xff0c;毕竟手机端好像确实不太适合做table&#xff01; 菜鸟…...