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

pdf 转html 在线预览和查询

方案一:
pdf2htmlex
package com.realize.controller;import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.realize.util.MsgUtil;
import com.realize.util.OssUtil;
import com.realize.util.PdfConvertUtil;
import com.realize.util.StreamGobbler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;@RestController
@Slf4j
public class ParserController {@GetMapping("/test")public String test() {return "test";}//    @PostMapping("/parseHtml")
//    public JSONObject parseHtml(@ModelAttribute("htmlUrl") String htmlUrl) {
//        try (Playwright playwright = Playwright.create()) {
//            Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
//            Page page = browser.newPage();
//            String filePath = "/mnt/temp/html/" + RandomUtil.randomString(10) + ".html";String filePath = "/Users/sunyechen/IdeaProjects/realize-nacos/bin/" + RandomUtil.randomString(10) + ".html";
//            HttpUtil.downloadFile(htmlUrl, filePath);
//            page.navigate("file:" + filePath);
//            page.evaluate("var imgList=document.getElementsByTagName('img');" +
//                    "for(var i=0;i<imgList.length;i++){" +
//                    "var src=imgList[i].getAttribute('src');" +
//                    "imgList[i].setAttribute('src','https://realizedongmi.oss-cn-shanghai.aliyuncs.com/a-filings/test/'+src);" +
//                    "}");
//            JSONObject result = new JSONObject();
//            result.put("html", page.innerHTML("css=body"));
//            result.put("css", page.innerHTML("css=style"));
//            result.put("txt", page.innerText("css=body").trim().replaceAll("\n", ""));
//            page.close();
//            browser.close();
//            return result;
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return null;
//    }@GetMapping("/batchConvertPdf")public String batchConvertPdf() {String folderName = "/root/pdf";File folder = new File(folderName);File[] files = folder.listFiles();for (int i = 0; i < files.length; i++) {String fileName = files[i].getName();if (fileName.toLowerCase().endsWith(".pdf")) {String exec = " docker run -i --rm -v /root/pdf:/pdf -w /pdf docker.io/pdf2htmlex/pdf2htmlex:0.18.8.rc2-master-20200820-ubuntu-20.04-x86_64 --font-size-multiplier 1 --zoom 1.3 " + fileName;try {
//                    Process process = new ProcessBuilder("/bin/sh", "-c", exec).start();
//                    String result = IOUtils.toString(process.getInputStream(), "utf-8");
//                    log.info("Executing Command [result]:{}", result);
//                    Runtime rt = Runtime.getRuntime();log.info("exec:{}", exec);
//                    String[] execArray = new String[]{"/bin/sh", "-c", " docker run -i --rm -v /root/pdf:/pdf -w /pdf docker.io/pdf2htmlex/pdf2htmlex:0.18.8.rc2-master-20200820-ubuntu-20.04-x86_64 --font-size-multiplier 1 --zoom 1.3 ", fileName};Process process = Runtime.getRuntime().exec(exec);StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");// 开启屏幕标准错误流errorGobbler.start();StreamGobbler outGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT");// 开启屏幕标准输出流outGobbler.start();int w = process.waitFor();int v = process.exitValue();if (w == 0 && v == 0) {log.info("转换成功:{}", fileName);} else {log.info("转换失败:{}", fileName);}} catch (Exception e) {log.error("{}", e);return null;}}}return "ok";}@PostMapping("/convertAndParsePdf")public JSONObject convertAndParsePdf(@ModelAttribute("pdfUrl") String pdfUrl, @ModelAttribute("ossKey") String ossKey) throws Exception {log.info("接收到转换请求{},{}", pdfUrl, ossKey);String fileFolder = "/mnt_real/pdf/";JSONObject result = new JSONObject();String tempFileName = ossKey.substring(ossKey.lastIndexOf("/") + 1, ossKey.lastIndexOf("."));String pdfFilePath = fileFolder + tempFileName + ".pdf";String htmlFilePath = fileFolder + tempFileName + ".html";HttpUtil.downloadFile(pdfUrl, pdfFilePath);log.info("pdf文件下载成功{},{}", pdfUrl, ossKey);//解析pdf正文
//        String pdfText = PdfBoxUtil.getPdfText(pdfFilePath);
//        result.put("pdfText", pdfText);
//        log.info("pdfbox正文解析成功{},{}", pdfUrl, ossKey);//解析Boolean convertResult = PdfConvertUtil.convertPdf(tempFileName + ".pdf");if (convertResult) {try {List<String> allLines = Files.readAllLines(Paths.get(htmlFilePath), Charset.forName("UTF-8"));String content = String.join("\n", allLines);
//                File file = new File(htmlFilePath);
//                BufferedReader reader = new BufferedReader(new FileReader(file));
//                String line = "", oldContent = "";
//                while ((line = reader.readLine()) != null) {
//                    oldContent += line + "\n";
//                }
//                reader.close();content = content.replaceAll("github", "zzz").replaceAll("pdf2htmlEX", "tg").replaceAll("<meta charset=\"utf-8\"/>", "<meta charset=\"utf-8\"/><script src=\"https://oss.imvib.com/a-filings/test/test/search.js\" type=\"text/javascript\" charset=\"utf-8\"></script> ");File file = new File(htmlFilePath);file.delete();FileWriter writer = new FileWriter(htmlFilePath);writer.write(content);writer.close();log.info("html文件处理完成{},{}", pdfUrl, ossKey);result.put("code", 0);} catch (IOException e) {e.printStackTrace();result.put("code", -1);} finally {//上传所有文件String ossPath = ossKey.substring(0, ossKey.lastIndexOf("/") + 1);OssUtil.batchFileUploadOssUrl(fileFolder, ossPath);log.info("文件上传成功,完整链接:https://oss.imvib.com/{}", ossKey.replace(".html", ".pdf"));}} else {MsgUtil.sendDingTalkMsg(pdfUrl);result.put("code", -1);}return result;}private static byte[] readAllBytes(File file) throws IOException {try (FileInputStream fileInputStream = new FileInputStream(file)) {byte[] buffer = new byte[(int) file.length()];fileInputStream.read(buffer);return buffer;}}public static void main(String[] args) throws Exception {
//        String htmlFilePath = "/Users/sunyechen/doc/test/矩阵股份:长江证券承销保荐有限公司关于矩阵纵横设计股份有限公司使用募集资金置换预先投入募投项目及已支付发行费用的自筹资金的核查意见.html";
//        File htmlFile = new File(htmlFilePath);
//        Document html = Jsoup.parse(htmlFile);Element script = html.select("script").first();String sourceScript = script.html();script.html(sourceScript + PdfConvertUtil.addScript);
//        FileOutputStream fos = new FileOutputStream(htmlFilePath.replace(".html", "_.html"), false);
//        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
//        osw.write(html.outerHtml());
//        osw.close();
//        try (Playwright playwright = Playwright.create()) {
//            Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
//            BrowserContext context = browser.newContext(new Browser.NewContextOptions());
//            Page page = browser.newPage();
//            String htmlUrl = "https://realizedongmi.oss-cn-shanghai.aliyuncs.com/a-filings/test/2023-01-03%201%20%E5%8F%91%E8%A1%8C%E4%BA%BA%E5%8F%8A%E4%BF%9D%E8%8D%90%E6%9C%BA%E6%9E%84%E5%85%B3%E4%BA%8E%E4%BA%8C%E8%BD%AE%E5%AE%A1%E6%A0%B8%E9%97%AE%E8%AF%A2%E5%87%BD%E7%9A%84%E5%9B%9E%E5%A4%8D%EF%BC%88%E4%BF%AE%E8%AE%A2%E7%A8%BF%EF%BC%89_%E6%98%93%E7%91%9E%E7%94%9F%E7%89%A9.htm";
//            HttpUtil.downloadFile(htmlUrl, "/Users/sunyechen/IdeaProjects/realize-nacos/bin/1.html");
//            page.navigate("file:/Users/sunyechen/IdeaProjects/realize-nacos/bin/1.html");
//            System.out.println(page.innerHTML("body"));
//        }
//        System.out.println(URLDecoder.decode("https://oss.imvib.com/a-filings%252Foriginal%252F000586%252F2023-04-07+%25E5%25B9%25B4%25E5%25BA%25A6%25E5%2585%25B3%25E8%2581%2594%25E6%2596%25B9%25E8%25B5%2584%25E9%2587%2591%25E5%258D%25A0%25E7%2594%25A8%25E4%25B8%2593%25E9%25A1%25B9%25E5%25AE%25A1%25E8%25AE%25A1%25E6%258A%25A5%25E5%2591%258A.PDF", "UTF-8"));
//        try {
//            File file = new File("/Users/sunyechen/doc/test/矩阵股份:长江证券承销保荐有限公司关于矩阵纵横设计股份有限公司使用募集资金置换预先投入募投项目及已支付发行费用的自筹资金的核查意见.html");
//            BufferedReader reader = new BufferedReader(new FileReader(file));
//            String line = "", oldContent = "";
//            while ((line = reader.readLine()) != null) {
//                oldContent += line + "\n";
//            }
//            reader.close();
//            String newContent = oldContent.replaceAll("<meta charset=\"utf-8\"/>", "<meta charset=\"utf-8\"/><script src=\"https://oss.imvib.com/a-filings/test/test/search.js\" type=\"text/javascript\" charset=\"utf-8\"></script> ");
//            FileWriter writer = new FileWriter(new File("/Users/sunyechen/doc/test/矩阵股份:长江证券承销保荐有限公司关于矩阵纵横设计股份有限公司使用募集资金置换预先投入募投项目及已支付发行费用的自筹资金的核查意见_1.html"));
//            writer.write(newContent);
//            writer.close();
//            System.out.println("File updated successfully.");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        log.info("start");
//        String htmlFilePath = "/Users/sunyechen/sfit/7745c98a5ba34525937bce19519c0b1e.html";
//        try {
//            File file = new File(htmlFilePath);
//            BufferedReader reader = new BufferedReader(new FileReader(file));
//            String line = "", oldContent = "";
//            while ((line = reader.readLine()) != null) {
//                oldContent += line + "\n";
//            }
//            reader.close();
//            String newContent = oldContent.replaceAll("github", "zzz").replaceAll("pdf2htmlEX", "tanqiuhuashigou").replaceAll("<meta charset=\"utf-8\"/>", "<meta charset=\"utf-8\"/><script src=\"https://oss.imvib.com/a-filings/test/test/search.js\" type=\"text/javascript\" charset=\"utf-8\"></script> ");
//            String newHtmlFilePath = htmlFilePath.replace(".html", "_.html");
//            FileWriter writer = new FileWriter(newHtmlFilePath);
//            writer.write(newContent);
//            writer.close();
//            log.info("html文件处理完成{},{}");
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }log.info("start");
//        String ossKey = "ann/688249/2023/4/688249_20230412_9XYK/688249_20230412_9XYK.html";
//        String ossPath = ossKey.substring(0, ossKey.lastIndexOf("/") + 1);
//        OssUtil.batchFileUploadOssUrl("/Users/sunyechen/sfit/test/", ossPath);
//        File[] fileList = new File("/Users/sunyechen/sfit/test/").listFiles();
//        for (int i = 0; i < fileList.length; i++) {
//            OssUtil.fileUploadOssUrl(fileList[i], ossPath + fileList[i].getName());
//            fileList[i].delete();
//        }String htmlFilePath = "/Users/sunyechen/sfit/test/600499_20230415_EVH7.html";List<String> allLines = Files.readAllLines(Paths.get(htmlFilePath), Charset.forName("UTF-8"));String content = String.join("\n", allLines);System.out.println(content);log.info("start");File file = new File(htmlFilePath);BufferedReader reader = new BufferedReader(new FileReader(file));String line = "", oldContent = "";while ((line = reader.readLine()) != null) {oldContent += line + "\n";}reader.close();System.out.println(oldContent);log.info("end");}}

