这个星期我的任务就是处理一些报表的打印问题,因为我算项目组里对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之前。