1.工具 

 // 生成PDF自定义模板内容

 (1) Adobe Acrobat Pro9 

 

2.操作步骤

 (1)利用Adobe Acrobat Pro9 生成一张根据业务场景的PDF,设置每个内容的字段(这款软件功能比较强大,可以设置条形码和二维码的参数) 

 

(3)JAVA实现代码

 

1 import com.itextpdf.text.pdf.PdfReader;
  2 import lombok.extern.slf4j.Slf4j;
  3 import org.springframework.beans.factory.annotation.Value;
  4 import org.springframework.stereotype.Component;
  5 import org.springframework.util.ClassUtils;
  6 import org.springframework.util.CollectionUtils;
  7 import org.springframework.util.ResourceUtils;
  8 
  9 import javax.servlet.ServletOutputStream;
 10 import javax.servlet.http.HttpServletResponse;
 11 import java.io.*;
 12 import java.util.HashMap;
 13 import java.util.List;
 14 import java.util.UUID;
 15 
 16 /**
 17  * @description: PDF下载
 18  * @author: ZhuCJ 
 19  * @date: 2020-05-20 15:36
 20  */
 21 @Slf4j
 22 @Component
 23 public class PdfDownUtils {
 24 
 25     /** 最终存放pdf位置 */
 26     @Value("${pdf.savePath}")
 27     private String savePath;
 28 
 29     /** 读取模板,生成的复制pdf位置 */
 30     @Value("${pdf.cachePath}")
 31     private String cacheTempPath;
 32 
 33     /**读取模板的位置 */
 34     @Value("${pdf.tempPath}")
 35     private String tempPath;
 36 
 37     /**
 38      * 读取的模板名字
 39      */
 40     public static String TEMPLATE_NAME = "temp.pdf";
 41 
 42     
 43     /**
 44      * 下载单张PDF
 45      * @param mapPDF
 46      * @param fileName
 47      * @param filePath
 48      * @param response
 49      * @throws IOException
 50      */
 51     public void pdfCompress(HashMap<String,String> mapPDF,String fileName
 52                          ,String filePath, HttpServletResponse response) throws IOException{
 53 
 54         String sysPath = ClassUtils.getDefaultClassLoader().getResource("").getPath();
 55         //项目下模板路径
 56         //String  readTempPath = sysPath +"data"+File.separator+"hanzt"+File.separator+"temp";
 57         //读取模板文件
 58         PdfReader reader = new PdfReader(tempPath + File.separator + TEMPLATE_NAME);
 59         //生成pdf
 60         InputStream  pdfStream = null;
 61         try {
 62            pdfStream  = this.print(reader, mapPDF,fileName,filePath);
 63         } catch (IOException e) {
 64             e.printStackTrace();
 65         }
 66         ServletOutputStream op = null;
 67         try {
 68             op = response.getOutputStream();
 69         } catch (IOException e) {
 70             e.printStackTrace();
 71         }
 72         response.setContentType("application/pdf");
 73         response.setHeader("Content-Disposition", "inline; filename=\""
 74                 + new String(fileName.getBytes("gb18030"), "ISO8859-1") + ".pdf" + "\"");
 75         int length = 0;
 76         byte[] bytes = new byte[1024];
 77         while((pdfStream != null) && ((length = pdfStream.read(bytes)) != -1)) {
 78             op.write(bytes, 0, length);
 79         }
 80         op.close();
 81         reader.close();
 82         response.flushBuffer();
 83     }
 84 
 85 
 86 
 87     /**
 88      * 生成pdf打成ZIP包下载
 89      * @param orderZips 模板参数
 90      * @param filePath   pdf 保存文件上级文件夹名
 91      * @param response
 92      * @throws IOException
 93      */
 94     public void pdfCompressZip(List<List<HashMap<String,Object>>> orderZips,
 95                                String filePath, HttpServletResponse response) throws IOException{
 96         if (CollectionUtils.isEmpty(orderZips)){
 97             return;
 98         }
 99 
100         for (List orderZip:orderZips){
101             if (CollectionUtils.isEmpty(orderZip)){
102                 continue;
103             }
104           for (Object orderPdf:orderZip){
105               HashMap<String,Object> mapPDF =(HashMap<String,Object>) orderPdf;
106               //获取生成pdf的文件名
107               String fileName = null;
108               if (mapPDF.containsKey("fileName")){
109                   fileName = mapPDF.get("fileName").toString();
110               }else {
111                   //默认随机生成一个,保证唯一性避免覆盖
112                   fileName = UUID.randomUUID().toString();
113               }
114               try {
115                   this.printFilePath(mapPDF, fileName, filePath);
116               } catch (IOException e) {
117                   log.error("生成Pdf文件IO异常:{}",e.getMessage());
118               }
119           }
120         }
121         //本次操作保存pdf文件路径,用于压缩成Zip包
122         String pdfFilePath = savePath+File.separator+filePath+File.separator;
123         log.info("待压缩zip包文件名:{}",pdfFilePath);
124         File file = new File(pdfFilePath);
125         String zipFile = null;
126         File ftp = null;
127         try {
128             zipFile = CompressZipUtil.zipFile(file,"zip");
129         } catch (Exception e) {
130             e.printStackTrace();
131         }
132         response.setContentType("APPLICATION/OCTET-STREAM");
133         response.setHeader("Content-Disposition","attachment; filename=listDown.zip");
134         OutputStream out = null;
135         InputStream in  = null;
136         try {
137             out = response.getOutputStream();
138             //
139             ftp = ResourceUtils.getFile(zipFile);
140             in = new FileInputStream(ftp);
141             // 循环取出流中的数据
142             byte[] b = new byte[100];
143             int len;
144             while ((len = in.read(b)) !=-1) {
145                 out.write(b, 0, len);
146             }
147         } catch (Exception e) {
148             e.printStackTrace();
149             log.error("文件读取异常:{}",e.getMessage());
150 
151         }finally {
152             if (in !=null){
153                 in.close();
154             }
155             if (out !=null){
156                 out.close();
157             }
158             log.info("zip下载完成,进行删除本地zip包");
159             //删除保存的Pdf文件
160             DeleteFileUtil.deleteFile(file);
161             //删除保存的压缩包
162             if (ftp!=null){
163                 ftp.delete();
164             }
165         }
166     }
167 
168     /**
169      *
170      * @param map
171      * @param fileName
172      * @return 所在文件地址
173      * @throws IOException
174      */
175     private String printFilePath(HashMap<String,Object> map
176             ,String fileName,String filePath) throws IOException {
177         String sysPath = ClassUtils.getDefaultClassLoader().getResource("").getPath();
178         //项目下模板路径
179        // String  readTempPath = sysPath +"data"+File.separator+"hanzt"+File.separator+"temp";
180         //判断是否存在文件目录,不存在创建
181         createFile(savePath,cacheTempPath);
182         //保存路径+随机文件名
183         String save = savePath+ File.separator+filePath+File.separator;
184         PdfFormater pdf = new PdfFormater(tempPath, save,cacheTempPath,TEMPLATE_NAME,map);
185         pdf.doTransform(fileName);
186         return save;
187     }
188 
189 
190         /**
191           * 打印,以PDF为模板
192           * @param templateName String 模板名字
193           * @param map 模板数据HashMap
194           * @return InputStream
195           * @throws IOException
196           */
197     private InputStream print(PdfReader reader, HashMap<String,String> map, String fileName, String filePath) throws IOException {
198         InputStream is = null;
199         String sysPath = ClassUtils.getDefaultClassLoader().getResource("").getPath();
200         //项目下模板路径
201         //String  readTempPath = sysPath +"data"+File.separator+"hanzt"+File.separator+"temp";
202         //判断是否存在文件目录,不存在创建
203         createFile(savePath,cacheTempPath);
204         //保存路径+随机文件名
205         String save = savePath+ File.separator+filePath+File.separator;
206         PdfFormater pdf = new PdfFormater(tempPath,save,cacheTempPath,TEMPLATE_NAME, map);
207         String PdfFilePath = pdf.doTransform(fileName);
208         is = new FileInputStream(PdfFilePath);
209         return is;
210     }
211 
212 
213 
214     /**
215      * 判断文件夹是否存在,不存在创建一个
216      * @param filePaths
217      * @return
218      */
219     public void createFile(String ... filePaths){
220         for (String filePath:filePaths){
221             File file = new File(filePath);
222             if (!file.exists()){
223                 file.mkdirs();
224             }
225         }
226     }
227 
228 }
1 import com.itextpdf.text.BadElementException;
  2 import com.itextpdf.text.DocumentException;
  3 import com.itextpdf.text.Image;
  4 import com.itextpdf.text.Rectangle;
  5 import com.itextpdf.text.pdf.*;
  6 import com.sf.vsolution.hb.sfce.util.string.StringUtils;
  7 import lombok.extern.slf4j.Slf4j;
  8 
  9 import java.io.File;
 10 import java.io.FileOutputStream;
 11 import java.io.IOException;
 12 import java.lang.reflect.Field;
 13 import java.util.Iterator;
 14 import java.util.List;
 15 import java.util.Map;
 16 import java.util.Objects;
 17 
 18 /**
 19  * @description:
 20  * @author: ZhuCJ 
 21  * @date: 2020-05-27 10:50
 22  */
 23 @Slf4j
 24 public class PdfFormater {
 25     /**
 26      * pdf模板路径
 27      */
 28     private String templatePath;
 29     /**
 30      * 下载完成的pdf路径
 31      */
 32     private String savePath;
 33     /**
 34      * 缓存pdf路径
 35      */
 36     private String cachePath;
 37 
 38     /**
 39      * 读取模板对象
 40      */
 41     private String templateName;
 42 
 43     /**
 44      * 需要填充的数据
 45      */
 46     private Map dataMap;
 47 
 48     private String cacheFileName;
 49 
 50     //新的PDF文件名称
 51     private String resultFileName;
 52     //动态数据
 53     private List dynData;
 54 
 55 
 56     /**
 57           * 构造器,生成PDF引擎实例,并引入相应模板文件XXX.FO、路径和报表数据HashMap
 58           *
 59           * @param templateDir
 60           *            模板文件所在目录
 61           * @param basePath
 62           *            模板文件工作副本及结果PDF文件所在工作目录
 63           * @param templateFileFo
 64           *            模板文件名,推荐格式为“XXXTemplate.FO”, 其文件由word模板文档在设计时转换而成
 65           * @param dataMap
 66           *            对应模板的数据HashMap,由调用该打印引擎的里程根据模板格式和约定进行准备
 67           */
 68     public PdfFormater(String templatePath, String savePath, String cachePath,
 69                        String templateName, Map dataMap) {
 70         this.templatePath = templatePath;
 71         this.savePath = savePath;
 72         this.templateName = templateName;
 73         this.cachePath = cachePath;
 74         this.dataMap = dataMap;
 75     }
 76 
 77     /**
 78      * 设置字体
 79      * @param font
 80      * @return
 81      */
 82     private BaseFont getBaseFont(String font) {
 83       // 需要根据不同的模板返回字体
 84         BaseFont bf = null;
 85         try {
 86             bf = BaseFont.createFont( StringUtils.isEmpty(font)?"STSong-Light":font, "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
 87         } catch (DocumentException e) {
 88             e.printStackTrace();
 89         } catch (IOException e) {
 90             e.printStackTrace();
 91         }
 92         return bf;
 93     }
 94 
 95     /**
 96      * 避免出现多线程重复读
 97      * @param fileName
 98      * @return
 99      */
100     public String doTransform(String fileName) {
101         long name = System.currentTimeMillis();
102         //缓存模板名字
103         cacheFileName =   name + ".pdf";
104         //最后保存模板名字
105         resultFileName =  fileName + ".pdf";
106         try {
107             PdfReader reader;
108             PdfStamper stamper;
109             //读取PDF模板对象
110             reader = new PdfReader(templatePath + File.separator + templateName);
111             //生成新的PDF模板对象
112             stamper = new PdfStamper(reader, new FileOutputStream(cachePath + File.separator + cacheFileName));
113             AcroFields form = stamper.getAcroFields();
114             form.addSubstitutionFont(getBaseFont(""));
115             transformRegular(form,stamper);
116             stamper.setFormFlattening(true);
117             stamper.close();
118             reader.close();
119             postProcess();
120         } catch (Exception e) {
121             e.printStackTrace();
122         }
123         return savePath + File.separator + resultFileName;
124     }
125 
126          /**
127           * 填充规整的表单域
128           * @param form
129           */
130     private void transformRegular(AcroFields form,PdfStamper stamper) {
131         if (dataMap == null || dataMap.size() == 0) {return;}
132         String key = "";
133         Iterator ekey = dataMap.keySet().iterator();
134         Object obj = null ;
135         while (ekey.hasNext()) {
136             key = ekey.next().toString();
137             try {
138                 obj = dataMap.get(key);
139                 if(obj instanceof List){
140                    //map中放的是list,为动态字段
141                     dynData = (List)obj;
142                     transformDynTable(form);
143                 }else{
144                    //非空放入
145                     if( dataMap.get(key) != null) {
146                         if (Objects.equals(key,"code1") || Objects.equals(key,"code2") ){
147                             //key = code1或code2 进行生成条形码;
148                             createBarCode(form,stamper,key,dataMap.get(key));
149                         }else if (Objects.equals(key,"qrCode")){
150                             //key = qrCode 进行生成二维码
151                             createQrCode(form,stamper,key,dataMap.get(key));
152                         }else {
153                             form.setField(key, dataMap.get(key).toString());
154                         }
155                     }
156 
157                 }
158             } catch (Exception e) {
159                log.error("pdf赋值异常:{}",e.getMessage());
160             }
161         }
162     }
163 
164           /**
165           * 动态table的填充
166           * @param form
167           */
168     private void transformDynTable(AcroFields form) {
169         if (dynData == null || dynData.size() == 0)
170         {return;}
171         Object obj = null;
172         String name = "";
173         String value = "";
174         for (int x = 0; x < dynData.size(); x++) {
175             obj = dynData.get(x);
176             Field[] fld = obj.getClass().getDeclaredFields();
177             for (int i = 0; i < fld.length; i++) {
178                 name = fld[i].getName();
179                 value = (String) ReflectUtils.getFieldValue(obj, name);
180                 try {
181                     form.setField(name + x, value);
182                 } catch (IOException e) {
183                     e.printStackTrace();
184                 } catch (DocumentException e) {
185                     e.printStackTrace();
186                 }
187             }
188         }
189     }
190 
191     /**
192           * 对生成的pdf文件进行后处理
193           *
194           * @throws RptException
195           */
196     private synchronized void postProcess() throws Exception {
197         FileOutputStream fosRslt = null;
198         PdfStamper stamper = null;
199         PdfReader reader = null;
200         try {
201             reader = new PdfReader(cachePath + File.separator + cacheFileName);
202             String save = savePath+File.separator+resultFileName;
203             File file = new File(save);
204             File parentFile = file.getParentFile();
205             if (!parentFile.exists()){
206                 parentFile.mkdirs();
207             }
208             fosRslt = new FileOutputStream(savePath + File.separator + resultFileName);
209             stamper = new PdfStamper(reader, fosRslt);
210 
211             Rectangle pageSize = reader.getPageSize(1);
212             float width = pageSize.getWidth();
213             BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
214             PdfContentByte over;
215             int total = reader.getNumberOfPages() + 1;
216             for (int i = 1; i < total; i++) {
217                 over = stamper.getOverContent(i);
218                 if (total <= 2){break;}
219                 over.beginText();
220                 over.setFontAndSize(bf, 10);
221                 over.setTextMatrix(width - 92f, 32);
222                 over.showText("第 " + i + " 页");
223                 over.endText();
224             }
225         } catch (Exception ie) {
226             ie.printStackTrace();
227         } finally {
228             if (stamper != null) {
229                 try {
230                     stamper.close();
231                 } catch (DocumentException e) {
232                     e.printStackTrace();
233                 } catch (IOException e) {
234                     e.printStackTrace();
235                 }
236             }
237             if (fosRslt != null) {
238                 try { fosRslt.close();
239                 } catch (IOException e) {
240                     e.printStackTrace();
241                 }
242             }
243             if (reader != null) {
244                 reader.close();
245             }
246             File pdfFile = new File(cachePath+File.separator + cacheFileName);
247             pdfFile.delete();
248         }
249 
250     }
251 
252     /**
253      * PDF中绘制条形码
254      * @param form
255      * @param stamper
256      * @param key
257      * @param value
258      */
259     public void createBarCode(AcroFields form, PdfStamper stamper,String key,Object value){
260 
261         // 获取属性的类
262         if (value != null && form.getField(key) != null) {
263             //获取位置(左上右下)
264             AcroFields.FieldPosition fieldPosition = form.getFieldPositions(key).get(0);
265             //绘制条码
266             Barcode128 barcode128 = new Barcode128();
267             //字号
268             barcode128.setSize(6);
269             //条码高度
270             if (key.equals("code1")){
271                 barcode128.setBarHeight(19.88f);
272                 barcode128.setBaseline(9);
273             }else {
274                 barcode128.setBarHeight(16.24f);
275                 //条码与数字间距
276                 barcode128.setBaseline(8);
277             }
278             //条码值
279             barcode128.setCode(value.toString());
280             barcode128.setStartStopText(false);
281             barcode128.setExtended(true);
282             //绘制在第一页
283             PdfContentByte cb = stamper.getOverContent(1);
284             //生成条码图片
285             Image image128 = barcode128.createImageWithBarcode(cb, null, null);
286             //条码位置
287             float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;
288             if (key.equals("code2")){
289                 //条码位置
290                 image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, 395.67f);
291             }else {
292                 image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, 157.8f );
293             }
294             //加入条码
295             try {
296                 cb.addImage(image128);
297             } catch (DocumentException e) {
298              log.error("创建条码异常:{}",e.getMessage());
299             }
300 
301         }
302 
303     }
304 
305     /**
306      * 绘制二维码
307      * @param form
308      * @param stamper
309      * @param key
310      * @param value
311      */
312     public void createQrCode(AcroFields form, PdfStamper stamper,String key,Object value){
313         // 获取属性的类型
314         if(value != null && form.getField(key) != null){
315             //获取位置(左上右下)
316             AcroFields.FieldPosition fieldPosition = form.getFieldPositions(key).get(0);
317             //绘制二维码
318             float width = fieldPosition.position.getRight() - fieldPosition.position.getLeft();
319             BarcodeQRCode pdf417 = new BarcodeQRCode(value.toString(), (int)width, (int)width, null);
320             //生成二维码图像
321             Image image128 = null;
322             try {
323                 image128 = pdf417.getImage();
324             } catch (BadElementException e) {
325                 log.error("创建二维码异常:{}",e.getMessage());
326             }
327             //绘制在第一页
328             PdfContentByte cb = stamper.getOverContent(1);
329             //左边距(居中处理)
330             float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;
331             //二维码位置
332             image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, 300);
333             image128.setBorderWidth(1000);
334             //加入二维码
335             try {
336                 cb.addImage(image128);
337             } catch (DocumentException e) {
338                 log.error("加入二维码异常:{}",e.getMessage());
339             }
340         }
341     }
342 
343 }
import lombok.extern.log4j.Log4j2;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;