方案二:

kkFileView-4.0.0

kkFileView - 在线文件预览

方案三:

wkhtmltox-0.12.6-1.centos7.x86_64.rpm

wkhtmltopdf 

相关文章:

pdf 转html 在线预览和查询

方案一&#xff1a;pdf2htmlex package com.realize.controller;import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSONObject; import com.realize.util.MsgUtil; import com.realize.util.OssUtil; import com.realize.util.PdfConvertUtil; import com.reali…...

docker 体验怀旧游戏(魂斗罗等)

docker run --restart always -p 8081:80 --name fc-games -d registry.cn-hangzhou.aliyuncs.com/bystart/fc-games:latest ip:8081访问 jsnes: js制作了一个网页版的NES模拟&#xff0c;可以在网页上玩fc游戏 (gitee.com)...

JS中判断数据类型总结以及方法封装

判断数据类型封装方法&#xff1a; 1&#xff09;type返回字符串类型 2&#xff09;is开头返回Boolean类型 测试实例&#xff1a; JavaScript 判断数据类型的方式共有四种 typeofinstanceofconstructorObject.prototype.toString typeof typeof 操作符返回一个字符串,表示操…...

【Midjourney】绘画风格关键词

1.松散素描(Loose Sketch) "Loose sketch"&#xff08;松散素描&#xff09;通常指的是一种艺术或设计中的手绘风格&#xff0c;其特点是线条和形状的表现相对宽松、自由&#xff0c;没有过多的细节和精确度。这样的素描通常用于表达创意、捕捉概念或者作为设计的初步…...

