Java使用io流生成pdf文件

首先生成pdf和正常请求接口一样,直接写~

· Controller层:

第一个注解:最顶层增加 @Controller 注解(控制器)不多讲了 直接加上。

第二个注解:最顶层增加 @CrossOrigin 注解此注解是为了浏览器请求的时候防止跨域,然后导致乱码,没有正常生成文件。

· 接口层面

复制代码
@GetMapping("createMyPdf")
@ApiOperation(value = "生成我的pdf", produces = "application/octet-stream")
public void createMyPdf(@RequestParam
 @ApiParam(value = "自己的入参,自己拼") String name, HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {

createMyPdfService.createMyPdf(name,response);

}

-------这一层结束了,往下走~~~

· Service层:

复制代码
void createMyPdf(String name, HttpServletResponse response);

-------这一层结束了,往下走~~~

` Impl实现层:

重头戏来了,值得期待
复制代码
@Override
public void createMyPdf(String name, HttpServletResponse response) {

// 根据入参,查询自己所需的数据

// 下面开始组装pdf架子

复制代码
//创建文档,纸张大小为A4
Document doc = new Document(PageSize.A4);
Rectangle pageSize = new Rectangle(PageSize.A4.getHeight(), PageSize.A4.getWidth());
pageSize.rotate();
doc.setPageSize(pageSize);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {            
String fileName = response.encodeURL(new String((自己生成的pdf表.pdf").getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
doc.addTitle(fileName);
doc.addAuthor("even");
doc.addCreationDate();
doc.addLanguage("中文");
PdfWriter pdfWriter = PdfWriter.getInstance(doc, outputStream);
pdfWriter.setViewerPreferences(PdfWriter.HideToolbar);
pdfWriter.setPageEvent(new PdfReportM1HeaderFooterCopy());
//pdfWriter.setPageEvent(new PageWatermarkEventHandler());
//中文处理
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
// 则需创建字体
Font titleFont = new Font(bfChinese, 16, Font.BOLD);
Font headFont = new Font(bfChinese, 14, Font.BOLD);
Font textFont6 = new Font(bfChinese, 6, Font.NORMAL);
Font textFont10 = new Font(bfChinese, 10, Font.NORMAL);
Paragraph blankRow = new Paragraph(18f, " ", headFont);
复制代码
//水印
pdfWriter.setPageEvent(new PageWatermarkEventHandler());
pdfWriter.setPageEvent(new PdfReportM1HeaderFooter());
复制代码
// 打开文档对象
doc.open();
doc.add(blankRow);
// 创建一个标题
doc.add(FundGeneralSituationPdfUtil.addTitle("我自己创建的标题", FundGeneralSituationPdfUtil.getFontByType(5), Element.ALIGN_CENTER));
// 开始渲染pdf中的数据
goCreatePdf(name);

// 关闭文档对象,释放资源
doc.close();
// 设置输出类型,这里我们需要以文件流的形式提供下载
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
//设置响应文档类型为pdf
response.setContentType("application/pdf");
//设置响应数据大小
response.setContentLength(outputStream.size());
//获得响应数据流
ServletOutputStream out = response.getOutputStream();
//防止发生getOutputStream() has already been called for this response异常, 但下载下来的文件不是定义的fileName的值,且没有扩展名
// response.reset();
//将pdf数据流写入相应数据流中
outputStream.writeTo(out);
out.flush();
out.close();
} catch (Exception e) {
    System.out.println("occurred one unknow Exception");
    e.printStackTrace();
    System.out.println("occurred one unknow Exception");
}
}

// 设置水印,下方有注释

public class PageWatermarkEventHandler extends PdfPageEventHelper {

@Override

public void onStartPage(PdfWriter pdfWriter, Document document) {

try {

BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

PdfContentByte waterMar = pdfWriter.getDirectContentUnder();

// 开始设置水印

waterMar.beginText();

// 设置水印透明度

PdfGState gs = new PdfGState();

// 设置填充字体不透明度为0.4f

gs.setFillOpacity(0.1f);

// 设置水印字体参数及大小 (字体参数,字体编码格式,是否将字体信息嵌入到pdf中(一般不需要嵌入),字体大小)

waterMar.setFontAndSize(bfChinese, 50);

// 设置透明度

waterMar.setGState(gs);

// 设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度

waterMar.showTextAligned(Element.ALIGN_RIGHT, "我的测试生成", 600, 800, 20);

waterMar.showTextAligned(Element.ALIGN_RIGHT, "我的测试生成", 600, 500, 20);

waterMar.showTextAligned(Element.ALIGN_RIGHT, "我的测试生成", 600, 200, 20);

// 设置水印颜色

waterMar.setColorFill(BaseColor.GRAY);

//结束设置

waterMar.endText();

waterMar.stroke();

} catch (Exception e) {

log.error("加水印异常:{}", e.getMessage());

throw new ExceptionConverter(e);

}

super.onStartPage(pdfWriter, document);

}

}

// 设置页眉页脚

public class PdfReportM1HeaderFooter extends PdfPageEventHelper {

/**

* 页眉

*/

public String header = "";

/**

* 文档字体大小,页脚页眉最好和文本大小一致

*/

public int presentFontSize = 12;

/**

* 文档页面大小,最好前面传入,否则默认为A4纸张

*/

public Rectangle pageSize = PageSize.A4;

// 模板

public PdfTemplate total;

// 基础字体对象

public BaseFont bf = null;

// 利用基础字体生成的字体对象,一般用于生成中文文字

public Font fontDetail = null;

/**

*

* Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.

*

*/

public PdfReportM1HeaderFooter() {

}

/**

*

* Creates a new instance of PdfReportM1HeaderFooter 构造方法.

*

* @param yeMei

* 页眉字符串

* @param presentFontSize

* 数据体字体大小

* @param pageSize

* 页面文档大小,A4,A5,A6横转翻转等Rectangle对象

*/

public PdfReportM1HeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) {

this.header = yeMei;

this.presentFontSize = presentFontSize;

this.pageSize = pageSize;

}

public void setHeader(String header) {

this.header = header;

}

public void setPresentFontSize(int presentFontSize) {

this.presentFontSize = presentFontSize;

}

/**

*

* TODO 文档打开时创建模板

*

* @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)

*/

@Override

public void onOpenDocument(PdfWriter writer, Document document) {

total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高

}

/**

*

* TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。

*

* @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)

*/

@Override

public void onEndPage(PdfWriter writer, Document document) {

try {

if (bf == null) {

bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);

}

if (fontDetail == null) {

fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体

}

} catch (DocumentException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

// 1.写入页眉

ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0);

// 2.写入前半部分的 第 X页/共

int pageS = writer.getPageNumber();

String foot1 = (pageS - 2)+"";

Phrase footer = new Phrase(foot1, fontDetail);

// 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len

float len = bf.getWidthPoint(foot1, presentFontSize);

// 4.拿到当前的PdfContentByte

PdfContentByte cb = writer.getDirectContent();

//自己增加的

if(pageS==1 || pageS == 2){

// 第一页、第二页不显示页脚

// Phrase footerLeft = new Phrase("", fontDetail);

// ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, footerLeft, document.left(), document.bottom() - 20, 0);

} else {

// 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了 ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。

ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);

}

// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F + len , y 轴和之前的保持一致,底边界-20

cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20); // 调节模版显示的位置

}

/**

*

* TODO 关闭文档时,替换模板,完成整个页眉页脚组件

*

* @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)

*/

@Override

public void onCloseDocument(PdfWriter writer, Document document) {

// 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。

total.beginText();

total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色

int pageS = writer.getPageNumber();

total.endText();

total.closePath();

}

}

复制代码
private void goCreatePdf(String name,Document doc, Paragraph blankRow) throws DocumentException, IOException {

// 可以根据条件继续查询出数据,然后传入到下一层进行铺数据

复制代码
setFundGeneralSituation(name);

}

复制代码
public static PdfPTable setFundGeneralSituation(String name) throws DocumentException{
复制代码
// 一共有多少列,从左到右
PdfPTable table = new PdfPTable(13);
table.setWidthPercentage(100);
table.setTotalWidth(500);
// 每一列多宽
int[] width3 = {70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,70};
table.setWidths(width3);

// 这个是定义的标题
Paragraph p = new Paragraph(自定义标题", textFont);
p.setAlignment(Element.ALIGN_CENTER);
PdfPCell firstCell = new PdfPCell(p);
// 合并列,Rowspan  是合并行
firstCell.setColspan(13);
firstCell.setHorizontalAlignment(Element.ALIGN_CENTER);
firstCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
firstCell.setFixedHeight(40);
table.addCell(firstCell);
复制代码
Paragraph p = new Paragraph("这个是表头", textFont);
p.setAlignment(Element.ALIGN_RIGHT);
PdfPCell cellcode = new PdfPCell(p);
cellcode.setHorizontalAlignment(Element.ALIGN_CENTER);
cellcode.setVerticalAlignment(Element.ALIGN_MIDDLE);
cellcode.setFixedHeight(23);
table.addCell(cellcode);

// 这个是数据
Paragraph p0 = new Paragraph(String.valueOf("这个是值"), textFont);
PdfPCell cellcode0 = new PdfPCell(p0);
cellcode0.setHorizontalAlignment(Element.ALIGN_CENTER);
cellcode0.setVerticalAlignment(Element.ALIGN_MIDDLE);
cellcode0.setFixedHeight(23);
table.addCell(cellcode0);
}
相关推荐
belldeep6 小时前
python:reportlab 将多个图片合并成一个PDF文件
python·pdf·reportlab
墨染辉11 小时前
pdf处理2
pdf
墨染辉1 天前
10.2 如何解决从复杂 PDF 文件中提取数据的问题?
pdf
shandianchengzi1 天前
【记录】Excel|Excel 打印成 PDF 页数太多怎么办
pdf·excel
bianshaopeng1 天前
android 原生加载pdf
android·pdf
卢卡斯2331 天前
在线PDF怎么转换成JPG图片?分享14种转换操作!
pdf
J不A秃V头A2 天前
iTextPDF中,要实现表格中的内容在数据长度超过边框时自动换行
java·pdf
嘻嘻仙人2 天前
【杂谈一之概率论】CDF、PDF、PMF和PPF概念解释与分析
pdf·概率论·pmf·cdf
资深前端之路3 天前
vue2 将页面生成pdf下载
前端·vue.js·pdf
Eiceblue3 天前
Python 复制PDF中的页面
vscode·python·pdf