有個朋友的項目需要用到 PDF 報表下載,之前我只做過 Excel 的,相信再做一次 PDF 的下載一定很有趣吧。在網上找了一大圈,似乎 iText 比較符合我的要求,而且這個工具很早很早以前就有了,生命力很旺盛。進入 iText 的主頁(http://www.lowagie.com/iText/),發現作者很勤勞,最近2個月都有新版本發布。哪知道現在高興得太早了,一堆問題接踵而至。
下載倒是很簡單,一個
iText-2.1.4.jar搞定,然后去找入門文檔,進了文檔頁面,一股濃郁的商業氣氛迎面而來,這里只提供了部分文檔,除非去買"iText in Action",隨后被踢到 iText by Example 頁面。好吧,既然這是老牌工具了,肯定有不少中文資料吧,找了一圈,沒發現什么和生成并下載相關的 out of box 文檔,很多都是經驗性的總結和進階文章。無奈又啃 iText by Example,在這里找到些有用的資源,
iText in a Web Application正是我要找的,不過這個例子很簡單。通過 Google 之后,又發現要下載一個 CJK 的包(iTextAsian.jar)才能正確顯示中文,好吧我去找。很幸運的是在 iText by Example 里找到了這個 jar 的 link,興致勃勃的跑去下載,結果這是個無效鏈接,最后在 sourceForge 上才找到,不容易啊。解決了這些問題,想必能夠安穩的使用了吧,由于這個項目比較急,沒什么耐心一個個的翻閱 iText by Example,想找點捷徑,據說 iText 可以從 html 直接生成 PDF,竊喜!找了 apache common 的 httpclient,動態模擬 http 請求來抓 html,根據控制臺的 print,的確把 html 抓到了,然后開始轉換到 PDF,先解決了中文顯示問題,可是后面的問題解決不了了,html 的 table 和 div 這些,轉換到 PDF 都走樣了... ...
很不爽,看來還是只有老老實實的啃 iText by Example實在點。這次稍微耐心點,一點點的看,首先搞清楚了它的 Font 設置,然后是 Table 和 Cell 的關系,經過反復調試,有點效果了。把代碼貼出來,做個標記吧。以免以后又抓狂。
1 package org.rosenjiang.servlet;
2
3 import java.awt.Color;
4 import java.io.IOException;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13
14 import org.springframework.web.context.WebApplicationContext;
15 import org.springframework.web.context.support.WebApplicationContextUtils;
16
17 import org.rosenjiang.service.UserService;
18 import com.lowagie.text.Document;
19 import com.lowagie.text.DocumentException;
20 import com.lowagie.text.Font;
21 import com.lowagie.text.Paragraph;
22 import com.lowagie.text.pdf.BaseFont;
23 import com.lowagie.text.pdf.PdfPCell;
24 import com.lowagie.text.pdf.PdfPTable;
25 import com.lowagie.text.pdf.PdfWriter;
26
27 /*
28 * ReportServlet
29 * @author rosen jiang
30 * @since 2008-12
31 */
32 public class ReportServlet extends HttpServlet {
33
34 /**
35 * Return a PDF document for download.
36 *
37 */
38 public void doGet (HttpServletRequest request, HttpServletResponse response)
39 throws IOException, ServletException {
40 String account_id = request.getParameter("account_id");
41 String search_date_from = request.getParameter("search_date_from");
42 String to = request.getParameter("to");
43 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
44 UserService userService = (UserService)ctx.getBean("userService");
45 List<Map<String, Object>> list = userService.getAccountActivity(account_id, search_date_from, to);
46 // create PDF document
47 Document document = new Document();
48 try {
49 //set response info
50 response.setContentType("application/x-msdownload;charset=UTF-8");
51 response.setHeader("Content-Disposition","attachment;filename=report.pdf");
52 //open output stream
53 PdfWriter.getInstance(document, response.getOutputStream());
54 // open PDF document
55 document.open();
56 // set chinese font
57 BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
58 Font f2 = new Font(bfChinese, 2, Font.NORMAL);
59 Font f6 = new Font(bfChinese, 6, Font.NORMAL);
60 Font f8 = new Font(bfChinese, 8, Font.NORMAL);
61 Font f10 = new Font(bfChinese, 10, Font.NORMAL);
62 Font f12 = new Font(bfChinese, 12, Font.BOLD);
63 //set title
64 document.add(new Paragraph("金融報表", f12));
65 //<br>
66 document.add(new Paragraph(" ",f6));
67 //set sub title
68 document.add(new Paragraph("賬戶信息", f10));
69 //<br>
70 document.add(new Paragraph(" ", f2));
71 //process business data
72 if(list.size()>0 && list.get(0).get("bankbook_no")!=null){
73 float openBalance = 0;
74 //create table with 7 columns
75 PdfPTable table = new PdfPTable(7);
76 //100% width
77 table.setWidthPercentage(100);
78 table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);
79 //create cells
80 PdfPCell cell = new PdfPCell();
81 //set color
82 cell.setBackgroundColor(new Color(213, 141, 69));
83 cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
84 //
85 cell.setPhrase(new Paragraph("交易日", f8));
86 table.addCell(cell);
87 cell.setPhrase(new Paragraph("類型", f8));
88 table.addCell(cell);
89 cell.setPhrase(new Paragraph("備注", f8));
90 table.addCell(cell);
91 cell.setPhrase(new Paragraph("ID", f8));
92 table.addCell(cell);
93 cell.setPhrase(new Paragraph("票號", f8));
94 table.addCell(cell);
95 cell.setPhrase(new Paragraph("合計", f8));
96 table.addCell(cell);
97 cell.setPhrase(new Paragraph("余額", f8));
98 table.addCell(cell);
99 //create another cell
100 PdfPCell newcell = new PdfPCell();
101 newcell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
102
103 Map<String, Object> map = new HashMap<String, Object>();
104 for(int i = 0; i < list.size(); i++){
105 map = list.get(i);
106 String cashInout = map.get("cash_inout").toString();
107 newcell.setPhrase(new Paragraph(map.get("trade_date").toString(), f8));
108 table.addCell(newcell);
109 newcell.setPhrase(new Paragraph(map.get("bankbook_type").toString(), f8));
110 table.addCell(newcell);
111 newcell.setPhrase(new Paragraph(map.get("memo").toString(), f8));
112 table.addCell(newcell);
113 newcell.setPhrase(new Paragraph(map.get("account_id").toString(), f8));
114 table.addCell(newcell);
115 newcell.setPhrase(new Paragraph(map.get("ticket_no").toString(), f8));
116 table.addCell(newcell);
117 newcell.setPhrase(new Paragraph(map.get("amount").toString(), f8));
118 table.addCell(newcell);
119 newcell.setPhrase(new Paragraph(openBalance+"", f8));
120 table.addCell(newcell);
121 if(cashInout.equals("I")){
122 openBalance = openBalance + Float.valueOf(map.get("amount").toString());
123 }else if(cashInout.equals("O")){
124 openBalance = openBalance - Float.valueOf(map.get("amount").toString());
125 }
126 }
127 //print total column
128 newcell.setPhrase(new Paragraph("合計"+openBalance, f8));
129 table.addCell("");
130 table.addCell("");
131 table.addCell("");
132 table.addCell("");
133 table.addCell("");
134 table.addCell("");
135 table.addCell(newcell);
136 document.add(table);
137 }else{
138 PdfPTable table = new PdfPTable(1);
139 table.setWidthPercentage(100);
140 table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);
141 PdfPCell cell = new PdfPCell(new Paragraph("暫無數據"));
142 cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
143 table.addCell(cell);
144 document.add(table);
145 }
146 }
147 catch(DocumentException de) {
148 de.printStackTrace();
149 System.err.println("document: " + de.getMessage());
150 }finally{
151 // close the document and the outputstream is also closed internally
152 document.close();
153 }
154 }
155 }
代碼結構清晰,本來也沒什么東西,就是通過 Spring 調用 service 方法,獲取數據后按照 iText 結構輸出即可。不過代碼里面有個很愚蠢的動作:
document.add(new Paragraph(" ",f6)),主要是找不到如何輸出空白行,所以只好出此下策。如果哪位有解法,請告知一下。
做技術的確不能太著急,慢慢來,總會找到出口的。
請注意!引用、轉貼本文應注明原作者:Rosen Jiang 以及出處:http://m.tkk7.com/rosen