vue+elementUI+springboot实现文件合并前端展示文件类型

news2025/6/7 17:05:33

项目场景:

element的table上传文件并渲染出文件名称点击所属行可以查看文件,并且可以导出合并文件,此文章是记录合并文档前端展示的帖子


解决方案:

后端定义三个工具类
分别是pdf,doc和word的excle的目前我没整
 

word的工具类

package com.sc.modules.biddinvestment.utils;

import org.apache.poi.xwpf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class WordMerger {
    private static final Logger logger = LoggerFactory.getLogger(WordMerger.class);

    public String mergeWordDocuments(List<String> filePaths) throws IOException {
        validateFiles(filePaths);
        XWPFDocument mergedDoc = new XWPFDocument();

        try {
            for (String filePath : filePaths) {
                addFileToDocument(mergedDoc, filePath);
            }
            return saveMergedDocument(mergedDoc);
        } finally {
            mergedDoc.close();
        }
    }

    private void addFileToDocument(XWPFDocument mergedDoc, String filePath) throws IOException {
        File file = new File(filePath);
        addSectionTitle(mergedDoc, file.getName());

        if (filePath.toLowerCase().endsWith(".txt")) {
            addTxtContent(mergedDoc, file);
        } else if (filePath.toLowerCase().endsWith(".docx")) {
            addDocxContent(mergedDoc, file);
        } else {
            throw new IllegalArgumentException("暂不支持的文件格式: " + filePath);
        }
    }

    private void addSectionTitle(XWPFDocument doc, String fileName) {
        XWPFParagraph titlePara = doc.createParagraph();
        titlePara.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun titleRun = titlePara.createRun();
//        titleRun.setText("===== 文件: " + fileName + " ====="); //添加上之后文档名称会出现在合并后的文档里
        titleRun.setFontSize(14);
        titleRun.setBold(true);
        titleRun.addBreak();
    }

    private void addTxtContent(XWPFDocument doc, File txtFile) throws IOException {
        List<String> lines = Files.readAllLines(txtFile.toPath());
        XWPFParagraph para = doc.createParagraph();
        XWPFRun run = para.createRun();
        for (String line : lines) {
            run.setText(line);
            run.addBreak();
        }
        run.addBreak(); // 段落间隔
    }

    private void addDocxContent(XWPFDocument mergedDoc, File docxFile) throws IOException {
        try (XWPFDocument sourceDoc = new XWPFDocument(new FileInputStream(docxFile))) {
            for (XWPFParagraph para : sourceDoc.getParagraphs()) {
                XWPFParagraph newPara = mergedDoc.createParagraph();
                newPara.getCTP().set(para.getCTP()); // 复制段落格式
            }
            for (XWPFTable table : sourceDoc.getTables()) {
                mergedDoc.createTable().getCTTbl().set(table.getCTTbl()); // 复制表格
            }
        }
    }

    private String saveMergedDocument(XWPFDocument doc) throws IOException {
        Path desktopPath = Paths.get(System.getProperty("user.home"), "Desktop");
        if (!Files.exists(desktopPath)) Files.createDirectories(desktopPath);

        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        Path outputPath = desktopPath.resolve("merged_word_" + timestamp + ".docx");

        try (FileOutputStream fos = new FileOutputStream(outputPath.toFile())) {
            doc.write(fos);
        }
        logger.info("Word合并完成,输出路径: {}", outputPath);
        return outputPath.toString();
    }

    private void validateFiles(List<String> filePaths) {
        for (String path : filePaths) {
            File file = new File(path);
            if (!file.exists() || !file.canRead()) {
                throw new IllegalArgumentException("文件无效或不可读: " + path);
            }
        }
    }
}

 doc的工具类

package com.sc.modules.biddinvestment.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class DocMerger {
    private static final Logger logger = LoggerFactory.getLogger(DocMerger.class);

    // 保留原文本合并功能(可选)
    public String mergeTxtDocuments(List<String> filePaths) throws IOException {
        validateFiles(filePaths);
        Path desktopPath = Paths.get(System.getProperty("user.home"), "Desktop");
        if (!Files.exists(desktopPath)) Files.createDirectories(desktopPath);

        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        Path outputPath = desktopPath.resolve("merged_txt_" + timestamp + ".txt");

        try (BufferedWriter writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)) {
            for (String path : filePaths) {
                File file = new File(path);
                writer.write("===== 文件: " + file.getName() + " =====\n");
                List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
                for (String line : lines) {
                    writer.write(line);
                    writer.newLine();
                }
                writer.write("\n\n");
            }
        }
        logger.info("文本合并完成,输出路径: {}", outputPath);
        return outputPath.toString();
    }

    private void validateFiles(List<String> filePaths) {
        for (String path : filePaths) {
            File file = new File(path);
            if (!file.exists() || !file.canRead()) {
                throw new IllegalArgumentException("文件无效或不可读: " + path);
            }
        }
    }
}

