参考文章来源:
springboot+itextpdf按模板生成PDF文件及在线下载PDF文件
JAVA根据模板生成PDF文件并导出

java将字符串按照指定长度分割成字符串数组

系统环境:win10、IDEA、jdk1.8

一、Adobe Acrobat DC的下载

百度链接:链接:https://pan.baidu.com/s/1RSV8D6kXDbWeV2owgw2Zyg
提取码:f8p8
可自取。

二、模板准备

1、在word中画好模板,另存为pdf格式

我生成的pdf模板如下图所示。

2、打开软件:Adobe Acrobat DC

页面如下图所示,选择【工具】–【准备表单】

将上述pdf文件放入这里

进入编辑表单页面,编辑字段(此字段名需和程序中字段名保持一致)。我的编辑如下图所示。

由于在【备注】这一字段中,我们的要求是文字带下划线的那种,且备注文字可能会有些长,因此我在这里设置成这样,我的思路如下:
1、在Adobe Acrobat DC中设置了bz-line1、bz-line2、bz-line3三个文本域,并分别设置其属性(双击该域即可,文字大小样式等都可以设置)。如下图所示:

2、程序中,读取数据(字符串类型),按固定长度对字符串进行截取并循环放入bz-line1、bz-line2、bz-line3中。后面在程序里我会展示我使用的笨方法。。。。

3、其实。。如果没有要求带下划线的话,完全可以直接在【属性】中勾选上【多行】即可实现多文字的换行。

3、保存编辑好的模板

三、java实现

1、添加Maven依赖

          <!-- PDF工具类 --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency><!-- PDF中文支持 --><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency>

2、直接生成pdf至本地指定路径

(1)、pdfUtils类

