OpenPDF是一个Java库,用于创建和编辑具有LGPL和MPL开源许可证的PDF文件。
官方git地址 链接: https://github.com/LibrePDF/OpenPDF
OpenPDF是iText的LGPL/MPL开源后续版本,它基于iText 4svn标记的fork、fork。我们欢迎其他开发者的贡献。请随时向这个GitHub存储库提交pull-requests和错误报告。
由于Itext 5.0和7.0要求使用它的项目也得开源,但这基本上不符合企业的项目。
若项目已有itext的相关构建代码,基本上就是重新引入包即可,相关接口的名字基本上一样。
这里引用一个demo创建相关接口。
项目结构为SpringBoot +thymeleaf+maven项目,如图所示:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<groupId>com.demo</groupId>
<artifactId>openPdfDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>openPdfDemo</name>
<description>openPdfDemo</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.29</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建PdfCreator接口类,对操作步骤进行抽象化,方便后续扩展。
import com.lowagie.text.DocumentException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
/**
* pdf生成器接口
*/
public interface PdfCreator {
/**
* 初始化
*
* @return PdfCreator
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
PdfCreator init() throws DocumentException, IOException;
/**
* 构建pdf
*
* @param map 导出数据参数
* @return ByteArrayOutputStream
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
ByteArrayOutputStream creator(Map<String, Object> map) throws DocumentException, IOException;
/**
* 资源关闭
*
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
void close() throws DocumentException, IOException;
}
创建 PdfCreateStrategy接口:
import com.lowagie.text.DocumentException;
import java.io.IOException;
import java.util.Map;
/**
* pdf 构建策略-用于不同pdf时指向各自的pdf构建实现
*/
public interface PdfCreateStrategy {
/**
* 够构建方法
*
* @param map 导出数据所需参数
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
void execute(Map<String, Object> map) throws DocumentException, IOException;
}
创建抽象实现类AbstractPdfCreator,将共用部分进行提取
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.Header;
import com.lowagie.text.PageSize;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
/**
* pdf构建抽象生成类
*/
public abstract class AbstractPdfCreator implements PdfCreator, PdfCreateStrategy {
/**
* 页框大小,采用的类型有 "crop", "trim", "art" and "bleed".,这里采用 "art"
*/
private static final String BOX_NAME = "art";
/**
* 文档类
*/
protected Document document;
/**
* 基础字体
*/
protected BaseFont baseFont;
/**
* 字体样式
*/
protected Font font;
/**
* 字体大小
*/
protected int fontSize;
/**
* 页面框架大小配置
*/
protected Rectangle pageSize;
/**
* 字节输出流
*/
private ByteArrayOutputStream byteArrayOutputStream;
/**
* pdf构建操作转为字节流
*
* @param map 导出数据参数
* @return ByteArrayOutputStream
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
@Override
public ByteArrayOutputStream creator(Map<String, Object> map) throws DocumentException, IOException {
execute(map);
close();
return byteArrayOutputStream;
}
/**
* pdf构建执行
*
* @param map 导出数据所需参数
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
@Override
public abstract void execute(Map<String, Object> map) throws DocumentException, IOException;
/**
* 默认初始化
*
* @return PdfCreator
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
@Override
public PdfCreator init() throws DocumentException, IOException {
return init(baseFont, fontSize, font, pageSize, null);
}
/**
* 自定义初始化监听
*
* @param helper 自定义文档操作监听
* @return PdfCreator
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
public PdfCreator init(PdfPageEventHelper helper) throws DocumentException, IOException {
return init(baseFont, fontSize, font, pageSize, helper);
}
/**
* 自定义初始化参数
*
* @param baseFont 基础字体
* @param fontSize 字体大小
* @param font 字体样式
* @param rectangle 页面大小设置
* @param pdfPageEventHelper 文档操作监听
* @return PdfCreator
* @throws DocumentException 文档操作异常
* @throws IOException IO操作异常
*/
public PdfCreator init(BaseFont baseFont, int fontSize, Font font, Rectangle rectangle, PdfPageEventHelper pdfPageEventHelper) throws DocumentException, IOException {
this.baseFont = null != baseFont ? baseFont : BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", Boolean.FALSE);
this.fontSize = 0 != fontSize ? fontSize : Header.PARAGRAPH;
this.font = null != font ? font : new Font(this.baseFont, this.fontSize, Font.NORMAL);
this.pageSize = null != pageSize ? pageSize : PageSize.A4;
document = new Document();
document.setMargins(30, 30, 50, 90);
byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, byteArrayOutputStream);
writer.setBoxSize(BOX_NAME, this.pageSize);
if (null != pdfPageEventHelper) {
writer.setPageEvent(pdfPageEventHelper);
}
document.open();
return this;
}
/**
* 资源关闭
*
* @throws DocumentException
* @throws IOException IO操作异常
*/
@Override
public void close() throws IOException {
document.close();
byteArrayOutputStream.close();
}
}
自定义监听器PdfPageEventListener创建
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.CMYKColor;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;
import org.springframework.util.StringUtils;
import java.io.IOException;
/**
* pdf页面自定义监听器
*/
public class PdfPageEventListener extends PdfPageEventHelper {
/**
* pdf标题字体大小
*/
private int headerFontSize;
/**
* pdf标题宽度
*/
private Float headerWidth;
/**
* pdf标题高度
*/
private Float headerHeight;
/**
* pdf标题模板
*/
private PdfTemplate headerTemplate;
/**
* pdf标题基础字体
*/
private BaseFont headerBaseFont;
/**
* pdf标题字体样式
*/
private Font headerFont;
/**
* pdf编号(一般左上角都会有类似流水号的编号,可有可无)
*/
private String noticeCode;
/**
* pdf签字(可有可无,根据实际情况进行赋值)
*/
private String signature;
/**
* 构建器,进行基本信息初始化
*
* @param headerFontSize pdf标题字体大小
* @param headerWidth pdf标题宽度
* @param headerHeight pdf标题高度
* @param headerBaseFont pdf标题基础字体
* @param headerFont pdf标题字体样式
* @param noticeCode pdf编号
* @param signature pdf签字
*/
public PdfPageEventListener(int headerFontSize, Float headerWidth, Float headerHeight, BaseFont headerBaseFont, Font headerFont, String noticeCode, String signature) {
this.headerFontSize = headerFontSize;
this.headerWidth = headerWidth;
this.headerHeight = headerHeight;
this.headerBaseFont = headerBaseFont;
this.headerFont = headerFont;
this.noticeCode = noticeCode;
this.signature = signature;
}
/**
* pdf监视器构建
*
* @return Builder
*/
public static Builder build() {
return new Builder();
}
/**
* 重写文档初始化的模板
*/
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
headerTemplate = writer.getDirectContent().createTemplate(headerWidth, headerHeight);
}
/**
* 重写每一页结束事件,等所有内容加载完毕后,进行页眉的数据加载和赋值
*/
@Override
public void onEndPage(PdfWriter writer, Document document) {
try {
if (headerBaseFont == null) {
headerBaseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", Boolean.FALSE);
}
if (headerFont == null) {
headerFont = new Font(headerBaseFont, headerFontSize, Font.NORMAL);
}
} catch (IOException e) {
e.printStackTrace();
}
//获取文档内容
PdfContentByte pdfContentByte = writer.getDirectContent();
float left = document.left();
float right = document.right();
float top = document.top();
float bottom = document.bottom();
int pageNumber = writer.getPageNumber();
String noticeCodeText = StringUtils.isEmpty(noticeCode) ? "" : "编号:" + noticeCode;
String previousHeaderText = "第 " + pageNumber + " 页 /共";
Phrase headerPhrase = new Phrase(previousHeaderText, headerFont);
Phrase noticePhrase = new Phrase(noticeCodeText, headerFont);
Phrase signaturePhrase = new Phrase(signature, headerFont);
float noticeLen = headerBaseFont.getWidthPoint(noticeCodeText, headerFontSize);
float headerLen = headerBaseFont.getWidthPoint(previousHeaderText, headerFontSize);
float signatureLen = headerBaseFont.getWidthPoint(signature, headerFontSize);
float x0 = left + noticeLen / 2;
float x1 = right - headerLen / 2 - 20F;
float x2 = right - 20F;
float x3 = right - signatureLen / 2;
float y1 = top + 10F;
float y2 = bottom - 40F;
ColumnText.showTextAligned(pdfContentByte, Element.ALIGN_CENTER, noticePhrase, x0, y1, Element.HEADER);
ColumnText.showTextAligned(pdfContentByte, Element.ALIGN_CENTER, headerPhrase, x1, y1, Element.HEADER);
ColumnText.showTextAligned(pdfContentByte, Element.ALIGN_CENTER, signaturePhrase, x3, y2, Element.HEADER);
pdfContentByte.addTemplate(headerTemplate, x2, y1);
float lineY = top + 6f;
CMYKColor magentaColor = new CMYKColor(1.f, 1.f, 1.f, 1.f);
pdfContentByte.setColorStroke(magentaColor);
pdfContentByte.moveTo(left, lineY);
pdfContentByte.lineTo(left, lineY);
pdfContentByte.closePathStroke();
}
/**
* 文档结束后,将总页码放在文档上
*/
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
headerTemplate.beginText();
headerTemplate.setFontAndSize(headerBaseFont, headerFontSize);
int pageNumber = writer.getPageNumber() - 1;
String behindHeaderText = " " + pageNumber + " 页";
headerTemplate.showText(behindHeaderText);
headerTemplate.endText();
headerTemplate.closePath();
}
/**
* 自定义一个构建器,设置页面相关信息
*/
public static class Builder {
private int headerFontSize;
private Float headerWidth;
private Float headerHeight;
private PdfTemplate headerTemplate;
private BaseFont headerBaseFont;
private Font headerFont;
private String noticeCode;
private String signature;
Builder() {
headerFontSize = Font.DEFAULTSIZE;
headerWidth = 50F;
headerHeight = 50F;
try {
headerBaseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", Boolean.FALSE);
} catch (IOException e) {
e.printStackTrace();
}
headerFont = new Font(headerBaseFont, headerFontSize, Font.NORMAL);
noticeCode = "";
signature = "";
}
public Builder setHeaderFontSize(int headerFontSize) {
this.headerFontSize = headerFontSize;
return this;
}
public Builder setHeaderWidth(Float headerWidth) {
this.headerWidth = headerWidth;
return this;
}
public Builder setHeaderHeight(Float headerHeight) {
this.headerHeight = headerHeight;
return this;
}
public Builder setHeaderTemplate(PdfTemplate headerTemplate) {
this.headerTemplate = headerTemplate;
return this;
}
public Builder setHeaderBaseFont(BaseFont headerBaseFont) {
this.headerBaseFont = headerBaseFont;
return this;
}
public Builder setHeaderFont(Font headerFont) {
this.headerFont = headerFont;
return this;
}
public Builder setNoticeCode(String noticeCode) {
this.noticeCode = noticeCode;
return this;
}
public Builder setSignature(String signature) {
this.signature = signature;
return this;
}
public PdfPageEventListener build() {
return new PdfPageEventListener(headerFontSize, headerWidth, headerHeight, headerBaseFont, headerFont, noticeCode, signature);
}
}
}
比如我们模拟用户信息打印。
创建用户信息实体类UserModel
public class UserModel {
private String name;
private int age;
private String sex;
private String nativePlace;
private String national;
private String education;
private String remark;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getNativePlace() {
return nativePlace;
}
public void setNativePlace(String nativePlace) {
this.nativePlace = nativePlace;
}
public String getNational() {
return national;
}
public void setNational(String national) {
this.national = national;
}
public String getEducation() {
return education;
}
public void setEducation(String education) {
this.education = education;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}
创建适用于用户信息打印的pdf构建实现类UserInfoPdfCreator
import com.demo.openpdfdemo.model.UserModel;
import com.demo.openpdfdemo.pdfCreator.core.AbstractPdfCreator;
import com.demo.openpdfdemo.pdfCreator.core.HtmlParserUtil;
import com.lowagie.text.Chunk;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 用户信息导出为pdf
*/
public class UserInfoPdfCreator extends AbstractPdfCreator {
@Override
public void execute(Map<String, Object> map) throws DocumentException, IOException {
//map中可以存放实体类信息,以及其他各种逻辑数据信息等
UserModel user = (UserModel) map.get("data");
Font titleFont = new Font(baseFont, 14, Font.BOLD);
Paragraph title = new Paragraph("用户信息表", titleFont);
title.setAlignment(Element.ALIGN_CENTER);
title.setSpacingAfter(10F);
document.add(title);
Paragraph paragraphText = new Paragraph();
Font font1 = new Font(baseFont, fontSize, Font.NORMAL);
paragraphText.add(new Chunk("此表为用户基本信息,请查看", font1));
paragraphText.setAlignment(Element.ALIGN_LEFT);
paragraphText.setFirstLineIndent(fontSize * 2);
document.add(paragraphText);
PdfPTable table = new PdfPTable(4);
table.setTotalWidth(530);
table.setWidths(new int[]{20, 30, 22, 28});
table.setSpacingBefore(20);
table.setWidthPercentage(100);
table.setLockedWidth(true);
Paragraph p1 = new Paragraph("姓名", font);
PdfPCell cell1 = new PdfPCell(p1);
cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell1);
Paragraph p2 = new Paragraph(user.getName(), font);
PdfPCell cell2 = new PdfPCell(p2);
cell2.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell2);
Paragraph p3 = new Paragraph("年龄", font);
PdfPCell cell3 = new PdfPCell(p3);
cell3.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell3);
Paragraph p4 = new Paragraph(String.valueOf(user.getAge()), font);
PdfPCell cell4 = new PdfPCell(p4);
cell4.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell4);
Paragraph p5 = new Paragraph("性别", font);
PdfPCell cell5 = new PdfPCell(p5);
cell5.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell5);
Paragraph p6 = new Paragraph(user.getSex(), font);
PdfPCell cell6 = new PdfPCell(p6);
cell6.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell6);
Paragraph p7 = new Paragraph("籍贯", font);
PdfPCell cell7 = new PdfPCell(p7);
cell7.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell7);
Paragraph p8 = new Paragraph(user.getSex(), font);
PdfPCell cell8 = new PdfPCell(p8);
cell8.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell8);
Paragraph p9 = new Paragraph("民族", font);
PdfPCell cell9 = new PdfPCell(p9);
cell9.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell9);
Paragraph p10 = new Paragraph(user.getSex(), font);
PdfPCell cell10 = new PdfPCell(p10);
cell10.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell10);
Paragraph p11 = new Paragraph("学历", font);
PdfPCell cell11 = new PdfPCell(p11);
cell11.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell11);
Paragraph p12 = new Paragraph(user.getSex(), font);
PdfPCell cell12 = new PdfPCell(p12);
cell12.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell12);
Paragraph p13 = new Paragraph("备注", font);
PdfPCell cell13 = new PdfPCell(p13);
cell13.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell13);
PdfPCell cell14 = new PdfPCell();
List<Element> elements = HtmlParserUtil.htmlParseToElementList(user.getRemark(), font);
if (!CollectionUtils.isEmpty(elements)) {
for (Element element : elements) {
cell14.addElement(element);
}
}
cell14.setColspan(3);
table.addCell(cell14);
table.setSplitLate(false);
document.add(table);
}
}
实际项目中有的字段信息为富文本类型的,数据库中存储的是html片段,但这个跟整个html转pdf还不一样,比如这里的用户的备注信息,这里要求这个备注信息插入到pdf中,其他字段不是html片段。官方提供的是通过HTMLWorker来实现,看源码,提供的注释也是少之甚少啊。
创建HtmlParserUtil工具类:
import com.lowagie.text.Chunk;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.html.simpleparser.StyleSheet;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPRow;
import com.lowagie.text.pdf.PdfPTable;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 实现对html片段解析为Document中所需的Element信息
*/
public class HtmlParserUtil {
/**
* 实现对html片段解析
*
* @param html html代码
* @param font 字体
* @return List
* @throws IOException IO操作异常
*/
public static List<Element> htmlParseToElementList(String html, Font font) throws IOException {
if (!"".equals(html)) {
//字符流
StringReader stringReader = new StringReader(html);
//用于存放字体样式实现类,这里为空即可,通过测试,发现用其他字体无法正常中文,故这里需要进行对baseFont重新定义
Map<String, Object> map = new HashMap<>();
// map.put("font_factory", new FontFactoryImp());
List<Element> elements = HTMLWorker.parseToList(stringReader, new StyleSheet(), map);
if (!CollectionUtils.isEmpty(elements)) {
//解析数据获取具体的element
List<Element> chunks = new ArrayList<>();
for (Element element : elements) {
if (element instanceof com.lowagie.text.List) {
com.lowagie.text.List list = (com.lowagie.text.List) element;
chunks.addAll(list.getChunks());
} else if (element instanceof PdfPTable) {
PdfPTable pdfPTable = (PdfPTable) element;
ArrayList<PdfPRow> rows = pdfPTable.getRows();
for (PdfPRow row : rows) {
for (PdfPCell cell : row.getCells()) {
List<Element> compositeElements = cell.getCompositeElements();
for (Element e : compositeElements) {
chunks.addAll(e.getChunks());
}
}
}
} else {
chunks.addAll(element.getChunks());
}
}
if (!CollectionUtils.isEmpty(chunks)) {
//将所有的Font的BaseFont重新定义,Font跟pdf其他元素一样即可,其他的是正常显示的。
//目前没有找到跟Itext一样的全局设置的接口,只能检索每个元素重新设置字体
for (Element chunk : chunks) {
if (chunk instanceof Chunk) {
Font chunkFont = ((Chunk) chunk).getFont();
Font newFont = new Font(font.getBaseFont(), chunkFont.getSize(), chunkFont.getStyle(), chunkFont.getColor());
((Chunk) chunk).setFont(newFont);
}
}
}
}
return elements;
}
return new ArrayList<>();
}
}
以上代码可以看出对font进行了相关处理,若不处理的话,中文是不能正常显示的。很多人就疑问itext可针对html进行字体注册和样式设置,这个没有吗?其实是有的;
再看源码,第二个参数就是存储样式的,第三个参数是自定义字体注册的实现类
worker.setInterfaceProps(interfaceProps);我们进一步看源码
可以看到FontProvider是根据需要进行自定义实现类,它默认有一个实现类
这里面有很多方法,可以通过各种方式来将本地或者指定路径的字体加载进来,如
我尝试把本地的其他中文字体加载进来后,并且在html标签上设置属性font-family后,还是pdf无法显示中文,这也是我为啥在工具类中直接获取解析后的信息直接替换的原因。
好,继续操作,创建UserService ,方法为printUserInfo,用户信息可以自行实现加载,这里是模拟。
import com.demo.openpdfdemo.model.UserModel;
import com.demo.openpdfdemo.pdfCreator.PdfPageEventListener;
import com.demo.openpdfdemo.pdfCreator.UserInfoPdfCreator;
import com.demo.openpdfdemo.pdfCreator.core.AbstractPdfCreator;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
/**
* 用户信息打印
*
* @param response
* @throws IOException
*/
public void printUserInfo(HttpServletResponse response) throws IOException {
UserModel model = new UserModel();
model.setName("张三");
model.setAge(12);
model.setEducation("本科");
model.setNational("汉族");
model.setSex("男");
model.setNativePlace("北京市");
model.setRemark("此人学习习惯很好
非常优秀
爱好- 篮球
- 乒乓球
毕业学校 专业 清华 计算机
");
Map<String, Object> map = new HashMap<>();
map.put("data", model);
String signature = "签字:________________" + "日期:" + LocalDate.now();
PdfPageEventListener listener = PdfPageEventListener.build().setNoticeCode("0001").setSignature(signature).build();
AbstractPdfCreator pdfCreator = new UserInfoPdfCreator();
ByteArrayOutputStream outputStream = pdfCreator.init(listener).creator(map);
response.reset();
response.setHeader("Content-Type", "application/pdf");
response.setHeader("content-disposition", "attachment;filename=111.pdf");
response.setContentLength(outputStream.size());
OutputStream output = response.getOutputStream();
outputStream.writeTo(output);
output.flush();
output.close();
}
}
创建controller :UserController
import com.demo.openpdfdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(path = "/userPrint", method = RequestMethod.POST)
@ResponseBody
public void userPrint(HttpServletResponse response) {
try {
userService.printUserInfo(response);
} catch (IOException e) {
e.printStackTrace();
}
}
@RequestMapping("/hello")
public String index(){
return "index";
}
}
创建一个页面,模拟一下下载操作,创建index.html,默认是加载templetes文件夹的页面,文件夹没有自行创建即可。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>OpenPdf测试title>
head>
<body>
<h1>OpenPdf测试h1>
<form action="/user/userPrint" method="post">
<input type="submit" value="下载"/>
form>
body>
html>
application.yml配置,我这里简单
server:
port: 8080
启动服务,访问
点击下载,看一下内容。备注里的信息全是中文都可正常显示。
链接: https://gitee.com/yang1112/openPdfDemo.git