pdf的 

package com.sc.modules.biddinvestment.utils;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class PdfMerger {
    private static final Logger logger = LoggerFactory.getLogger(PdfMerger.class);
    private static final String DEFAULT_OUTPUT_NAME = "merged";
    private static final String PDF_EXTENSION = ".pdf";

    /**
     * 合并多个PDF文件
     *
     * @param filePaths 要合并的PDF文件路径列表
     * @return 合并后的文件绝对路径
     * @throws IOException 如果合并过程中发生错误
     */
    public String mergePdfs(List<String> filePaths) throws IOException {
        validateInputFiles(filePaths);
        File outputFile = prepareOutputFile();
        mergeFiles(filePaths, outputFile);
        logger.info("成功合并 {} 个PDF文件到: {}", filePaths.size(), outputFile.getAbsolutePath());
        return outputFile.getAbsolutePath();
    }

    /**
     * 验证输入文件
     */
    private void validateInputFiles(List<String> filePaths) {
        if (filePaths == null || filePaths.isEmpty()) {
            throw new IllegalArgumentException("文件路径列表不能为空");
        }

        for (String path : filePaths) {
            if (path == null || path.trim().isEmpty()) {
                throw new IllegalArgumentException("文件路径不能为空");
            }

            File file = new File(path);
            if (!file.exists()) {
                throw new IllegalArgumentException("文件不存在: " + path);
            }
            if (!file.isFile()) {
                throw new IllegalArgumentException("路径不是文件: " + path);
            }
            if (!file.canRead()) {
                throw new IllegalArgumentException("文件不可读: " + path);
            }
            if (!path.toLowerCase().endsWith(".pdf")) {
                throw new IllegalArgumentException("仅支持PDF文件: " + path);
            }
        }
    }

    /**
     * 准备输出文件
     */
    private File prepareOutputFile() throws IOException {
        Path desktopPath = Paths.get(System.getProperty("user.home"), "Desktop");

        // 确保桌面目录存在
        if (!Files.exists(desktopPath)) {
            logger.warn("桌面目录不存在,尝试创建: {}", desktopPath);
            try {
                Files.createDirectories(desktopPath);
            } catch (IOException e) {
                throw new IOException("无法创建桌面目录: " + desktopPath, e);
            }
        }

        // 生成唯一文件名
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String baseName = DEFAULT_OUTPUT_NAME + "_" + timestamp + PDF_EXTENSION;

        Path outputPath = desktopPath.resolve(baseName);

        // 处理文件名冲突
        int counter = 1;
        while (Files.exists(outputPath)) {
            baseName = DEFAULT_OUTPUT_NAME + "_" + timestamp + "_" + counter + PDF_EXTENSION;
            outputPath = desktopPath.resolve(baseName);
            counter++;
        }

        return outputPath.toFile();
    }

    /**
     * 执行PDF合并
     */
    private void mergeFiles(List<String> inputFilePaths, File outputFile) throws IOException {
        PDFMergerUtility merger = new PDFMergerUtility();

        try {
            // 添加所有源文件
            for (String filePath : inputFilePaths) {
                merger.addSource(new File(filePath));
            }

            // 设置输出文件
            merger.setDestinationFileName(outputFile.getAbsolutePath());

            // 执行合并
            merger.mergeDocuments(null);
        } catch (IOException e) {
            // 合并失败时删除可能已创建的部分输出文件
            if (outputFile.exists() && !outputFile.delete()) {
                logger.error("无法删除部分合并的文件: {}", outputFile.getAbsolutePath());
            }
            throw new IOException("PDF合并失败: " + e.getMessage(), e);
        }
    }

    // 重载方法,支持可变参数
    public String mergePdfs(String... filePaths) throws IOException {
        return mergePdfs(Arrays.asList(filePaths));
    }

}

调用方法 

@PostMapping("/mergeDocuments")
public String mergeFiles(@RequestBody Map<String, List<String>> request) {
    try {
        List<String> filePaths = request.get("filePaths");
        if (filePaths == null || filePaths.isEmpty()) {
            return "错误:文件路径列表为空!";
        }

        boolean allPdf = filePaths.stream()
                .allMatch(path -> path.toLowerCase().endsWith(".pdf"));

        String mergedFilePath;
        if (allPdf) {
            PdfMerger merger = new PdfMerger();
            mergedFilePath = merger.mergePdfs(filePaths);
        } else {
            WordMerger wordMerger = new WordMerger();
            mergedFilePath = wordMerger.mergeWordDocuments(filePaths);
        }

        return "文件合并成功,保存路径: " + mergedFilePath;
    } catch (Exception e) {
        return "文件合并失败:" + e.getMessage();
    }
}