/**
 * @description: 文件打ZIP包工具类
 * @author: ZhuCJ  
 * @date: 2020-05-27 14:43
 */
@Log4j2
public class CompressZipUtil {

    /**
     * 压缩文件(文件夹)
     * @param path   目标文件流
     * @param format zip 格式 | rar 格式
     * @throws Exception
     */
    public static String zipFile(File path, String format) throws Exception {
        String generatePath = "";
        if (path.isDirectory()) {
            generatePath = path.getParent().endsWith(File.separator) == false ?
                    path.getParent() + File.separator + path.getName() + "." + format :
                    path.getParent() + path.getName() + "." + format;
        } else {
            generatePath = path.getParent().endsWith(File.separator) == false ? path.getParent() + File.separator :
                    path.getParent();
            generatePath += path.getName().substring(0, path.getName().lastIndexOf(".")) + "." + format;
        }
        // 输出流
        FileOutputStream outputStream = new FileOutputStream(generatePath);
        // 压缩输出流
        ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(outputStream));
        zip(out, path, "");
        out.flush();
        out.close();

        return generatePath;
    }

    /**
     * @param sourcePath 要压缩的文件路径
     * @param suffix     生成的格式后最(zip、rar)
     */
    public static void generateFile(String sourcePath, String suffix) throws Exception {

        File file = new File(sourcePath);
        // 压缩文件的路径不存在
        if (!file.exists()) {
            throw new Exception("路径 " + sourcePath + " 不存在文件,无法进行压缩...");
        }
        // 用于存放压缩文件的文件夹
        String generateFile = file.getParent() + File.separator + "CompressFile";
        File compress = new File(generateFile);
        // 如果文件夹不存在,进行创建
        if (!compress.exists()) {
            compress.mkdirs();
        }
        // 目的压缩文件
        String generateFileName = compress.getAbsolutePath() + File.separator + "AAA" + file.getName() + "." + suffix;

        // 输入流 表示从一个源读取数据
        // 输出流 表示向一个目标写入数据

        // 输出流
        FileOutputStream outputStream = new FileOutputStream(generateFileName);

        // 压缩输出流
        ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(outputStream));

        generateFile(zipOutputStream, file, "");

        System.out.println("源文件位置:" + file.getAbsolutePath() + ",目的压缩文件生成位置:" + generateFileName);
        // 关闭 输出流
        zipOutputStream.close();
    }

    /**
     * @param out  输出流
     * @param file 目标文件
     * @param dir  文件夹
     * @throws Exception
     */
    private static void generateFile(ZipOutputStream out, File file, String dir) {
        FileInputStream inputStream = null;
        try {
            // 当前的是文件夹,则进行一步处理
            if (file.isDirectory()) {
                //得到文件列表信息
                File[] files = file.listFiles();

                //将文件夹添加到下一级打包目录
                out.putNextEntry(new ZipEntry(dir + File.separator));

                dir = dir.length() == 0 ? "" : dir + File.separator;

                //循环将文件夹中的文件打包
                for (int i = 0; i < files.length; i++) {
                    generateFile(out, files[i], dir + files[i].getName());
                }

            } else { // 当前是文件

                // 输入流
                inputStream = new FileInputStream(file);
                // 标记要打包的条目
                out.putNextEntry(new ZipEntry(dir));
                // 进行写操作
                int len = 0;
                byte[] bytes = new byte[1024];
                while ((len = inputStream.read(bytes)) > 0) {
                    out.write(bytes, 0, len);
                }

            }
        } catch (Exception e) {
            log.error("generateFile异常:", e);
        } finally {
            // 关闭输入流
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    /**
     * 递归压缩文件
     *
     * @param output    ZipOutputStream 对象流
     * @param file      压缩的目标文件流
     * @param childPath 条目目录
     */
    private static void zip(ZipOutputStream output, File file, String childPath) {
        FileInputStream input = null;
        try {
            // 文件为目录
            if (file.isDirectory()) {
                // 得到当前目录里面的文件列表
                File list[] = file.listFiles();
                childPath = childPath + (childPath.length() == 0 ? "" : File.separator)
                        + file.getName();
                // 循环递归压缩每个文件
                for (File f : list) {
                    zip(output, f, childPath);
                }
            } else {
                // 压缩文件
                childPath = (childPath.length() == 0 ? "" : childPath + File.separator)
                        + file.getName();
                output.putNextEntry(new ZipEntry(childPath));
                input = new FileInputStream(file);
                int readLen = 0;
                byte[] buffer = new byte[1024 * 8];
                while ((readLen = input.read(buffer, 0, 1024 * 8)) != -1) {
                    output.write(buffer, 0, readLen);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            // 关闭流
            if (input != null) {
                try {
                    input.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

    }

}
import lombok.extern.slf4j.Slf4j;

import java.io.File;

/**
 * @description: 删除指定文件或文件夹下所有内容
 * @author: ZhuCJ 
 * @date: 2020-06-02 0:18
 */
@Slf4j
public class DeleteFileUtil {

    public static void deleteFile(File file){
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f: files){
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()){
                deleteFile(f);
            }else {
                f.delete();
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
        file.delete();
    }
}
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.lang.reflect.*;
import java.util.Date;

/**
 * @description: 反射设置对象属性值
 * @author: ZhuCJ
 * @date: 2020-05-27 11:16
 */
public class ReflectUtils {

    private static final String SETTER_PREFIX = "set";

    private static final String GETTER_PREFIX = "get";

    private static final String CGLIB_CLASS_SEPARATOR = "$$";

    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);

    /**
     * 调用Getter方法.
     * 支持多级,如:对象名.对象名.方法
     */
    public static Object invokeGetter(Object obj, String propertyName) {
        Object object = obj;
        for (String name : StringUtils.split(propertyName, ".")){
            String getterMethodName = GETTER_PREFIX + org.springframework.util.StringUtils.capitalize(name);
            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
        }
        return object;
    }

    /**
     * 调用Setter方法, 仅匹配方法名。
     * 支持多级,如:对象名.对象名.方法
     */
    public static void invokeSetter(Object obj, String propertyName, Object value) {
        Object object = obj;
        String[] names = StringUtils.split(propertyName, ".");
        for (int i=0; i<names.length; i++){
            if(i<names.length-1){
                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
            }else{
                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
                invokeMethodByName(object, setterMethodName, new Object[] { value });
            }
        }
    }

    /**
     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
     */
    public static Object getFieldValue(final Object obj, final String fieldName) {
        Field field = getAccessibleField(obj, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }

        Object result = null;
        try {
            result = field.get(obj);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常{}", e.getMessage());
        }
        return result;
    }

    /**
     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
     */
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
        Field field = getAccessibleField(obj, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }

        try {
            field.set(obj, value);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常:{}", e.getMessage());
        }
    }

    /**
     * 直接调用对象方法, 无视private/protected修饰符.
     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
     * 同时匹配方法名+参数类型,
     */
    public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
                                      final Object[] args) {
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        }

        try {
            return method.invoke(obj, args);
        } catch (Exception e) {
            throw convertReflectionExceptionToUnchecked(e);
        }
    }

    /**
     * 直接调用对象方法, 无视private/protected修饰符,
     * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
     * 只匹配函数名,如果有多个同名函数调用第一个。
     */
    public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
        Method method = getAccessibleMethodByName(obj, methodName);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        }

        try {
            return method.invoke(obj, args);
        } catch (Exception e) {
            throw convertReflectionExceptionToUnchecked(e);
        }
    }

    /**
     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
     *
     * 如向上转型到Object仍无法找到, 返回null.
     */
    public static Field getAccessibleField(final Object obj, final String fieldName) {
        Validate.notNull(obj, "object can't be null");
        Validate.notBlank(fieldName, "fieldName can't be blank");
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException e) {//NOSONAR
                // Field不在当前类定义,继续向上转型
                continue;// new add
            }
        }
        return null;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
     * 如向上转型到Object仍无法找到, 返回null.
     * 匹配函数名+参数类型。
     *
     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
     */
    public static Method getAccessibleMethod(final Object obj, final String methodName,
                                             final Class<?>... parameterTypes) {
        Validate.notNull(obj, "object can't be null");
        Validate.notBlank(methodName, "methodName can't be blank");

        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            try {
                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
                makeAccessible(method);
                return method;
            } catch (NoSuchMethodException e) {
                // Method不在当前类定义,继续向上转型
                continue;// new add
            }
        }
        return null;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
     * 如向上转型到Object仍无法找到, 返回null.
     * 只匹配函数名。
     *
     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
     */
    public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
        Validate.notNull(obj, "object can't be null");
        Validate.notBlank(methodName, "methodName can't be blank");

        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            Method[] methods = searchType.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    makeAccessible(method);
                    return method;
                }
            }
        }
        return null;
    }

    /**
     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
     */
    public static void makeAccessible(Method method) {
        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
                && !method.isAccessible()) {
            method.setAccessible(true);
        }
    }

    /**
     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
     */
    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
                .isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }
    }

    /**
     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
     * 如无法找到, 返回Object.class.
     * eg.
     * public UserDao extends HibernateDao<User>
     *
     * @param clazz The class to introspect
     * @return the first generic declaration, or Object.class if cannot be determined
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getClassGenricType(final Class clazz) {
        return getClassGenricType(clazz, 0);
    }

    /**
     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
     * 如无法找到, 返回Object.class.
     *
     * 如public UserDao extends HibernateDao<User,Long>
     *
     * @param clazz clazz The class to introspect
     * @param index the Index of the generic ddeclaration,start from 0.
     * @return the index generic declaration, or Object.class if cannot be determined
     */
    public static Class getClassGenricType(final Class clazz, final int index) {

        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
                    + params.length);
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
            return Object.class;
        }

        return (Class) params[index];
    }

    public static Class<?> getUserClass(Object instance) {
        Validate.notNull(instance, "Instance must not be null");
        Class clazz = instance.getClass();
        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null && !Object.class.equals(superClass)) {
                return superClass;
            }
        }
        return clazz;

    }

    /**
     * 将反射时的checked exception转换为unchecked exception.
     */
    public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
                || e instanceof NoSuchMethodException) {
            return new IllegalArgumentException(e);
        } else if (e instanceof InvocationTargetException) {
            return new RuntimeException(((InvocationTargetException) e).getTargetException());
        } else if (e instanceof RuntimeException) {
            return (RuntimeException) e;
        }
        return new RuntimeException("Unexpected Checked Exception.", e);
    }

    /**
     * 判断属性是否为日期类型
     *
     * @param clazz
     *            数据类型
     * @param fieldName
     *            属性名
     * @return 如果为日期类型返回true,否则返回false
     */
    public static <T> boolean isDateType(Class<T> clazz, String fieldName) {
        boolean flag = false;
        try {
            Field field = clazz.getDeclaredField(fieldName);
            Object typeObj = field.getType().newInstance();
            flag = typeObj instanceof Date;
        } catch (Exception e) {
            // 把异常吞掉直接返回false
        }
        return flag;
    }

    /**
     * 根据类型将指定参数转换成对应的类型
     *
     * @param value
     *            指定参数
     * @param type
     *            指定类型
     * @return 返回类型转换后的对象
     */
    public static <T> Object parseValueWithType(String value, Class<?> type) {
        Object result = null;
        try { // 根据属性的类型将内容转换成对应的类型
            if (Boolean.TYPE == type) {
                result = Boolean.parseBoolean(value);
            } else if (Byte.TYPE == type) {
                result = Byte.parseByte(value);
            } else if (Short.TYPE == type) {
                result = Short.parseShort(value);
            } else if (Integer.TYPE == type) {
                result = Integer.parseInt(value);
            } else if (Long.TYPE == type) {
                result = Long.parseLong(value);
            } else if (Float.TYPE == type) {
                result = Float.parseFloat(value);
            } else if (Double.TYPE == type) {
                result = Double.parseDouble(value);
            } else {
                result = (Object) value;
            }
        } catch (Exception e) {
            // 把异常吞掉直接返回null
        }
        return result;
    }
}

4.使用的maven依赖

<!--文件转成PDF-->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<!--打成zip压缩包-->
<dependency>
    <groupId>org.apache.ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.10.5</version>
</dependency>