public class PdfUtils {private final static Logger log = LoggerFactory.getLogger(PdfUtils.class);// 利用模板生成pdf,这将直接保存到指定路径public static void pdfout(Map<String,Object> o,String templatePath,String newPDFPath) {PdfReader reader;FileOutputStream out=null;ByteArrayOutputStream bos=null;PdfStamper stamper;try {//系统字体String prefixFont = "";String os = System.getProperties().getProperty("os.name");if (os.startsWith("win") || os.startsWith("Win")) {prefixFont = "C:\\Windows\\Fonts" + File.separator;} else {prefixFont = "/usr/share/fonts/chinese" + File.separator;}//必须加“,0”或“,1”,否则会报错:com.itextpdf.text.DocumentException: Font 'C:\Windows\Fonts\simsun.ttc' with 'Identity-H' is not recognized.BaseFont bf = BaseFont.createFont(prefixFont + "simsun.ttc,0" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);out = new FileOutputStream(newPDFPath);// 输出流reader = new PdfReader(templatePath);// 读取pdf模板bos = new ByteArrayOutputStream();stamper = new PdfStamper(reader, bos);AcroFields form = stamper.getAcroFields();//文字类的内容处理Map<String,String> datemap = (Map<String,String>)o.get("datemap");form.addSubstitutionFont(bf);for(String key : datemap.keySet()){//为了文字可以有下划线,并且换行,控制每行字数,当字数超过时,将剩余文字填充至下一备选域if ("hzbz".equals(key)){String hzbz = datemap.get(key);String[] hzbzArray = stringToStringArray(hzbz,24);for(int i = 0; i < hzbzArray.length; i++){String fkey = "hzbz-line" + (i+1);form.setField(fkey,hzbzArray[i]);}}else if("bz".equals(key)){String bz = datemap.get(key);String[] bzArray = stringToStringArray(bz,24);for(int i = 0; i < bzArray.length; i++){String fkey = "bz-line" + (i+1);form.setField(fkey,bzArray[i]);}}else{String value = datemap.get(key);form.setField(key,value);}}//图片类的内容处理Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");for(String key : imgmap.keySet()) {Image value = imgmap.get(key);//String imgpath = value;Image image = value;int pageNo = form.getFieldPositions(key).get(0).page;Rectangle signRect = form.getFieldPositions(key).get(0).position;float x = signRect.getLeft();float y = signRect.getBottom();//根据路径读取图片//Image image = Image.getInstance(imgpath);//获取图片页面PdfContentByte under = stamper.getOverContent(pageNo);//图片大小自适应image.scaleToFit(signRect.getWidth(), signRect.getHeight());//添加图片image.setAbsolutePosition(x, y);under.addImage(image);}stamper.setFormFlattening(true);// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑stamper.close();Document doc = new Document(PageSize.A4, 50, 40, 40, 50);PdfCopy copy = new PdfCopy(doc, out);doc.open();//form.getTotalRevisions();int pages= stamper.getReader().getNumberOfPages();for(int i=1;i<=pages;i++){PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);copy.addPage(importPage);}doc.close();} catch (IOException e) {log.error("pdfout",e);} catch (DocumentException e) {log.error("pdfout",e);}finally {if(out!=null){try{out.close();}catch(Exception e){}}if(bos!=null){try{bos.close();}catch(Exception e){}}}}// 将字符串按照指定长度分割成字符串数组public static String[] stringToStringArray(String src, int length) {//检查参数是否合法if (null == src || src.equals("")) {return null;}if (length <= 0) {return null;}int n = (src.length() + length - 1) / length; //获取整个字符串可以被切割成字符子串的个数String[] split = new String[n];for (int i = 0; i < n; i++) {if (i < (n - 1)) {split[i] = src.substring(i * length, (i + 1) * length);} else {split[i] = src.substring(i * length);}}return split;}public static  byte[] inputstream2Bytes(InputStream inStream)  throws IOException{byte[] in_b = null;try{ByteArrayOutputStream swapStream = new ByteArrayOutputStream();byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据int rc = 0;while ((rc = inStream.read(buff, 0, 100)) > 0) {swapStream.write(buff, 0, rc);}in_b = swapStream.toByteArray(); //in_b为转换之后的结果}catch(Exception e){log.error("inputstream2Bytes",e);}finally {inStream.close();}return in_b;}/*** @Description: 文件转流*/public static InputStream file2InputStream(File file)  throws IOException{return new FileInputStream(file);}

(2)、controller层

@Controller
@RequestMapping("/pdf")
public class PdfController {@PostMapping("/createPdf")@ResponseBodypublic DataObject CreatePdf() throws AppException {//1、调用数据库,获取数据//此处写读取数据的代码//2、将数据存为key-value//存文字信息Map<String,String> map = new HashMap();//存图像信息Map<String,Image> mapI = new HashMap();map.put("name","田XX");map.put("sex","女");map.put("grbh","123456789010");map.put("sfzh","000000000000000000");map.put("rylb","啊哦");map.put("time1","2021-9-27");map.put("ddyy1","啊哦");map.put("time2","");map.put("ddyy2","");map.put("hzbz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");map.put("bz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");try{//图片路径File pic_file = new File("F:\\1555074510295049.jpg");Image pic_image = Image.getInstance(inputstream2Bytes(file2InputStream(pic_file)));mapI.put("pic",pic_image);}catch(Exception e){}Map<String,Object> o=new HashMap();o.put("datemap",map);o.put("imgmap",mapI);// 模板路径String templatePath = "/META-INF/resources/static/template/template.pdf";// 生成的新文件路径String newPDFPath = "F:\\template_sc.pdf";pdfout(o,templatePath,newPDFPath);return DataObject.getInstance();}
}

(3)前端入口

layui.sight.ajaxRequest({type : 'post',async : true,url : layui.sight.compileUrl('${rc.contextPath}/pdf/CreatePdf'),data : [],callback : function(data) {alert("成功!")},failedCallback : function(data) {}
});

3、导出pdf

(1)pdfUtils类

public class PdfUtils {private final static Logger log = LoggerFactory.getLogger(PdfUtils.class);/*** 利用模板生成pdf导出*/public static void pdfExport(Map<String, Object> o, HttpServletResponse response) {// 模板路径String templatePath = "/META-INF/resources/static/template/template.pdf";File file = new File(templatePath);if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}PdfReader reader;ByteArrayOutputStream bos;PdfStamper stamper;OutputStream out = null;try {BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);// 输出流response.setContentType("application/pdf");response.setHeader("Content-Disposition","attachment;fileName=" + URLEncoder.encode("template_scsc.pdf", "UTF-8"));out = new BufferedOutputStream(response.getOutputStream());// 读取pdf模板reader = new PdfReader(templatePath);bos = new ByteArrayOutputStream();stamper = new PdfStamper(reader, bos);AcroFields form = stamper.getAcroFields();//文字类的内容处理Map<String,String> datemap = (Map<String,String>)o.get("datemap");form.addSubstitutionFont(bf);for(String key : datemap.keySet()){//为了文字可以有下划线,并且换行,控制每行字数,当字数超过时,将剩余文字填充至下一备选域if ("hzbz".equals(key)){String hzbz = datemap.get(key);String[] hzbzArray = stringToStringArray(hzbz,24);for(int i = 0; i < hzbzArray.length; i++){String fkey = "hzbz-line" + (i+1);form.setField(fkey,hzbzArray[i]);}}else if("bz".equals(key)){String bz = datemap.get(key);String[] bzArray = stringToStringArray(bz,24);for(int i = 0; i < bzArray.length; i++){String fkey = "bz-line" + (i+1);form.setField(fkey,bzArray[i]);}}else{String value = datemap.get(key);form.setField(key,value);}}//图片类的内容处理Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");for(String key : imgmap.keySet()) {Image value = imgmap.get(key);//String imgpath = value;Image image = value;int pageNo = form.getFieldPositions(key).get(0).page;Rectangle signRect = form.getFieldPositions(key).get(0).position;float x = signRect.getLeft();float y = signRect.getBottom();//根据路径读取图片//Image image = Image.getInstance(imgpath);//获取图片页面PdfContentByte under = stamper.getOverContent(pageNo);//图片大小自适应image.scaleToFit(signRect.getWidth(), signRect.getHeight());//添加图片image.setAbsolutePosition(x, y);under.addImage(image);}stamper.setFormFlattening(true);stamper.close();Document doc = new Document();PdfCopy copy = new PdfCopy(doc, out);doc.open();PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);copy.addPage(importPage);doc.close();} catch (IOException | DocumentException e) {System.out.println(e);} finally {try {assert out != null;out.close();} catch (IOException e) {e.printStackTrace();}}}// 将字符串按照指定长度分割成字符串数组public static String[] stringToStringArray(String src, int length) {//检查参数是否合法if (null == src || src.equals("")) {return null;}if (length <= 0) {return null;}int n = (src.length() + length - 1) / length; //获取整个字符串可以被切割成字符子串的个数String[] split = new String[n];for (int i = 0; i < n; i++) {if (i < (n - 1)) {split[i] = src.substring(i * length, (i + 1) * length);} else {split[i] = src.substring(i * length);}}return split;}public static  byte[] inputstream2Bytes(InputStream inStream)  throws IOException{byte[] in_b = null;try{ByteArrayOutputStream swapStream = new ByteArrayOutputStream();byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据int rc = 0;while ((rc = inStream.read(buff, 0, 100)) > 0) {swapStream.write(buff, 0, rc);}in_b = swapStream.toByteArray(); //in_b为转换之后的结果}catch(Exception e){log.error("inputstream2Bytes",e);}finally {inStream.close();}return in_b;}/*** @Description: 文件转流*/public static InputStream file2InputStream(File file)  throws IOException{return new FileInputStream(file);}

(2)、controller层

@Controller
@RequestMapping("/pdf")
public class PdfController {@RequestMapping("/exportPdf")public void exportPdf(HttpServletRequest request, HttpServletResponse response) throws AppException {//调用数据库,获取数据//将数据存为key-value//存文字信息Map<String,String> map = new HashMap();//存图像信息Map<String,Image> mapI = new HashMap();map.put("name","田XX");map.put("sex","女");map.put("grbh","12345678910");map.put("sfzh","00000000000000000");map.put("rylb","啊哦");map.put("time1","2021-9-27");map.put("ddyy1","啊哦");map.put("time2","");map.put("ddyy2","");map.put("hzbz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");map.put("bz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");try{//图片路径File pic_file = new File("F:\\1555074510295049.jpg");Image pic_image = Image.getInstance(inputstream2Bytes(file2InputStream(pic_file)));mapI.put("pic",pic_image);}catch(Exception e){}Map<String,Object> o=new HashMap();o.put("datemap",map);o.put("imgmap",mapI);pdfExport(o,response);}
}

(3)前端入口

function down(){var url = layui.sight.compileUrl('${rc.contextPath}/pdf/exportPdf');window.open(encodeURI(url));
}

四、最终效果

图片选的不太好。。

五、出现问题

将项目打包后,启动jar包时会报空指针的错误,具体错误描述我忘记复制了呜呜呜呜。

解决方案:
修改PdfUtils。修改后:

 /*** 利用模板生成pdf导出*/public static void pdfExport(Map<String, Object> o, HttpServletResponse response) throws IOException {// 生成的新文件路径String filePath = "D:\\test.text";// 模板路径Resource resource = new ClassPathResource("/META-INF/resources/static/template/template.pdf");File inuModel = new File(filePath);FileUtils.copyInputStreamToFile(resource.getInputStream(), inuModel);PdfReader reader;ByteArrayOutputStream bos;PdfStamper stamper;OutputStream out = null;try {BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);// 输出流response.setContentType("application/pdf");response.setHeader("Content-Disposition","attachment;fileName=" + URLEncoder.encode("template_scsc.pdf", "UTF-8"));out = new BufferedOutputStream(response.getOutputStream());// 读取pdf模板reader = new PdfReader(filePath);bos = new ByteArrayOutputStream();stamper = new PdfStamper(reader, bos);AcroFields form = stamper.getAcroFields();//文字类的内容处理Map<String,String> datemap = (Map<String,String>)o.get("datemap");form.addSubstitutionFont(bf);for(String key : datemap.keySet()){String value = datemap.get(key);form.setField(key,value);}//图片类的内容处理Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");for(String key : imgmap.keySet()) {Image value = imgmap.get(key);//String imgpath = value;Image image = value;int pageNo = form.getFieldPositions(key).get(0).page;Rectangle signRect = form.getFieldPositions(key).get(0).position;float x = signRect.getLeft();float y = signRect.getBottom();//根据路径读取图片//Image image = Image.getInstance(imgpath);//获取图片页面PdfContentByte under = stamper.getOverContent(pageNo);//图片大小自适应image.scaleToFit(signRect.getWidth(), signRect.getHeight());//添加图片image.setAbsolutePosition(x, y);under.addImage(image);}stamper.setFormFlattening(true);stamper.close();Document doc = new Document();PdfCopy copy = new PdfCopy(doc, out);doc.open();PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);copy.addPage(importPage);doc.close();} catch (IOException | DocumentException e) {System.out.println(e);} finally {try {assert out != null;out.close();} catch (IOException e) {e.printStackTrace();}}}

Adobe Acrobat DC + Java 生成pdf相关推荐

  1. Adobe Acrobat DC无法生成pdf:an unexpected error occurred pdfmaker was unable to produce the adobe pdf

    在分享笔者解决这个问题的经验之前,首先说一下笔者的结论: 在排除Adobe Acrobat自身软件原因之后,若出现an unexpected error occurred pdfmaker was u ...

  2. Adobe Acrobat DC pro 打开PDF文件后目录默认折叠,或默认展开

    有时候我们使用PDF阅读器(Adobe或者Foxit等)PDF文件时,目录默认是全部折叠.全部展开或者部分折叠的,如果要改变默认状态,只需手动折叠或展开成想要的状态,然后另存即可.打开另存的PDF,目 ...

  3. 在Adobe Acrobat DC中设置PDF单页连续

    点击 编辑-->首选项-->辅助工具-->选择总是使用页面布局样式-->单页连续,如下图所示. 然后点击 文档-->打开设置,去掉"重新打开文档时恢复上次视图设 ...

  4. 利用Adobe Acrobat DC制作pdf模板后,使用java直接生成pdf至本地指定路径或导出pdf文件

    参考文章来源: springboot+itextpdf按模板生成PDF文件及在线下载PDF文件 JAVA根据模板生成PDF文件并导出 java将字符串按照指定长度分割成字符串数组 感谢上述博主大大,救 ...

  5. Java使用Adobe Acrobat DC根据PDF模板生成PDF文件

    制作模板 首先需要安装Adobe Acrobat DC来制作模板 打开dc工具-->准备表单,然后打开你需要制作的pdf源文件 将文本域拖到你需要代码替换的位置 你可以双击文本域修改当前文本域的 ...

  6. Adobe Acrobat pro生成PDF模版 java生成PDF

    最近做了一个关于动态生成PDF合同的需求  java生成PDF 网络上随便一搜遍有了 不要用手动在代码里面输入合同中的文字这种方式 如这样的方式 http://blog.csdn.net/justin ...

  7. 《Adobe Acrobat DC经典教程》—第1章1.11节在阅读模式下查看PDF文件

    本节书摘来自异步社区<Adobe Acrobat DC经典教程>一书中的第1章1.11节在阅读模式下查看PDF文件,作者[美]Lisa Fridsma(丽莎 弗里斯玛) , Brie Gy ...

  8. 最强大的PDF编辑器Adobe Acrobat DC Pro

    前言 PDF(Portable Document Format的简称,意为"便携式文档格式"),是由Adobe Systems用于与应用程序.操作系统.硬件无关的方式进行文件交换所 ...

  9. acrobat PDF删除部分_PDF编辑器Adobe Acrobat DC 2019

    很多小伙伴在公众号内留言说想要一款PDF编辑软件,于是今天就给大家带来了最新款的PDF编辑器 → Adobe Acrobat DC 2019 别慌,先看看我抄来的介绍 → → Adobe Acroba ...

最新文章

  1. [ACM] hdu 1253 胜利大逃亡 (三维BFS)
  2. Ubuntu下通过 PPA 安装 Komodo 编辑器
  3. (剑指Offer)面试题18:树的子结构
  4. 群晖docker装huginn_应用篇:Docker版Zerotier实现内网穿透
  5. 信息学奥赛一本通(1092:求出e的值)
  6. [ZT]firefox实现ie的方法和属性)
  7. oracle有没有mysql if_Oracle中没有 if exists(...)
  8. Python:集合、三元运算符
  9. vue项目中对接微信公众号使用微信js-sdk
  10. 淡定的写代码,淡定的人生
  11. PAT (Basic Level) Practice1025 反转链表
  12. STM32程序下载的三种方式
  13. oracle插入获取当前时间,Oracle中如何获取系统当前时间
  14. JS 获取操作删除节点
  15. arcEngine开发之查询相关接口
  16. sicily 9562 SUME
  17. linux终端删除文件命令_如何在Linux终端中删除文件和目录
  18. CentOS 7 安装教程
  19. Python之pandas库(万年一更版)
  20. 面向对象案例——贪吃蛇游戏

热门文章

  1. C语言进程(第三章,exec函数族,execl,execlp,execle,execv,execvp,execve)
  2. 使用软件破解BIOS密码
  3. Automatic Open-World Reliability Assessment
  4. 用Powershell命令批量获取域客户端某个补丁是否安装
  5. 学习笔记——数据格式的变更和自定义
  6. 习题3-3 出租车计价
  7. 调程序的小女孩(我转我转我转转转)
  8. 教你如何将视频去除水印
  9. 一维地震子波合成记录c语言,地震子波 数字信号实验报告
  10. VRTK基础入门案例演示