使用itext和freemarker来根据Html模板生成PDF文件,加水印、印章

青旅半醒 2024-04-18 11:47 106阅读 0赞

功能:

实现根据freemarker模板生成对应的PDF文件;

可以指定文字、位置、页数生成指定的印章(图片),可以指定印章大小;

指定字体、字体大小、文字方向、颜色等生成文字水印

maven依赖:

  1. <dependency>
  2. <groupId>org.xhtmlrenderer</groupId>
  3. <artifactId>flying-saucer-pdf-itext5</artifactId>
  4. <version>9.1.18</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.freemarker</groupId>
  8. <artifactId>freemarker</artifactId>
  9. <version>2.3.27-incubating</version>
  10. </dependency>

将html模板和数据进行匹配,然后用流的方式生成PDF文件

生成PDF工具类源码:

  1. package com.lifengdi.file.pdf;
  2. import com.itextpdf.text.*;
  3. import com.itextpdf.text.pdf.*;
  4. import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
  5. import com.lifengdi.config.GlobalConfig;
  6. import com.lifengdi.config.PDFFontConfig;
  7. import com.lifengdi.config.SystemConfig;
  8. import com.lifengdi.file.pdf.listener.MyTextLocationListener;
  9. import com.lifengdi.model.pdf.Location;
  10. import com.lifengdi.model.pdf.PDFStamperConfig;
  11. import com.lifengdi.model.pdf.PDFTempFile;
  12. import com.lifengdi.model.pdf.PDFWatermarkConfig;
  13. import com.lifengdi.util.GeneratedKey;
  14. import com.lifengdi.util.MyStringUtil;
  15. import freemarker.template.Configuration;
  16. import freemarker.template.Template;
  17. import freemarker.template.TemplateExceptionHandler;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.apache.commons.io.FileUtils;
  20. import org.apache.commons.lang3.StringUtils;
  21. import org.springframework.core.io.ClassPathResource;
  22. import org.springframework.stereotype.Component;
  23. import org.xhtmlrenderer.pdf.ITextFontResolver;
  24. import org.xhtmlrenderer.pdf.ITextRenderer;
  25. import javax.annotation.Resource;
  26. import java.io.*;
  27. import java.util.Objects;
  28. /**
  29. * 生成PDF工具类
  30. *
  31. * @author 李锋镝
  32. * @date Create at 10:42 2019/5/9
  33. */
  34. @Component
  35. @Slf4j
  36. public class HtmlToPDF {
  37. @Resource
  38. private SystemConfig systemConfig;
  39. @Resource
  40. private GeneratedKey generatedKey;
  41. /**
  42. * 模板和数据匹配
  43. *
  44. * @param data 数据
  45. * @param pdfTempFile pdfTempFile
  46. * @return html
  47. */
  48. public String matchDataToHtml(Object data, PDFTempFile pdfTempFile) {
  49. StringWriter writer = new StringWriter();
  50. String html;
  51. try {
  52. // FreeMarker配置
  53. Configuration config = new Configuration(Configuration.VERSION_2_3_25);
  54. config.setDefaultEncoding(GlobalConfig.DEFAULT_ENCODING);
  55. // 注意这里是模板所在文件夹,不是模版文件
  56. String parentPath, tempFileName = pdfTempFile.getTemplateFileName();
  57. if (MyStringUtil.isHttpUrl(pdfTempFile.getTemplateFileParentPath())) {
  58. parentPath = systemConfig.getLocalTempPath();
  59. } else {
  60. parentPath = pdfTempFile.getTemplateFileParentPath();
  61. // 将项目中的文件copy到服务器本地
  62. if (!parentPath.endsWith(File.separator))
  63. parentPath = parentPath + File.separator;
  64. String localTempPath = systemConfig.getLocalTempPath();
  65. String target = (localTempPath.endsWith(File.separator) ? localTempPath : localTempPath + File.separator) + tempFileName;
  66. InputStream tempFileInputStream = new ClassPathResource(parentPath + tempFileName).getInputStream();
  67. FileUtils.copyInputStreamToFile(tempFileInputStream, new File(target));
  68. }
  69. log.info("模板和数据匹配,模板文件parentPath:{}", parentPath);
  70. config.setDirectoryForTemplateLoading(new File(systemConfig.getLocalTempPath()));
  71. config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
  72. config.setLogTemplateExceptions(false);
  73. // 根据模板名称 获取对应模板
  74. Template template = config.getTemplate(tempFileName);
  75. // 模板和数据的匹配
  76. template.process(data, writer);
  77. writer.flush();
  78. html = writer.toString();
  79. return html;
  80. } catch (Exception e) {
  81. log.error("PDF模板和数据匹配异常", e);
  82. } finally {
  83. try {
  84. writer.close();
  85. } catch (IOException e) {
  86. log.error("StringWriter close exception.", e);
  87. }
  88. }
  89. return null;
  90. }
  91. /**
  92. * 生成PDF
  93. *
  94. * @param html html字符串
  95. * @param targetFileName 目标文件名
  96. * @return 生成文件的名称
  97. * @throws Exception e
  98. */
  99. public String createPDF(String html, String targetFileName) throws Exception {
  100. if (StringUtils.isBlank(html)) {
  101. return null;
  102. }
  103. targetFileName = getFileName(targetFileName);
  104. log.info("生成PDF,targetFileName:{}", targetFileName);
  105. String targetFilePath = getTargetFileTempPath(targetFileName);
  106. FileOutputStream outFile = new FileOutputStream(targetFilePath);
  107. ITextRenderer renderer = new ITextRenderer();
  108. renderer.setDocumentFromString(html);
  109. // 解决中文支持问题
  110. log.info("加载字体");
  111. ITextFontResolver fontResolver = renderer.getFontResolver();
  112. fontResolver.addFont(SystemConfig.SourceHanSansCN_Regular_TTF, "SourceHanSansCN", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, null);
  113. fontResolver.addFont(SystemConfig.FONT_PATH_SONG, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
  114. renderer.layout();
  115. renderer.createPDF(outFile);
  116. log.info("生成PDF,targetFileName:{},生成成功", targetFileName);
  117. return targetFileName;
  118. }
  119. /**
  120. * 渲染文件
  121. *
  122. * @param filePath PDF文件路径
  123. * @param outFilePath PDF文件路径
  124. * @param pdfStamperConfig pdfStamperConfig
  125. * @param pdfWatermarkConfig pdfWatermarkConfig
  126. */
  127. public void renderLayer(String filePath, String outFilePath, PDFStamperConfig pdfStamperConfig, PDFWatermarkConfig pdfWatermarkConfig) {
  128. log.info("渲染文件,filePath:{},outFilePath:{}", filePath, outFilePath);
  129. InputStream inputStream = null;
  130. try {
  131. filePath = getTargetFileTempPath(filePath);
  132. inputStream = new FileInputStream(filePath);
  133. PdfReader reader = new PdfReader(inputStream);
  134. PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(getTargetFileTempPath(outFilePath)));
  135. if (Objects.nonNull(pdfStamperConfig) && pdfStamperConfig.getGenerate()) {
  136. // 印章
  137. log.info("添加印章,pdfStamperConfig:{}", pdfStamperConfig);
  138. stamper(pdfStamperConfig, reader, stamper);
  139. }
  140. if (Objects.nonNull(pdfWatermarkConfig) && pdfWatermarkConfig.getGenerate()) {
  141. // 水印
  142. log.info("添加水印,pdfWatermarkConfig:{}", pdfWatermarkConfig);
  143. watermark(reader, stamper, pdfWatermarkConfig);
  144. }
  145. stamper.close();
  146. reader.close();
  147. } catch (Exception e) {
  148. e.printStackTrace();
  149. } finally {
  150. try {
  151. if (null != inputStream) {
  152. inputStream.close();
  153. }
  154. } catch (IOException e) {
  155. e.printStackTrace();
  156. }
  157. }
  158. }
  159. /**
  160. * 印章
  161. *
  162. * @param pdfStamperConfig pdfStamperConfig
  163. * @param reader reader
  164. * @param stamper stamper
  165. * @throws IOException IOException
  166. * @throws DocumentException DocumentException
  167. */
  168. private void stamper(PDFStamperConfig pdfStamperConfig, PdfReader reader, PdfStamper stamper) throws IOException, DocumentException {
  169. Image image;
  170. if (!MyStringUtil.isHttpUrl(pdfStamperConfig.getStamperUrl())) {
  171. // 将项目中的文件copy到服务器本地
  172. String imagePath = pdfStamperConfig.getStamperUrl();
  173. String imageName = imagePath.substring(imagePath.indexOf("/") + 1, imagePath.length());
  174. String localTempPath = systemConfig.getLocalTempPath();
  175. String target = (localTempPath.endsWith(File.separator) ? localTempPath : localTempPath + File.separator) + imageName;
  176. InputStream tempFileInputStream = new ClassPathResource(pdfStamperConfig.getStamperUrl()).getInputStream();
  177. FileUtils.copyInputStreamToFile(tempFileInputStream, new File(target));
  178. image = Image.getInstance(target);
  179. } else {
  180. image = Image.getInstance(pdfStamperConfig.getStamperUrl());
  181. }
  182. PdfReaderContentParser parser = new PdfReaderContentParser(reader);
  183. Document document = new Document();
  184. log.info("A4纸width:{},height:{}", document.getPageSize().getWidth(), document.getPageSize().getHeight());
  185. // // 取所在页和坐标,左下角为起点
  186. // float x = document.getPageSize().getWidth() - 240;
  187. // float y = document.getPageSize().getHeight() - 680;
  188. int pageSize = reader.getNumberOfPages();
  189. Location location = pdfStamperConfig.getLocation();
  190. if (Objects.nonNull(location)) {
  191. Integer page = location.getPage();// -1:全部,0:最后一页,1:首页
  192. if (Objects.nonNull(page)) {
  193. switch (page) {
  194. case -1:
  195. for (int pageNumber = 1; pageNumber <= pageSize; pageNumber++) {
  196. insertImage(pdfStamperConfig, stamper, image, parser, pageSize);
  197. }
  198. break;
  199. case 0:
  200. insertImage(pdfStamperConfig, stamper, image, parser, pageSize);
  201. break;
  202. default:
  203. if (page > 0) {
  204. insertImage(pdfStamperConfig, stamper, image, parser, page);
  205. }
  206. break;
  207. }
  208. }
  209. }
  210. }
  211. /**
  212. * 向指定位置插入图片
  213. *
  214. * @param pdfStamperConfig pdfStamperConfig
  215. * @param stamper stamper
  216. * @param image image
  217. * @param parser parser
  218. * @param pageNumber pageNumber
  219. * @throws IOException IOException
  220. * @throws DocumentException DocumentException
  221. */
  222. private void insertImage(PDFStamperConfig pdfStamperConfig, PdfStamper stamper, Image image, PdfReaderContentParser parser, int pageNumber)
  223. throws IOException, DocumentException {
  224. float x, y;
  225. Location xy = new Location();
  226. if (StringUtils.isNotBlank(pdfStamperConfig.getLocation().getWord())) {
  227. parser.processContent(pageNumber, new MyTextLocationListener(pdfStamperConfig, xy));
  228. } else {
  229. xy = pdfStamperConfig.getLocation();
  230. }
  231. if (Objects.isNull(xy)) {
  232. return;
  233. }
  234. if (Objects.isNull(xy.getX()) || Objects.isNull(xy.getY())) {
  235. return;
  236. }
  237. x = xy.getX();
  238. y = xy.getY();
  239. if (x < 0 || y < 0) {
  240. return;
  241. }
  242. // 读图片
  243. // 获取操作的页面
  244. PdfContentByte under = stamper.getOverContent(pageNumber);
  245. // 根据域的大小缩放图片
  246. // image.scaleToFit(Objects.isNull(pdfStamperConfig.getFitWidth()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_WIDTH : pdfStamperConfig.getFitWidth(),
  247. // Objects.isNull(pdfStamperConfig.getFitHeight()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_HEIGHT : pdfStamperConfig.getFitHeight());
  248. image.scaleAbsolute(Objects.isNull(pdfStamperConfig.getFitWidth()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_WIDTH : pdfStamperConfig.getFitWidth(),
  249. Objects.isNull(pdfStamperConfig.getFitHeight()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_HEIGHT : pdfStamperConfig.getFitHeight());
  250. // 添加图片
  251. image.setAbsolutePosition(x, y);
  252. under.addImage(image);
  253. }
  254. /**
  255. * 水印
  256. *
  257. * @param reader reader
  258. * @param stamper stamper
  259. * @param pdfWatermarkConfig pdfWatermarkConfig
  260. */
  261. private void watermark(PdfReader reader, PdfStamper stamper, PDFWatermarkConfig pdfWatermarkConfig) {
  262. if (Objects.isNull(pdfWatermarkConfig) || !pdfWatermarkConfig.getGenerate()) {
  263. return;
  264. }
  265. PdfContentByte under;
  266. // 字体
  267. BaseFont font = PDFFontConfig.FONT_MAP.get(PDFFontConfig.SIM_SUN);
  268. String fontFamily = pdfWatermarkConfig.getFontFamily();
  269. if (StringUtils.isNotBlank(fontFamily) && PDFFontConfig.FONT_MAP.containsKey(fontFamily)) {
  270. font = PDFFontConfig.FONT_MAP.get(fontFamily);
  271. }
  272. // 原pdf文件的总页数
  273. int pageSize = reader.getNumberOfPages();
  274. PdfGState gs = new PdfGState();
  275. // 设置填充字体不透明度为0.1f
  276. gs.setFillOpacity(0.1f);
  277. Document document = new Document();
  278. float documentWidth = document.getPageSize().getWidth(), documentHeight = document.getPageSize().getHeight();
  279. Location location = pdfWatermarkConfig.getLocation();
  280. if (Objects.isNull(location)) {
  281. location = new Location();
  282. }
  283. final float xStart = 0, yStart = 0,
  284. xInterval = Objects.nonNull(location.getXInterval()) ? location.getXInterval() : GlobalConfig.DEFAULT_X_INTERVAL,
  285. yInterval = Objects.nonNull(location.getYInterval()) ? location.getYInterval() : GlobalConfig.DEFAULT_Y_INTERVAL,
  286. rotation = 45,
  287. fontSize = Objects.isNull(pdfWatermarkConfig.getFontSize()) ? GlobalConfig.DEFAULT_FONT_SIZE : pdfWatermarkConfig.getFontSize();
  288. String watermarkWord = pdfWatermarkConfig.getWatermarkWord();
  289. int red = -1, green = -1, blue = -1;
  290. String[] colorArray = pdfWatermarkConfig.getWatermarkColor().split(",");
  291. if (colorArray.length >= 3) {
  292. red = Integer.parseInt(colorArray[0]);
  293. green = Integer.parseInt(colorArray[1]);
  294. blue = Integer.parseInt(colorArray[2]);
  295. }
  296. for (int i = 1; i <= pageSize; i++) {
  297. // 水印在之前文本下
  298. if (Objects.nonNull(location.getOverContent()) && location.getOverContent()) {
  299. under = stamper.getOverContent(i);
  300. } else {
  301. under = stamper.getUnderContent(i);
  302. }
  303. under.beginText();
  304. // 文字水印 颜色
  305. if (red >= 0) {
  306. under.setColorFill(new BaseColor(red, green, blue));
  307. } else {
  308. under.setColorFill(BaseColor.GRAY);
  309. }
  310. // 文字水印 字体及字号
  311. under.setFontAndSize(font, fontSize);
  312. under.setGState(gs);
  313. // 文字水印 起始位置
  314. under.setTextMatrix(xStart, yStart);
  315. if (StringUtils.isNotBlank(watermarkWord)) {
  316. for (float x = xStart; x <= documentWidth + xInterval; x += xInterval) {
  317. for (float y = yStart; y <= documentHeight + yInterval; y += yInterval) {
  318. under.showTextAligned(Element.ALIGN_CENTER, watermarkWord, x, y, rotation);
  319. }
  320. }
  321. }
  322. under.endText();
  323. }
  324. }
  325. /**
  326. * 获取生成的PDF文件本地临时路径
  327. *
  328. * @param targetFileName 目标文件名
  329. * @return 本地临时路径
  330. */
  331. public String getTargetFileTempPath(String targetFileName) {
  332. String localTempPath = systemConfig.getLocalTempPath();
  333. if (!localTempPath.endsWith(File.separator)) {
  334. localTempPath = localTempPath + File.separator;
  335. }
  336. return localTempPath + targetFileName;
  337. }
  338. private String getFileName(String targetFileName) {
  339. if (StringUtils.isBlank(targetFileName)) {
  340. targetFileName = generatedKey.generatorKey();
  341. }
  342. if (!StringUtils.endsWithIgnoreCase(targetFileName, GlobalConfig.PDF_SUFFIX)) {
  343. targetFileName = targetFileName + GlobalConfig.PDF_SUFFIX;
  344. }
  345. return targetFileName;
  346. }
  347. }

获取指定文字坐标,用来在指定文字上生成印章,主要实现了RenderListener来获取指定文字的坐标。

源码:

  1. package com.lifengdi.file.pdf.listener;
  2. import com.itextpdf.awt.geom.Rectangle2D;
  3. import com.itextpdf.text.pdf.parser.ImageRenderInfo;
  4. import com.itextpdf.text.pdf.parser.RenderListener;
  5. import com.itextpdf.text.pdf.parser.TextRenderInfo;
  6. import com.lifengdi.config.GlobalConfig;
  7. import com.lifengdi.model.pdf.Location;
  8. import com.lifengdi.model.pdf.PDFStamperConfig;
  9. import lombok.extern.slf4j.Slf4j;
  10. import org.apache.commons.lang3.StringUtils;
  11. import java.util.Objects;
  12. /**
  13. * @author 李锋镝
  14. * @date Create at 15:32 2019/5/9
  15. */
  16. @Slf4j
  17. public class MyTextLocationListener implements RenderListener {
  18. private String text;
  19. private PDFStamperConfig pdfStamperConfig;
  20. private Location location;
  21. public MyTextLocationListener(PDFStamperConfig pdfStamperConfig, Location location) {
  22. if (StringUtils.isNotBlank(pdfStamperConfig.getLocation().getWord())) {
  23. this.text = pdfStamperConfig.getLocation().getWord();
  24. }
  25. this.pdfStamperConfig = pdfStamperConfig;
  26. this.location = location;
  27. }
  28. @Override
  29. public void beginTextBlock() {
  30. }
  31. @Override
  32. public void renderText(TextRenderInfo renderInfo) {
  33. String renderInfoText = renderInfo.getText();
  34. if (!StringUtils.isEmpty(renderInfoText) && renderInfoText.contains(text)) {
  35. Rectangle2D.Float base = renderInfo.getBaseline().getBoundingRectange();
  36. float leftX = (float) base.getMinX();
  37. float leftY = (float) base.getMinY() - 1;
  38. float rightX = (float) base.getMaxX();
  39. float rightY = (float) base.getMaxY() + 1;
  40. Rectangle2D.Float rect = new Rectangle2D.Float(leftX, leftY, rightX - leftX, rightY - leftY);
  41. // 当前行长度
  42. int length = renderInfoText.length();
  43. // 单个字符的长度
  44. float wordWidth = rect.width / length;
  45. // 指定字符串首次出现的索引
  46. int i = renderInfoText.indexOf(text);
  47. Float fitWidth = Objects.isNull(pdfStamperConfig.getFitWidth()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_WIDTH : pdfStamperConfig.getFitWidth();
  48. Float fitHeight = Objects.isNull(pdfStamperConfig.getFitHeight()) ? GlobalConfig.PDF_STAMPER_DEFAULT_FIT_HEIGHT : pdfStamperConfig.getFitHeight();
  49. float fitWidthRadius = 0f, fitHeightRadius = 0f;
  50. if (fitWidth > 0) {
  51. fitWidthRadius = fitWidth / 2;
  52. }
  53. if (fitHeight > 0) {
  54. fitHeightRadius = fitHeight / 2;
  55. }
  56. // 偏移量
  57. Float xOffset = Objects.isNull(pdfStamperConfig.getXOffset()) ? 0F : pdfStamperConfig.getXOffset();
  58. Float yOffset = Objects.isNull(pdfStamperConfig.getYOffset()) ? 0F : pdfStamperConfig.getYOffset();
  59. // 设置印章的XY坐标
  60. float x, y;
  61. if (rect.x < 60) {
  62. x = wordWidth * i + fitHeightRadius + xOffset;
  63. } else {
  64. x = rect.x + xOffset;
  65. }
  66. y = rect.y - fitWidthRadius + yOffset;
  67. location.setY(y > 0 ? y : 0);
  68. location.setX(x > 0 ? x : 0);
  69. log.info("text:{}, location:{}", text, location);
  70. }
  71. }
  72. @Override
  73. public void endTextBlock() {
  74. }
  75. @Override
  76. public void renderImage(ImageRenderInfo renderInfo) {
  77. }
  78. }

其他配置类:

  1. package com.lifengdi.model.pdf;
  2. import lombok.Data;
  3. /**
  4. * PDF模板配置
  5. * @author 李锋镝
  6. * @date Create at 11:10 2019/5/9
  7. */
  8. @Data
  9. public class PDFTempFile {
  10. /**
  11. * PDF模板文件类型
  12. */
  13. private String pdfType;
  14. /**
  15. * 模板文件名称
  16. */
  17. private String templateFileName;
  18. /**
  19. * 模板文件所在父级路径
  20. */
  21. private String templateFileParentPath;
  22. /**
  23. * 模板文件本地地址
  24. */
  25. private String templateFileLocalPath;
  26. }
  27. package com.lifengdi.config;
  28. import lombok.Getter;
  29. import org.springframework.beans.factory.annotation.Value;
  30. import org.springframework.context.annotation.Configuration;
  31. /**
  32. * @author 李锋镝
  33. * @date Create at 10:51 2019/5/9
  34. */
  35. @Getter
  36. @Configuration
  37. public class SystemConfig {
  38. /**
  39. * 文件本地缓存目录
  40. */
  41. @Value("${file.localTempPath}")
  42. private String localTempPath;
  43. /**
  44. * 项目中自带字体的目录
  45. */
  46. public static final String FONT_PATH_SONG = "font/simsun.ttf";
  47. public static final String SourceHanSansCN_Regular_TTF = "font/SourceHanSansCN-Regular.ttf";
  48. /**
  49. * 项目中的缓存目录
  50. */
  51. @Value("${file.appTempFolder:file/}")
  52. private String appTemplateFolder;
  53. }
  54. package com.lifengdi.model.pdf;
  55. import lombok.Data;
  56. /**
  57. * PDF印章配置
  58. * @author 李锋镝
  59. * @date Create at 11:16 2019/5/9
  60. */
  61. @Data
  62. public class PDFStamperConfig {
  63. /**
  64. * 是否生成印章
  65. */
  66. private Boolean generate = false;
  67. /**
  68. * 印章文件路径(PNG格式)
  69. */
  70. private String stamperUrl;
  71. /**
  72. * 生成印章的位置
  73. */
  74. private Location location;
  75. /**
  76. * 印章宽度
  77. */
  78. private Float fitWidth;
  79. /**
  80. * 印章高度
  81. */
  82. private Float fitHeight;
  83. /**
  84. * X偏移量
  85. */
  86. private Float xOffset;
  87. /**
  88. * Y偏移量
  89. */
  90. private Float yOffset;
  91. }
  92. package com.lifengdi.model.pdf;
  93. import lombok.Data;
  94. /**
  95. * PDF文件水印配置
  96. * @author 李锋镝
  97. * @date Create at 11:17 2019/5/9
  98. */
  99. @Data
  100. public class PDFWatermarkConfig {
  101. /**
  102. * 是否生成水印
  103. */
  104. private Boolean generate;
  105. /**
  106. * 水印文字
  107. */
  108. private String watermarkWord;
  109. /**
  110. * 水印文字颜色 red,green,blue
  111. */
  112. private String watermarkColor = "128,128,128";
  113. /**
  114. * 水印透明度
  115. */
  116. private Float fillOpacity = 0.1F;
  117. /**
  118. * 水印文字大小
  119. */
  120. private Integer fontSize = 38;
  121. /**
  122. * 水印文字字体
  123. */
  124. private String fontFamily;
  125. /**
  126. * 生成水印的位置,不指定则默认整页
  127. */
  128. private Location location;
  129. }
  130. package com.lifengdi.model.pdf;
  131. import lombok.Data;
  132. /**
  133. * 页面位置坐标
  134. * @author 李锋镝
  135. * @date Create at 11:35 2019/5/9
  136. */
  137. @Data
  138. public class Location {
  139. /**
  140. * X坐标
  141. */
  142. private Float x;
  143. /**
  144. * Y坐标
  145. */
  146. private Float y;
  147. /**
  148. * 横向间隔
  149. */
  150. private Float xInterval;
  151. /**
  152. * 纵向间隔
  153. */
  154. private Float yInterval;
  155. /**
  156. * 指定页 -1:全部,0:最后一页,1:首页
  157. */
  158. private Integer page;
  159. /**
  160. * 在指定文字上盖章
  161. */
  162. private String word;
  163. /**
  164. * 水印是否在内容上边
  165. */
  166. private Boolean overContent;
  167. }
  168. package com.lifengdi.model.pdf;
  169. import com.lifengdi.model.IType;
  170. import lombok.Data;
  171. /**
  172. * @author 李锋镝
  173. * @date Create at 14:07 2019/5/9
  174. */
  175. @Data
  176. public class PDFType implements IType {
  177. private PDFTempFile pdfTempFile;
  178. private PDFStamperConfig pdfStamperConfig;
  179. private PDFWatermarkConfig pdfWatermarkConfig;
  180. }
  181. package com.lifengdi.config;
  182. import com.lifengdi.model.pdf.PDFType;
  183. import lombok.Data;
  184. import org.springframework.boot.context.properties.ConfigurationProperties;
  185. import org.springframework.stereotype.Component;
  186. import java.util.HashMap;
  187. import java.util.Map;
  188. /**
  189. * PDF配置
  190. * @author 李锋镝
  191. * @date Create at 11:10 2019/5/9
  192. */
  193. @Data
  194. @Component
  195. @ConfigurationProperties("pdf")
  196. public class PDFConfig {
  197. private Map<String, PDFType> pdfType = new HashMap<>();
  198. }

在application.yml配置如下:

  1. # 生成PDF文件配置
  2. pdf:
  3. pdfType:
  4. test:
  5. pdfTempFile:
  6. pdfType: test
  7. templateFileName: test.ftl
  8. templateFileParentPath: file/
  9. pdfStamperConfig:
  10. generate: true
  11. # 印章所在路径
  12. stamperUrl: image/666.png
  13. xOffset: 0
  14. yOffset: 45
  15. fitWidth: 120
  16. fitHeight: 120
  17. location:
  18. x: -1
  19. y: -1
  20. page: 1
  21. word: 检测日期
  22. pdfWatermarkConfig:
  23. generate: true
  24. watermarkWord: 水印
  25. watermarkColor:
  26. fillOpacity:
  27. fontSize:
  28. fontFamily: SourceHanSansCN
  29. location:
  30. xInterval: 100
  31. yInterval: 120
  32. page:
  33. overContent: true

生成PDF效果截图:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI1MDA4NDg_size_16_color_FFFFFF_t_70

源码地址:https://github.com/lifengdi/generate-file


除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/archives/article/tech/861

发表评论

表情:
评论列表 (有 0 条评论,106人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Itext生成PDF文件

    最近做一个项目的报表,设计导出问题,要求pdf、excel、word。说实话一个字,烦。写个备忘录吧。。。虽然还是很烦 所需依赖:itext-asian-5.2.0.jar