About itext
在网上看到java关于pdf的第三方库有名的是com.itextpdf的。
上git上查看,官网的意思是推荐itext7,而itext5只用于修复bug和安全了:
所以,下面是以itext7进行的开发 :
The Leading PDF Library for Developers | iTexthttps://itextpdf.com/en
API Doc
Demo
好的,接下里开始上demo:
布局设定
分为title、table、detail三大类,如下用绿色框出来了:
按照这个设定封装对应的数据载体
然后编写工具类
接下测试即可。
工具类
imageUtil
用于读取base64的图片到byte数组
import org.bouncycastle.util.encoders.Base64;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class ImageUtil {
/**
* 校验base64是否合法
* @param base64
* @return
*/
public static boolean safeCheckImgFile(String base64) {
//check image
String regex = ",";
String[] split = base64.split(regex);
String imageBase64 = split[1];
byte[] decode = Base64.decode(imageBase64);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
try {
BufferedImage image = ImageIO.read(byteArrayInputStream);
if (image != null && image.getWidth() > 0 && image.getHeight() > 0) {
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
/*
Base64Encoder base64Encoder = new Base64Encoder();
try {
FileOutputStream fileImageOutputStream = new FileOutputStream("/data/temp/");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileImageOutputStream);
base64Encoder.decode(img, bufferedOutputStream);
} catch (IOException e) {
e.printStackTrace();
}
*/
}
/**
* 读取base64字符串,转换为bimage的ytes数组并返回
* @param base64
* @return
*/
public static byte[] readFromImage(String base64) {
String regex = ",";
String[] split = base64.split(regex);
String imageBase64 = split[1];
byte[] decode = Base64.decode(imageBase64);
/* ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
try {
BufferedImage image = ImageIO.read(byteArrayInputStream);
// System.out.println(image);
} catch (IOException e) {
e.printStackTrace();
}*/
return decode;
}
}
PdfUtil_v2
Pdf生成工具
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
public class PdfUtil_v2 {
private Logger logger = LoggerFactory.getLogger(PdfUtil_v2.class);
private MyPdfDocument pdfDocumnt;
private String file_PATH;//文件绝对路径,包含文件名和后缀,如:I:\\jfqqqq\\test\\1.pdf
private String font_PATH;
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
private String font_INTERNAL_PATH;
public PdfUtil_v2(MyPdfDocument pdfDocumnt, String file_PATH, String font_PATH) {
this.pdfDocumnt = pdfDocumnt;
this.file_PATH = file_PATH;
this.font_PATH = font_PATH;
File directory = new File("src/main/resources");
try {
String resourcesPath = directory.getCanonicalPath();
font_INTERNAL_PATH = resourcesPath + "/fonts/SimSun-01.ttf";
logger.debug("配置的字体地址:{}, 工程预备的字体地址:{}", font_PATH, font_INTERNAL_PATH);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成pdf,注意:会覆盖
*
* @return
*/
public File generate() {
Document document = null;
try {
createFilePath(file_PATH, false);
PdfWriter pdfWriter = new PdfWriter(file_PATH);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
PdfFont font = getPdfFont();//PdfFontFactory.createFont(font_PATH);
document = new Document(pdfDocument).setFont(font);
writeHeader(document);
writeStaticsGrid(document);
staticsDetails(document);
// document.close();
return new File(file_PATH);
// }
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document != null) {
document.close();
}
}
return null;
}
private PdfFont getPdfFont() {
PdfFont font = null;
try {
font = PdfFontFactory.createFont(font_PATH);
} catch (IOException e) {
logger.error("{} 字体文件不存在!即将采用更称默认字体,默认路径:{}", font_PATH, font_INTERNAL_PATH);
synchronized (this) {
font_PATH = font_INTERNAL_PATH;
}
}
if (font == null) {
try {
font = PdfFontFactory.createFont(font_PATH);
} catch (IOException e) {
logger.error("{} 默认的字体文件不存在!即将采用itext7默认内置字体!不支持中文!", font_INTERNAL_PATH);
}
}
if (font == null) {
try {
font = PdfFontFactory.createFont();
} catch (IOException e) {
logger.error("", e);
e.printStackTrace();
}
}
return font;
}
public void writeHeader(Document document) {
Paragraph paragraphTitle = new Paragraph(pdfDocumnt.getTitle());
paragraphTitle.setFontSize(22);
Paragraph paragraphBatchName = new Paragraph("(" + pdfDocumnt.getSmallTitle() + ")");
paragraphBatchName.setFontSize(12);
Paragraph header = new Paragraph();
header.setTextAlignment(TextAlignment.CENTER);
header.add(paragraphTitle);
header.add(paragraphBatchName);
document.add(header);
Table table = new Table(2);
table.useAllAvailableWidth();
Cell cell = new Cell(1, 1);
cell.setBorder(Border.NO_BORDER);
cell.setTextAlignment(TextAlignment.LEFT);
cell.add(new Paragraph(pdfDocumnt.getTopLeft()));
table.addCell(cell);
cell = new Cell(1, 1);
cell.setBorder(Border.NO_BORDER);
cell.setTextAlignment(TextAlignment.RIGHT);
cell.add(new Paragraph(pdfDocumnt.getTopRight()));
table.addCell(cell);
Border border = new SolidBorder(ColorConstants.RED, 2.0f);
table.setBorderBottom(border);
document.add(table);
document.add(new Paragraph());
//
}
public void writeStaticsGrid(Document document) {
//开头描述
Paragraph paragraphParent = new Paragraph();
PdfTable pdfTable = pdfDocumnt.getTable();
List<PdfTable.MyParagrah> beforeBegin = pdfTable.getBeforeBegin();
for (PdfTable.MyParagrah begin : beforeBegin) {
paragraphParent.add(new Paragraph(begin.getContent()).setFontColor(begin.getColor()));
}
document.add(paragraphParent);
//统计表格
LinkedList<PdfTable.Header> headers = pdfTable.getHeaders();
Table table = new Table(headers.size());
table.setWidth(500);
for (PdfTable.Header header : headers) {
table.addHeaderCell(header.getTitle());
}
List<PdfTable.MyLine> lines = pdfTable.getLines();
for (PdfTable.MyLine line : lines) {
for (PdfTable.Header header : headers) {
table.addCell(new Paragraph(line.getCell(header.getCode()).getValue()));
}
}
document.add(table);
//空一行
document.add(new Paragraph());
//注意点描述
List<String> pations = pdfTable.getPations();
document.add(new Paragraph("注:").setFontColor(ColorConstants.RED));
for (String pation : pations) {
document.add(new Paragraph(pation).setFontColor(ColorConstants.RED));
}
}
public void staticsDetails(Document document) {
document.add(new Paragraph("报告详情").setFontSize(18));
int questionNum = 0;
List<PdfDetail> details = pdfDocumnt.getDetails();
for (PdfDetail detail : details) {
questionNum += 1;
// addDetails(document, "问题1", " " + checkValue, 12);
addDetailsNextLine(document, "问题" + questionNum, "", 15, false);
Table table = new Table(1);
table.useAllAvailableWidth();
List<PdfDetail.MyEntry> items = detail.getItems();
for (PdfDetail.MyEntry item : items) {
if (item.getEntryType() == PdfDetail.EntryType.STRING) {
addDetailsInLine(table, item.getKey(), item.getVal(), null);
} else if (item.getEntryType() == PdfDetail.EntryType.IMAGE) {
addDetailsInLine(table, item.getKey(), "", null);
Image image = readByBase64(item.getVal());
image.setTextAlignment(TextAlignment.CENTER);
image.setAutoScale(true);
table.addCell(image);
}
}
document.add(table);
//这段代码注释了,这里演示的是直接给document增加图片
// Image image = readByBase64(item.getVal());
// image.setTextAlignment(TextAlignment.CENTER);
// image.setAutoScale(true);
// document.add(image);
// document.add(new Paragraph(""));//增加一个空行
}
}
private Image readByBase64(String base64) {
byte[] bytes = ImageUtil.readFromImage(base64);
Image image = new Image(ImageDataFactory.create(bytes));
return image;
}
private void addDetailsInLine(Table table, String key, String value, Integer fontSize) {
Paragraph paragraph = new Paragraph(key + ": " + value);
paragraph.setMarginLeft(20);
if (fontSize != null) {
paragraph.setFontSize(fontSize);
}
Cell cell = new Cell();
cell.add(paragraph);
cell.setBorder(Border.NO_BORDER);
table.addCell(cell);
}
private void addDetailsNextLine(Document document, String key, String value, Integer fontSize, boolean useMaoHao) {
String content = key + (useMaoHao ? ":" : "") + value;
Paragraph paragraph = new Paragraph(content);
paragraph.setMarginLeft(3);
if (fontSize != null) {
paragraph.setFontSize(fontSize);
}
document.add(paragraph);
}
public static File createFilePath(String path, boolean createFile) {
File file = new File(path);
if (!file.exists()) {
if (file.isDirectory()) {
file.mkdirs();
} else {
File parentFile = file.getParentFile();
parentFile.mkdirs();
try {
if (createFile) {
file.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
// return parentFile;
}
}
return file;
}
}
用于携带pdf数据的实体类
MyPdfDocument
pdf数据载体
import java.util.List;
public class MyPdfDocument {
private String title;
private String smallTitle;
private String topLeft;
private String topRight;
private PdfTable table;
private List<PdfDetail> details;
public MyPdfDocument() {
}
public String getTitle() {
return title;
}
public String getSmallTitle() {
return smallTitle;
}
public void setSmallTitle(String smallTitle) {
this.smallTitle = smallTitle;
}
public void setTitle(String title) {
this.title = title;
}
public String getTopLeft() {
return topLeft;
}
public void setTopLeft(String topLeft) {
this.topLeft = topLeft;
}
public String getTopRight() {
return topRight;
}
public void setTopRight(String topRight) {
this.topRight = topRight;
}
public PdfTable getTable() {
return table;
}
public void setTable(PdfTable table) {
this.table = table;
}
public List<PdfDetail> getDetails() {
return details;
}
public void setDetails(List<PdfDetail> details) {
this.details = details;
}
}
PdfDetail
MyPdfDocument中的detail数据载体
import java.util.LinkedList;
import java.util.List;
public class PdfDetail {
private List<MyEntry> items = new LinkedList<>();
public PdfDetail addItem(String key, String value) {
items.add(new MyEntry(key, value));
return this;
}
public PdfDetail addItem(String key, String value, EntryType type) {
items.add(new MyEntry(key, value, type));
return this;
}
public List<MyEntry> getItems() {
return items;
}
public static enum EntryType{
IMAGE, STRING
}
public static class MyEntry{
private EntryType entryType = EntryType.STRING;
private String key;
private String val;
public MyEntry(String key, String val) {
this.key = key;
this.val = val;
}
public MyEntry(String key, String val, EntryType type) {
this.key = key;
this.val = val;
this.entryType = type == null ? entryType : type;
}
public EntryType getEntryType() {
return entryType;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
}
}
PdfTable
MyPdfDocument中的table数据载体
import com.itextpdf.kernel.colors.Color;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class PdfTable {
private List<MyParagrah> beforeBegin;
private LinkedList<Header> headers;
private List<MyLine> lines;
private List<String> pations;
public static class MyParagrah {
private String content;
private Color color;//ColorConstants.BLACK
public MyParagrah(String content, Color color) {
this.content = content;
this.color = color;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
public static class MyCell {
private int headerCode;
private String value;
public MyCell(int headerCode, String value) {
this.headerCode = headerCode;
this.value = value;
}
public int getHeaderCode() {
return headerCode;
}
public void setHeaderCode(int headerCode) {
this.headerCode = headerCode;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class MyLine {
private Map<Integer, MyCell> cells = new HashMap<>();
public MyLine addCell(MyCell cell) {
cells.put(cell.getHeaderCode(), cell);
return this;
}
public Map<Integer, MyCell> getCells() {
return cells;
}
public MyCell getCell(int headerCode) {
return cells.get(headerCode);
}
}
public static class Header {
private int code;
private String title;
public Header(int code, String title) {
this.code = code;
this.title = title;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public List<MyParagrah> getBeforeBegin() {
return beforeBegin;
}
public void setBeforeBegin(List<MyParagrah> beforeBegin) {
this.beforeBegin = beforeBegin;
}
public LinkedList<Header> getHeaders() {
return headers;
}
public void setHeaders(LinkedList<Header> headers) {
this.headers = headers;
}
public List<MyLine> getLines() {
return lines;
}
public void setLines(List<MyLine> lines) {
this.lines = lines;
}
public List<String> getPations() {
return pations;
}
public void setPations(List<String> pations) {
this.pations = pations;
}
}
测试类
@Test
public void testHelper() {
MyPdfDocument myPdfDocument = new MyPdfDocument();
myPdfDocument.setTitle("jfqqqqq的监测报告");
myPdfDocument.setSmallTitle("他很帅");
myPdfDocument.setTopLeft("jfqqqq的个人管理平台");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
myPdfDocument.setTopRight(simpleDateFormat.format(new Date()));
PdfTable pdfTable = new PdfTable();
List<PdfTable.MyParagrah> beforeBegins = new LinkedList<>() {{
add(new PdfTable.MyParagrah("说点什么好呢,总的来说,这次的监测效果还算不错,我很努力,", ColorConstants.BLACK));
add(new PdfTable.MyParagrah("值得嘉奖一下kkkkkkkkkkk值得嘉奖一下kkkkkkkkkkk值得嘉奖一下kkkkkkkkkkk值得嘉奖一下kkkkkkkkkkk值得嘉奖一下kkkkkkkkkkk", ColorConstants.RED));
add(new PdfTable.MyParagrah("。嘉奖一下我自己!", ColorConstants.BLACK));
}};
pdfTable.setBeforeBegin(beforeBegins);
LinkedList<PdfTable.Header> headers = new LinkedList<>() {{
add(new PdfTable.Header(1, "序号"));
add(new PdfTable.Header(2, "项目"));
add(new PdfTable.Header(3, "努力"));
add(new PdfTable.Header(4, "视力"));
}};
pdfTable.setHeaders(headers);
List<PdfTable.MyLine> lines = new LinkedList<>();
for (int i = 0; i < 5; i++) {
PdfTable.MyLine line = new PdfTable.MyLine();
line.addCell(new PdfTable.MyCell(1, "1")).addCell(new PdfTable.MyCell(2, "身高" + i)).addCell(new PdfTable.MyCell(3, "很努力,还行吧" + i)).addCell(new PdfTable.MyCell(4, "哈哈" + i));
lines.add(line);
}
pdfTable.setLines(lines);
pdfTable.setPations(new LinkedList<String>() {{
add("1、这里是注释1");
add("2、这里是注释2");
}});
myPdfDocument.setTable(pdfTable);
List<PdfDetail> details = new ArrayList<>();
for (int i = 0; i < 5; i++) {
PdfDetail pdfDetail = new PdfDetail();
String base64Image = "data:image/gif;base64,R0lGODlhDwAPAKECAAAAzMzM/wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==";
pdfDetail.addItem("身高", "身高" + i).addItem("努力", "很努力,还行吧" + i).addItem("视力", "哈哈" + i).addItem("截图", base64Image, PdfDetail.EntryType.IMAGE);
details.add(pdfDetail);
}
myPdfDocument.setDetails(details);
PdfUtil_v2 pdf = new PdfUtil_v2(myPdfDocument, "I:\\tobedelete\\asd.pdf", "F:\\anytest\\pdf\\src\\main\\resources\\fonts\\SimSun-01.ttf");
pdf.generate();
System.out.println("success!");
}
字体文件
想要打印中文需要有中文字体支持的字体文件。可以到C:\Windows\Fonts中找一个中文字体文件给程序使用,或者自己从网上下载。
效果
附加
返回pdf文件时,响应头一般用这两种:
1. content-type:application/pdf
使用比如:
response.setContentType("application/pdf");
2. Content-Disposition:attachment; filename=aa.pdf
使用比如: response.setHeader("Content-Disposition", "attachment; filename=" + new String((batchName + ".pdf").getBytes(), "utf-8"));