java生成pdf并加水印

1生成pdf并通过输出流返回生成的pdf文件(常用于下载pdf)

2生成pdf并上传到minio,并返回图片的url(常用于pdf的预览)

  • 场景梳理

    1 ,根据事先制作好的pdf模板生成pdf(使用Adobe Acrobat软件)

    2, 在用户签名处给pdf加上签名的图片

    3, 给pdf生成水印(水印可换行)

    4, 直接返回输出流给前端,前端直接可以下载pdf

    需要的pom依赖
      <!-- 导出pdf需要使用的包:xdocreport -->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itext-asian</artifactId>
                <version>5.2.0</version>
            </dependency>
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.13</version>
            </dependency>
            <dependency>
                <groupId>fr.opensagres.xdocreport</groupId>
                <artifactId>org.apache.poi.xwpf.converter.core</artifactId>
                <version>1.0.4</version>
            </dependency>
            <dependency>
                <groupId>fr.opensagres.xdocreport</groupId>
                <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
                <version>1.0.4</version>
            </dependency>
            <dependency>
                <groupId>fr.opensagres.xdocreport</groupId>
                <artifactId>fr.opensagres.xdocreport.itext.extension</artifactId>
                <version>1.0.4</version>
            </dependency>
            <!-- 文件流转化需要的依赖 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.3.20</version>
            </dependency>
    

该方法的代码如下

package com.ruoyi.common.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.AcroFields.Item;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * pdf工具类
 *
 * @author wuhuc
 * @data 2022/7/12 - 9:12
 */
public class PdfUtill {
    /**
     * @param templatePdfPath 模板pdf路径
     * @param data            数据
     */
    public static void generatePDFByOutputStream(String templatePdfPath,
                                                 Map<String, Object> data, Map<String, byte[]> imgMap, HttpServletResponse response) {
        OutputStream fos = null;
        ByteArrayOutputStream bos = null;
        try {
            PdfReader reader = new PdfReader(templatePdfPath);
            bos = new ByteArrayOutputStream();
            /* 将要生成的目标PDF文件名称 */
            PdfStamper ps = new PdfStamper(reader, bos);
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.4f);// 设置透明度
            /* 使用中文字体 */
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
            fontList.add(bf);
            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            for (int i = 1; i < total; i++) {
                content = ps.getOverContent(i);
                content.beginText();
                content.setGState(gs);
                content.setColorFill(BaseColor.DARK_GRAY); //水印颜色
                content.setFontAndSize(bf, 20); //水印字体样式和大小
                final String username = SecurityUtils.getUsername();
                for (int x = 0; x < 700; x = x + 300) {
                    for (int y = 0; y < 900; y = y + 200) {
                        //水印内容和水印位置
                        content.showTextAligned(Element.ALIGN_CENTER, "xxx", x - 20, y + 10, 30);
                        content.showTextAligned(Element.ALIGN_CENTER, username + LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN), x, y, 30);
                    }
                }
                content.endText();
            }

            /* 取出报表模板中的所有字段 */
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);
            fillData(fields, data);
            // 添加图片
            if (imgMap != null) {
                addImage(ps, fields, imgMap);
            }
            /* 必须要调用这个,否则文档不会生成的  如果为false那么生成的PDF文件还能编辑,一定要设为true*/
            ps.setFormFlattening(true);
            ps.close();
            //设置导出的数据的文件流
            response.setContentType("application/pdf");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("xxx", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
            fos = response.getOutputStream();
            fos.write(bos.toByteArray());
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static AjaxResult generatePDFByMinio(String templatePdfPath,
                                                Map<String, Object> data, Map<String, byte[]> imgMap) {
        ByteArrayOutputStream bos = null;
        try {
            PdfReader reader = new PdfReader(templatePdfPath);
            bos = new ByteArrayOutputStream();
            /* 将要生成的目标PDF文件名称 */
            PdfStamper ps = new PdfStamper(reader, bos);
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.4f);// 设置透明度
            /* 使用中文字体 */
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
            fontList.add(bf);
            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            for (int i = 1; i < total; i++) {
                content = ps.getOverContent(i);
                content.beginText();
                content.setGState(gs);
                //水印颜色
                content.setColorFill(BaseColor.DARK_GRAY);
                //水印字体样式和大小
                content.setFontAndSize(bf, 20);
                final String username = SecurityUtils.getUsername();
                for (int x = 0; x < 700; x = x + 300) {
                    for (int y = 0; y < 900; y = y + 200) {
                        //水印内容和水印位置
                        content.showTextAligned(Element.ALIGN_CENTER, "xxx", x - 20, y + 10, 30);
                        content.showTextAligned(Element.ALIGN_CENTER, username + LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN), x, y, 30);
                    }
                }
                content.endText();
            }
            /* 取出报表模板中的所有字段 */
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);
            fillData(fields, data);
            // 添加图片
            if (imgMap != null) {
                addImage(ps, fields, imgMap);
            }
            /* 必须要调用这个,否则文档不会生成的  如果为false那么生成的PDF文件还能编辑,一定要设为true*/
            ps.setFormFlattening(true);
            ps.close();
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
            MultipartFile file = new MockMultipartFile("xxx.pdf", "xxx.pdf", "application/pdf", byteArrayInputStream);
            String fileName = FileUploadUtils.uploadMinio(file);
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", fileName);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void fillData(AcroFields fields, Map<String, Object> data) throws IOException, DocumentException, DocumentException {
        List<String> keys = new ArrayList<String>();
        Map<String, Item> formFields = fields.getFields();
        for (String key : data.keySet()) {
            if (formFields.containsKey(key)) {
                //忽略值为null的字段
                if (data.get(key) != null) {
                    String value = String.valueOf(data.get(key));
                    fields.setField(key, value, true); // 为字段赋值,注意字段名称是区分大小写的
                    keys.add(key);
                }
            }
        }
        Iterator<String> itemsKey = formFields.keySet().iterator();
        while (itemsKey.hasNext()) {
            String itemKey = itemsKey.next();
            if (!keys.contains(itemKey)) {
                fields.setField(itemKey, " ");
            }
        }
    }

    private static void addImage(com.itextpdf.text.pdf.PdfStamper ps, com.itextpdf.text.pdf.AcroFields fields, Map<String, byte[]> imgMap) throws IOException, com.itextpdf.text.DocumentException {
        for (String key : imgMap.keySet()) {
            int pageNo = fields.getFieldPositions(key).get(0).page;
            Rectangle signRect = fields.getFieldPositions(key).get(0).position;
            float x = signRect.getLeft();
            float y = signRect.getBottom();
            // 读图片
            Image image = Image.getInstance(imgMap.get(key));
            // 获取操作的页面
            PdfContentByte under = ps.getOverContent(pageNo);
            // 根据域的大小缩放图片
            image.scaleToFit(signRect.getWidth(), signRect.getHeight());
            // 添加图片
            image.setAbsolutePosition(x, y);
            under.addImage(image);
        }
    }

}

posted @ 2022-07-14 20:18  小猫爱哭鬼  阅读(3066)  评论(0编辑  收藏  举报