• JAVA项目实战-实现生成固定格式PDF文件和打包成zip压缩包并在浏览器中输出


    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>
  • 相关阅读:
    6.简单总结一下类与对象
    5.创建对象内存分析
    4.构造器详解
    3.类和对象的关系
    业余草推荐18个Java开源免费的CMS系统
    业余草教你解读Spark源码阅读之HistoryServer
    业余草公众号运营攻略:教你一天涨粉200以上
    从菜鸟到大牛的码农升职必学文章推荐
    倒排索引的AND操作
    程序员,如何在工作之外,增加自己的收入
  • 原文地址:https://www.cnblogs.com/zhucj-java/p/13384998.html
Copyright © 2020-2023  润新知