教你如何低成本自建「幻兽帕鲁」服务器,快速一键部署

创建幻兽帕鲁服务器1分钟部署教程&#xff0c;阿里云和腾讯云均推出幻兽帕鲁服务器服务器和部署教程&#xff0c;4核16G和4核32G配置可选&#xff0c;阿腾云atengyun.com分享1分钟自建幻兽帕鲁Palworld服务器教程&#xff1a; 幻兽帕鲁服务器创建教程 幻兽帕鲁服务器官方推荐…...

拥抱社交电商浪潮:微信小程序商城崛起引领电商新风向-亿发

在经过多年的发展后&#xff0c;各大传统电商平台的流量增速基本上已经见顶。同时&#xff0c;新兴的带有社交性质的电商平台&#xff0c;如抖音、小红书和微信商城&#xff08;小程序商城&#xff09;等&#xff0c;使得传统中心化平台的流量关注度逐渐分散。由于中心化平台需…...

一个使用pyqt的word文档查重工具

一个使用pyqt的word文档查重工具 使用场景代码使用截图打包好的软件下载链接结尾 使用场景 有时我们在借鉴一篇文档之后还不想有太多重复&#xff0c;这个时候可以使用这个工具对两个word文档进行对比 代码 import sys from PyQt5.QtWidgets import QApplication, QMainWind…...