前端:
 

getMenuData() {
  setTimeout(() => {
    url.getMenusTree().then(res => {
      // 定义文件类型映射
      const fileTypeMap = {
        pdf: 'PDF文件',
        doc: 'Word文件',
        docx: 'Word文件',
        xls: 'Excel文件',
        xlsx: 'Excel文件'
      };
      // 提取文件后缀的工具函数
      const getFileType = (filepatch, filecode) => {
        if (filepatch) {
          const ext = filepatch.split('.').pop().toLowerCase();
          return fileTypeMap[ext] || '目录';
        }
        // fallback 用 filecode 判断
        return filecode === 0 ? '目录' : '目录';
      };
      // 定义递归处理函数
      const processTree = (nodes) => {
        return nodes.map(item => ({
          ...item,
          filetype: getFileType(item.filepatch, item.filecode),
          children: item.children ? processTree(item.children) : []
        }));
      };
      // 处理后的树结构赋值
      this.biddData = processTree(res.data);
    });
  }, 100);
},

前端定义递归方法遍历每条数据的filepatch 然后利用

filepatch.split('.').pop().toLowerCase();
获取名称的拓展名判断是哪一类
之后调用fileTypeMap将对应的文件名称写进去
就可以展示了
我这里是树形结构所以调用了processTree

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高效绘制业务流程图!专业模板免费下载

在复杂的业务流程管理中&#xff0c;可视化工具已成为提升效能的核心基础设施。为助力开发者、项目经理及业务架构师高效落地流程标准化&#xff0c;本文将为你精选5套开箱即用的专业流程图模板。这些模板覆盖跨部门协作、电商订单、客户服务等高频场景&#xff0c;具备以下核心…

Spring Boot + Prometheus 实现应用监控(基于 Actuator 和 Micrometer)

文章目录 Spring Boot Prometheus 实现应用监控&#xff08;基于 Actuator 和 Micrometer&#xff09;环境准备示例结构启动和验证验证 Spring Boot 应用Prometheus 抓取配置&#xff08;静态方式&#xff09;Grafana 面板配置总结 Spring Boot Prometheus 实现应用监控&…

PowerBI企业运营分析—列互换式中国式报表分析

PowerBI企业运营分析—列互换式中国式报表分析 欢迎来到Powerbi小课堂&#xff0c;在竞争激烈的市场环境中&#xff0c;企业运营分析平台成为提升竞争力的核心工具。 该平台通过高效整合多源数据&#xff0c;并实时监控关键指标&#xff0c;能够迅速揭示业务表现的全貌&#…

BugKu Web渗透之需要管理员

启动场景&#xff0c;打开网页&#xff0c;显示如下&#xff1a; 一般没有上面头绪的时候&#xff0c;就是两步&#xff1a;右键查看源代码 和 扫描网站目录。 步骤一&#xff1a; 右键查看源代码 和 扫描网站目录。 右键查看源代码没有发现异常。 于是扫描网站目录&…

TDengine 开发指南—— UDF函数

UDF 简介 在某些应用场景中&#xff0c;应用逻辑需要的查询功能无法直接使用内置函数来实现&#xff0c;TDengine 允许编写用户自定义函数&#xff08;UDF&#xff09;&#xff0c;以便解决特殊应用场景中的使用需求。UDF 在集群中注册成功后&#xff0c;可以像系统内置函数一…

使用vsftpd搭建FTP服务器(TLS/SSL显式加密)

安装vsftpd服务 使用vsftpd RPM安装包安装即可&#xff0c;如果可以访问YUM镜像源&#xff0c;通过dnf或者yum工具更加方便。 yum -y install vsftpd 启动vsftpd、查看服务状态 systemctl enable vsftpd systemctl start vsftpd systemctl status vsftpd 备份配置文件并进…

1.1Nodejs和浏览器中的二进制处理

Buffer 在 Node.js 中&#xff0c;Buffer 类用于处理二进制数据。由于 JavaScript 在浏览器环境中主要用于处理字符串和数字等类型的数据&#xff0c;对二进制数据的处理能力较弱&#xff0c;因此 Node.js 引入了 Buffer 类来弥补这一不足&#xff0c;特别是在处理文件系统操作…

入门AJAX——XMLHttpRequest(Post)

一、前言 在上篇文章中&#xff0c;我们已经介绍了 HMLHttpRequest 的GET 请求的基本用法&#xff0c;并基于我提供的接口练习了两个简单的例子。如果你还没有看过第一篇文章&#xff0c;强烈建议你在学习完上篇文章后再学习本篇文章&#xff1a; &#x1f517;入门AJAX——XM…

