参考文章来源:
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制作pdf模板后,使用java直接生成pdf至本地指定路径或导出pdf文件相关推荐

  1. PDF转word、excel、PPT软件---------Adobe Acrobat DC 2019

    目录 前言/背景 网盘下载 安装教程 功能使用 注意声明:本文继续留给有需要Adobe Acrobat DC 2019学习者使用,作者将不再继续解答相关的问题. 前言/背景 PDF格式是adobe公司 ...

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

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

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

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

  4. Adobe Acrobat DC + Java 生成pdf

    参考文章来源: springboot+itextpdf按模板生成PDF文件及在线下载PDF文件 JAVA根据模板生成PDF文件并导出 java将字符串按照指定长度分割成字符串数组 系统环境:win10 ...

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

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

  6. Adobe Acrobat Pro制作带有表单的pdf

    最近项目中表单填写提交完毕之后需要生成pdf文件,选择了使用Adobe Acrobat Pro制作带有表单的pdf.首先根据pdf样式我先用excel画出了表格转换成pdf.用Acrobat Pro ...

  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. (2分钟解决)Windows找不到文件报错:‘C:\Program Files(x86)\Adobe\Acrobat DC\Acrobat\AcroTray.exe’。请确定文件名是否正确后,再试一次

    Adobe Acrobat有时候莫名其妙找不到转换PDF的文件,无法转换PDF,上方加载项也消失了. 这种情况需要重新添加加载项 点击文件–>更多–>选项–>加载项–>点击&q ...

最新文章

  1. 最后一周报名微生物组-宏基因组分析(线上/线下同步开课,2020最后一期)
  2. 博客园博客停止更新的通知,程序员生存定律会在CSDN发完
  3. Cannot create file Altium\AD15\Library\BSDL\Generic\BSDL_FileMap.txt.拒绝访问
  4. Python比对指定目录下的Excel数据(附源码)
  5. Scala函数式编程:偏函数
  6. ES6的新特性(8)——数组的扩展
  7. ADB 基础命令使用
  8. WPF 凭证分录控件
  9. 《深度学习笔记》——深度神经网络的调试笔记
  10. Facebook跟踪用户手机地理位置 并借此推介朋友
  11. Effective C++: lambda表达式与闭包.
  12. 测试两个主机之间的连通性_如何使用知行EDI系统模拟连通性测试?
  13. Idea导入项目及相关环境配置
  14. 集美大学计算机课程考试系统,集美大学教务管理系统入口http://jwgl3.jmu.edu.cn
  15. 电路仿真软件用matlab,基于MATLAB的电路仿真软件设计.doc
  16. 信号完整性测试入门——SECOND
  17. VBS以强制启用宏的方式打开EXCEL文件,无视用户设置
  18. 狗年拜年php源码,2018新年拜年贺词【2018狗年拜年贺词】
  19. 爬虫练习(二)—股票信息抓取
  20. zurb是什么网站_Zurb的Tribute库的Vue.js包装器,用于本机@mentions

热门文章

  1. 解决安装流氓软件时,在桌面生成 小游戏 淘宝特卖,以及 Internet 图标的问题。
  2. tplink连接服务器失败_TP-LINK无线路由器拨号失败,服务器无响应。该怎样设置?
  3. 封印战记怎么在电脑上玩 封印战记电脑版玩法教程
  4. 程序员常用的技术网站(http://bbs.jointforce.com/topic/17717)
  5. 如何有效控制情绪?实用方法帮你掌控自己的情绪,让生活更加美好!你想知道如何应对情绪吗?这里有一些经过验证的方法。
  6. 七月三日服务器维护,7月3日服务器例行维护公告
  7. HashMap中负载因子的意义是什么?
  8. Android实现wake-on-lan
  9. 更改计算机用户名 拒绝访问,电脑修改Administrator帐户属性提示拒绝访问的解决方法...
  10. Eclipse中文注释字体变大方法