SpringCloud Alibaba Sentinel 与 SpringCloud Gateway 的限流有什么差别?(三种限流算法原理分析)

目录 一、Sentinel 与 Gateway 的限流有什么差别&#xff1f; 1.1、前置知识 - 四种常见的限流算法 1.1.1、Tips 1.1.2、计数器算法 1&#xff09;固定窗口计数器算法 2&#xff09;滑动窗口计数器算法 1.1.3、令牌桶算法 1.1.4、漏桶算法 1.2、解决问题 一、Sentinel…...

邦芒忠告:职场新人最需要避开的十大雷坑

职场人最害怕的就是踩雷进坑&#xff0c;很多新入职场的小白都会战战兢兢&#xff0c;生怕哪里不对&#xff0c;冒犯了哪一位&#xff0c;或者触犯了哪一条潜规则。害怕自己踩到雷&#xff0c;没有走好职场第一步。最近&#xff0c;单位进了几个新人&#xff0c;看到他们就想起…...

MySQL-进阶-索引

一、索引概述 1、介绍 2、有误索引搜索效率演示 3、优缺点 二、索引结构 1、B-Tree&#xff08;多路平衡查找树&#xff09; 2、BTree 3、Hash 三、索引分类 四、索引语法 1、语法 2、案例 五、SQL性能分析 1、查看执行频次 2、慢查询日志 3、show-profile 4、explain...

