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);
}
}
}