SpringBoot-iText-Pdf
SpringBoot-iText-Pdf
需要的全部Maven
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.6.RELEASE</version></parent><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- itextpdf --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.11</version></dependency><!-- itext水印--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.47</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcmail-jdk15on</artifactId><version>1.47</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>core-renderer</artifactId><version>R8</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-io</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.28</version></dependency><!-- 渲染 css 样式 --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.16</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version></dependency></dependencies>
生成一个PDF
需要5个步骤
创建文档
Document document = new Document();
生成PDF
PdfWriter.getInstance(doc, new FileOutputStream(DEST+ File.separator+"HelloWorld.pdf") );
打开PDF
document.open();
往PDF中写入内容
document.add(new Paragraph("Hello World"));
关闭PDF
document.close();
完整版
Document doc = new Document();PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR +"createSamplePDF.pdf"));doc.open();doc.add(new Paragraph("Hello World"));doc.close();
必须知道的内容
在操作演示PDF前我们需要知道如何获取 classes目录的路径 (项目打包后的根路径)
只有这样我们生成的PDF会在项目内部(当然如果你不需要PDF在项目的classes目录而且在其他地方,自行补充路径)
private static String FILE_DIR = null;static {try {FILE_DIR = Paths.get(ResourceUtils.getURL("classpath:").getPath().substring(1)).toString()+ File.separator;} catch (FileNotFoundException e) {e.printStackTrace();}}
我们还需要知道一个问题就是itext默认不支持中文(默认隐藏中文字体只显示英文)
我们可以在添加中文时候的那个对象中(基本都有设置字体格式的方法) 添加下面方法,就能识别中文了
对象.setFont(PdfUtils.getChineseFont());
在块.短语,段落,的构造第二个参数是可以直接添加PdfUtils.getChineseFont()
中文字体工具类
package com.pdf.utils;import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;import java.io.IOException;public class PdfFont {// color= BaseColor.BLUE(蓝色) BaseColor.BLACK(黑色) new BaseColor(105, 105, 105)(文本色)// style= Font.ITALIC细,Font.NORMA正常L,Font.BOLD粗// size=字体大小public static Font getChineseFont( int size,int style,BaseColor color) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, size, style, color);} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}public static Font getChineseFont(int size, int style) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, size, style, new BaseColor(105, 105, 105));} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}public static Font getChineseFont( int size) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, size, Font.NORMAL, new BaseColor(105, 105, 105));} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}public static Font getChineseFont(int style,BaseColor color) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese,style, Font.NORMAL, color);} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}public static Font getChineseFont( long size, BaseColor color) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, size, Font.NORMAL, color);} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}public static Font getChineseFont( BaseColor color) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, 15, Font.NORMAL, color);} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}// 默认配置 黑色字体 大小15 不加粗public static Font getChineseFont( ) {BaseFont bfChinese;Font fontChinese = null;try {bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);fontChinese = new Font(bfChinese, 15, Font.NORMAL, new BaseColor(105, 105, 105));} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return fontChinese;}}
PDF基础配置
需要倒入的包
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.List;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.draw.DottedLineSeparator;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.itextpdf.text.pdf.draw.VerticalPositionMark;
import lombok.SneakyThrows;
import org.junit.Test;
import org.springframework.util.ResourceUtils;import java.awt.*;
import java.io.*;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
注意:看每个配置 ,哪行代码的后面 ,如果顺序错了那么久无效了
配置PDF
页面大小
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);
不止B4你进入PageSize类里有一大堆 常用B4
比如:
- B5 ,B6 B 7 这些都是比B4小
- B3, B2 都是比B4大
页面背景
不设置默认为白色
Rectangle rect = new Rectangle(PageSize.B4.rotate()); rect.setBackgroundColor(new BaseColor(199 , 237, 204) ); //设置颜色 Document doc = new Document(rect);
推荐几款护眼的颜色:
new BaseColor(199 , 237, 204) 豆沙绿(推荐)
new BaseColor(200, 200, 169) 淡青色
new BaseColor(254, 67, 101) 淡红色
new BaseColor(252, 167, 154) 淡粉色
new BaseColor(249, 205, 173) 淡黄色
PDF版本设置(默认1.4)
PdfWriter writer = PdfWriter.getInstance(xxxxxx);writer.setPdfVersion(PdfWriter.PDF_VERSION_1_2); //设置版本号 一般不设置默认就可以
PDF文档属性(Title,Author,Subject,Keywords )
Document doc = new Document(); PdfWriter writer = PdfWriter.getInstance(xxxxxx); //文档属性 注意: 如果设置了版本号那么需要在版本号后面写 doc.addTitle("标题"); doc.addAuthor("作者"); doc.addSubject("主题"); doc.addKeywords("关键字"); doc.addCreator("创建者");
文档属性可以有可无 看你心情
页边空白
Document doc = new Document(); PdfWriter writer = PdfWriter.getInstance(xxxxxx);//必须在这行后面 doc.setMargins(10, 20, 30, 40); //页边空白 左 右 上 下
配置后的效果
PDF密码
就相当于给文件加密需要使用密码验证后才能观看
Document doc = new Document(); PdfWriter writer = PdfWriter.getInstance(xxxxxx);//必须在这行后面// 设置密码 //第一个参数是用户密码(允许复制,签名 不允许打印,编辑) //第二个参数是管理员密码(允许打印,编辑,复制,签名 加密级别) writer.setEncryption("user".getBytes(), "admin".getBytes(), PdfWriter.ALLOW_COPY, // 允许复制,签名 不允许打印,编辑 PdfWriter.STANDARD_ENCRYPTION_128); //允许打印,编辑,复制,签名 加密级别
增删page(页)
添加PDF页 看代码你就懂了
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));doc.open(); //打开PDF 默认为第一页doc.add(new Paragraph("First page")); // 给第一个添加内容doc.add(new Paragraph("Hello World"));doc.newPage(); // 创建第2页writer.setPageEmpty(false); //可以允许第2页为空 如果不设置那么PDF默认给没有内容的页 取消掉doc.newPage(); // 创建第3页doc.add(new Paragraph("New page"));doc.close();
删除PDF页
只选择指定类其他的删除
PdfReader reader = new PdfReader(FILE_DIR + "createSamplePDF.pdf");// 从原PDF中抽取指定页 生成reader.selectPages("1,3,5"); //只选择1和3页和第5页//生成新的PDFPdfStamper stamp = new PdfStamper(reader, new FileOutputStream(FILE_DIR+ "createSamplePDF_de.pdf"));stamp.close();reader.close();
只选择指定范围页其他页删除
/*** 截取pdfFile的第from页至第end页,组成一个新的文件名* @param respdfFile 需要分割的PDF* @param savepath 新PDF* @param from 起始页* @param end 结束页*/public static void splitPDFFile(String respdfFile, String savepath, int from, int end) {Document document = null;PdfCopy copy = null;try {PdfReader reader = new PdfReader(respdfFile);int n = reader.getNumberOfPages();if(end==0){end = n;}ArrayList<String> savepaths = new ArrayList<String>();savepaths.add(savepath);document = new Document(reader.getPageSize(1));copy = new PdfCopy(document, new FileOutputStream(savepaths.get(0)));document.open();for(int j=from; j<=end; j++) {document.newPage();PdfImportedPage page = copy.getImportedPage(reader, j);copy.addPage(page);}document.close();} catch (IOException e) {e.printStackTrace();} catch(DocumentException e) {e.printStackTrace();}}
PDF内容
如果你对BaseFont类自带的字体颜色不满足的话我们可以自己进行配色
这个网站是rgb颜色表
http://www.wahart.com.hk/rgb.htm
new BaseColor(r, g, b);
基础
Chunk(块)
Chunk : 块,PDF文档中描述的最小原子元素 ,其他高级的文本对象都是基于Chunk的
在水平方向,Chunk的字符满一行,就会从头开始。请注意,这是从头开始,而不是另起一行。对于Chunk来说,行间距默认为0,那么当文档中只有Chunk时,这些字符永远只会出现再第一行。
注意:块一般不会单独使用而且和其他文本对象进行组合使用的
doc.open(); //打开PDF 默认为第一页//定义一个块Chunk chunk = new Chunk("Cat");//设置块的背景色 (可选)
// chunk.setBackground(BaseColor.WHITE); //白色背景(默认)//设置快内的字体为可识别中文字体//字体样式,编码格式,插入方式,字体大小,字体样式(Font.ITALIC细,Font.NORMA正常L,Font.BOLD粗),字体颜色)Font font = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED,17, Font.NORMAL, new BaseColor(105, 105, 105));//设置快内的字体颜色chunk.setFont(font);//增加块到文档doc.add(chunk);doc.close();
如果单独使用块的话-块重叠案例
doc.open(); //打开PDF 默认为第一页//建块int i=0;for(i=1; i<=11; i++){doc.add(new Chunk("This is sentence "+i+". "));}doc.close();
可以发现重叠了 ,所以块一般是不能单独使用的,我们要配合下面的更高级文本对象进行使用,进行改变一条句子中的某些字的样式
Phrase(短句)
Phrase作用是添加一个短句。短语类知道如何添加行与行之间的间距。 但是没法和Chunk一样设置样式
doc.open(); //打开PDF 默认为第一页//添加短句int i=0;for(i=1; i<11; i++){doc.add(new Phrase("This is sentence "+i+". "));}doc.close();
可以看到了和Chunk不同的是,会自动换行了,既然Chunk可以设置样式,Phrase可以自动换行那么我们将他们组合不就可以了
Phrase组合Chunk使用
doc.open(); //打开PDF 默认为第一页//定义一个块Chunk chunk1 = new Chunk("哈哈哈哈哈哈1");//添加横线 比如下划线(0.2f, -2f) 删除线(0.2f, 4f) 第一个参数是浓度 ,第二个参数是位置 横线位置chunk1.setUnderline(0.2f, 4f);Font font1 = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED,17, Font.NORMAL, new BaseColor(105, 105, 105));chunk1.setFont(font1);Chunk chunk2 = new Chunk("惺惺惜惺惺想寻2");chunk2.setBackground(new BaseColor(200, 200, 169) );//添加块背景颜色Font font2 = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED,22, Font.NORMAL, new BaseColor(105, 105, 105));chunk2.setFont(font2);//将块添加到短句里Phrase elements = new Phrase(50); //设置行间距elements.add(chunk1);elements.add(chunk2);doc.add(elements);doc.close();
这样Phrase就能有Chunk的样式效果了
doc.open(); //打开PDF 默认为第一页//定义段落Paragraph paragraph = new Paragraph();//插入十条文本块到段落中int i=0;for(i=0; i<10; i++){Chunk chunk = new Chunk("This is a sentence which is long " + i + ". ");paragraph.add(chunk);}//添加段落doc.add(paragraph);doc.close();
Paragraph(段落)
Paragraph 是段落的处理。在一个段落中 每一个段落都会结尾自带换行,
你可以设置段落的对齐方式,缩进和间距。 简单来说就是对Phrase进行升级了
可以操控文本在PDF中的位置了
doc.open(); //打开PDF 默认为第一页//定义段落Paragraph paragraph = new Paragraph();//插入10条文本块到段落中int i=0;for(i=0; i<10; i++){Chunk chunk = new Chunk("This is a sentence which is long " + i + ". ");paragraph.add(chunk);}doc.add(paragraph);doc.close();
暂时看来和短句的运行效果差不多,每句都在自己的行。
您可以设置一个段落前后的间距。 也就是行的上间距和下间距
paragraph.setSpacingAfter(50);
paragraph.setSpacingBefore(50);
您可以设置使用setAlignment()方法的段落的对齐方式。
paragraph.setAlignment(Element.ALIGN_LEFT); //靠左
paragraph.setAlignment(Element.ALIGN_CENTER); //居中
paragraph.setAlignment(Element.ALIGN_RIGHT); //靠右
您可以设置该段左,右缩进。
paragraph.setIndentationLeft(50);
paragraph.setIndentationRight(50);
案例演示
doc.open(); //打开PDF 默认为第一页//定义段落1Paragraph paragraph = new Paragraph("This is a sentence which is long . ");//设置段段落居中paragraph.setAlignment(Element.ALIGN_CENTER);//设置段落行缩进paragraph.setIndentationLeft(10); //左边缩进//添加段落doc.add(paragraph);//定义段落2Paragraph paragraph1 = new Paragraph("This is a sentence which is long . ");//设置段落行的上间距paragraph1.setSpacingAfter(20);//设置段段落居中paragraph1.setAlignment(Element.ALIGN_CENTER);//设置段落行缩进paragraph1.setIndentationLeft(150); //左边缩进//添加段落doc.add(paragraph1);doc.close();
拿什么时候使用Chunk 什么时候使用Phrase 什么时候使用Paragraph呢?
Chunk: 只能设置字体和背景样式 ,而且内容只能在一行中
Phrase: 行满自动换行,可以设置行高, 但是不能手动换行,不能设置字体样式
Paragraph: 除了不能设置字体样式和背景外 基本文本所能用于的特性都可以实现 ,每个Paragraph结尾自带换行
通俗易懂的话来讲就是 Paragraph用来设置内容排版 Phrase用来拼接语句的, Chunk用来设置字体和背景样式的
操作字的位置透明旋转…
PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));doc.open(); //打开PDF 默认为第一页PdfGState gs = new PdfGState();gs.setFillOpacity(0.3f);//透明度PdfContentByte canvas = instance.getDirectContent();canvas.setGState(gs);Phrase phrase1 = new Phrase("This is a test!left");Phrase phrase2 = new Phrase("This is a test!right");Phrase phrase3 = new Phrase("This is a test!center");// 参数1 默认就行 ,参数2默认就行,参数3内容,参数4x轴,参数5y轴,参数6字体旋转ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase1, 100, 500, 10);ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase2, 150, 536, 40);ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase3, 200, 572, 60);doc.close();
注意 :起始位置是左上角 x 是正数=往右 y是正数=往上 否则反之
List(列表)
有序列表 无需列表 字母列表
注意导包 import com.itextpdf.text.*; 而不是java.util
有序列表
doc.open(); //打开PDF 默认为第一页List orderedList = new List(List.ORDERED);for (int i = 0; i < 10; i++) {orderedList.add(new ListItem("Item "));}doc.add(orderedList);doc.close();
无序列表
doc.open(); //打开PDF 默认为第一页List unorderedList = new List(List.UNORDERED);for (int i = 0; i < 10; i++) {unorderedList.add(new ListItem("Item "));}doc.add(unorderedList);doc.close();
手指列表
doc.open(); //打开PDF 默认为第一页ZapfDingbatsList zapfDingbatsList = new ZapfDingbatsList(43, 30);for (int i = 0; i < 10; i++) {zapfDingbatsList.add(new ListItem("Item "));}doc.add(zapfDingbatsList);
列表嵌套
doc.open(); //打开PDF 默认为第一页// 父列表List orderedList = new List(List.ORDERED);orderedList.add(new ListItem("Item "));// 子列表List unorderedList = new List(false, false, 30);for (int i = 0; i < 5; i++) {//取消列表符合unorderedList.setListSymbol(new Chunk("", FontFactory.getFont(FontFactory.HELVETICA, 6)));unorderedList.add(new ListItem("Item"));}orderedList.add(unorderedList);doc.add(orderedList);doc.close();
高级
Anchor(链接)
Anchor,相当于html中的超链接,主要实现2个功能:
1.跳转到外部站点。
2.跳转到文档的特定位置。
跳转到特定网站,只需要设置Anchor对象的Reference属性
调转到文档的特定位置(在HTML中是描点),先要创建一个Anchor对象到特定位置,并为其命名,如“China”,然后,在创建一个Anchor至于需要点击的位置,设置其Reference属性为“#China”
演示一个锚链接
doc.open(); //打开PDF 默认为第一页// Anchor超链接和锚点对象: internal and external linksAnchor dest = new Anchor("连接到设置的UN锚点", PdfFont.getChineseFont(BaseColor.BLUE));dest.setName("CN"); // 设置锚点dest.setReference("#UN");// 跳转到UN锚点doc.add(dest);doc.newPage(); // 创建第2页instance.setPageEmpty(false); //可以允许第2页为空 如果不设置那么PDF默认给没有内容的页 取消掉doc.newPage(); // 创建第3页Anchor toUS = new Anchor("连接到设置的CN锚点。", PdfFont.getChineseFont(BaseColor.BLUE));toUS.setName("UN");toUS.setReference("#CN");// 跳转到CN锚点doc.add(toUS);doc.close();
锚链可以制作目录和导航
演示创建超链接跳转百度
doc.open(); //打开PDF 默认为第一页Anchor dest = new Anchor("超链接", PdfFont.getChineseFont(BaseColor.BLUE));dest.setReference("http://www.baidu.com");// 如果不是描点,那么我们可以使用超链接连接doc.add(dest);doc.close();
Chapter(章) Section(节)
doc.open(); //打开PDF 默认为第一页//定义段落Paragraph paragraph = new Paragraph();//添加段落内容paragraph.add(new Phrase("This is a chapter."));//定义章Chapter chapter = new Chapter(paragraph, 1);//添加章-节内容chapter.addSection("This is section 1", 2);chapter.addSection("This is section 2", 2);//添加章节doc.add(chapter);doc.close();
代码中chapter.addSection(“This is section 1”, 2)中的2是设置深度,如果设置成1跟章得头是一个级别了。
Image(图片)
如果同一个图像创建多次并都添加到文档中,文档的大小就增长很快,如果一个图像要在多个地方使用,只要生成一个Image对象,在添加到文档前,设置其属性就可以了,没有必要创建多份。
创建图像
Image img = Image.getInstance(FILE_DIR+"baidu.jpg");doc.add(img);
图片的配置
img.setBorder(Image.BOX) //边框,img.setBorderWidth(10)//边框宽度img.setBorderColor(BaseColor.WHITE) //边框颜色,img.setRotationDegrees(-30) //旋转 正向左旋转 负向右旋转img.setAbsolutePosition(x,y) //绝对位置 0,0 是最左下角 x变大向右移动 y变大向上移动
缩放图片
img.scaleAbsolute(150, 150);//绝对宽和高
img.scaleAbsoluteWidth(150);//绝对宽
img.scaleAbsoluteHeight(150);//绝对高
img.scalePercent(50); //百分比
img.scaleToFit(400,300);//像素大小
对其方式
img.setAlignment(Image.LEFT)
// Image.LEFT(最左边) Image.RIGHT(最右边) Image.TOP(中)
图片自适应大小
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页Image img = Image.getInstance(FILE_DIR+"37.jpg");img.scaleToFit(rect.getWidth(), rect.getHeight()); //关键代码doc.add(img);doc.close();
简单小演示
doc.open(); //打开PDF 默认为第一页Paragraph paragraph = new Paragraph("你妹的", PdfFont.getChineseFont(BaseColor.BLACK));paragraph.setAlignment(Element.ALIGN_CENTER);doc.add(paragraph );//插入图片Image img = Image.getInstance(FILE_DIR+"baidu.jpg");img.setAlignment( Image.RIGHT); //图片靠右img.scaleToFit(200, 100);//大小img.setRotationDegrees(-30);//旋转doc.add(img);//定义段落Paragraph paragraph1 = new Paragraph("作者:xxxxxxxxx",PdfFont.getChineseFont(BaseColor.BLACK));paragraph1.setAlignment(Element.ALIGN_RIGHT);doc.add(paragraph1);doc.close();
分割线线条
箭头
doc.open(); //打开PDF 默认为第一页doc.add(new VerticalPositionMark() {public void draw(PdfContentByte canvas, float llx, float lly,float urx, float ury, float y) {canvas.beginText();BaseFont bf = null;try {bf = BaseFont.createFont(BaseFont.ZAPFDINGBATS, "", BaseFont.EMBEDDED);} catch (Exception e) {e.printStackTrace();}canvas.setFontAndSize(bf, 12);// LEFTcanvas.showTextAligned(Element.ALIGN_CENTER, String.valueOf((char) 220), llx - 10, y, 0);// RIGHTcanvas.showTextAligned(Element.ALIGN_CENTER, String.valueOf((char) 220), urx + 10, y + 8, 180);canvas.endText();}});doc.close();
直线
doc.open(); //打开PDF 默认为第一页Paragraph p1 = new Paragraph("LEFT");p1.add(new Chunk(new LineSeparator()));p1.add("RIGHT");doc.add(p1);doc.close();
点线
Paragraph p1 = new Paragraph("LEFT");p1.add(new Chunk(new DottedLineSeparator()));p1.add("RIGHT");doc.add(p1);
下划线
doc.open(); //打开PDF 默认为第一页LineSeparator UNDERLINE = new LineSeparator(1, 100, null, Element.ALIGN_CENTER, -2);Paragraph p3 = new Paragraph();p3.setFont(PdfFont.getChineseFont());//设置中文支撑p3.add("三生三世惺惺惜惺惺想寻寻寻寻寻寻寻寻寻寻寻寻寻");p3.add(UNDERLINE);//下划线p3.add("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN");p3.add(UNDERLINE);//下划线doc.add(p3);doc.close();
PDF转换
给PDF添加水印
分为图片水印和字体水印 因为有点复杂的缘故我直接封装好了工具类直接可以使用 ,但是也不是一成不变的,
需要你根据情况进行调整大小,一般默认配置就够用了
注意:设置水印和设置图片不是一个概念,如果PDF有背景颜色的话会将水印盖住这个需要注意 ,
因为水印是PDF文件生成好后,后期添加上去的,在堆层的最底层
PdfWatermark水印工具类
package com.pdf.utils;import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class PdfWatermark {/*** 文字水印* <p>* 中间或者两边水印** @param bos 添加完水印的输出* @param input 原PDF文件输入* @param word 水印内容* @param model 水印添加位置1中间,2两边*/public static void setWatermark(String bos, String input, String word, int model)throws DocumentException, IOException {PdfReader reader = new PdfReader(new FileInputStream(input));PdfStamper stamper = new PdfStamper(reader,new BufferedOutputStream(new FileOutputStream(bos) ));PdfContentByte content;// 创建字体,第一个参数是字体路径,itext有一些默认的字体比如说:BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);PdfGState gs = new PdfGState();gs.setFillOpacity(0.3f);//水印透明度// 获取PDF页数int total = reader.getNumberOfPages();// 遍历每一页for (int i = 0; i < total; i++) {float width = reader.getPageSize(i + 1).getWidth(); // 页宽度float height = reader.getPageSize(i + 1).getHeight(); // 页高度content = stamper.getOverContent(i + 1);// 内容content.beginText();//开始写入文本content.setGState(gs);content.setColorFill(BaseColor.LIGHT_GRAY);content.setTextMatrix(70, 200);//设置字体的输出位置if (model == 1) { //平行居中的3条水印content.setFontAndSize(base, 40); //字体大小//showTextAligned 方法的参数分别是(文字对齐方式,位置内容,输出水印X轴位置,Y轴位置,旋转角度)content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, height/3, 30);content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, height/2, 30);content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, height/4-50, 30);} else { // 左右两边个从上到下4条水印float rotation = 30;// 水印旋转度数content.setFontAndSize(base, 20);content.showTextAligned(Element.ALIGN_LEFT, word, 20, height - 50, rotation);content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 * 3 - 50, rotation);content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 2 - 50, rotation);content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 - 50, rotation);content.setFontAndSize(base, 22);content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height - 50, rotation);content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 * 3 - 50, rotation);content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 2 - 50, rotation);content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 - 50, rotation);}content.endText();//结束写入文本}stamper.close();reader.close();}/*** 给pdf文件添加水印 (注意如果有添加背景颜色的话那么 图片水印将失效被盖住了)** @param outPdfFile 加了水印后要输出的路径* @param InPdfFile 要加水印的原pdf文件路径* @param markImagePath 水印图片路径* @throws Exception*/public static void addPdfMark( String outPdfFile,String InPdfFile, String markImagePath) throws Exception {PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes());PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(outPdfFile));PdfGState gs = new PdfGState();Image img = Image.getInstance(markImagePath);// 插入水印img.setRotationDegrees(30);//旋转 角度
// img.scaleAbsolute(200,100);//自定义图片大小img.scalePercent(50);//图片依照比例缩放 百分之50gs.setFillOpacity(0.3f);//水印透明度int total = reader.getNumberOfPages(); //全部页PdfContentByte content;for (int i = 0; i < total; i++) {content = stamp.getUnderContent(+ 1); // 内容content.setGState(gs);float width = reader.getPageSize(i + 1).getWidth(); // 页宽度float height = reader.getPageSize(i + 1).getHeight(); // 页高度img.setAbsolutePosition(width / 2, height/3); //图片位置 第1张图content.addImage(img);img.setAbsolutePosition(width / 2, height/2); //图片位置 第2张图content.addImage(img);img.setAbsolutePosition(width / 2, height/4-50); //图片位置 第3张图content.addImage(img);}stamp.close();// 关闭reader.close();}}
使用教程
文字水印 (原PDF可以有背景颜色) 使用的最多
参数1是加完水印后的PDF存储位置,参数2是原PDF,参数3是添加的文字水印 参数4是位置 (1中间,2两边)
@Testpublic void test2() throws Exception { //文字水印PdfWatermark.setWatermark(FILE_DIR + "createSamplePDF_sui.pdf", FILE_DIR + "createSamplePDF.pdf", "测试打印", 1);}
参数4:是1的情况
参数4:是2的情况
图片水印 (原PDF不能有背景颜色 否则图片水印无效)
参数1是加完水印后的PDF存储位置,参数2是原PDF,参数3是水印图片位置
@Testpublic void test2_1() throws Exception { //图片水印PdfWatermark.addPdfMark(FILE_DIR + "createSamplePDF_sui.pdf", FILE_DIR + "createSamplePDF.pdf", FILE_DIR + "baidu.jpg");}
删除PDF内的空页
/***** @param pdfSourceFile 原文件* @param pdfDestinationFile 处理后新生成的文件*/public static void removeBlankPdfPages(String pdfSourceFile, String pdfDestinationFile){try{// step 1: create new readerPdfReader r = new PdfReader(pdfSourceFile);RandomAccessFileOrArray raf = new RandomAccessFileOrArray(pdfSourceFile);Document document = new Document(r.getPageSizeWithRotation(1));// step 2: create a writer that listens to the documentPdfCopy writer = new PdfCopy(document, new FileOutputStream(pdfDestinationFile));// step 3: we open the documentdocument.open();// step 4: we add contentPdfImportedPage page = null;//loop through each page and if the bs is larger than 20 than we know it is not blank.//if it is less than 20 than we don't include that blank page.for (int i=1;i<=r.getNumberOfPages();i++){//get the page contentbyte bContent [] = r.getPageContent(i,raf);ByteArrayOutputStream bs = new ByteArrayOutputStream();//write the content to an output streambs.write(bContent);//add the page to the new pdfif (bs.size() > 20){page = writer.getImportedPage(r, i);writer.addPage(page);}bs.close();}//close everythingdocument.close();writer.close();raf.close();r.close();}catch(Exception e){//do what you need here}}
压缩PDF到Zip
这种压缩是在生成PDF的时候直接写入到zip里
//创建一个zipZipOutputStream zip = new ZipOutputStream(new FileOutputStream(FILE_DIR + "zipPDF.zip"));//创建PDF文件ZipEntry entry = new ZipEntry("hello_" + 1 + ".pdf");//将PDF添加到ZIPzip.putNextEntry(entry);Document document = new Document();PdfWriter writer = PdfWriter.getInstance(document, zip);// 后面内容writer.setCloseStream(false);document.open();document.add(new Paragraph("Hello " + 1));document.close();zip.closeEntry();zip.close();
合并PDF
读取所有文档然后追加到新的文档
/**** @param fileList 文档地址* @param savepath 合并后地址*/public static void mergepdf(ArrayList<String> fileList, String savepath) {Document document = null;try {document = new Document(new PdfReader(fileList.get(0)).getPageSize(1));PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));document.open();for (int i = 0; i < fileList.size(); i++) {PdfReader reader = new PdfReader(fileList.get(i));copy.addDocument(reader);reader.close();}} catch (IOException | DocumentException e) {e.printStackTrace();} finally {if (document != null) {document.close();}}}
@Testpublic void he() throws IOException, DocumentException {ArrayList<String> arrayList=new ArrayList();arrayList.add(FILE_DIR + "splitPDF1.pdf");arrayList.add(FILE_DIR + "splitPDF2.pdf");mergepdf(arrayList, FILE_DIR + "mergePDF.pdf");}
读取PDF文档的页,然后一页一页追加到新的文档。 (也就是可以控制合并的页)
/**** @param fileList 文档地址* @param savepath 合并后地址*/public static void mergepdf(ArrayList<String> fileList, String savepath) {Document document = null;try {document = new Document(new PdfReader(fileList.get(0)).getPageSize(1));PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));document.open();for (int i = 0; i < fileList.size(); i++) {PdfReader reader = new PdfReader(fileList.get(i));copy.addDocument(reader);reader.close();}} catch (IOException e) {e.printStackTrace();} catch (DocumentException e) {e.printStackTrace();} finally {if (document != null) {document.close();}}}
@Testpublic void he() throws IOException, DocumentException {ArrayList<String> arrayList=new ArrayList();arrayList.add(FILE_DIR + "splitPDF1.pdf");arrayList.add(FILE_DIR + "splitPDF2.pdf");mergepdf(arrayList, FILE_DIR + "mergePDF.pdf");}
添加批注和附件
PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));instance.setLinearPageMode();doc.open(); //打开PDF 默认为第一页doc.add(new Paragraph("1 page"));//给第一页添加批注doc.add(new Annotation("Title", "This is a annotation!"));doc.newPage();doc.add(new Paragraph("2 page"));//给第二页添加批注doc.add(new Annotation("Title", "This is a annotation!"));doc.newPage();doc.add(new Paragraph("3 page"));//给第三页添加附件Chunk chunk2 = new Chunk("\u00a0\u00a0"); // 必须有PdfAnnotation annotation = PdfAnnotation.createFileAttachment(instance, null, "Title", null,FILE_DIR+"baidu.jpg","img.jpg");annotation.put(PdfName.NAME,new PdfString("Paperclip"));chunk2.setAnnotation(annotation);doc.add(chunk2);doc.close();
PDF表格
在PDF中整个表格没有控制位置的方法,但是会始终在PDF中间,而且还是自适应,并且独占一行,
插入表格
doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(3);//设置3列PdfPCell cell;cell = new PdfPCell(new Phrase("Cell with colspan 3"));//设置列的内容cell.setColspan(3);//合并3列table.addCell(cell);//将内容添加到表格里第一行cell = new PdfPCell(new Phrase("Cell with rowspan 2")); //设置列的内容cell.setRowspan(2); //合并2行table.addCell(cell); //将内容添加到表格里第二行// 然后开始填空行table.addCell("row 1; cell 1");table.addCell("row 1; cell 2");table.addCell("row 2; cell 1");table.addCell("row 2; cell 2");doc.add(table);doc.close();
设置表格宽度位置
在上面代码的后面添加
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(3);//设置3列PdfPCell cell;cell = new PdfPCell(new Phrase("Cell with colspan 3"));//设置列的内容cell.setColspan(3);//合并3列table.addCell(cell);//将内容添加到表格里第一行cell = new PdfPCell(new Phrase("Cell with rowspan 2")); //设置列的内容cell.setRowspan(2); //合并2行table.addCell(cell); //将内容添加到表格里第二行// 然后开始填空行table.addCell("row 1; cell 1");table.addCell("row 1; cell 2");table.addCell("row 2; cell 1");table.addCell("row 2; cell 2");doc.add(table);//宽度100%table.setWidthPercentage(100);doc.add(table);doc.add(new Paragraph("\n\n"));//宽度50% 居左table.setWidthPercentage(50);table.setHorizontalAlignment(Element.ALIGN_LEFT);doc.add(table);doc.add(new Paragraph("\n\n"));//宽度50% 居中table.setWidthPercentage(50);table.setHorizontalAlignment(Element.ALIGN_CENTER);doc.add(table);doc.add(new Paragraph("\n\n"));//宽度50% 居右table.setWidthPercentage(50);table.setHorizontalAlignment(Element.ALIGN_RIGHT);doc.add(table);doc.add(new Paragraph("\n\n"));//固定宽度 居中table.setTotalWidth(300);table.setLockedWidth(true);table.setHorizontalAlignment(Element.ALIGN_CENTER);doc.add(table);doc.close();
设置表格边框
//没有边框
PdfPTable table1 = new PdfPTable(3);
table1.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
table1.addCell(new Paragraph("Cell 1"));
table1.addCell(new Paragraph("Cell 2"));
table1.addCell(new Paragraph("Cell 3"));
document.add(table1);
设置边框粗细颜色
doc.open(); //打开PDF 默认为第一页//边框粗细颜色doc.newPage();Rectangle b1 = new Rectangle(0f, 0f);b1.setBorderWidthLeft(6f);//左边框大小b1.setBorderWidthBottom(5f);b1.setBorderWidthRight(4f);b1.setBorderWidthTop(2f);b1.setBorderColorLeft(BaseColor.RED);//左边框b1.setBorderColorBottom(BaseColor.ORANGE);//下边框b1.setBorderColorRight(BaseColor.YELLOW);b1.setBorderColorTop(BaseColor.GREEN);PdfPTable table2 = new PdfPTable(1);PdfPCell cell = new PdfPCell(new Paragraph("Cell 1"));cell.cloneNonPositionParameters(b1);table2.addCell(cell);doc.add(table2);doc.close();
设置表格的边框和背景颜色
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(3);PdfPCell cell = new PdfPCell(new Paragraph("合并3列单元格",PdfFont.getChineseFont()));cell.setColspan(3);//合并3个列单元格table.addCell(cell);table.addCell("1.1");table.addCell("2.1");table.addCell("3.1");table.addCell("1.2");table.addCell("2.2");table.addCell("3.2");cell = new PdfPCell(new Paragraph("红色边框",PdfFont.getChineseFont()));//边框颜色cell.setBorderColor(new BaseColor(255, 0, 0));table.addCell(cell);cell = new PdfPCell(new Paragraph("合并2列元格,背景灰色",PdfFont.getChineseFont()));cell.setColspan(2);//背景色cell.setBackgroundColor(new BaseColor(0xC0, 0xC0, 0xC0));table.addCell(cell);table.setWidthPercentage(50); //设置表格的宽度doc.add(new Paragraph("表格1",PdfFont.getChineseFont()));doc.add(table);doc.close();
设置表格前后间隔
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(3);PdfPCell cell = new PdfPCell(new Paragraph("合并3列单元格",PdfFont.getChineseFont()));cell.setColspan(3);//合并3个列单元格table.addCell(cell);table.addCell("1.1");table.addCell("2.1");table.addCell("3.1");table.addCell("1.2");table.addCell("2.2");table.addCell("3.2");doc.newPage();doc.add(new Paragraph("表格前的间距",PdfFont.getChineseFont()));table.setSpacingBefore(150f); //设置表格前的间距table.setSpacingAfter(150f); //设置表格后的间距doc.add(table);doc.add(new Paragraph("表格后的间距",PdfFont.getChineseFont()));doc.close();
设置单个的单元格宽度
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页doc.add(new Paragraph("按百分比设置单元格宽度\n\n",PdfFont.getChineseFont()));float[] widths = {0.1f, 0.1f, 0.05f, 0.75f};PdfPTable table = new PdfPTable(widths);table.addCell("10%");table.addCell("10%");table.addCell("5%");table.addCell("75%");table.addCell("aa");table.addCell("aa");table.addCell("a");table.addCell("aaaaaaaaaaaaaaa");table.addCell("bb");table.addCell("bb");table.addCell("b");table.addCell("bbbbbbbbbbbbbbb");table.addCell("cc");table.addCell("cc");table.addCell("c");table.addCell("ccccccccccccccc");doc.add(table);doc.add(new Paragraph("\n\n"));doc.close();
设置单个的单元格高度
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(2);PdfPCell cell;//设置高度table.addCell(new PdfPCell(new Paragraph("任意高度",PdfFont.getChineseFont())));cell = new PdfPCell(new Paragraph("1. blah blah\n2. blah blah blah\n3. blah blah\n4. blah blah blah\n5. blah blah\n6. blah blah blah\n7. blah blah\n8. blah blah blah"));table.addCell(cell);//固定高度table.addCell(new PdfPCell(new Paragraph("固定高度",PdfFont.getChineseFont())));cell.setFixedHeight(50f);table.addCell(cell);//最小高度table.addCell(new PdfPCell(new Paragraph("最小高度",PdfFont.getChineseFont())));cell = new PdfPCell(new Paragraph("最小高度:50",PdfFont.getChineseFont()));cell.setMinimumHeight(50f);table.addCell(cell);//最后一行拉长到page底部table.setExtendLastRow(true);table.addCell(new PdfPCell(new Paragraph("拉长最后一行",PdfFont.getChineseFont())));cell = new PdfPCell(new Paragraph("最后一行拉长到page底部",PdfFont.getChineseFont()));table.addCell(cell);doc.add(table);doc.close();
PDF之二维码和条形码
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页//条形码PdfContentByte cd = instance.getDirectContent();Barcode128 code128 = new Barcode128();code128.setCode("http://www.baidu.com".trim());code128.setCodeType(Barcode128.CODE128);Image code128Image = code128.createImageWithBarcode(cd, null, null);code128Image.setAbsolutePosition(400,300);//条形码的位置code128Image.scalePercent(125);doc.add(code128Image);//二维码BarcodeQRCode qrcode = new BarcodeQRCode("http://www.baidu.com".trim(), 1, 1, null);Image qrcodeImage = qrcode.getImage();qrcodeImage.setAbsolutePosition(200,400);//二维码的位置qrcodeImage.scalePercent(200);doc.add(qrcodeImage);doc.close();
固定模板生成PDF方式
手动生成PDF发票(使用较少)
公司提供具体模板格式你使用itext画出来…:
我这里随便从网上找来了一个发票
链接:https://pan.baidu.com/s/11iy8M0_Oo0E1tzEITMSSLw
提取码:1234
下面就来演示将上面这张图完整的还原出来,其实很简单,将这张图设置为背景就行了,自己在需要添加值得地方设置变量就可以了
Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);PdfWriter instance = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));doc.open(); //打开PDF 默认为第一页Image img = Image.getInstance(FILE_DIR+"37.jpg");img.scaleToFit(rect.getWidth(), rect.getHeight());doc.add(img);Phrase phrase1 = new Phrase("胡123",PdfFont.getChineseFont(12));Phrase phrase2 = new Phrase("212346512312311",PdfFont.getChineseFont(12));Phrase phrase3 = new Phrase("河南北京",PdfFont.getChineseFont(12));PdfContentByte canvas = instance.getDirectContent();// 参数1 默认就行 ,参数2默认就行,参数3内容,参数4x轴,参数5y轴,参数6字体旋转ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase1, 230, 550, 0);ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase2, 255, 530, 0);ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, phrase3, 240, 510, 0);doc.close();
这种方式的好处就是灵活,只需要提供画好的图片就行,
但是就是太麻烦了,需要自己控制文本的位置
常用于特别复杂的场景,使用word画不出来的场景,需要的样式花样特别多的场景,将样式效果脱落出去,我们只管文字的填充就行
利用word生成PDF(使用较多)
需要的工具
本地word(windows10自带 或者 wps 都行)
在线word转PDF
免费word转PDF https://smallpdf.com/cn/word-to-pdf 一天2次(足够用了)
免费word转PDF http://www.pdfdo.com/doc-to-pdf.aspx 没有次数限制
免费word转PDF http://wordtopdf.55.la/ 限制每次转换大小最多100m 没有次数限制
… 网上一大堆都是免费的如果上面都过期了那么自己找
给PDF添加表单控件的工具 Adobe Acrobat DC
链接:https://pan.baidu.com/s/1dah5Gxh-YZRGFbZiCEVXFg
提取码:1234
解压后记得断网,不然就不能使用,然后找到目录里的AcroPro.msi 双击安装就行 之后就可以正常使用了
第一步先创建好word模板
利用上面提供的网站进行转换为PDF,转换完成后双击打开PDF(使用Adobe Acrobat DC打开的)
如果你右下角没有的话在更多工具里是有的,然后进到下面这个页面
之后会自动在空白的地方补充,文本框 如果没有自动补充那么在最上面有工具栏里自行添加
然后我们需要调整 文框的大小和位置自行调整最合适的位置,否则字默认显示位置是top,我们需要将文本框变小刚好够一个字的大小
字体的大小默认是跟随着文本框的高度进行变换的…
我们还可以点击某个文本右键属性设置文本格式(字体颜色 字体大小 ,自动计算…太多了基本HTML表单能实现的功能这里都能实现)
如果你要设置多个的话可以 shift+鼠标左键或者ctrl+a全部选中进行统一设置都行
调整后的效果
第二步使用java代码给文本框中对应的属性赋值
需要使用到3个关键的对象
PdfReader reader = new PdfReader(templateFile); // 模版文件目录PdfStamper ps = new PdfStamper(reader, new FileOutputStream(outFile)); // 生成的输出流AcroFields s = ps.getAcroFields(); //获取全部表单
案例:
public void editPdfTemplate(String templateFile, String outFile) throws IOException, DocumentException {PdfReader reader = new PdfReader(templateFile); // 模版文件目录PdfStamper ps = new PdfStamper(reader, new FileOutputStream(outFile)); // 生成的输出流AcroFields s = ps.getAcroFields();//编辑文本域表单的内容s.setField("fill_1", "558");s.setField("fill_2", "99966");ps.setFormFlattening(true); // 模板中的变量赋值之后不能编辑ps.close();reader.close();}
@Testpublic void mob() throws DocumentException, IOException {// 模板pdf 生成的pdfeditPdfTemplate(FILE_DIR+"moban.pdf",FILE_DIR+"wordPDF.pdf");}
动态 freemarket模板生成PDF文档
我们使用 freemarket+itext+springboot 方式
一般pdf是用来生成发票或者简单的报告用的, 而某些领导蛋疼非要使用PDF导出数据统计报表你说气不气,没办法都是打工的不解决不行啊…
网上有很多种方式但是我一 一都进行了实验最后得出了结论就是 别乱搞没用,基本都失真,HTML转PDF基本都没有不失真的,
而且html的定位…很多css都不支持…浪费了我2天的我时间把网上各种生成PDF都试了个遍,最后还是放弃了,发现这种方式不能实现特别复杂的html页面 只能实现一些需要大量数据报表的显示,而且对样式要求不高,一般遇到这种情况都是采用导出Excel了而不是导出PDF了.
而且这种方式没法手动添加页只能自动适配页,也就是利用模板语法<#list xxx >
,进行循环.
每页大具体大小是可以控制的多大都行
但是必须要保证每次循环的内容必须都是在一页中. 之后每循环一次就是一页
我们HTML模板使用的是 Freemarker 也就是需要一些模板语法懂得都懂不会上百度…
简单来说就只需要3种语法就足够了:
获取值
${name}
if
<#if var ??> 不是空 <#else> 为空 </#if>
循环
<#list goodsList as goods> 姓名: ${goods.name} 年龄: ${goods.age} 性别${goods.sex} <br/> </#list>
我们还需要知道这种方式的弊端
css 各种定位 和 浮动 弹性布局 … 都不能使用 那么如何控制属性的位置呢?? 可以通过表格的方式 表格内地元素都能使用的.
比如 text-align控制文本位置,valign 垂直对齐,align水平对齐 , 行高 … 都可以进行控制,自己慢慢试试就行了
图片不能加载本地图片,只能加载服务器图片, 也就是http请求的图片,如果想加载本地图片需要使用nginx做本地文件代理
location /images/ {alias D:/nginx/nginx-1.19.10/html/images/; # 代理的路径autoindex on; #是否开启目录浏览}
当访问
http://xxxx:80/images
就相当于在访问 D:/nginx/nginx-1.19.10/html/images/使用的话我们只需要在后面在追加一个图片名称就行了
http://xxxx:80/images/1.jpg
对于空值的校验,Freemarker 在渲染模板时不允许取值为空,如果某一项值可能为空,则必须添加校验,推荐取值方式
<#if demoValue??>${demoValue}
</#if>
模板样式必须添加的
/*-------------- 必须有的内容-------------------------*//* 调整生成PDF页面宽和高 */@page {size: 340mm 350mm;}body{margin: 0;padding: 0;font-family: SimSun;}table {page-break-inside: auto;-fs-table-paginate: paginate;border-spacing: 0;cellspacing: 0;cellpadding: 0;border: solid 1px #ccc;padding: 2px 2px;}tr {page-break-inside: avoid;page-break-after: auto;}/*---------------必须有的内容------------------------*/
上代码就是防止生成的PDF时候表格内容超过当前页的时候不能自动适配
下面就详细演示所有代码 (web版下载)
项目结构
宋体字体
链接:https://pan.baidu.com/s/15uLOVmh2NZHG3g2zoPoaKw
提取码:1234
html模板
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" ><title>Title</title><style>/*-------------- 必须有的内容-------------------------*//* 调整页面宽和高 */@page {size: 340mm 350mm;}body{margin: 0;padding: 0;font-family: SimSun;}table {page-break-inside: auto;-fs-table-paginate: paginate;border-spacing: 0;cellspacing: 0;cellpadding: 0;border: solid 1px #ccc;padding: 2px 2px;}tr {page-break-inside: avoid;page-break-after: auto;}/*---------------必须有的内容------------------------*/table{border: 1px solid #333;border-bottom: none;border-left: none;}td{height: 30px;border: 1px solid #333;border-top: none;text-align: center;}tr.title{font-weight: bold;}td.title{height: 50px;font-weight: bold;}td.value{color: blue;}td.content{font-size: 12px;text-align: left;}td.sign{text-align: left;height: 40px;}</style></head>
<body><#list 1..max as i><table class="table" cellspacing="0"><tr ><td class="title" colspan="10">项目成员绩效考核表</td></tr><tr ><td style="width: 10%;" align="">被考核者</td><td class="value" style="width: 10%;"><#if employee??><#if employee.name??>${employee.name}</#if></#if></td><td style="width: 10%;">部门</td><td colspan="2" class="value" style="width: 20%;"><#if employeeDepart??><#if employeeDepart.name??>${employeeDepart.name}</#if></#if></td><td style="width: 10%;">考核者</td><td class="value" style="width: 10%;"><#if acceptUser??><#if acceptUser.name??>${acceptUser.name}</#if></#if></td><td style="width: 10%;">考核时间</td><td colspan="2" class="value" style="width: 20%;"><#if statisticalTime??>${statisticalTime}</#if></td></tr><tr ><td colspan="10">第一部分工作目标(权重80%)</td></tr><tr class="title"><td colspan="2">指标名称</td><td >权重</td><td colspan="3">指标定义与评分标准</td><td >完成值</td><td >数据提供部门/人</td><td >自评得分</td><td >上级评分</td></tr><tr ><td colspan="2">工作计划完成率</td><td >30%</td><td colspan="3" class="content">实际完成量/计划完成量*100%<br/>1.完成比≥100%,本项为满分;<br/>2.完成比在90%(含)-100%(不含),扣10分;<br/>3.完成比在80%(含)-90%(不含),扣20分;<br/>4.完成比在80%(不含)以下的,本项为0分</td><td class="value"><#if jobCompletionRate??>${jobCompletionRate*100}%</#if></td><td >项目经理</td><td class="value"><#if jobCompletionRateScore??>${jobCompletionRateScore}</#if></td><td class="value"><#if jobCompletionRateSuperiorScore??>${jobCompletionRateSuperiorScore}</#if></td></tr><tr ><td colspan="2">工作计划完成及时率</td><td >25%</td><td colspan="3" class="content">实际完成天数/计划完成天数*100%<br/>1.完成比≦100%,本项为满分;<br/>2.完成比在100%-110%(不含),扣5分;<br/>3.完成比在110%(含)-130%(不含)扣10分;<br/>4.完成比在130%(含)以上的,本项为0分</td><td class="value"><#if finishRate??>${finishRate*100}%</#if></td><td >项目经理</td><td class="value"><#if finishRateScore??>${finishRateScore}</#if></td><td class="value"><#if finishRateSuperiorScore??>${finishRateSuperiorScore}</#if></td></tr><tr ><td colspan="2">返工率</td><td >20%</td><td colspan="3" class="content">实际返工次数/计划返工次数*100%<br/>1.完成比≤100%,本项为满分;<br/>2.完成比在100%(不含)-110%(不含),扣10分;<br/>3.完成比在110%(不含)-120%(含),扣15分;<br/>4.完成比在120%(不含)以上的,本项为0分</td><td class="value"><#if returnRate??>${returnRate*100}%</#if></td><td >项目经理<br/>外型供应商</td><td class="value"><#if returnRateScore??>${returnRateScore}</#if></td><td class="value"><#if returnRateSuperiorScore??>${returnRateSuperiorScore}</#if></td></tr><tr ><td colspan="2">技术文档资料保存完整性</td><td >15%</td><td colspan="3" class="content">实际上传资料数/要求上传资料数*100%<br/>1.完成比100%,本项得满分;<br/>2.完成比<100%,本项为0分</td><td class="value"><#if uploadRate??>${uploadRate*100}%</#if></td><td >项目经理</td><td class="value"><#if uploadRateScore??>${uploadRateScore}</#if></td><td class="value"><#if uploadRateSuperiorScore??>${uploadRateSuperiorScore}</#if></td></tr><tr ><td colspan="2">满意度</td><td >10%</td><td colspan="3" class="content">及时参加项目例会、积极汇报工作<br/>总分10分<br/>每遗漏一次,扣4分;扣完为止</td><td >--</td><td >项目经理</td><td class="value"><#if satisfactionScore??>${satisfactionScore}</#if></td><td class="value"><#if satisfactionSuperiorScore??>${satisfactionSuperiorScore}</#if></td></tr><tr ><td colspan="10">第二部分工作态度(权重20%)</td></tr><tr class="title"><td colspan="2">工作态度指标</td><td>衡量方法</td><td colspan="4">衡量标准</td><td >权重</td><td >自评得分</td><td >上级评分</td></tr><tr ><td colspan="2">责任心</td><td>上级评价</td><td colspan="4" class="content">1.仅仅能按上级要求完成本职工作(5分); <br/>2.能够严格按照工作标准完成工作目标对本职工作负责到底,<br/>工作中不推卸责任、不上交矛盾,失误较少(10分); <br/>3.对待工作不怕繁琐、有耐心,考虑问题与做事细致、周到(15分); <br/>4.对待工作精益求精,力求一次性做到完美(20分); <br/>5.对团队成员拥有强烈的责任感,努力帮助团队成员提升工作质量(25分)</td><td >25%</td><td class="value"><#if responsibilityScore??>${responsibilityScore}</#if></td><td class="value"><#if responsibilitySuperiorScore??>${responsibilitySuperiorScore}</#if></td></tr><tr ><td colspan="2">主动性</td><td>上级评价</td><td colspan="4" class="content">1.按上级安排/ 指示做事,安排什么做什么(5分)<br/>2.按自己的职位职责做事,工作任务大多能完成;<br/>同时对工作中出现的问题,也能被动反应,予以处理(10分)<br/>3.对自己的工作大致有思考,上级安排的任务能有效配合确定工作计划,<br/>并按计划完成工作任务;同时能积极处理工作中出现的各种问题,<br/>需要请示或上级支持时也能按程序办理(15分)<br/>4.提前思考、主动安排自己的工作计划,并将之主动与上级沟通、协商、确定,<br/>按计划推进、完成工作任务;对工作问题提前预防,并妥善处理各类问题;<br/>能积极主动地协助同事完成职责范围外的其他工作(20分)<br/>5.上级只给出一个方向或任务,既能独立地制定计划、组织资源、推进实施、保证完成,<br/>支持、鼓励团队成员与周围同事积极主动开展工作,<br/>能营造积极、主动的文化氛围(25)</td><td >25%</td><td class="value"><#if initiativeScore??>${initiativeScore}</#if></td><td class="value"><#if initiativeSuperiorScore??>${initiativeSuperiorScore}</#if></td></tr><tr ><td colspan="2">团队合作</td><td>上级评价</td><td colspan="4" class="content">1.积极融入团队并乐于接受同事帮助,配合团队完成工作(5分)<br/>2.主动给予同事必要的帮助;碰到困难时,善于利用团队的力量解决问题(10分)<br/>3.决策前积极发表个人意见,充分参与团队讨论;决策后,个人无论是否有异议,<br/>必须从行动上完全予以支持(15分);<br/>4.能够客观认识同事的优缺点,并在工作中充分体现“对事不对人”的原则(20分)<br/>5.能够以积极正面的心态去影响团队,并改善团队表现和氛围(25分)<br/></td><td >25%</td><td class="value"><#if teamCooperationScore??>${teamCooperationScore}</#if></td><td class="value"><#if teamCooperationSuperiorScore??>${teamCooperationSuperiorScore}</#if></td></tr><tr ><td colspan="2">保密意识</td><td>上级评价</td><td colspan="4" class="content">1.对岗位的保密责任有一定的认识(5分);<br/>2.熟悉公司保密协议,明确职责范围内的保密事项,并采取相应的维护措施(10分)<br/>3.以身作则,自觉、严格遵守保密协议,对保密协议未明确界定的问题能够很好的处理(15分)<br/>4.影响身边的同事,宣传保密意识,随时提醒同事;发现保密协议的缺陷和漏洞<br/>能及时向有关部门报告,并提出完善建议(20分);<br/>5.获悉他人违反和破坏保密协议时,积极抵制,能够及时向公司有关部门报告,<br/>并分情况采取积极措施以最大限度减少恶性后果,处理得当(25分)</td><td >25%</td><td class="value"><#if secrecyScore??>${secrecyScore}</#if></td><td class="value"><#if secrecySuperiorScore??>${secrecySuperiorScore}</#if></td></tr><tr ><td colspan="8">合计</td><td class="value"><#if totalScore??>${totalScore}</#if></td><td class="value"><#if totalSuperiorScore??>${totalSuperiorScore}</#if></td></tr><tr ><td colspan="2">等级评定规则</td><td class="content" colspan="5">A:优秀(100分以上)<br/>B:良好(90-100分)<br/>C:合格(80-90分)<br/>D:基本合格(70-80分)<br/>E:需改进(60-70分)<br/>F:不合格(60分以下)</td><td >等级评定</td><td class="value" colspan="2"><#if grade??>${grade}</#if></td></tr><tr style="height: 100px;" ><td colspan="2">自我总结</td><td colspan="8" class="content value"><#if selfSummary??>${selfSummary}</#if></td></tr><tr ><td rowspan="2" colspan="2">考核结果确认</td><td class="sign" colspan="4">考核者签名:</td><td class="sign" colspan="4">日期:</td></tr><tr><td class="sign" colspan="4">被考核者签名:</td><td class="sign" colspan="4">日期:</td></tr></table></#list></body>
</html>
获取资源路径工具类
package com.pdf.utils;import org.springframework.util.ResourceUtils;import java.io.File;
import java.io.FileNotFoundException;/*** @Description: 项目静态资源文件工具类* 仅可用于包含在web项目中的资源文件路径,资源文件必须放置于 web 模块下*/
public class ResourceFileUtil {/*** 获取资源文件** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)* eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static File getFile(String relativePath) throws FileNotFoundException {if (relativePath == null || relativePath.length() == 0) {return null;}if (relativePath.startsWith("/")) {relativePath = relativePath.substring(1);}File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX+ relativePath);return file;}/*** 获取资源绝对路径** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)* eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getAbsolutePath(String relativePath) throws FileNotFoundException {return getFile(relativePath).getAbsolutePath();}/*** 获取资源父级目录** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)* eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getParent(String relativePath) throws FileNotFoundException {return getFile(relativePath).getParent();}/*** 获取资源文件名** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)* eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getFileName(String relativePath) throws FileNotFoundException {return getFile(relativePath).getName();}}
生成PDF工具类
package com.pdf.utils;import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.*;
import java.util.Map;public class PDFUtil {// 必须在resoures下面private static String font="templates/font/simsun.ttf"; //字体private static String templ="templates/pdf_export_employee_kpi.html"; //模板private PDFUtil(){}private volatile static Configuration configuration;static {if (configuration == null) {synchronized (PDFUtil.class) {if (configuration == null) {configuration = new Configuration(Configuration.VERSION_2_3_28);}}}}/*** freemarker 引擎渲染 html** @param dataMap 传入 html 模板的 Map 数据* @param ftlFilePath html 模板文件相对路径(相对于 resources路径,路径 + 文件名)* eg: "templates/pdf_export_demo.ftl"* @return*/public static String freemarkerRender(Map<String, Object> dataMap, String ftlFilePath) {Writer out = new StringWriter();configuration.setDefaultEncoding("UTF-8");configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);try {configuration.setDirectoryForTemplateLoading(new File(ResourceFileUtil.getParent(ftlFilePath)));configuration.setLogTemplateExceptions(false);configuration.setWrapUncheckedExceptions(true);Template template = configuration.getTemplate(ResourceFileUtil.getFileName(ftlFilePath));template.process(dataMap, out);out.flush();return out.toString();} catch (IOException e) {e.printStackTrace();} catch (TemplateException e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}return null;}/*** 使用 iText 生成 PDF 文档** @param htmlTmpStr html 模板文件字符串* @param fontFile 所需字体文件(相对路径+文件名)* */public static byte[] createPDF(String htmlTmpStr, String fontFile) {ByteArrayOutputStream outputStream = null;byte[] result = null;try {outputStream = new ByteArrayOutputStream();ITextRenderer renderer = new ITextRenderer();renderer.setDocumentFromString(htmlTmpStr);ITextFontResolver fontResolver = renderer.getFontResolver();// 解决中文支持问题,需要所需字体(ttc)文件fontResolver.addFont(ResourceFileUtil.getAbsolutePath(fontFile),BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(outputStream);result=outputStream.toByteArray();if(outputStream != null) {outputStream.flush();outputStream.close();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return result;}/*** PDF 文件导出** @return*/public static ResponseEntity<?> export(Map<String, Object> dataMap, String pdfName) {HttpHeaders headers = new HttpHeaders();/*** 数据导出(PDF 格式)*/String htmlStr = PDFUtil.freemarkerRender(dataMap, templ);String s = formatHtml(htmlStr);System.out.println(s);byte[] pdfBytes = PDFUtil.createPDF(s, font);if (pdfBytes != null && pdfBytes.length > 0) {String fileName=null;if (pdfName!=null){fileName= pdfName;}else {fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";}headers.setContentDispositionFormData("attachment", fileName);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);return new ResponseEntity<byte[]>(pdfBytes, headers, HttpStatus.OK);}headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}public static ResponseEntity<?> export(Map<String, Object> dataMap) {return export( dataMap ,null);}/*** 使用jsoup规范化html** @param html html内容* @return 规范化后的html*/private static String formatHtml(String html) {Document doc = Jsoup.parse(html);// 去除过大的宽度String style = doc.attr("style");if (StringUtils.isNotEmpty(style) && style.contains("width")) {doc.attr("style", "");}Elements divs = doc.select("div");for (Element div : divs) {String divStyle = div.attr("style");if (StringUtils.isNotEmpty(divStyle) && divStyle.contains("width")) {div.attr("style", "");}}// jsoup生成闭合标签doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);return doc.html();}
}
Controller
package com.pdf.controller;import com.pdf.utils.PDFUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Date;
import java.util.HashMap;
import java.util.Map;@RestController
public class PdfController {/*** PDF 文件导出*/@GetMapping(value = "/pdf")public ResponseEntity<?> export(){try {Map<String, Object> dataMap = new HashMap<>(16);dataMap.put("statisticalTime",new Date().toString());dataMap.put("max",5);ResponseEntity<?> responseEntity = PDFUtil.export(dataMap);return responseEntity;} catch (Exception e) {e.printStackTrace();}HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}
}
启动类
package com.pdf;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(scanBasePackages = "com")
public class ApplictioBoot {public static void main(String[] args) {SpringApplication.run(ApplictioBoot.class,args);}
}
然后进行测试 访问 http://localhost:8080/pdf
注意:如果上面 word 模板方式或者 html+freemaret模板方式都不满足你的业务需求的话那么,你就需要手写Itext的方式进行生成PDF了
web页面下载方式
有两种方式
- 先生成PDF文件到本地 然后在读取本地pdf文件将二进制数据,发送到前端之后在删除本地生成的PDF
- 直接在缓存中生成pdf 生成后直接想二进制发给前端
我们常用于第二种方式 ,而第一种方式只需要会io流就行了这里就不多讲了,直接上第二种方式的代码就行了
package com.pdf.utils;import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;public class PdfDownLoadUtils {public static ByteArrayOutputStream ini() throws DocumentException {Rectangle rect = new Rectangle(PageSize.B4.rotate());Document doc = new Document(rect);ByteArrayOutputStream baos = new ByteArrayOutputStream();PdfWriter instance = PdfWriter.getInstance(doc, baos);doc(doc);return baos;}private static void doc(Document doc) throws DocumentException {doc.open(); //打开PDF 默认为第一页PdfPTable table = new PdfPTable(3);//设置3列PdfPCell cell;cell = new PdfPCell(new Phrase("Cell with colspan 3"));//设置列的内容cell.setColspan(3);//合并3列table.addCell(cell);//将内容添加到表格里第一行cell = new PdfPCell(new Phrase("Cell with rowspan 2")); //设置列的内容cell.setRowspan(2); //合并2行table.addCell(cell); //将内容添加到表格里第二行// 然后开始填空行table.addCell("row 1; cell 1");table.addCell("row 1; cell 2");table.addCell("row 2; cell 1");table.addCell("row 2; cell 2");doc.add(table);doc.close();}}
核心代码
/*** PDF 文件导出*/@GetMapping(value = "/pdfDow")public ResponseEntity<?> export1(HttpServletRequest request, HttpServletResponse response) {HttpHeaders headers = new HttpHeaders();String pdName="student.pdf"; //文件名称//设置页面编码格式try {ByteArrayOutputStream ini = PdfDownLoadUtils.ini();
// 页面打开PDF 不下载
// response.setContentLength(ini.size());
// OutputStream out = response.getOutputStream();
// ini.writeTo(out);
// return new ResponseEntity<byte[]>( headers, HttpStatus.OK);// 下载PDFheaders.setContentDispositionFormData("attachment", pdName);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);return new ResponseEntity<byte[]>(ini.toByteArray(), headers, HttpStatus.OK);} catch (DocumentException e) {e.printStackTrace();}// 返回错误信息headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}
如果非要使用第一种方式的话只需要下面这一个方法就行了
public static void downloadFile(String path, HttpServletResponse response) {try {// path是指欲下载的文件的路径。File file = new File(path);// 取得文件名。String filename = file.getName();// 以流的形式下载文件。InputStream fis = new BufferedInputStream(new FileInputStream(path));byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();// 清空responseresponse.reset();// 设置response的Headerresponse.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));response.addHeader("Content-Length", "" + file.length());OutputStream toClient = new BufferedOutputStream(response.getOutputStream());response.setContentType("application/octet-stream");toClient.write(buffer);toClient.flush();toClient.close();} catch (IOException ex) {ex.printStackTrace();}}
/*** PDF 文件导出*/@GetMapping(value = "/pdfDow")public ResponseEntity<?> export1(HttpServletRequest request, HttpServletResponse response){try {int a=1/0;PdfDownLoadUtils.downloadFile(ResourceFileUtil.getAbsolutePath("PDF/student.pdf"),response);} catch (Exception e) {e.printStackTrace();}HttpHeaders headers = new HttpHeaders();// 失败返回错误信息headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}table.addCell("row 2; cell 1");table.addCell("row 2; cell 2");doc.add(table);doc.close();}}
核心代码
/*** PDF 文件导出*/@GetMapping(value = "/pdfDow")public ResponseEntity<?> export1(HttpServletRequest request, HttpServletResponse response) {HttpHeaders headers = new HttpHeaders();String pdName="student.pdf"; //文件名称//设置页面编码格式try {ByteArrayOutputStream ini = PdfDownLoadUtils.ini();
// 页面打开PDF 不下载
// response.setContentLength(ini.size());
// OutputStream out = response.getOutputStream();
// ini.writeTo(out);
// return new ResponseEntity<byte[]>( headers, HttpStatus.OK);// 下载PDFheaders.setContentDispositionFormData("attachment", pdName);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);return new ResponseEntity<byte[]>(ini.toByteArray(), headers, HttpStatus.OK);} catch (DocumentException e) {e.printStackTrace();}// 返回错误信息headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}
SpringBoot-iText-Pdf相关推荐
- springBoot+itext处理富文本转pdf
springBoot+itext处理富文本转pdf pom文件引入依赖 html转PDF方法 处理不换行 创建包 新增Breaker.java类 pom文件引入依赖 <!-- itext5 st ...
- springboot集成PDF导出
内容目录 知识准备 什么是itext itext的历史版本和License问题 标准的itextpdf导出的步骤 实现案例 Pom依赖 导出PDF 添加页眉页脚和水印 进一步理解 遇到license问 ...
- SpringBoot 将PDF转成图片或Word
SpringBoot 将PDF转成图片或Word 准备工作 Apache PDFBox 将PDF转成一张图片 将PDF转成多张图片 将PDF转成其他文件格式 总结 SpringBoot 是一款非常流行 ...
- SpringBoot 实现 PDF 添加水印
SpringBoot 实现 PDF 添加水印 使用场景 方式一:使用 Apache PDFBox 库 方式二:使用 iText 库 方式三:Free Spire.PDF for Java Demo 使 ...
- # Itext Pdf 生成、相关API
Itext Pdf 生成.相关API 需求 需求java代码生成PDF效果如下:后端生成 Pdf文件,内容包含基本信息表格,图片.pdf需要有页眉,pdf每页含有页码,pdf含有多页. 上图看看最后生 ...
- # Itext Pdf 5 教程
Itext Pdf 5 教程 Itext Pdf Itext7收费,故使用Itext5传统版,Itext5不再维护 官网:iText 5 |iText PDF Itext5 Java Api 地址:i ...
- springboot操作pdf(二)之合并pdf
系列文章目录 文章列表 1. springboot操作pdf(一)之word转pdf 文章目录 系列文章目录 前言 一.pdfbox是什么? 二.使用步骤 1.导入依赖 2.合并pdf的代码如下 总结 ...
- itext pdf 合并会翻转方向的问题. 修复方法.
itext pdf 合并会翻转方向的问题. 修复方法. itext pdf 在处理合并多个页面的时候. 有两种方法 一种是直接用itext 的Write 控制输出. 另外一种方法是使用 PdfCopy ...
- springboot itext下载pdf
1.在pom.xml文件中配置itext的依赖包 <!-- itext方式导出pdf --><dependency><groupId>com.lowagie< ...
- SpringBoot 导出 PDF 图表(折现图、饼状图等)
主要是基于 jfreechart + itext <dependencies><dependency><groupId>org.springframework.bo ...
最新文章
- 2018年,关于CAP最精彩的小故事!
- Extjs 4.0.7 中模式窗口的CURD
- 一生一世高圆圆经典台词
- java中static x 5_java中static作用详解
- c++ string 删除字符_字符串操作的全面总结(附完整代码)
- windows安装nvm
- MTK 驱动---(11) EMI定制
- sas数字转日期格式_[转载]SAS日期格式输出格式大全
- 使用windbg通过vtable找到优化后的this指针
- linphone android下载,Linphone | F-Droid - Free and Open Source Android App Repository
- 好听无损的flac格式歌曲怎么转换成mp3格式的
- 软考中级网络工程师学习技巧
- 百度 php 图片文字识别,使用百度接口实现图片识别文字
- 计算上周一开始时间戳
- 微信小程序秀才成语接龙趣味答题小游戏带流量主源码
- 计算机专业本科毕业论文字数要求,计算机科学与技术专业本科毕业设计论文要求...
- c语言程序设计教学要求,C语言程序设计教学中的问题及改革建议①
- Kafka知识总结之Broker原理总结
- asp.net夜话之九:验证控件
- android调用在线天气服务,android通过google api获取天气信息示例