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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM