`

利用itext操作pdf从数据库导出大量数据--功能汇总(一)

阅读更多
【原始需求】
通过SQL及JDBC模式导出各类业务数据,以PDF文件格式存放,要求该文件只能查看和打印(不能编辑和篡改),文件要有公司相关标志和水印功能。

【需求分析】
1、 通过SQL及JDBC模式导出业务数据,业务数据以表格内容格式存放于PDF文件
2、 PDF文件注明版权
3、 PDF页面中增加水印,公司文字或图片

【设计分析】
1、 生成PDF文件
2、 PDF文件注明版权
3、 PDF增加文字和图片水印
4、 PDF表格列数可能很多,比如1-50列信息,导出时需判断A4纸格式或其他格式宽度。
5、 PDF表格行数量可能超大,比如10万以上,甚至100万以上。
6、 增加水印信息后,文件大小增量应比较小,比如小于5%。

【功能开发】
1、 生成PDF文件
2、 支持中文字体
3、 PDF文件内容为表格,表格有表头
4、 PDF文件内容支持中文,表格内容上下居中,左右居中或左对齐/右对齐
5、 PDF列信息多寡不同,PDF采用页面宽度也能根据列信息按比例调整
6、 PDF行信息超大时写入模式,不能引起内存溢出等问题,有一定的并发性支撑能力。
7、 PDF文件增加作者相关版权信息
8、 PDF页头增加版权相关信息
9、 PDF文件修改权限限制,实现文档只可读取的权限
10、 PDF文件增加文字或图片水印功能,要求文字或图片在整个页面清晰可见。增加的水印信息不能使PDF文件大小增长超过5%。
11、 对PDF文件进行加密

【开发总结】
1、 大数据量写入的内存溢出问题采用文件流模式解决
2、 图片水印需要采用单例图片对象来处理,避免增加图片水印后PDF文件大小猛增
3、 PDF文件生成时,特别是当表格数据比较大时,CPU和JVM内存资源消耗都比较高,这样系统并发性较低。个人笔记本电脑单PDF文件导出时,CPU资源使用率在30%左右,JVM内存资源达到堆大小的极限,因为垃圾回收的缘故避免了内存溢出(已按流式数据处理方式)。
4、 水印的位置需要根据PDF页面大小和水印本身的信息位置范围来确定

利用itext操作pdf从数据库导出大量数据--功能汇总(一)

利用itext操作pdf从数据库导出大量数据--创建PDF相关(二)

利用itext操作pdf从数据库导出大量数据--创建PDF表格(三)

利用itext操作pdf从数据库导出大量数据--添加水印(四)

package com.fruitking.testpdf.util;

import java.awt.Color;
import java.io.IOException;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;

public class PdfFileExportUtil {
	
	private static Font pdf8Font = null;
	private static Font pdf20Font = null;
	
	/**
	 * 设置PDF创建者信息
	 * @param pdfDocument
	 */
	public static Document setCreatorInfo(Document pdfDocument){
		if(pdfDocument==null){
			return null;
		}
		//文档属性
        pdfDocument.addTitle("水果大王信息技术有限公司数据安全产品");
        pdfDocument.addAuthor("杭州水果大王信息技术有限公司");
        pdfDocument.addSubject("文件导出的信息安全管控");
        pdfDocument.addKeywords("文件导出,信息安全");//文档关键字信息
        pdfDocument.addCreator("水果大王文件取数系统");//应用程序名称
        return pdfDocument;
    }
	
	
	/**
	 * 获取中文字符集且是8号字体,常用作表格内容的字体格式
	 * @param fullFilePath
	 */
	public static Font getChinese8Font()throws DocumentException,IOException{
		if(pdf8Font==null){
    		//设置中文字体和字体样式
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);  
            pdf8Font = new Font(bfChinese, 8, Font.NORMAL);
    	}
    	return pdf8Font;      
    }
	
	/**
	 * 获取中文字符集且是8号字体,常用作文字水印信息
	 * @param fullFilePath
	 */
	public static Font getChinese20Font()throws DocumentException,IOException{
		if(pdf20Font==null){
    		//设置中文字体和字体样式
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);  
            pdf20Font = new Font(bfChinese, 20, Font.BOLD, Color.CYAN);
    	}
    	return pdf20Font;      
    }
	
	/**
	 * 设置成只读权限
	 * @param pdfWriter
	 */
	public static PdfWriter setReadOnlyPDFFile(PdfWriter pdfWriter)throws DocumentException{
		pdfWriter.setEncryption(null, null,PdfWriter.ALLOW_PRINTING, PdfWriter.STANDARD_ENCRYPTION_128);
		return pdfWriter;
    }
	
	/**
	 * 变更一个图片对象的展示位置和角度信息
	 * @param waterMarkImage
	 * @param xPosition
	 * @param yPosition
	 * @return
	 */
	public static Image getWaterMarkImage(Image waterMarkImage,float xPosition,float yPosition){
    	waterMarkImage.setAbsolutePosition(xPosition, yPosition);//坐标
    	waterMarkImage.setRotation(-20);//旋转 弧度
    	waterMarkImage.setRotationDegrees(-45);//旋转 角度
    	waterMarkImage.scalePercent(100);//依照比例缩放
        return waterMarkImage;
    }
	
	/**
	 * 为PDF分页时创建添加文本水印的事件信息
	 */
	class TextWaterMarkPdfPageEvent extends PdfPageEventHelper{
		
		private String waterMarkText;
		
		public TextWaterMarkPdfPageEvent(String waterMarkText){
			this.waterMarkText = waterMarkText;
		}
		
		public void onEndPage(PdfWriter writer, Document document) {
	        try{
		        float pageWidth = document.right()+document.left();//获取pdf内容正文页面宽度
		        float pageHeight = document.top()+document.bottom();//获取pdf内容正文页面高度
		        //设置水印字体格式
		        Font waterMarkFont = PdfFileExportUtil.getChinese20Font();
		        PdfContentByte waterMarkPdfContent = writer.getDirectContentUnder();
		        Phrase phrase = new Phrase(waterMarkText, waterMarkFont);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.25f,pageHeight*0.2f,45);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.25f,pageHeight*0.5f,45);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.25f,pageHeight*0.8f,45);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.65f,pageHeight*0.2f,45);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.65f,pageHeight*0.5f,45);
		        ColumnText.showTextAligned(waterMarkPdfContent,Element.ALIGN_CENTER,phrase,  
	                    pageWidth*0.65f,pageHeight*0.8f,45);
	        }catch(DocumentException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }catch(IOException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }
	    }
	}
	
	/**
	 * 为PDF分页时创建添加图片水印的事件信息
	 */
	class PictureWaterMarkPdfPageEvent extends PdfPageEventHelper{
		
		private String waterMarkFullFilePath;
		private Image waterMarkImage;
		
		public PictureWaterMarkPdfPageEvent(String waterMarkFullFilePath){
			this.waterMarkFullFilePath = waterMarkFullFilePath;
		}
		
		public void onEndPage(PdfWriter writer, Document document) {
	        try{
		        float pageWidth = document.right()+document.left();//获取pdf内容正文页面宽度
		        float pageHeight = document.top()+document.bottom();//获取pdf内容正文页面高度
		        PdfContentByte waterMarkPdfContent = writer.getDirectContentUnder();
	            //仅设置一个图片实例对象,整个PDF文档只应用一个图片对象,极大减少因为增加图片水印导致PDF文档大小增加
		        if(waterMarkImage == null){
		        	waterMarkImage = Image.getInstance(waterMarkFullFilePath);
		        }
                //添加水印图片,文档正文内容采用横向三列,竖向两列模式增加图片水印
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.2f,pageHeight*0.1f));
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.2f,pageHeight*0.4f));
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.2f,pageHeight*0.7f));
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.6f,pageHeight*0.1f));
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.6f,pageHeight*0.4f));
                waterMarkPdfContent.addImage(getWaterMarkImage(waterMarkImage,pageWidth*0.6f,pageHeight*0.7f));
                PdfGState gs = new PdfGState();
                gs.setFillOpacity(0.2f);//设置透明度为0.2
                waterMarkPdfContent.setGState(gs);
	        }catch(DocumentException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }catch(IOException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }
	    }
	}
	
	/**
	 * 为PDF分页时创建添加header和footer信息的事件信息
	 */
	class HeadFootInfoPdfPageEvent extends PdfPageEventHelper{
		
		public HeadFootInfoPdfPageEvent(){
		}
		
		public void onEndPage(PdfWriter writer, Document document) {
	        try{
	        	PdfContentByte headAndFootPdfContent = writer.getDirectContent();
	        	headAndFootPdfContent.saveState();
	        	headAndFootPdfContent.beginText();
	        	BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    	        headAndFootPdfContent.setFontAndSize(bfChinese, 10);
    	        //文档页头信息设置
    	        float x = document.top(-20);
    	        //页头信息左面
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_LEFT,
    	                           "数据安全产品",
    	                           document.left(), x, 0);
    	        //页头信息中间
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_CENTER,
    	                            "第"+writer.getPageNumber()+ "页",
    	                           (document.right() + document.left())/2,
    	                           x, 0);
    	        //页头信息右面
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_RIGHT,
    	                           "杭州水果大王信息技术有限公司",
    	                           document.right(), x, 0);
    	        //文档页脚信息设置
    	        float y = document.bottom(-20);
    	        //页脚信息左面
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_LEFT,
    	                           "--",
    	                           document.left(), y, 0);
    	        //页脚信息中间
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_CENTER,
    	                            "-",
    	                           (document.right() + document.left())/2,
    	                           y, 0);
    	        //页脚信息右面
    	        headAndFootPdfContent.showTextAligned(PdfContentByte.ALIGN_RIGHT,
    	                           "--",
    	                           document.right(), y, 0);
    	        headAndFootPdfContent.endText();
    	        headAndFootPdfContent.restoreState();
	        }catch(DocumentException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }catch(IOException de) {
	            de.printStackTrace();
	            System.err.println("pdf watermark font: " + de.getMessage());
	        }
	    }
	}
}


package com.fruitking.testpdf.util;

import java.awt.Color;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

public class PdfFileExport {
	
	/**
	 * 从数据库中导出数据并以PDF文件形式存储
	 * 列信息较多,行信息可能超过100万
	 * 文档仅有只读权限,设置文档作者信息
	 * 在文档页头设置公司信息版权信息
	 * 添加公司的文字和图片水印信息
	 * @param fullFilePath
	 * @param tableContent
	 * @param rowsNumber
	 * @param submitAmount
	 * @return
	 */
	public boolean exportTableContent(String fullFilePath,String[][] tableContent,int rowsNumber,int submitAmount){
		Document pdfDocument = new Document(PageSize.A2,50,50,50,50);
        try {
        	//构建一个PDF文档输出流程
        	OutputStream pdfFileOutputStream = new FileOutputStream(new File(fullFilePath));
        	PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument,pdfFileOutputStream);
        	//设置作者信息
        	PdfFileExportUtil.setCreatorInfo(pdfDocument);
        	//设置文件只读权限
        	PdfFileExportUtil.setReadOnlyPDFFile(pdfWriter);
        	//通过PDF页面事件模式添加文字水印功能
        	PdfFileExportUtil pdfFileExportUtil = new PdfFileExportUtil();
        	pdfWriter.setPageEvent(pdfFileExportUtil.new TextWaterMarkPdfPageEvent("杭州水果大王信息技术"));
        	//通过PDF页面事件模式添加图片水印功能
        	String waterMarkFullFilePath = "D:/temp/pdftest/login_logo.gif";//水印图片
        	pdfWriter.setPageEvent(pdfFileExportUtil.new PictureWaterMarkPdfPageEvent(waterMarkFullFilePath));
        	//通过PDF页面事件模式添加页头和页脚信息功能
        	pdfWriter.setPageEvent(pdfFileExportUtil.new HeadFootInfoPdfPageEvent());
        	//设置中文字体和字体样式
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);  
            Font f8 = new Font(bfChinese, 8, Font.NORMAL);
            //打开PDF文件流
        	pdfDocument.open();
            //创建一个N列的表格控件
            PdfPTable pdfTable = new PdfPTable(tableContent[0].length);
            //设置表格占PDF文档100%宽度
            pdfTable.setWidthPercentage(100);
            //水平方向表格控件左对齐
            pdfTable.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);
            //创建一个表格的表头单元格
            PdfPCell pdfTableHeaderCell = new PdfPCell();
            //设置表格的表头单元格颜色
            pdfTableHeaderCell.setBackgroundColor(new Color(213, 141, 69));
            pdfTableHeaderCell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
            for(String tableHeaderInfo : tableContent[0]){
            	pdfTableHeaderCell.setPhrase(new Paragraph(tableHeaderInfo, f8));
            	pdfTable.addCell(pdfTableHeaderCell);
            }
            //创建一个表格的正文内容单元格
            PdfPCell pdfTableContentCell = new PdfPCell();
            pdfTableContentCell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
            pdfTableContentCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
            //表格内容行数的填充
            for(int i = 0;i < rowsNumber;i++){
	            for(String tableContentInfo : tableContent[1]){
	            	pdfTableContentCell.setPhrase(new Paragraph(tableContentInfo, f8));
	            	pdfTable.addCell(pdfTableContentCell);
	            }
	            //表格内容每写满某个数字的行数时,其内容一方面写入物理文件,另一方面释放内存中存留的内容。
	            if((i%submitAmount)==0){
	            	pdfDocument.add(pdfTable);
	            	pdfTable.deleteBodyRows();
                }else if(i==rowsNumber){
                	//如果全部类容完毕且又没达到某个行数限制,则也要写入物理文件中。
                	pdfDocument.add(pdfTable);
                	pdfTable.deleteBodyRows();
                }
            }
            return true;
        }catch(FileNotFoundException de) {
            de.printStackTrace();
            System.err.println("pdf file: " + de.getMessage());
            return false;
        }catch(DocumentException de) {
            de.printStackTrace();
            System.err.println("document: " + de.getMessage());
            return false;
        }catch(IOException de) {
            de.printStackTrace();
            System.err.println("pdf font: " + de.getMessage());
            return false;
        }finally{
            //关闭PDF文档流,OutputStream文件输出流也将在PDF文档流关闭方法内部关闭
        	if(pdfDocument!=null){
        		pdfDocument.close();
        	}
        }        
    }
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String[][] tableContent = new String[][]{
				{"序号","姓名","年龄","职业","籍贯","学历","单位名称","联系电话","联系地址",
					"语文","数学","英语","物理","化学","生物","政治","历史","地理","音乐","美术","体育","课外实践","学校名称","备注"},
				{"1","许果","31","软件工程师","浙江杭州","大学本科","浙江水果大王信息技术有限公司","18905710571","浙江省杭州市西湖区三墩镇三墩街188号",
						"85","95","75","90","90","85","80","90","90","75","65","75","80","石城中学","他是一名优秀的IT工程师,日常爱好旅游,运动"}
		};
		PdfFileExport pdfFileExport = new PdfFileExport();
		pdfFileExport.exportTableContent("D:/temp/pdftest/41导出PDF文档.pdf", tableContent, 100000, 2000);
	}
	
}

  • 大小: 3.5 KB
分享到:
评论
2 楼 北方狼 2015-11-12  
请问,当表格列数过多时,除了调整pdf页面宽度,能否设置分页显示?
1 楼 weir2009 2013-10-21  
复杂的交叉表crosstab  怎么处理?

相关推荐

    利用itext操作pdf从数据库导出大量数据--汇总(一)

    这篇博客"利用iText操作PDF从数据库导出大量数据--汇总(一)"显然讨论了如何利用iText将数据库中的数据高效地导出到PDF文件中,这对于报告生成、数据分析或者报表制作等场景非常有用。 首先,我们需要了解iText的...

    PDF表格数据的提取合并CSV, PDF文件从服务器上传下载,

    在eDataLoggerWebLite这个项目中,我们可以推测它是一个轻量级的Web应用,专注于PDF表格的操作,提供用户友好的界面进行表格填写、提交、上传下载以及数据的提取和合并。开发这样的系统需要深入理解PDF处理技术,...

    freemaker导出word的doc_docx_带动态图片及word转pdf工具类_jar_万能整理汇总rengm.zip

    在Freemarker中,我们可以利用Java代码将图片数据嵌入到模板中,比如从数据库获取图片的Base64编码,然后在Word文档中展示。这在生成报告时非常有用,例如根据用户数据生成个性化的图表或照片。 接下来,我们讨论...

    PB9打印文件成pdf.rar

    压缩包内的文件名"新建文本文档 (2).txt"可能包含了一些关于如何使用这个转换功能的说明或代码示例,而"PB9导出PDF可支持多次打印在同份PDF中"可能是一个源代码文件或一个执行脚本,实现了在一份PDF文档中合并多个...

    java+sql server,工资管理信息系统,源程序+数据库+报告

    通过Java的报表工具,如iText或JasperReports,根据需求生成各种工资报告,如月度工资报表、年度总结报告等,支持导出为PDF、Excel等格式,方便打印和分发。 综上所述,"Java+SQL Server"的工资管理信息系统集成了...

    ireport+jasperReport+Swing总结.doc

    - **用途**:ireport 是一个用于设计报表的图形用户界面工具,它允许用户通过简单的拖拽操作来构建复杂的报表布局。 - **版本**:本文档基于 ireport 4.1.3 版本进行讲解。 - **下载地址**:...

    jasperreports-6.1.1_all_jar.rar资源包下载.zip

    它支持SQL查询,能动态处理数据集,提供数据汇总、分组等功能。 3. **图表生成**:JasperReports内置了多种图表类型,如柱状图、饼图、线图等,可以自定义颜色、样式,使得报表更具视觉吸引力。 4. **导出功能**:...

    iReport web开发配置向导

    6. **汇总区域**:用于展示整个报表的数据汇总信息。 ##### 3.3 数据查询 1. **SQL 查询**:可以直接编写 SQL 语句来获取数据。 2. **参数化查询**:支持通过参数化的方式执行 SQL 语句。 3. **变量管理**:可以...

    软件工程课程设计 教师工资管理系统

    4. 报表生成模块:利用Java的报表库如iText或JasperReports生成各类报表,支持导出为PDF或Excel格式。 四、Java技术应用 本系统选用Java作为开发语言,原因在于Java具有跨平台性、丰富的类库和强大的社区支持。使用...

    JasperReport jar

    4. **报表分组和汇总**:JasperReport支持基于字段的分组,并可以对分组进行总计、平均、最大值、最小值等统计操作。 5. **多格式输出**:JasperReport能够导出报表为多种格式,满足不同需求。例如,PDF适合打印,...

    jasperreports-1.3.3与iReport1.3.3初级使用

    在使用JasperReports时,你需要依赖一些第三方库,例如:itext-1.3.1.jar用于PDF生成,jfreechart-1.0.0.jar用于图表绘制,poi-2.5.1.jar用于处理Excel数据,mysql.jar用于连接MySQL数据库。这些库在压缩包文件中已...

    java 报表例子.rarjava 报表例子.rarjava 报表例子.rarjava 报表例子.rar

    在Java中,开发报表通常涉及选择一个适合的报表库,如JFreeReport、iText、JasperReports、BIRT等,这些库提供了丰富的功能,包括数据检索、格式化、分组、排序、过滤以及复杂的图表绘制。 JasperReports是Java世界...

    jasperreport完整的jar包

    通常,为了在项目中使用 JasperReport,我们需要下载一系列的 JAR 文件,这些文件包括 JasperReport 自身的核心组件以及它的依赖库,例如 iText(用于 PDF 输出)、JFreeChart(用于图表绘制)等。 描述 ...

    基于Springboot的员工工资管理系统.zip

    同时,如果需要导出Excel或PDF格式,可以借助Apache POI或iText等库。 在安全方面,Spring Security是Springboot默认的安全框架,它可以提供用户认证和授权功能,保护系统免受非法访问。开发者可以根据需求配置权限...

Global site tag (gtag.js) - Google Analytics