Freemark 模板生成doc文件,xml doc文件转docx 文件,docx文件转pdf文件

freemark 模板生成doc文件,此doc文件为xml格式,无法直接转pdf

需要doc转docx文件,才能转pdf

方法1:docx4j 转 pdf

方法2: e-iceblue docx 转 pdf、xml-doc 转 pdf

打包方式,需要本地引入jar包,下载后,将lib里的jar包放入项目中

Free Spire.Doc for Java | 100% 免费 Java Word 组件

pom文件引入 ${project.basedir} 是系统变量,代表本目录,build配置是打包时,将本地文件加入项目

<dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.pdf</artifactId>
            <version>5.2.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/Spire.Doc.jar</systemPath>
        </dependency>

 <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
        </plugins>
    </build>

​​​​​​​

 

方法3:poi (可以自己搜教程)

依赖

<!-- iText pdf 依赖-->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.13</version>
            </dependency>

            <dependency>
                <groupId>org.xhtmlrenderer</groupId>
                <artifactId>flying-saucer-pdf-itext5</artifactId>
                <version>9.1.5</version>
            </dependency>

            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.31</version>
            </dependency>

            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.11.0</version>
                <scope>compile</scope>
            </dependency>

            <!-- docx 依赖 导出pdf -->
            <dependency>
                <groupId>org.docx4j</groupId>
                <artifactId>docx4j</artifactId>
                <version>6.1.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

            <dependency>
                <groupId>org.docx4j</groupId>
                <artifactId>docx4j-export-fo</artifactId>
                <version>6.0.0</version>
            </dependency>

            <!-- e-iceblue 导出pdf -->
            <dependency>
                <groupId>e-iceblue</groupId>
                <artifactId>spire.doc.free</artifactId>
                <version>5.2.0</version>
            </dependency>
<repositories>
        <repository>
            <id>public</id>
            <name>阿里云公共仓库</name>
            <url>https://maven.aliyun.com/repository/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
        <repository>
            <id>com.e-iceblue</id>
            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
    </repositories>
/**
 * @Author: LiSaiHang
 * @Date: 2023/4/23 3:26 下午
 */
@RestController
@RequestMapping("/module/documents")
@Slf4j
public class FreeMarkController {

