一键导出资料(图片和PDF)到ZIP

一键导出所有影像资料并压缩成ZIP格式

思路:
利用Hutool、Freemarker、jsoup、xhtmlrenderer工具简单实现。
先看效果,再看代码:
在这里插入图片描述

1. 所需JAR包

 		<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        <!-- html转pdf -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.13.1</version>
        </dependency>
        <!-- xml读取操作 -->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf-itext5</artifactId>
            <version>9.0.3</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </dependency>

2. 友情提示
Freemarker读取模板路径问题;模板处理中文乱码,不显示问题均已在代码中已注释的形式指出,希望大家认真细心的看注释,避免大家无法达到理想效果。

3. Freemarker模板准备, 文件后缀为.ftl

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Freemarker</title>
    <style type="text/css">
        #all {
            width: 600px;
            <#-- 使文档在pdf页面居中 -->
            margin: auto;
        }
        table {
            width: 100%;
            height: auto;
            font-family: SimSun;
            text-align: center;
            <#-- table中单元格自动换行 -->
            table-layout: fixed;
            word-wrap: break-word;
        }
        tr td {
            padding: 2px;
            font-size: 10px;
            height: 20px;
        }
        tr th {
            padding: 2px;
            font-weight: bold;
            font-size: 10px;
            height: 20px;
        }
    </style>
</head>
<body>
<div id="all">
    <#-- @@提醒@@:此处必须指定字体,不然不识别中文  -->
    <table border="1" cellspacing="0" cellpadding="0" align="center">

        <#list params as param>
        <tr>
            <th colspan="4" style="height: 10px;"></th>
        </tr>
        <tr>
            <th>姓名</th>
            <td>${param.name}</td>
            <th>电话</th>
            <td>${param.phone}</td>
        </tr>
        <tr>
            <th>昵称</th>
            <td>${param.nickname}</td>
            <th>邮箱</th>
            <td>${param.email}</td>
        </tr>
    </#list>
    </table>
</div>
</body>
</html>

4. Controller接口代码

package com.example.export;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ZipUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author Mr.Nectarine
 * @Description 一键导出生成Zip包功能
 */
@Slf4j
@RestController
public class GenerateZip {


    /**
    * @Description 一键生成Zip包,导出需要的资料数据,包括文本+图片+pdf
    * @Param [request, response]
    * @Version 1.0
    */
    @GetMapping("/getZip")
    public void getZip(HttpServletRequest request, HttpServletResponse response) {
        // 获取前端的参数,以此获取导出的数据资料
        String param = request.getParameter("param");

        OutputStream os = null;
        try {
            // 文件名:20200813
            String zipName = LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE);
            File dir = FileUtil.mkdir(zipName);

            // ========== 图片处理方式 ============
            // 子文件路径
            File childPath = FileUtil.mkdir(zipName + File.separator + "wings");
            File picture = FileUtil.file("D:\\Images\\wallpaper\\ad0863c3fca3026036a004a202682f18.jpg");
            // 将图片File copy到子路径下
            FileUtil.copy(picture, childPath, true);

            // ========== pdf处理方式 ===========
            // 利用Apache的Freemarker工具,灵活处理
            Map<String, Object> map1 = new HashMap<>();
            map1.put("name", "赵小刚");
            map1.put("phone", "15673890987");
            map1.put("nickname", "红孩儿");
            map1.put("email", "15673890987@163.com");

            Map<String, Object> map2 = new HashMap<>();
            map2.put("name", "赵小刚");
            map2.put("phone", "15673890987");
            map2.put("nickname", "红孩儿");
            map2.put("email", "15673890987@163.com");
            List<Map<String, Object>> stuffList = Arrays.asList(map1,map2);
			// Freemarker模板数据填充只认Map对象,如果是实体类需要转换成Map,否则数据无法填充
            Map<String, List<Map<String, Object>>> stuffMap = MapUtil.builder("params", stuffList).build();

            // Freemarker读取模板并填充模板
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
            // 如果填充值中与模板不匹配,或者为null值,则默认此值为空;
            cfg.setClassicCompatible(true);
            // 模板路径加载方式:基于类路径,即在src\main\resources\templates包下的ftl模板
            cfg.setClassForTemplateLoading(this.getClass(),"/templates");
            Template template = cfg.getTemplate( "free.ftl");
            Writer writer = new StringWriter();
            template.process(stuffMap, writer);

            // 对pdf资料进行创建
            File pdfFile = FileUtil.file(dir, "pdf资料.pdf");
            os = new FileOutputStream(pdfFile);
            HtmlToPdf.htmlToPdf(writer.toString(),os);
			
            generateZip(response, zipName, dir);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * @Description 生成Zip
     * @Param [response, tempDir/压缩包的名字, dir/压缩的文件]
     * @Version 1.0
     */
    public void generateZip(HttpServletResponse response, String zipName, File dir){
        try {
            File zip = ZipUtil.zip(FileUtil.file(zipName+ ".zip"), true, dir);
            byte[] data = FileUtil.readBytes(zip);

            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s",
                    URLEncoder.encode(zip.getName(), "UTF-8")));
            response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));
            response.setContentType("application/octet-stream; charset=UTF-8");
            IoUtil.write(response.getOutputStream(), Boolean.TRUE, data);
        } catch (IOException e) {
            log.info("打Zip包出现未知异常,详情{}",e.getMessage());
        } finally {
            // 因为把文件目录生成在项目路径(target\classes\wings)下,所以在生成zip并导出后需要删除
            if (dir.exists()) {
                FileUtil.del(dir);
            }
        }
    }

}

5. 需要的自定义工具类HtmlToPdf

package com.example.export;

import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.pdf.BaseFont;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.OutputStream;

/**
 * @Author Mr.Nectarine
 * @Description html字符串格式的数据转pdf
 */
@Slf4j
public class HtmlToPdf {

    /**
     * 将HTML转成PD格式的文件。html文件的格式比较严格
     * @param htmlText  html内容
     * @param os   pdf存储文件输出流, 需要调用方关闭流
     * @throws Exception
     */
    public static void htmlToPdf(String htmlText, OutputStream os) throws Exception {
        // <!DOCTYPE html> 没有闭合标签,故删掉
        htmlText = htmlText.replace("<!DOCTYPE html>", StrUtil.EMPTY);
        Document document = Jsoup.parse(htmlText);
        /*手动为一些标签添加闭合*/
        Elements meta = document.getElementsByTag("meta");
        String html = document.html();
        for (Element link : meta) {
            String s = link.outerHtml();
            String s1 = s.replace("/>", ">");
            html = html.replace(s, s1 + "</meta>");
        }
        Elements link1 = document.getElementsByTag("link");
        for (Element link : link1) {
            String s = link.outerHtml();
            String s1 = s.replace("/>", ">");
            html = html.replace(s, s1 + "</link>");

        }
        html = html.replaceAll("<br>", "<br/>");
        html = html.replaceAll("&nbsp", "&#160");

        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        // 解决中文支持
        ITextFontResolver fontResolver = renderer.getFontResolver();
        String currentSystem = System.getProperty("os.name").toLowerCase();
        if("linux".equals(currentSystem)){
            fontResolver.addFont("/usr/share/fonts/chinese/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        }else{
            fontResolver.addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        }

        renderer.layout();
        renderer.createPDF(os);
    }

}

希望对大家有所帮助,谢谢!
(本文完!如有套用本文信息,必须付此原文链接!)

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_函数_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值