GitLab入门指南:上传与下载操作一网打尽

GitLab简介&#xff1a; GitLab是一个基于Git的开源仓库管理系统&#xff0c;提供了一个Web界面的Git存储库管理器&#xff0c;并集成了多种开发工具的功能&#xff0c;如代码审查、问题跟踪、持续集成和持续部署等。GitLab可以在本地服务器上部署&#xff0c;也可以使用其提供…...

GPT应用_PrivateGPT

项目地址&#xff1a;https://github.com/imartinez/privateGPT 1 功能 1.1 整体功能&#xff0c;想解决什么问题 搭建完整的 RAG 系统&#xff0c;与 FastGPT 相比&#xff0c;界面比较简单。但是底层支持比较丰富&#xff0c;可用于知识库的完全本地部署&#xff0c;包含大…...

Qt‘s 撤销框架(Qt‘s Undo Framework)

一、开篇序言 我们常常有这样的业务场景,需要支持撤回的动作(即 undo)。如果让你来设计,聪明的你肯定也能立即想到解决问题的办法,对,将操作的 command { 对象,指令,属性 } 保存到一个容器中。 如果是仅需要单步撤销, 使用栈容器 保存command,动作执行即指令入栈, …...

【C++】stack、queue的使用及模拟实现

目录 一、stack1.1 stack的使用1.2 stack的模拟实现 二、queue2.1 queue的使用2.2 queue的模拟实现 一、stack 1.1 stack的使用 stack是一种容器适配器&#xff0c;它的特点是后进先出&#xff0c;只能在容器的一端进行插入和删除操作。 stack的使用很简单&#xff0c;主要有…...

外包干了2个多月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...

html5实现好看的年会邀请函源码模板

文章目录 1.设计来源1.1 邀请函主界面1.2 诚挚邀请界面1.3 关于我们界面1.4 董事长致词界面1.5 公司合作方界面1.6 活动流程界面1.7 加盟支持界面1.8 加盟流程界面1.9 加盟申请界面1.10 活动信息界面 2.效果和源码2.1 动态效果2.2 源码目录结构 源码下载 作者&#xff1a;xcLei…...

【C++】反向迭代器模拟实现

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.利用适配器的思想…...

【低照度图像增强系列(5)】Zero-DCE算法详解与代码实现(CVPR 2020)

前言 ☀️ 在低照度场景下进行目标检测任务&#xff0c;常存在图像RGB特征信息少、提取特征困难、目标识别和定位精度低等问题&#xff0c;给检测带来一定的难度。 &#x1f33b;使用图像增强模块对原始图像进行画质提升&#xff0c;恢复各类图像信息&#xff0c;再使用目标…...

三维重建衡量指标记录

1、完整性比率 Completeness Rati (CR) 完整性比率 完整性比率是用于评估三维重建质量的指标之一&#xff0c;它衡量了重建结果中包含的真实物体表面或点云的百分比。完整性比率通常是通过比较重建结果中的点云或三维模型与真实或标准点云或模型之间的重叠来计算的。 具体计算…...

在WinForms中控制模态对话框的关闭行为

博客文章&#xff1a;在WinForms中控制模态对话框的关闭行为 引言 在Windows Forms (WinForms) 应用程序中&#xff0c;对话框的行为控制是提升用户体验的关键部分。特别是在使用模态对话框时&#xff0c;防止用户不经意间关闭它变得尤为重要。本文将探讨如何通过重写 FormClo…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...