一键导出所有影像资料并压缩成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(" ", " ");
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);
}
}
希望对大家有所帮助,谢谢!
(本文完!如有套用本文信息,必须付此原文链接!)