日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java生成pdf文件或jpg圖片的案例講解

瀏覽:24日期:2022-08-17 14:43:39

在一些業(yè)務場景中,需要生成pdf文件或者jpg圖片,有時候還需要帶上水印。我們可以事先用freemarker定義好html模板,然后把模板轉(zhuǎn)換成pdf或jpg文件。

同時freemarker模板還支持變量的定義,在使用時可以填充具體的業(yè)務數(shù)據(jù)。

1、Maven導包

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version></parent><dependencies> <!-- freemarker --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> </dependency> <!-- pdf核心包 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.12</version> </dependency> <!-- 適配中文字體 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <!-- html轉(zhuǎn)pdf --> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.12</version> </dependency> <!-- pdf轉(zhuǎn)圖片 --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.5</version> </dependency></dependencies>2、接口定義

2.1、請求

@Datapublic class GeneratePdfReq { /** * 生成pdf文件的絕對路徑 */ @NotBlank(message = '生成pdf文件的絕對路徑不能為空') @Pattern(regexp = '^.*(.pdf|.jpg)$', message = '生成的文件必須以.pdf或.jpg結(jié)尾') private String absolutePath; /** * 使用html模板的絕對路徑 */ @NotBlank(message = '使用的模板路徑不能為空') private String templateName; /** * 渲染模板的業(yè)務數(shù)據(jù) */ private Object dataModel; /** * 水印信息 */ private WaterMarkInfo waterMarkInfo; /** * pdf文件的寬,默認A4 */ private float width = 595; /** * pdf文件的高,默認A4 */ private float height = 842;}

2.2、水印

@Datapublic class WaterMarkInfo { /** * 如果為null設置水印時會報錯 */ private String waterMark = ''; /** * 水印透明度,值越小透明度越高 */ private float opacity = 0.2F; /** * 水印字體,如果亂碼設置為本地宋體字體:fonts/simsun.ttc,1 */ private String fontName = 'STSong-Light'; /** * 水印編碼格式,如果亂碼設置為:BaseFont.IDENTITY_H */ private String encoding = 'UniGB-UCS2-H'; /** * 字體大小 */ private float fontSize = 24; /** * 橫坐標在頁面寬度的百分比,左下角為原點 */ private float x = 50; /** * 縱坐標在頁面高度的百分比,左下角為原點 */ private float y = 40; /** * 水印旋轉(zhuǎn)角度 */ private float rotation = 45;}

2.3、響應

@Datapublic class GeneratePdfResp { /** * 生成pdf的絕對路徑 */ private String absolutePath;}3、應用代碼

3.1、渲染freemarker模板獲取html網(wǎng)頁

