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

参考文章来源:
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模板如下图所示。
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")
    @ResponseBody
    public 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();
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_42622871/article/details/121516207