天天看點

iText操作PDF問題總結

這個星期我的任務就是處理一些報表的列印問題,因為我算項目組裡對jasperreport比較熟悉的了,這個東東也是我引進到這個項目。ireport畫報表,使用struts的action輸出pdf到浏覽器,這是我們目前的解決方案。今天遇到一個ireport解決不了的要求——合并單元格。類似下面這樣的表結構:

----------------------------------------------

          |          |__c_____________

   dept   | value    |__b_____________

          |          |  a

--------------------------------------------------------

也就是需要跨行,跨列!-_-。在html表格中解決這個很簡單,隻要設定單元格的colspan和rowspan即可。我在ireport沒有找到解決方案,如果您知道,請不吝賜教。查找資料弄了兩個小時沒進展,決定自己用itext寫吧,通過google、baidu資料順利達到了我的要求,僅在此記錄下遇到的問題和解決方法。

一。一個helloworld執行個體:

package com.lowagie.examples.general;

import java.io.fileoutputstream;

import java.io.ioexception;

import com.lowagie.text.*;

import com.lowagie.text.pdf.pdfwriter;

/**

 * generates a simple 'hello world' pdf file.

 *

 * @author blowagie

 */

public class helloworld {

 * generates a pdf file with the text 'hello world'

 * @param args no arguments needed here

public static void main(string[] args) {

system.out.println("hello world");

// step a: creation of a document-object

      document document = new document();

try {

// step b:

// we create a writer that listens to the document

// and directs a pdf-stream to a file

        pdfwriter.getinstance(document,new fileoutputstream("helloworld.pdf"));

// step c: we open the document

        document.open();

// step d: we add a paragraph to the document

        document.add(new paragraph("hello world"));

} catch (documentexception de) {

system.err.println(de.getmessage());

} catch (ioexception ioe) {

system.err.println(ioe.getmessage());

}

// step e: we close the document

        document.close();

可以看到一個pdf檔案的輸出,總共隻需要5個步驟

a.建立一個document執行個體

document document = new document();

b.将document執行個體和檔案輸出流用pdfwriter類綁定在一起

pdfwriter.getinstance(document,new fileoutputstream("helloworld.pdf"));

c.打開文檔

document.open();

d.在文檔中添加文字

document.add(new paragraph("hello world"));

e.關閉文檔

document.close();

這樣5個步驟,就可以生成一個pdf文檔了。

二。如何使用jsp、servlet輸出itext生成的pdf?

  如果每次都在服務端生成一個pdf檔案給使用者,不僅麻煩,而且浪費伺服器資源,最好的方法就是以二進制流的形式輸送到用戶端。

1)jsp輸出:

<%@ page import="java.io.*,java.awt.color,com.lowagie.text.*,com.lowagie.text.pdf.*"%>

<%

response.setcontenttype

( "application/pdf" );

document document = new document();

bytearrayoutputstream buffer

= new bytearrayoutputstream();

pdfwriter writer=

pdfwriter.getinstance( document, buffer );

document.add(new paragraph("hello world"));

dataoutput output =

new dataoutputstream

( response.getoutputstream() );

byte[] bytes = buffer.tobytearray();

response.setcontentlength(bytes.length);

for( int i = 0;

i < bytes.length;

i++ )

{

output.writebyte( bytes[i] );

%>

2)servlet輸出,稍微改造下就可以使用在struts中:

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import com.lowagie.text.pdf.*;

public void doget

(httpservletrequest request,

httpservletresponse response)

throws ioexception,servletexception

document document =

new document(pagesize.a4, 36,36,36,36);

bytearrayoutputstream ba

try

pdfwriter writer =

pdfwriter.getinstance(document, ba);

document.add(new

paragraph("hello world"));

catch(documentexception de)

de.printstacktrace();

system.err.println

("a document error:" +de.getmessage());

("application/pdf");

response.setcontentlength(ba.size());

servletoutputstream out

= response.getoutputstream();

ba.writeto(out);

out.flush();

三。如何輸出中文?

    首先需要下載下傳itextasian.jar包,可以到itext的主站上下,ireport也是需要這個包的。然後定義中文字型:

    private static final font getchinesefont() {

        font fontchinese = null;

        try {

            basefont bfchinese = basefont.createfont("stsong-light",

                    "unigb-ucs2-h", basefont.not_embedded);

            fontchinese = new font(bfchinese, 12, font.normal);

        } catch (documentexception de) {

            system.err.println(de.getmessage());

        } catch (ioexception ioe) {

            system.err.println(ioe.getmessage());

        }

        return fontchinese;

    }

我将産生中文字型封裝在方法内,自定義一個段落pdfparagraph繼承自paragraph,預設使用中文字型:

class pdfparagraph extends paragraph {

        public pdfparagraph(string content) {

            super(content, getchinesefont());

使用的時候就可以簡化了:

paragraph par = new pdfparagraph("你好");

四。如何設定pdf橫向顯示和列印?

rectangle rectpagesize = new rectangle(pagesize.a4);// 定義a4頁面大小

rectpagesize = rectpagesize.rotate();// 加上這句可以實作a4頁面的橫置

document doc = new document(rectpagesize,50,50,50,50);//4個參數,設定了頁面的4個邊距

五。如何設定跨行和跨列?

使用pdfptable和pdfpcell 是沒辦法實作跨行的,隻能跨列,要跨行使用com.lowagie.text.table和com.lowagie.text.cell類,cell類有兩個方法:setrowspan()和setcolspan()。

六。如何設定單元格邊界寬度?

cell類的系列setborderwidthxxxx()方法,比如setborderwidthtop(),setborderwidthright()等

七。如何設定表頭?

希望每一頁都有表頭,可以通過設定表頭來實作。對于pdfptable類來說,可以這樣設定:

pdfptable table = new pdfptable(3);

table.setheaderrows(2); // 設定了頭兩行為表格頭

而對于om.lowagie.text.table類,需要在添加完所有表頭的單元格後加上一句代碼:

table.endheaders();

八。如何設定列寬?

table table = new table(8);

float[] widths = { 0.10f, 0.15f, 0.21f, 0.22f, 0.08f, 0.08f, 0.10f,

                    0.06f };

table.setwidths(widths);

上面的代碼設定了一個有8列的表格,通過一個float數組設定列寬,這裡是百分比。

九。單元格内段落文字居中和換行?

居中通過cell類來設定,一開始我以為設定段落對齊就可以了,沒想到是需要設定單元格:

cell.sethorizontalalignment(element.align_center);

轉義符\n實作。在我的這個應用中,因為資料庫取出的資料是為了顯示在html上的,是以有很多<br>标簽,可以使用正規表達式替換成"\n"

"<br>1.測試<br>2.測試2".replaceall("<br>|</br>","\n");

十。如何顯示頁碼?

複雜的頁碼顯示和水印添加,需要使用到pdfpageeventhelper、pdftemplate等輔助類,具體的例子參見itext的文檔,如果隻是為了簡單的顯示頁數,可以使用下面的代碼:

            headerfooter footer = new headerfooter(new phrase("頁碼:",getchinesefont()), true);

            footer.setborder(rectangle.no_border);

            document.setfooter(footer);

            document.open();

你可能注意到了,添加footer需要在document.open之前。