luofl
2025-04-21 ef30e3f2eebad385c8b26bd0ff931c028d46f3ce
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
@@ -1,11 +1,13 @@
package com.ruoyi.web.controller.tool;
import cn.hutool.core.io.FileUtil;
import com.ruoyi.common.utils.StringUtils;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.mock.web.MockMultipartFile;
@@ -13,14 +15,10 @@
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -67,126 +65,49 @@
    private TencentCosUtil tencentCosUtil;
    @Resource
    private PdfUtils pdfUtils;
    public String generate(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
        try {
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
//            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
            String encodedFileName =fileName ;
            // 定义保存文件的路径
            File saveDir = new File(saveDirectory);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            // 定义文件名
            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
            String s = tencentCosUtil.upLoadFile(mockMultipartFile,"/wordGenerate");
            return s;
        } catch (IOException | TemplateException e) {
            log.error("生成Word文档异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
        }
    }
    public String generatePdf(String basePackagePath, String templateFileName, Map<String,Object> templateParam, String fileName, String saveDirectory) {
        try {
            fillTemplate(basePackagePath+templateFileName, saveDirectory+fileName+".docx", templateParam);
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding("utf-8");
//            // 设置模板加载器,加载模板文件
//            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
//            Template t = configuration.getTemplate(templateFileName, "utf-8");
//
//            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
////            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
//            String encodedFileName =fileName ;
//
//            // 定义保存文件的路径
//            File saveDir = new File(saveDirectory);
//            if (!saveDir.exists()) {
//                saveDir.mkdirs();
//            }
//
//            // 定义文件名
//            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
//
//            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
//            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
//
//            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
//            t.process(templateParam, out);
//            out.close();
            String filePath = saveDirectory + File.separator + fileName + ".docx";
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            String test = pdfUtils.test(fileName + ".docx");
//            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
//            String s = ObsUploadUtil.obsUpload(mockMultipartFile);
            return test;
        } catch (IOException e) {
            log.error("生成pdf异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage());
        }
    }
    public static void fillTemplate(String templatePath, String outputPath,Map<String, Object> dataMap) {
    public static void fillTemplate(String templatePath, String outputPath,Map<String, Object> dataMap,String url) {
        try (FileInputStream fis = new FileInputStream(templatePath)) {
            // 设置默认编码为UTF-8
            System.setProperty("file.encoding", "UTF-8");
            XWPFDocument document = new XWPFDocument(fis);
            XWPFParagraph pic = document.createParagraph();
            XWPFRun picRun = pic.createRun();
            dataMap.put("${picture}", picRun.addPicture(
                    new FileInputStream("/usr/local/project/file/1.jpg"), XWPFDocument.PICTURE_TYPE_JPEG,
                    "/usr/local/project/file/1.jpg",
                    Units.toEMU(60),
                    Units.toEMU(30)
            ));
            Base64.Decoder decoder = Base64.getDecoder();
            if(StringUtils.isNotEmpty(url)){
                byte[] imageByte = decoder.decode(url);
                InputStream stream = new ByteArrayInputStream(imageByte);
//            File tempFile = FileUtil.createTempFile("/usr/local/project/file/temp", ".jpg", true);
                File tempFile = File.createTempFile("/usr/local/project/file/temp", ".jpg");
                tempFile.deleteOnExit(); // 程序结束时删除文件
                try (OutputStream out = Files.newOutputStream(tempFile.toPath());
                     InputStream in = stream) {
                    Thumbnails.of(in).scale(0.8).rotate(270).outputFormat("jpg").toOutputStream(out);
                    byte[] buffer = new byte[1024];
                    int length;
                    // 从原始流读取数据并写入临时文件
                    while ((length = in.read(buffer)) > 0) {
                        out.write(buffer, 0, length);
                    }
                }
                //处理图片
                for (XWPFParagraph paragraph : document.getParagraphs()) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (text != null && text.contains("picture")) {
                            run.setText("", 0); // 清除占位符文本
                            run.addPicture(
                                    new FileInputStream(tempFile), XWPFDocument.PICTURE_TYPE_JPEG,
                                    tempFile.getName(),
                                    Units.toEMU(60),
                                    Units.toEMU(30)); // 插入图片
                        }
                    }
                }
            }
            // 处理段落
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                replaceParagraph(paragraph, dataMap);
@@ -202,7 +123,7 @@
                    }
                }
            }
            // 使用UTF-8编码保存文件
            try (FileOutputStream fos = new FileOutputStream(outputPath)) {
                document.write(fos);
@@ -304,20 +225,6 @@
        return result.toString();
    }
    private static class ReplacementInfo {
        int startRun;
        int endRun;
        String originalText;
        String replacementText;
        ReplacementInfo(int startRun, int endRun, String originalText, String replacementText) {
            this.startRun = startRun;
            this.endRun = endRun;
            this.originalText = originalText;
            this.replacementText = replacementText;
        }
    }
    private static void replaceRunRange(XWPFParagraph paragraph, ReplacementInfo info) {
        List<XWPFRun> runs = paragraph.getRuns();
@@ -338,6 +245,125 @@
        style.applyStyle(newRun);
    }
    public String generate(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
        try {
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
//            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
            String encodedFileName =fileName ;
            // 定义保存文件的路径
            File saveDir = new File(saveDirectory);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            // 定义文件名
            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
            String s = tencentCosUtil.upLoadFile(mockMultipartFile,"/wordGenerate");
            return s;
        } catch (IOException | TemplateException e) {
            log.error("生成Word文档异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
        }
    }
    public String generatePdf(String basePackagePath, String templateFileName, Map<String,Object> templateParam, String fileName, String saveDirectory,String url) {
        try {
            fillTemplate(basePackagePath+templateFileName, saveDirectory+fileName+".docx", templateParam,url);
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding("utf-8");
//            // 设置模板加载器,加载模板文件
//            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
//            Template t = configuration.getTemplate(templateFileName, "utf-8");
//
//            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
////            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
//            String encodedFileName =fileName ;
//
//            // 定义保存文件的路径
//            File saveDir = new File(saveDirectory);
//            if (!saveDir.exists()) {
//                saveDir.mkdirs();
//            }
//
//            // 定义文件名
//            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
//
//            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
//            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
//
//            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
//            t.process(templateParam, out);
//            out.close();
            String filePath = saveDirectory + File.separator + fileName + ".docx";
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            String test = pdfUtils.test(fileName + ".docx");
//            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
//            String s = ObsUploadUtil.obsUpload(mockMultipartFile);
            return test;
        } catch (IOException e) {
            log.error("生成pdf异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage());
        }
    }
    private static class ReplacementInfo {
        int startRun;
        int endRun;
        String originalText;
        String replacementText;
        ReplacementInfo(int startRun, int endRun, String originalText, String replacementText) {
            this.startRun = startRun;
            this.endRun = endRun;
            this.originalText = originalText;
            this.replacementText = replacementText;
        }
    }
    // 用于保存和恢复运行样式的辅助类
    private static class RunStyle {
        String fontFamily;