    @GetMapping("/generate")
    public void doc(HttpServletResponse response) {
        Map<String, Object> dataMap = new HashMap<>();
        ///姓名
        dataMap.put("name", "张三");
        dataMap.put("phone", "15532123328");
        dataMap.put("idCard", "130429199711113617");
        dataMap.put("sex", "男");
        String result = "";

        String docName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".doc";
        String pdfName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";

        response.setHeader("content-Type", "application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + pdfName);

        // 下载输出流
        ServletOutputStream outputStream = null;
        // doc文件输出流
        InputStream inputStream = null;
        // pdf文件输出流
        ByteArrayOutputStream fileOutputStream = null;

        try {
            // 获取渲染数据
            result = FreeMarkUtils.freemarkerRender(dataMap, "test.doc");
            inputStream = new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
            // 生成 doc 文件
            FileUtils.copyInputStreamToFile(inputStream, new File(docName));
            // doc 文件转docx文件
            final String docxFile = this.docToDocx(docName);
            // 方法1:docx文件转pdf文件
            // this.docx4jWordToPdf(docxFile, pdfName);
            
            // 方法2:docx文件转pdf文件
            // com.spire.doc.Document 实例化Document类的对象
            Document doc = new Document();
            // 加载Word
            doc.loadFromFile(docxFile);
            // 保存为PDF格式 com.spire.doc.FileFormat
            doc.saveToFile(pdfName, FileFormat.PDF);
            // pdf 缩放设置
            pdfPageSetting(pdfName);
            // 获取文件输出流
            fileOutputStream = FreeMarkUtils.getFileOutputStream(new File(pdfName));
            // 设置文件名
            outputStream = response.getOutputStream();
            outputStream.write(fileOutputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * doc转docx
     * @param docPath doc文件路径
     * @return
     */
    private String docToDocx(String docPath) {
        String docxPath = docPath.replaceAll("(\\.docx)|(\\.doc)", ".docx");
        try (FileInputStream inputStream = new FileInputStream(docPath);) {
            WordprocessingMLPackage wmlPackage = Docx4J.load(inputStream);
            //转换为DOCX
            try (FileOutputStream docx = new FileOutputStream(docxPath);) {
                Docx4J.save(wmlPackage, docx, Docx4J.FLAG_SAVE_ZIP_FILE);
                docPath = docxPath;
            }
        } catch (Exception e) {
            System.out.println((docPath + ":不需要转换:" + e.getLocalizedMessage()));
        }
        return docPath;
    }

    /**
     * 通过docx4j 实现word转pdf
     *
     * @param sourcePath 源文件地址 如 /root/example.doc
     * @param targetPath 目标文件地址 如 /root/example.pdf
     */
    public String docx4jWordToPdf(String sourcePath, String targetPath) {
        try {
            WordprocessingMLPackage pkg = Docx4J.load(new File(sourcePath));
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
            fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
            fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
            fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
            fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
            fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
            fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
            fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
            fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
            fontMapper.put("等线", PhysicalFonts.get("SimSun"));
            fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
            fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
            fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
            fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
            fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
            fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
            fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
            fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
            fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
            fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
            fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
            PhysicalFonts.addPhysicalFonts("SimSun", WordUtils.class.getResource("/simsun.ttc"));
            pkg.setFontMapper(fontMapper);

            Docx4J.toPDF(pkg, new FileOutputStream(targetPath));
        } catch (Exception e) {
            log.error("[docx4j] word转pdf失败:{}", e.toString());
        }
        return targetPath;
    }

    /**
     * 对pdf页面设置,缩放比例设置
     * @param pdfName pdf文件名称
     */
    private void pdfPageSetting(String pdfName) {
        //创建PdfDocument实例
        PdfDocument originalDoc = new PdfDocument();
        //加载PDF文件
        originalDoc.loadFromFile(pdfName);

        //创建一个新的PdfDocument实例
        PdfDocument newDoc = new PdfDocument();

        //遍历所有PDF 页面
        for (int i = 0; i < originalDoc.getPages().getCount(); i++) {
            PdfPageBase page = originalDoc.getPages().get(i);
            //设置新文档的页边距为10
            PdfMargins margins = new PdfMargins(10);
            //设置新文档的页面大小为A2
            PdfPageBase newPage = newDoc.getPages().add(PdfPageSize.A2, margins);
            //调整画布,设置内容也根据页面的大小进行缩放
            double wScale = (PdfPageSize.A2.getWidth() - 20) /         PdfPageSize.A4.getWidth();
            double hScale = (PdfPageSize.A2.getHeight() - 20) / PdfPageSize.A4.getHeight();
            newPage.getCanvas().scaleTransform(wScale, hScale);
            //复制原文档的内容到新文档
            newPage.getCanvas().drawTemplate(page.createTemplate(), new Point2D.Float());
        }
        //保存PDF
        newDoc.saveToFile(pdfName);
    }
}

工具类

package com.dpxdata.framework.common.utils;

import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.util.Map;

/**
 * @Description: pdf 导出工具类
 * @Author: LiSaiHang
 * @Date: 2022/1/7 11:30 上午
 */
@Component
@Slf4j
public class FreeMarkUtils {
    private FreeMarkUtils() {
    }

    private volatile static Configuration configuration;

    static {
        if (configuration == null) {
            synchronized (FreeMarkUtils.class) {
                if (configuration == null) {
                    configuration = new Configuration(Configuration.VERSION_2_3_28);
                }
            }
        }
    }

    /**
     * freemarker 引擎渲染 html
     *
     * @param dataMap  传入 html 模板的 Map 数据
     * @param fileName 模板文件名称
     *                 eg: "templates/template.ftl"
     * @return
     */
    public static String freemarkerRender(Map<String, Object> dataMap, String fileName) {
        configuration.setDefaultEncoding("UTF-8");
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        try {
            // TODO Jar包运行时,是无法读取classpath下资源文件,可以通过 SpringTemplateLoader 读取资源文件目录
            // 本地运行时,可以通过本地文件流读取资源文件
            final SpringTemplateLoader templateLoader = new SpringTemplateLoader(new DefaultResourceLoader(), "classpath:templates");
            configuration.setTemplateLoader(templateLoader);
            // 服务器运行时,可以通过目录,获取文件流读取资源文件
//            configuration.setDirectoryForTemplateLoading(new File("/Users/lisaihang/Documents/"));
            configuration.setLogTemplateExceptions(false);
            configuration.setWrapUncheckedExceptions(true);
            Template template = configuration.getTemplate(fileName);
            log.info("填充模板动态数据");
            return FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用 iText 生成 PDF 文档
     *
     * @param htmlTmpStr html 模板文件字符串
     * @param fontFile   所需字体文件(相对路径+文件名)
     */
    public static byte[] createHtml2Pdf(String htmlTmpStr, String fontFile) {
        log.info("根据模板生成PDF文件");
        ByteArrayOutputStream outputStream = null;
        byte[] result = null;
        // 生成 字体临时文件
        // TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件
        final String tempFont = "simsun_temp_"+ ".ttc";
        File existFile = new File(tempFont);
        if (!existFile.exists()) {
            final File tempFile = getTempFile(fontFile, tempFont);
            existFile = tempFile;
        }
        // TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件
        try {
            outputStream = new ByteArrayOutputStream();
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlTmpStr);
            ITextFontResolver fontResolver = renderer.getFontResolver();
            // 解决中文支持问题,需要所需字体(ttc)文件
            fontResolver.addFont(existFile.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            renderer.layout();
            renderer.createPDF(outputStream);
            // 对Html2Pdf 的文件插入水印图片
            final String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";
            addWaterMark(outputStream.toByteArray(), fileName);
            final ByteArrayOutputStream fileOutputStream = getFileOutputStream(new File(fileName));
            result = fileOutputStream.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.flush();
                    outputStream.close();
                }
//                if (tempFile.exists()) {
//                    tempFile.delete();
//                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 文件转字节输出流
     *
     * @param outFile 文件
     * @return
     */
    public static ByteArrayOutputStream getFileOutputStream(File outFile) {
        // 获取生成临时文件的输出流
        InputStream input = null;
        ByteArrayOutputStream bytestream = null;
        try {
            input = new FileInputStream(outFile);
            bytestream = new ByteArrayOutputStream();
            int ch;
            while ((ch = input.read()) != -1) {
                bytestream.write(ch);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                input.close();
                bytestream.close();
                log.info("删除临时文件");
                if (outFile.exists()) {
                    outFile.delete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytestream;
    }

    /**
     * 获取资源文件的临时文件
     * 资源文件打jar包后,不能直接获取,需要通过流获取生成临时文件
     *
     * @param fileName 文件路径 temp/temp.ftl
     * @return
     */
    public static File getTempFile(String fileName, String tempFont) {
        final File tempFile = new File(tempFont);
        InputStream fontTempStream = null;
        try {
            fontTempStream = FreeMarkUtils.class.getClassLoader().getResourceAsStream(fileName);
            FileUtils.copyInputStreamToFile(fontTempStream, tempFile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fontTempStream != null) {
                    fontTempStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return tempFile;
    }


    /**
     * 插入图片水印
     * @param srcByte 已生成PDF的字节数组(流转字节)
     * @param destFile 生成有水印的临时文件 temp.pdf
     * @return
     */
    public static FileOutputStream addWaterMark(byte[] srcByte, String destFile) {
        // 待加水印的文件
        PdfReader reader = null;
        // 加完水印的文件
        PdfStamper stamper = null;
        FileOutputStream fileOutputStream = null;
        try {
            reader = new PdfReader(srcByte);
            fileOutputStream = new FileOutputStream(destFile);
            stamper = new PdfStamper(reader, fileOutputStream);
            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            // 设置字体
            //BaseFont font = BaseFont.createFont();
            // 循环对每页插入水印
            for (int i = 1; i < total; i++) {
                final PdfGState gs = new PdfGState();
                // 水印的起始
                content = stamper.getUnderContent(i);
                // 开始
                content.beginText();
                // 设置颜色 默认为蓝色
                //content.setColorFill(BaseColor.BLUE);
                // content.setColorFill(Color.GRAY);
                // 设置字体及字号
                //content.setFontAndSize(font, 38);
                // 设置起始位置
                // content.setTextMatrix(400, 880);
                //content.setTextMatrix(textWidth, textHeight);
                // 开始写入水印
                //content.showTextAligned(Element.ALIGN_LEFT, text, textWidth, textHeight, 45);

                // 设置水印透明度
                // 设置笔触字体不透明度为0.4f
                gs.setStrokeOpacity(0f);
                Image image = null;
                image = Image.getInstance("https://dpxdata.oss-cn-beijing.aliyuncs.com/upload/kbt/null_1660715685801.png");
                // 设置坐标 绝对位置 X Y
                image.setAbsolutePosition(472, 785);
                // 设置旋转弧度
                image.setRotation(0);// 旋转 弧度
                // 设置旋转角度
                image.setRotationDegrees(0);// 旋转 角度
                // 设置等比缩放
                image.scalePercent(4);// 依照比例缩放
                // image.scaleAbsolute(200,100);//自定义大小
                // 设置透明度
                content.setGState(gs);
                // 添加水印图片
                content.addImage(image);
                // 设置透明度
                content.setGState(gs);
                //结束设置
                content.endText();
                content.stroke();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                stamper.close();
                fileOutputStream.close();
                reader.close();
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileOutputStream;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、项目概述 近年来,旅游业发展迅速,旅游景点的游客数量也在不断增加。然而,疫情的爆发和持续,给旅游产业带来了很大的冲击。为了保障游客和景区工作人员的安全,需要实行疫情防控措施。因此,设计一个疫情防控下的旅游景点预约系统显得尤为重要。 本项目采用了Spring Boot作为后端框架,使用Vue作为前端框架,实现了一个旅游景点预约系统,在预约过程中实现了疫情防控措施,确保游客和景区工作人员的安全。 二、系统设计 1.系统架构 本系统采用了前后端分离的架构,前端使用Vue框架,后端使用Spring Boot框架。前端通过HTTP请求与后端进行交互,后端将数据存储在MySQL数据库中,并通过API返回数据给前端。 2.系统功能 本系统主要有以下功能: (1)用户注册和登录:游客可以通过注册账号并登录,进行景点预约和查询等操作。管理员可以通过登录后台管理系统,管理景区信息和预约信息等。 (2)景点管理:管理员可以对景点进行增删改查操作,包括景点名称、景点介绍、景点图片等。 (3)预约管理:管理员可以查看预约信息、审核预约、取消预约等操作。游客可以进行预约操作,包括选择预约日期、预约人数、联系方式等。 (4)疫情防控:系统实现了疫情防控措施,包括游客健康码、预约时间间隔、人数限制等。 3.系统流程 (1)用户注册和登录流程: 游客通过注册页面注册账号,填写用户名、密码、手机号码等信息,系统进行账号验证后,将信息存储至数据库中。游客可以通过登录页面登录账号,输入用户名和密码,系统进行验证后,登录成功后跳至主页面。 (2)景点管理流程: 管理员登录后台管理系统,查看景点列表,可以对景点进行增删改查操作。 (3)预约管理流程: 游客登录系统后,可以进行景点预约操作,选择预约日期、预约人数、联系方式等信息。管理员登录后台管理系统,查看预约列表,可以审核预约、取消预约等操作。 4.系统界面 系统主要界面包括登录界面、注册界面、景点列表界面、预约界面、预约管理界面等。 三、系统实现 1.技术栈 后端技术栈:Spring Boot、MySQL、MyBatis、Spring Security。 前端技术栈:Vue、ElementUI、Axios。 2.数据库设计 本系统共设计了两个表,分别是用户表和景点表。 用户表包括:用户ID、用户名、密码、手机号码、角色等字段。 景点表包括:景点ID、景点名称、景点介绍、景点图片等字段。 3.系统代码结构 (1)后端代码结构: com.example.demo.config:系统配置文件。 com.example.demo.controller:控制器类,处理HTTP请求。 com.example.demo.entity:实体类,对应数据库中的表。 com.example.demo.mapper:MyBatis映射文件。 com.example.demo.security:Spring Security配置文件。 com.example.demo.service:服务类,实现系统核心功能。 com.example.demo.util:工具类,提供系统所需的一些工具方法。 (2)前端代码结构: src/components:组件类,实现系统的各个功能模块。 src/router:路由配置文件。 src/store:状态管理文件。 src/utils:工具类,提供系统所需的一些工具方法。 src/views:视图类,实现系统的各个页面。 src/App.vue:系统主页面。 src/main.js:系统启动文件。 四、总结 本系统基于Spring Boot和Vue框架实现了疫情防控下的旅游景点预约系统。系统具有用户注册和登录、景点管理、预约管理、疫情防控等功能。通过本项目的实现,可以更好地保障游客和景区工作人员的安全,提升旅游业的服务质量和水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值