这个星期我的任务就是处理一些报表的打印问题,因为我算项目组里对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.open(); document.add(
new
Paragraph(
"
Hello World
"
)); document.close(); 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.
*
;
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
=
new
ByteArrayOutputStream();
try
{ PdfWriter writer
=
PdfWriter.getInstance(document, ba); document.open(); document.add(
new
Paragraph(
"
Hello World
"
)); }
catch
(DocumentException de) { de.printStackTrace(); System.err.println (
"
A Document error:
"
+
de.getMessage()); } document.close(); response.setContentType (
"
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之前。
相关资源:敏捷开发V1.0.pptx