本次需求是,pdf是表格类型的文件,我这里使用了word模板进行处理。但由于是多个文件一起导出,因此全部放到一个目录底下进行打包下载。

## 整体思路

 /*** 下载思路:* 1、查询出数据后;* 2、将数据按照word模板插入数据生成word文件,将word文件转成pdf(所有生成的数据都同一新增的目录下);* 3、将该目录底下的所有文件打包成压缩包;* 4、进行下载操作;* 5、下载完毕需要对于zip包和word文件目录删除*/

1.前提先准备好word模板, 记得模板里面的字段名字 要和实体类的属性名要一致 才能填充数据成功。
操作方法 跳转链接:https://blog.csdn.net/XuDream/article/details/122121892

使用模板生成word文档工具类 GenerateWordUtil :

ps:fileUtil方法步骤4有;


import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.jeecg.common.util.file.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.util.Map;/*** 模板生成word文档工具类* @author xty*/
public class GenerateWordUtil {private static final Logger LOGGER = LoggerFactory.getLogger(GenerateWordUtil.class);/*** 通过模板生成word文档* @param data 要填充的数据* @param templatePath 模板路径* @param templateFileName 模板名称* @param docFilePath 输出文档路径* @param docFileName 输出文档名称**/public static void generateWordByTemplate(Map<String, Object> data ,String templatePath, String templateFileName, String docFilePath, String docFileName) throws Exception {try{//Configuration 用于读取ftl文件Configuration configuration = new Configuration();configuration.setDefaultEncoding("utf-8");//指定路径的第二种方式,我的路径是F:/test.ftlconfiguration.setDirectoryForTemplateLoading(new File(templatePath));//ftl文件目录//输出文档File outFile = new File(docFilePath+File.separator+docFileName);//创建目录FileUtils.isExistDir(docFilePath);//以utf-8的编码读取ftl文件Template template = configuration.getTemplate(templateFileName, "utf-8");Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);template.process(data, out);out.close();}catch (Exception e){e.printStackTrace();}}}

ps:传入的map,可以用实体类转换一下,记得属性不能为空,为空的话可以就行循环赋值“ ”;

  • Java实体类与Map互转工具类
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/**1. Java实体类与Map互转2.  3. @author xty*/
public class EntityMapTransUtils {private static final Logger logger = LoggerFactory.getLogger(EntityMapTransUtils.class);/**4. Java实体类转Map:方法一5. @param obj6. @return*/public static Map<String, Object> entityToMap1(Object obj){Map<String, Object> map = new HashMap<String, Object>();Class<?> clazz = obj.getClass();for(Field field : clazz.getDeclaredFields()){field.setAccessible(true);String fieldName = field.getName();Object object = null;try {object = field.get(obj);} catch (IllegalArgumentException | IllegalAccessException e) {logger.info(e.getMessage());}map.put(fieldName, object);}return map;}/**7. Java实体类转Map:方法二8. @param obj9. @return*/public static Map<String, Object> entityToMap2(Object obj){Map<String, Object> map = new HashMap<String, Object>();try {BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();for (PropertyDescriptor property : propertyDescriptors) {String key = property.getName();// 过滤class属性if (!key.equals("class")) {// 得到property对应的getter方法Method getter = property.getReadMethod();Object value = getter.invoke(obj);map.put(key, value);}}} catch (Exception e) {logger.info(e.getMessage());}return map;}/**10. Map转实体类:要转换的Map的key跟实体类属性名相同的数据会转过去,不相同的字段会为null11. @param clazz12. @param map13. @return*/public static <T> T mapToEntity1(Class<T> clazz,Map<String, Object> map){T obj = null;try {BeanInfo beanInfo = Introspector.getBeanInfo(clazz);obj = clazz.newInstance(); // 创建 JavaBean 对象PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();// 给 JavaBean 对象的属性赋值for (int i = 0; i < propertyDescriptors.length; i++) {PropertyDescriptor descriptor = propertyDescriptors[i];String propertyName = descriptor.getName();if (map.containsKey(propertyName)) {Object value = map.get(propertyName);Object[] args = new Object[1];args[0] = value;try {descriptor.getWriteMethod().invoke(obj, args);} catch (InvocationTargetException e) {logger.info(e.getMessage());}}}} catch (IllegalAccessException e) {logger.info(e.getMessage());} catch (IntrospectionException e) {logger.info(e.getMessage());} catch (IllegalArgumentException e) {logger.info(e.getMessage());} catch (InstantiationException e) {logger.info(e.getMessage());}return (T)obj;}
}
  1. 生成word文件到目录底下后,在将word文件转成pdf,然后删除掉word文件

依赖:

<!--导出word--><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId><version>2.0.2</version></dependency><!--word转pdf--><dependency><groupId>e-iceblue</groupId><artifactId>spire.doc.free</artifactId><version>5.2.0</version></dependency>

Word转pdf工具类:


import com.spire.doc.Document;
import com.spire.doc.FileFormat;import java.io.File;/*** Word转pdf工具类* @author xty*/
public class WordToPdfUtil {/*** Word转pdf* @param docFilePath* @param pdfFilePath*/public static void wordToPdf( String docFilePath, String pdfFilePath) {//实例化Document类的对象Document doc = new Document();//加载Word docFilePath需要为完整路径+文件名doc.loadFromFile(docFilePath);//保存为PDF格式 pdfFilePath需要为完整路径+文件名doc.saveToFile(pdfFilePath, FileFormat.PDF);//删除原来的doc文件File file = new File(docFilePath);file.delete();}}
  1. 将指定路径下的所有文件打包zip导出下载