@Service('freeMarkerService')@Slf4jpublic class FreeMarkerServiceImpl implements FreeMarkerService { @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; /** * 渲染html后獲取整個頁面內(nèi)容 * * @param templatePath 模板路徑 * @param dataModel 業(yè)務數(shù)據(jù),一般以map形式傳入 * @return */ @Override public String getHtml(String templatePath, Object dataModel) { log.info('開始將模板{}渲染為html,業(yè)務數(shù)據(jù){}', templatePath, JSONUtil.toJsonPrettyStr(dataModel)); Configuration cfg = freeMarkerConfigurer.getConfiguration(); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); // freemaker異常時仍舊拋出,統(tǒng)一異常處理 cfg.setClassicCompatible(true);// 不需要對null值預處理,否則需要在模板取值時判斷是否存在,不然報錯 StringWriter stringWriter = new StringWriter(); try { // 設置模板所在目錄,絕對路徑方式,不打進jar包// cfg.setDirectoryForTemplateLoading(new File(templatePath).getParentFile());// Template temp = cfg.getTemplate(new File(templatePath).getName()); // 相對路徑設置模板所在目錄,模板打進jar包,默認就是resources目錄下的/templates目錄。 cfg.setClassForTemplateLoading(this.getClass(), '/templates'); Template temp = cfg.getTemplate(templatePath); temp.process(dataModel, stringWriter); } catch (Exception e) { log.error(PdfErrorCode.PDF_TEMPLATE_RENDER_FAIL.getDesc(), e); throw new PdfBizException(PdfErrorCode.PDF_TEMPLATE_RENDER_FAIL); } return stringWriter.toString(); }}

3.2、將html網(wǎng)頁轉(zhuǎn)pdf,并添加水印

@Service('pdfService')@Slf4jpublic class PdfServiceImpl implements PdfService { public static final String FONT_PATH = 'fonts/simsun.ttc,1'; @Autowired private WaterMarkerService waterMarkerService; /** * html頁面內(nèi)容轉(zhuǎn)pdf,并給每頁附上水印 * * @param html html頁面內(nèi)容 * @param width pdf的寬 * @param height pdf的高 * @param waterMarkInfo 水印信息 * @return */ @Override public byte[] html2Pdf(String html, float width, float height, WaterMarkInfo waterMarkInfo) { log.info('=================開始將html轉(zhuǎn)換為pdf================='); ByteArrayOutputStream out = new ByteArrayOutputStream(); this.html2Pdf(html, width, height, out); byte[] bytes = out.toByteArray(); // 設置水印 if (waterMarkInfo != null) { bytes = waterMarkerService.addWaterMarker(bytes, waterMarkInfo); } return bytes; } /** * html轉(zhuǎn)pdf * * @param html html頁面內(nèi)容 * @param width pdf的寬 * @param height pdf的高 * @param out 輸出流,pdf文件用此流輸出,需要pdf文檔關閉后流中才會有數(shù)據(jù) */ @Override @SneakyThrows public void html2Pdf(String html, float width, float height, OutputStream out) { @Cleanup Document document = new Document(new RectangleReadOnly(width, height)); // 默認A4縱向 // 這里需要關閉document才能讓生成的pdf字節(jié)數(shù)據(jù)刷到輸出流中 PdfWriter writer = PdfWriter.getInstance(document, out); // 關閉可能導致生成的pdf顯示異常(Chrome) document.open(); // 設置字體,這里統(tǒng)一用simsun.ttc即宋體 XMLWorkerFontProvider asianFontProvider = new XMLWorkerFontProvider() { @Override public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) { Font font; try { font = new Font(BaseFont.createFont(FONT_PATH, BaseFont.IDENTITY_H, BaseFont.EMBEDDED)); } catch (Exception e) { log.error(PdfErrorCode.SET_PDF_FONT_FAIL.getDesc(), e); throw new PdfBizException(PdfErrorCode.SET_PDF_FONT_FAIL); } font.setStyle(style); font.setColor(color); if (size > 0) { font.setSize(size); } return font; } }; // 生成pdf try { XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes('UTF-8')), null, Charset.forName('UTF-8'), asianFontProvider); // 如果系統(tǒng)已經(jīng)裝有simsun.ttc字體,則不需要單獨設置字體也不需要itext-asian jar包// XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes('UTF-8')), null, Charset.forName('UTF-8')); } catch (RuntimeWorkerException e) { log.error(PdfErrorCode.HTML_CONVERT2PDF_FAIL.getDesc(), e); throw new PdfBizException(PdfErrorCode.HTML_CONVERT2PDF_FAIL); } }}

添加水印實現(xiàn)類

@Service('waterMarkerService')@Slf4jpublic class WaterMarkerServiceImpl implements WaterMarkerService { /** * 給pdf文件每頁添加水印 * * @param source pdf文件的字節(jié)數(shù)組形式 * @param waterMarkInfo 水印信息 * @return */ @Override public byte[] addWaterMarker(byte[] source, WaterMarkInfo waterMarkInfo) { log.info('開始設置水印數(shù)據(jù){}', JSONUtil.toJsonPrettyStr(waterMarkInfo)); ByteArrayOutputStream out = new ByteArrayOutputStream(); this.addWaterMarker(source, waterMarkInfo, out); return out.toByteArray(); } /** * 給pdf文件每頁添加水印 * * @param source pdf文件的字節(jié)數(shù)組形式 * @param waterMarkInfo 水印信息 * @param out 輸出流,pdf文件用此流輸出,需要pdf文檔關閉后流中才會有數(shù)據(jù) */ @Override @SneakyThrows public void addWaterMarker(byte[] source, WaterMarkInfo waterMarkInfo, OutputStream out) { @Cleanup PdfReader reader = new PdfReader(source); // 這里需要關閉PdfStamper才能讓生成的pdf字節(jié)數(shù)據(jù)刷到輸出流中 @Cleanup PdfStamper pdfStamper = new PdfStamper(reader, out); BaseFont font = BaseFont.createFont(waterMarkInfo.getFontName(), waterMarkInfo.getEncoding(), BaseFont.EMBEDDED); PdfGState gs = new PdfGState(); gs.setFillOpacity(waterMarkInfo.getOpacity()); // 給每頁pdf生成水印 for (int i = 1; i <= reader.getNumberOfPages(); i++) { PdfContentByte waterMarker = pdfStamper.getUnderContent(i); waterMarker.beginText(); // 設置水印透明度 waterMarker.setGState(gs); // 設置水印字體和大小 waterMarker.setFontAndSize(font, waterMarkInfo.getFontSize()); // 設置水印位置、內(nèi)容、旋轉(zhuǎn)角度 float X = reader.getPageSize(i).getWidth() * waterMarkInfo.getX() / 100; float Y = reader.getPageSize(i).getHeight() * waterMarkInfo.getY() / 100; waterMarker.showTextAligned(Element.ALIGN_CENTER, waterMarkInfo.getWaterMark(), X, Y, waterMarkInfo.getRotation()); // 設置水印顏色 waterMarker.setColorFill(BaseColor.GRAY); waterMarker.endText(); } }}

3.3、整合實現(xiàn)

@Slf4j@Service('generatePdfService')public class GeneratePdfServiceImpl implements RestService { @Autowired private FreeMarkerService freeMarkerService; @Autowired private PdfService pdfService; @Override @SneakyThrows public GeneratePdfResp service(GeneratePdfReq generatePdfReq) { log.info('開始生成pdf文件,請求報文:{}', JSONUtil.toJsonPrettyStr(generatePdfReq)); /* 1.根據(jù)freemarker模板填充業(yè)務數(shù)據(jù)獲取完整的html字符串 */ String html = freeMarkerService.getHtml(generatePdfReq.getTemplateName(), generatePdfReq.getDataModel()); /* 2.生成pdf文件(內(nèi)存) */ byte[] bytes = pdfService.html2Pdf(html, generatePdfReq.getWidth(), generatePdfReq.getHeight(), generatePdfReq.getWaterMarkInfo()); /* 3.本地保存pdf文件 */ File targetFile = new File(generatePdfReq.getAbsolutePath()); // 上級目錄不存在則創(chuàng)建 if (!targetFile.getParentFile().exists()) { targetFile.getParentFile().mkdirs(); } // 根據(jù)不同文件名后綴生成對應文件 if (generatePdfReq.getAbsolutePath().endsWith('pdf')) { FileUtils.writeByteArrayToFile(targetFile, bytes); } else { @Cleanup PDDocument document = PDDocument.load(bytes); PDFRenderer renderer = new PDFRenderer(document); BufferedImage bufferedImage = renderer.renderImageWithDPI(0, 150);// 只打第一頁,dpi越大圖片越高清也越耗時 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, 'jpg', baos); FileUtils.writeByteArrayToFile(targetFile, baos.toByteArray()); } log.info('文件本地保存完成,文件路徑:[{}]', targetFile.getAbsolutePath()); /* 4.組織返回 */ GeneratePdfResp generatePdfResp = new GeneratePdfResp(); generatePdfResp.setAbsolutePath(targetFile.getAbsolutePath()); return generatePdfResp; }}

3.4、controller

@Slf4j@RestControllerpublic class PdfController { @Autowired private RestService generatePdfService; @PostMapping(value = '/html2Pdf') public GeneratePdfResp html2Pdf(@RequestBody @Validated GeneratePdfReq req) { GeneratePdfResp resp = generatePdfService.service(req); return resp; }}4、應用

4.1、freemarker模板(html模板)

<html><head> <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> <meta http-equiv='Content-Style-Type' content='text/css'/> <style> body { font-family: SimSun } </style> <title>html模板</title></head><body><div> <p style='margin:0pt; orphans:0; text-align:center; widows:0'> <span style='font-family:SimSun; font-size:16pt'>html模板</span><br/> </p> <p>姓名:${name}</p> <p>證件號碼:${cardNo}</p> <p>日期:${date}</p></div></body></html>

4.2、接口調(diào)用生成pdf

Java生成pdf文件或jpg圖片的案例講解

Java生成pdf文件或jpg圖片的案例講解

5、說明

1、根據(jù)參數(shù)后綴名可以生成pdf或jpg文件,生成的pdf文件默認為A4大小,也可以通過請求參數(shù)設置大小。

2、pdf文件會根據(jù)html模板內(nèi)容大小自動分頁。

3、如果生成圖片,多頁不會生成多張圖片,可以把高度設置大一些,最后會生成長圖。

4、水印每頁都會自動添加。

5、為了提高代碼的復用性和可維護性,工程內(nèi)渲染html模板、生成pdf文件、添加水印都有單獨的接口實現(xiàn)。

代碼地址

github:https://github.com/senlinmu1008/spring-boot/tree/master/html2pdf

gitee:https://gitee.com/ppbin/spring-boot/tree/master/html2pdf

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持好吧啦網(wǎng)。如有錯誤或未考慮完全的地方,望不吝賜教。

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
91九色精品| 亚洲电影在线一区二区三区| 国产九九精品| 美女精品网站| 欧美日韩一区二区综合| 精品视频久久| 欧美专区一区| 亚洲天堂成人| 欧美日韩视频网站| 欧美激情视频一区二区三区免费 | 精品国产亚洲一区二区三区| 男人操女人的视频在线观看欧美| 国产精品毛片久久| 欧美日韩亚洲一区| 日韩国产在线不卡视频| 美女网站久久| 欧美精品不卡| 国产欧美在线| 国产精品调教| 国产精品白丝久久av网站| 日本午夜精品久久久久| 日韩欧美久久| 日本a级不卡| 欧美偷窥清纯综合图区| 亚洲精品一区二区在线播放∴| 黄色成人在线网址| 欧美亚洲在线日韩| 伊人精品视频| 国产v日韩v欧美v| 涩涩av在线| 婷婷成人基地| 亚洲九九精品| 国产欧美69| 国产成人久久精品麻豆二区 | 国内在线观看一区二区三区| 欧美天堂在线| 午夜日韩av| 精品三级在线| 久久麻豆视频| 欧美精品导航| 色爱av综合网| 国产一区 二区| 欧美影院三区| 欧美激情网址| 精品一区不卡| 欧洲激情综合| 久久精品国产大片免费观看| 国产精品一区高清| 奇米777国产一区国产二区| 欧美a一区二区| 欧美日韩国产综合网| 日韩欧美中文在线观看| 色爱av综合网| 久久国产精品久久w女人spa| 日韩精品成人在线观看| 国产成人精选| 亚洲精品裸体| 久久精品av| 欧美精品1区| 蜜桃视频第一区免费观看| 久久精品日韩欧美| 天堂va蜜桃一区二区三区| 精品伊人久久久| 日韩精品一区二区三区av | 狠狠操综合网| 亚洲女人av| 欧美精选一区二区三区| 美女视频网站久久| 免费黄网站欧美| 欧美日韩在线播放视频| 精品国产91| 国产精品草草| 久久国产尿小便嘘嘘| 天使萌一区二区三区免费观看| 都市激情国产精品| 麻豆精品在线播放| 日本不卡的三区四区五区| 亚洲精品乱码久久久久久蜜桃麻豆 | 国产视频一区二| 国产精品视频一区视频二区| 美女久久久久久 | 夜夜嗨av一区二区三区网站四季av| 久久中文字幕二区| 美女被久久久| 欧美激情视频一区二区三区免费 | 欧美亚洲日本精品| 国产精品毛片在线| 日本不卡的三区四区五区| 欧美午夜网站| 99精品在线观看| 欧美综合社区国产| 99久久久国产精品美女| 日本不卡一二三区黄网| 日产精品一区二区| 亚洲18在线| 久久久久网站| 久久爱www.| 蜜臀av一区二区在线免费观看| 久久精品免费看| 亚洲精品综合| 国产精品99一区二区三区| 亚洲欧洲国产精品一区| 精精国产xxxx视频在线播放| 亚洲视频二区| 在线精品亚洲欧美日韩国产| 99国产精品私拍| 日韩专区精品| 麻豆精品国产91久久久久久| 亚洲深夜福利| 91精品国产成人观看| 国产精品毛片视频| 日韩精品一二三四| 精品一区三区| 高清av一区二区三区| 久久三级中文| 石原莉奈在线亚洲三区| 蜜桃视频在线网站| 欧美成a人片免费观看久久五月天| 亚洲专区一区| 美女网站一区| 亚洲a一区二区三区| 国产一区二区三区探花| 久久精品99国产精品日本| 免费久久99精品国产自在现线| 久久蜜桃精品| 尤物tv在线精品| 日韩av免费| 久久蜜桃精品| 日韩黄色大片网站| 午夜精品成人av| 麻豆视频在线看| 中文字幕在线官网| 97精品国产| av在线日韩| 一区在线观看| 亚洲欧美网站| 久久午夜视频| 国产另类在线| 国产不卡精品| 99久久婷婷| 午夜在线精品| 国产欧美日韩视频在线| 国产精品视频一区二区三区四蜜臂| 国产美女视频一区二区| 国产999精品在线观看| 精品一区二区三区中文字幕| 国产精品久久久久久久久妇女| 丝袜av一区| 日本在线视频一区二区| 国产精品一区二区av交换| 精品一区二区三区中文字幕在线| 日韩1区2区| 国产亚洲精品v| 国产精品亚洲综合久久| 日韩在线观看一区| 亚洲影视一区二区三区| 久久这里只有| 亚洲制服少妇| 精品三级久久久| 性色一区二区| 欧美激情在线精品一区二区三区| 在线看片福利| 日韩一区二区三区精品视频第3页| 欧美久久精品| 国产亚洲一区在线| 国产精品sss在线观看av| 日韩中文字幕91| 免费在线观看精品| 国产精品sss在线观看av| 99久精品视频在线观看视频| 日韩精品a在线观看91| 精品日韩视频| 国产欧美在线| 亚洲国产影院| 成人国产精选| 亚洲人成亚洲精品| 欧美一区二区性| 国产成人久久| 国产精品九九| 欧美亚洲色图校园春色| 亚洲免费成人| 亚洲成人不卡| 国产福利片在线观看| 国产精品一页| 日韩欧美高清一区二区三区| 在线亚洲免费| 日韩三级精品| 中文精品视频| 国产99久久| 久久裸体视频| 三上亚洲一区二区| 国产精品亚洲综合久久| 青青草国产精品亚洲专区无| 国产免费成人| 蜜臀av一区二区在线免费观看| 在线视频精品| 亚洲专区一区| 亚洲日本三级| 国产日韩高清一区二区三区在线 | 视频一区视频二区中文|