Qt(part1)Qpushbutton,信号与槽,对象树,自定义信号与槽,lamda表达式。

1、创建Qt程序 2、命名规范及快捷键 3、Qpushbutton按钮创建 4、对象树概念 5、信号与槽 6、自定义信号与槽 7、当自定义信号和槽发生重载时 8、信号可以连接信号&#xff0c;信号也可以断开。 9、lamda表达式

西北某省级联通公司:3D动环模块如何实现机房“一屏统管”?

一、运营商机房监控痛点凸显 在通信行业快速发展的当下&#xff0c;西北某省级联通公司肩负着保障区域通信畅通的重任。然而&#xff0c;公司分布广泛的机房面临着诸多监控难题&#xff0c;尤其是偏远机房环境风险无法实时感知这一痛点&#xff0c;严重影响了机房的稳定运行和通…

视觉分析在人员行为属性检测中的应用

基于视觉分析的人员行为属性检测方案 一、背景与需求分析 在工业生产、建筑施工、公共安全等领域&#xff0c;人员行为属性的合规性检测是保障安全生产的关键环节。例如&#xff0c;工地工人未佩戴安全帽、厨房人员未佩戴手套、作业现场人员使用手机等行为&#xff0c;均可能…

电子行业AI赋能软件开发经典案例——某金融软件公司

01.案例标题 金融行业某金融软件公司通过StarShip CodeSouler达成效率突破性增长&#xff0c;零流程侵入验证AI代码高度可行性 02.执行摘要 某金融软件公司在核心产品研发中引入开放传神&#xff08;OpenCSG&#xff09;的StarShip CodeSouler AI代码生成平台&#xff0c;在无…

摆脱硬件依赖:SkyEye在轨道交通中的仿真应用

在城市轨道交通系统中&#xff0c;信号系统承担着确保列车安全、高效运行的关键任务。从排列进路、信号开放&#xff0c;到终点折返与接发车&#xff0c;几乎每一个调度动作背后都依赖于信号系统的精密控制与实时响应。作为信号系统的重要组成部分&#xff0c;目标控制器&#…

使用变异系数增强 CFD 收敛标准

将描述性统计整合到 CFD 中&#xff0c;以评估可变性和收敛性。 挑战 在工程设计中&#xff0c;尤其是在进行仿真时&#xff0c;我们经常处理描述流体、温度、应力或浓度行为的大型数据集。以有意义的方式解释这些值需要的不仅仅是原始数字;它需要对统计的理解。 统计学在工程…

物联网通信技术全景指南(2025)之如何挑选合适的物联网模块

物联网通信技术全景指南&#xff08;2025&#xff09;之 如何挑选合适的物联网模块 物联网通信技术全景指南&#xff08;2025&#xff09;一、技术代际演进与退网背景二、5G 物联网技术体系&#xff08;Sub-6 GHz 核心&#xff09;1. 技术分层架构2. 蜂窝技术性能矩阵3. Sub-6 …

影楼精修-AI衣服祛褶皱算法解析

注&#xff1a;为避免侵权&#xff0c;本文所用图像均为AIGC生成或无版权网站提供&#xff1b; 衣服祛褶皱功能&#xff0c;目前在像素蛋糕、美图云修、百度网盘AI修图、阿里云都有相关的功能支持&#xff0c;它的价值就是将不平整的衣服图像&#xff0c;变得整齐平整&#xf…

Day46 Python打卡训练营

知识点回顾&#xff1a; 1. 不同CNN层的特征图&#xff1a;不同通道的特征图 2. 什么是注意力&#xff1a;注意力家族&#xff0c;类似于动物园&#xff0c;都是不同的模块&#xff0c;好不好试了才知道。 3. 通道注意力&#xff1a;模型的定义和插入的位置 4. 通道注意力后…

linux安全加固(非常详细)

安全加固方案原则 1.版本升级 对于系统和应用在使用过程中暴露的安全缺陷&#xff0c;系统或应用厂商会及时发布解决问题的升级补丁包。升级系统或应用版本&#xff0c;可有效解决旧版本存在的安全风险。2.关闭端口服务 在不影响业务系统正常运行情况下&#xff0c;停止或禁用承…

动手学深度学习12.7. 参数服务器-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;35 分布式训练【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址&#xff1a;12.7. 参数服务器…

告别数据泥沼,拥抱智能中枢:King’s四位一体重塑科研生产力

在现代科研的战场上&#xff0c;数据堪称科研人员手中的“弹药”。然而&#xff0c;许多实验室却深陷数据管理的泥沼&#xff1a;硬盘里堆满了不同年份的实验记录&#xff0c;U盘里塞着各种格式的谱图&#xff0c;Excel表格里还留着手动计算的痕迹……&#xff0c;当科研人员想…