    工具类:

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;/**1.  将指定路径下的所有文件打包zip导出工具类2. @author xty*/
public class FileZipUtil {/*** 将指定路径下的所有文件打包zip导出** @param response       HttpServletResponse* @param sourceFilePath 要打包的路径* @param fileName       下载时的文件名称*                       //     * @param postfix 下载时的文件后缀 .zip/.rar*/public static void exportZip(HttpServletResponse response, String sourceFilePath, String fileName) {// 默认文件名以时间戳作为前缀SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String downloadName = sdf.format(new Date()) + fileName;// 将文件进行打包下载try {OutputStream os = response.getOutputStream();// 接收压缩包字节byte[] data = createZip(sourceFilePath);response.reset();response.setCharacterEncoding("UTF-8");response.addHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Expose-Headers", "*");// 下载文件名乱码问题response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadName, "UTF-8"));//response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + downloadName);response.addHeader("Content-Length", "" + data.length);response.setContentType("application/octet-stream;charset=UTF-8");IOUtils.write(data, os);os.flush();os.close();} catch (Exception e) {e.printStackTrace();}}/*** 创建zip文件** @param sourceFilePath* @return byte[]* @throws Exception*/private static byte[] createZip(String sourceFilePath) throws Exception {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ZipOutputStream zip = new ZipOutputStream(outputStream);// 将目标文件打包成zip导出File file = new File(sourceFilePath);handlerFile(zip, file, "");// 无异常关闭流,它将无条件的关闭一个可被关闭的对象而不抛出任何异常。IOUtils.closeQuietly(zip);return outputStream.toByteArray();}/*** 打包处理** @param zip* @param file* @param dir* @throws Exception*/private static void handlerFile(ZipOutputStream zip, File file, String dir) throws Exception {// 如果当前的是文件夹,则循环里面的内容继续处理if (file.isDirectory()) {//得到文件列表信息File[] fileArray = file.listFiles();if (fileArray == null) {return;}//将文件夹添加到下一级打包目录zip.putNextEntry(new ZipEntry(dir + "/"));dir = dir.length() == 0 ? "" : dir + "/";// 递归将文件夹中的文件打包for (File f : fileArray) {handlerFile(zip, f, dir + f.getName());}} else {// 如果当前的是文件,打包处理BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));ZipEntry entry = new ZipEntry(dir);zip.putNextEntry(entry);zip.write(FileUtils.readFileToByteArray(file));IOUtils.closeQuietly(bis);zip.flush();zip.closeEntry();}}
}
  1. 下载完成之后,删掉临时zip包和临时生成的文件夹

fileUtil工具类新增两个方法

/*** 删除指定文件夹下文件** @param filePath*/public static void deleteFolders(String filePath) {Path path = Paths.get(filePath);try {Files.walkFileTree(path, new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {Files.delete(file);LOGGER.info("删除文件: {}", file);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult postVisitDirectory(Path dir,IOException exc) throws IOException {Files.delete(dir);LOGGER.info("文件夹被删除: {}", dir);return FileVisitResult.CONTINUE;}});} catch (IOException e) {e.printStackTrace();}}/*** 判断多级路径是否存在,不存在就创建** @param filePath 支持带文件名的Path:如:D:ews201412abc.text,和不带文件名的Path:如:D:ews201412*/public static void isExistDir(String filePath) {String paths[] = {""};//切割路径try {String tempPath = new File(filePath).getCanonicalPath();//File对象转换为标准路径并进行切割,有两种windows和linuxpaths = tempPath.split("\\\\");//windowsif(paths.length==1){paths = tempPath.split("/");}//linux} catch (IOException e) {System.out.println("切割路径错误");e.printStackTrace();}//判断是否有后缀boolean hasType = false;if(paths.length>0){String tempPath = paths[paths.length-1];if(tempPath.length()>0){if(tempPath.indexOf(".")>0){hasType=true;}}}//创建文件夹String dir = paths[0];for (int i = 0; i < paths.length - (hasType?2:1); i++) {// 注意此处循环的长度,有后缀的就是文件路径,没有则文件夹路径try {dir = dir + "/" + paths[i + 1];//采用linux下的标准写法进行拼接,由于windows可以识别这样的路径,所以这里采用警容的写法File dirFile = new File(dir);if (!dirFile.exists()) {dirFile.mkdir();System.out.println("成功创建目录:" + dirFile.getCanonicalFile());}} catch (Exception e) {System.err.println("文件夹创建发生异常");e.printStackTrace();}}}

最后附上接口方法;上面那些代码块都是对于方法的补充,只是记录学习一下,整合了各个大佬的方法最终实现的。

路径和模板配置

引入属性;

接口方法:

// 下载体检报告PDF@AutoLog(value = "学校体检列表-下载体检报告PDF", operateType = CommonConstant.OPERATE_TYPE_ADD)@ApiOperation(value="学校体检列表-下载体检报告PDF", notes="学校体检列表-下载体检报告PDF")@GetMapping(value = "/uploadPhysicalExaminationListPDF")public void uploadPhysicalExaminationListPDF(@RequestParam Integer activityId,@RequestParam Integer gradeCode,@RequestParam Integer classCode,@RequestParam Integer gender,@RequestParam Integer releaseStatus,HttpServletResponse response) throws Exception {/*** 下载思路:* 1、查询出数据后;* 2、将数据按照word模板插入数据生成word文件,将word文件转成pdf(所有生成的数据都同一新增的目录下);* 3、将该目录底下的所有文件打包成压缩包;* 4、进行下载操作;* 5、下载完毕需要对于zip包和word文件目录删除*/PePhysicalExaminationQuery pePhysicalExaminationQuery = new PePhysicalExaminationQuery();pePhysicalExaminationQuery.setActivityId(activityId);pePhysicalExaminationQuery.setGradeCode(gradeCode);pePhysicalExaminationQuery.setClassCode(classCode);pePhysicalExaminationQuery.setGender(gender);pePhysicalExaminationQuery.setReleaseStatus(releaseStatus);List<PePhysicalExaminationVo> pePhysicalExaminationVos = pePhysicalExaminationService.selectPhysicalExaminationListToPDF(pePhysicalExaminationQuery);if(pePhysicalExaminationVos==null||pePhysicalExaminationVos.size()<1){log.error("查询到体检数据为空");return;}//存放doc和pdf的目录 后面用前缀路径拼接起来。因为打包要单独在一个目录底下String folderName = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN)+(int) (Math.random()*9000+1000);//时间+随机生成一个四位整数;//循环进行数据插入到doc模板中,生成word文件;然后转pdf到底下for (PePhysicalExaminationVo pePhysicalExaminationVo:pePhysicalExaminationVos){try {//Java实体类与Map互转Map<String, Object> map = EntityMapTransUtils.entityToMap1(pePhysicalExaminationVo);//处理字段为空的时候,数据载入到模板会报错,所以赋值为“ ”for(String key:map.keySet()){if(StringUtils.isNull(map.get(key))){map.put(key," ");}}//输出文档路径及名称String docFilePath = generatePath + folderName;String docFileName = pePhysicalExaminationVo.getStudentName() + ".doc";if("男".equals(pePhysicalExaminationVo.getGender())){//使用男生体检模板GenerateWordUtil.generateWordByTemplate(map,templatePath,maleExaminationTemplateFileName, docFilePath,docFileName);}else {//使用女生体检模板GenerateWordUtil.generateWordByTemplate(map,templatePath,femaleExaminationTemplateFileName, docFilePath,docFileName);}//将生成的word转换成pdf File.separator分隔符String pdfFileName = generatePath + folderName + File.separator + pePhysicalExaminationVo.getStudentName() + ".pdf";WordToPdfUtil.wordToPdf(docFilePath+File.separator+docFileName,pdfFileName);} catch (Exception e) {e.printStackTrace();}}//将指定路径下的所有文件打包zip导出下载FileZipUtil.exportZip(response, generatePath+folderName, generatePath+"temporary.zip");//下载完成之后,删掉临时zip包和临时生成的文件夹File file = new File(generatePath+"temporary.zip");file.delete();FileUtils.deleteFolders(generatePath+folderName);}

对了;前端下载的话,返回的流。前端直接保存即可

java关于对于word或者pdf文件的批量下载实现,其中包括(Java实现创建word文档模板,根据模板导出word文档)相关推荐

  1. JSZip解压PDF文件并批量下载

    JSzip解压PDF文件并批量下载 因需要解压PDF文件并且实现批量下载,但网上找到的基本都是图片的解压和下载,所以参考图片的解压修改了一下. 用到了jszip,jszip-utils,file-sa ...

  2. 利用Word制作pdf文件的方法

    利用Word制作pdf文件的方法 一.先用手机照成图片 二.把图片拖到word中 三.生成pdf文件 一.先用手机照成图片 二.把图片拖到word中 三.生成pdf文件 点文件 点导出 点创建PDF ...

  3. 实现Word转Pdf文件

    在项目中需要以Word文件为模板,填充指定数据,并转换为Pdf文件.可以分为两步,第一步使用POI进行文本替换,第二步把替换后的Word转换为pdf文件. 当前遇到的问题是网上所有的转换工具依赖的包都 ...

  4. java将HTML文件转化为pdf文件,如何使用Java将HTML网页转换为PDF文件

    我一直在互联网上搜索如何使用Java将HTML页面转换为PDF文件.我发现了很多指针,简而言之,它们不起作用或难以实现.我也下载了一个商业产品,pdf4ml;该API是我很乐意与之合作的,除了当我在维 ...

  5. java在linux生成pdf文件,从 Java 应用程序动态生成 PDF 文件

    简介: 如果您的应用程序需要动态生成 PDF 文档,那么您需要 iText 库.开源的 iText 库使得 PDF 的创建变得轻松易行.本文介绍了 iText 并提供了一个使用它从 Java 技术应用 ...

  6. Web方式预览Office/Word/Excel/pdf文件解决方案

    Web方式预览Office/Word/Excel/pdf文件解决方案 参考文章: (1)Web方式预览Office/Word/Excel/pdf文件解决方案 (2)https://www.cnblog ...

  7. 在线查看word,excel,pdf文件解决

    眼看着项目要结束,提出新的需求(-_-!!习惯成自然了)需要支持在线查看word,excel,pdf文件,网页中嵌套word的时候,不让word文档占据整个网页,页面内还要有审批等功能,第一感觉想到控 ...

  8. 解决word转PDF文件时图片位置改变和字体格式改变的问题

    解决word转PDF文件时图片位置改变和字体格式改变的问题 在写论文的时候,使用word编辑完文本后将其导出为PDF总是出现图片位置改变或者字体格式改变的问题,好不容易在word中编辑好的格式却不能在 ...

  9. 通过Spire-java实现word和pdf文件相互转换

    通过Spire-java实现word和pdf文件相互转换 导入依赖包 iceBlue官网 简介 接口文档 两个工具类 WordConvertUtils PdfConvertUtils 导入依赖包 sp ...

最新文章

  1. 3D中OBJ文件格式详解
  2. 基于S3C2440A+SDRAM(K4M51163)
  3. Oracle Supplemental 补全日志介绍
  4. c#推箱子小游戏代码_推箱子小游戏V1.0制作
  5. SQL Server Reporting Services(简称SSRS)
  6. 看动画学算法之:排序-冒泡排序
  7. 【Luogu】P1131时态同步(树形DP)
  8. 实验一 线性表的顺序存储与实现_数据结构篇之单链表的创建以及实现
  9. Outlook验证服务器证书,OUTLOOK2019 解决 无法验证您连接到的服务器使用的安全证书...
  10. 64位程序如何调用32位dll(简单解决方案 )
  11. PHP分类输出代码,PHP无限分类代码,支持数组格式化、直接输出菜单两种方式_php技巧...
  12. 两层板(双面板)如何控制50欧特性阻抗
  13. Parallels Desktop 15.1.4 直装版 — 苹果电脑虚拟机
  14. 微信小程序之如何获取输入框的内容
  15. 痞子衡嵌入式:PCM编码与Waveform音频文件(.wav)格式详解
  16. C#练习题答案: 巴路士惠勒改造【难度:4级】--景越C#经典编程题库,1000道C#基础练习题等你来挑战
  17. 一起来看流星雨剧情简介/剧情介绍/剧情分集介绍第二十八集
  18. Java终结类用的关键字_java习题集及答案
  19. 故障管理系统,如何使用二维码报修
  20. Gstreamer 中的playback插件

热门文章

  1. 华为路由hilink_友猫:华为路由器的 Hi 按键功能(HiLink 智联和WPS)
  2. DOS命令字典..收藏
  3. 【科创人独家】PerfMa“寒泉子”李嘉鹏:成长和创业都要能人所不能,真强者何惧资本寒冬
  4. graylog+kafka+zookeeper(单机测试及源码),graylog设置URL报警方式(五)
  5. 【立创开源】RY3730-带充电的恒流驱动LED照明灯
  6. 如何判断某个物体当前是顺时针还是逆时针旋转
  7. 2022支付宝集五福攻略,一天20张不是事
  8. 鲲鹏Arm64 openEuler 虚拟机学习
  9. 区块链与金融基础设施——兼论Facebook Libra
  10. import_meta_graph 和 replicate_model_fn