使用itextpdf的工具包来生成PDF数据流,pdfbox将pdf转成图片。
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.20</version> </dependency>
应需求开发pdf生成的代码,对pdf流有两种处理方式,1、直接返回文件;2、将PDF转成图片。
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
public class PDFUtil {
private static Logger logger = LoggerFactory.getLogger(PDFUtil.class);
// 定义全局的字体静态变量
private static com.itextpdf.text.Font titleFont;
private static com.itextpdf.text.Font titleFont1;
private static com.itextpdf.text.Font titleFont2;
private static com.itextpdf.text.Font textFont;
private static com.itextpdf.text.Font textFont2;
private static com.itextpdf.text.Font textFont3;
// 最大宽度
private static final int maxWidth = 450;
// 静态代码块(设置PDF里面会用到的字体的样式)
static {
try {
// 不同字体(这里定义为同一种字体:包含不同字号、不同style)
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
titleFont = new com.itextpdf.text.Font(bfChinese, 15, com.itextpdf.text.Font.BOLD);
titleFont1 = new com.itextpdf.text.Font(bfChinese, 12, com.itextpdf.text.Font.BOLD);
titleFont2 = new com.itextpdf.text.Font(bfChinese, 12, com.itextpdf.text.Font.NORMAL);
textFont = new com.itextpdf.text.Font(bfChinese, 12, com.itextpdf.text.Font.NORMAL);
textFont2 = new com.itextpdf.text.Font(bfChinese, 9, com.itextpdf.text.Font.NORMAL);
textFont3 = new com.itextpdf.text.Font(bfChinese, 10, com.itextpdf.text.Font.NORMAL, com.itextpdf.text.BaseColor.DARK_GRAY);
} catch (Exception e) {
e.printStackTrace();
logger.error("字体设置失败:{}", e);
}
}
// 生成PDF文件
public static ByteArrayOutputStream generatePDF(GeneratePDFRequest request) {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
// 1.新建document对象
Document document = new Document(PageSize.A4, 90, 90, 60, 70);// 建立一个Document对象
// 2.建立一个书写器(Writer)与document对象关联
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
// 段落
String titleText = "第一行标题";
Paragraph title = new Paragraph(titleText, titleFont);
title.setAlignment(1); //设置文字居中 0靠左 1,居中 2,靠右
title.setSpacingAfter(10f); //设置段落上空白
document.add(title);
String titleText2 = "第二行小标题";
Paragraph title2 = new Paragraph(titleText2, titleFont);
title2.setAlignment(1); //设置文字居中 0靠左 1,居中 2,靠右
title2.setSpacingAfter(10f); //设置段落上空白
document.add(title2);
// 表格20,40等数字表示表格单元宽度,一共5列,pdf的添加方式就是addCell,拼接单元格到pdf上面
PdfPTable table = createTable(new float[]{20, 40, 50, 40, 50});
table.addCell(createCellRows("第一行合并第二行", titleFont1, Element.ALIGN_CENTER, 2));
table.addCell(createCell("第一行第2列", textFont, Element.ALIGN_CENTER));
table.addCell(createCellCols(request.getField1(), textFont3, Element.ALIGN_CENTER, 3));//合并第一行的3-5列
table.addCell(createCell("第二行第2列", textFont, Element.ALIGN_CENTER));
table.addCell(createCell(request.getField2(), textFont3, Element.ALIGN_CENTER));
table.addCell(createCell("第二行第4列", textFont, Element.ALIGN_CENTER));
table.addCell(createCell(request.getField3(), textFont3, Element.ALIGN_CENTER));
//给复选框打勾(类似签名的方式)
String isSign = request.getIsSign();
if ("1".equals(isSign)) {
//如果需要签名,那么报账一致需要勾选
RadioCheckField bt = new RadioCheckField(writer, new Rectangle(90, 605, 100, 615),
"check1", "No");//90(100)表示图片左(右)下角离PDF文件左下角的横向距离,605(615)表示图片左(右)上角离PDF文件左下角的纵向距离
bt.setCheckType(RadioCheckField.TYPE_CHECK);
bt.setBorderWidth(BaseField.BORDER_WIDTH_THIN);
bt.setBorderColor(BaseColor.BLACK);
bt.setBackgroundColor(BaseColor.WHITE);
bt.setChecked(true);
PdfFormField ck = bt.getCheckField();
writer.addAnnotation(ck);
PdfPCell cell = createCell("", textFont, Element.ALIGN_CENTER);
table.addCell(cell);
table.addCell(createCell("数据一致", titleFont1, Element.ALIGN_CENTER));
table.addCell(createCellCols("复选框已打勾",
textFont, Element.ALIGN_LEFT, 3));
} else {
table.addCell(createCell("□", textFont, Element.ALIGN_CENTER));
table.addCell(createCell("数据不一致", titleFont1, Element.ALIGN_CENTER));
table.addCell(createCellCols("复选框未打勾",
textFont, Element.ALIGN_LEFT, 3));
}
document.add(table);
Paragraph title4 = new Paragraph("备注信息:1。", textFont2);
title4.setAlignment(0);
document.add(title4);
Chunk textAsChunk = new Chunk("备注信息2", textFont2);
textAsChunk.setBackground(BaseColor.YELLOW);//加背景色
Paragraph title5 = new Paragraph(textAsChunk);
title5.setAlignment(0);
document.add(title5);
// 5.关闭文档
document.close();
return out;
} catch (Exception e) {
e.printStackTrace();
logger.error("生成异常报告失败:{}", e);
throw ExceptionFactory.service("Fl00005");
}
}
/**
* 创建指定列宽、列数的表格
*/
private static PdfPTable createTable(float[] widths) {
PdfPTable table = new PdfPTable(widths);
try {
table.setTotalWidth(maxWidth);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setBorder(1);
} catch (Exception e) {
e.printStackTrace();
}
return table;
}
/**
* 创建单元格(指定字体、水平..)
*/
private static PdfPCell createCell(String value, com.itextpdf.text.Font font, int align) {
PdfPCell cell = new PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(align);
cell.setPhrase(new Phrase(value, font));
return cell;
}
/**
* 创建单元格列合并(指定字体、水平居..、单元格跨x列合并)
*/
private static PdfPCell createCellCols(String value, com.itextpdf.text.Font font, int align, int colspan) {
PdfPCell cell = new PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(align);
cell.setColspan(colspan);
cell.setPhrase(new Phrase(value, font));
return cell;
}
/**
* 创建单元格行合并(指定字体、水平居..、单元格跨x列合并)
*/
private static PdfPCell createCellRows(String value, com.itextpdf.text.Font font, int align, int rowspan) {
PdfPCell cell = new PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(align);
cell.setRowspan(rowspan);
cell.setPhrase(new Phrase(value, font));
return cell;
}
/**
* dpi越大转换后越清晰,相对转换速度越慢
*/
private static final Integer DPI = 100;
/**
* 转换后的图片类型
*/
private static final String IMG_TYPE = "png";
/**
* PDF转图片
*
* @param fileContent PDF文件的二进制流
* @return 图片文件的二进制流
*/
public static byte[] pdfToImage(byte[] fileContent) throws IOException {
List<byte[]> result = new ArrayList<>();
try (PDDocument document = PDDocument.load(fileContent)) {
PDFRenderer renderer = new PDFRenderer(document);
for (int i = 0; i < document.getNumberOfPages(); ++i) {
BufferedImage bufferedImage = renderer.renderImageWithDPI(i, DPI);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, IMG_TYPE, out);
result.add(out.toByteArray());
}
}
return result.get(0);
}
}
调用返回的方法
ByteArrayOutputStream bos = PDFUtil.generatePDF(request);
try {
OutputStream os = httpServletResponse.getOutputStream();
if ("1".equals(request.getIsSign())) {
//如果是选择的,直接返回图片
byte[] bs = PDFUtil.pdfToImage2(bos.toByteArray());
os.write(bs);
os.close();
} else {
//如果未选中,那么返回pdf文件
os.write(bos.toByteArray());
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
以上是生成PDF工具方法以及调用方法,记录下来方便自己和他人查看使用。