做的Struts 項目中有這樣的功能,用戶可以將數據導出到Excel 報表,如圖1 所示。

圖1 報表樣式圖
1 設計思路
Java 對于Excel 的操作一般借助于POI 類庫,由于該報表的表頭比較復雜,直接用POI 控制報表的生成比較困難,這時可以先制作Excel 報表模板
,而后再通過Java 調用POI 函數將用戶數據寫入到Excel 報表模板,最后導出到新的目標文件即可。
2 設計步驟
2.1 Excel 報表模板
根據需要設計出Excel 報表,并保存為report.xls。該報表有復雜的表頭,報表第4 行為合計行,用于對所有數值型列的各行數據進行匯總,如圖1 所示。
2.2 Struts 的動作執行函數ExcelExportAction
該Action 函數在用戶需要執行報表導出時通過Struts 頁面調用或用戶觸發執行。
package com.tj.struts.action;
import java.io.FileOutputStream;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import databaseUtil.ExcelPoi;
public class ExcelExportAction extends Action {
public ActionForward execute ( ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response)
throws Exception {
//執行SQL 獲得輸出到報表的數據
String sql=" select * fron project" ;
//準備輸出的報表路徑,及文件名
String outputfile =" c:\\output.xls" ;
//制作好的報表模板存放路徑
String templatefile=" c:\\report.xls" ;
//模板的列數為39
int column=39;
try {
//實例化具體的業務處理類ExcelPoi
ExcelPoi pd = new ExcelPoi (colnum) ;
//getExcelSheet 以sql 為參數執行查詢,將查詢數據寫入模版文件“templatefile”的當前工作簿的選定工作表pd.getExcelSheeet (sql,templatefile) ;
// 新建以文件outputfile 為目標的輸出文件流
FileOutputStream fos = new FileOutputStream (outputfile) ;
//將工作簿寫入輸出文件流,得到輸出報表文件
pd.exportExcel (fos) ;
} catch (Exception e) {
e.printStackTrace () ;
} finally {
try {fos.close () ;
} catch (Exception e) {
e.printStackTrace () ;
}}
return mapping.findForward (" success") ;
}}
2.3 設計業務處理類ExcelPoi
package databaseUtil;
import java.io.*;
import java.sql.*;
import java.util.*;
import org.apache.poi.hssf.usermodel.*;
public class ExcelPoi {
private int columNumber = 0;
private int cellNumber=0;
private HSSFWorkbook workbook = null;
private HSSFSheet worksheet=null;
public ExcelPoi (int columNumber)
{this.columNumber=columNumber;}
<! —sql:傳入參數,實現輸出數據查詢,templatefile:傳入參數,Excel 模板的存放路徑-->
public void getExcelSheeet ( String sql,String templatefile)
throws SQLException
{try {
//新建以文件templatefile 為源文件的輸文件流,而后從中取得模板文件templatefile 的當前工作簿
workbook = new HSSFWorkbook ( new FileInputStream
(templatefile)) ;
} catch (FileNotFoundException e) {
e.printStackTrace () ;
} catch (IOException e) {
e.printStackTrace () ;}
//取得當前工作簿中的“天津大學工程項目庫管理系統”工作表
worksheet=workbook.getSheet (" 天津大學工程項目庫管
理系統") ;
//載入數據庫驅動,獲得數據庫的連接,數據庫名為tj,用戶名swm, 密碼adminClass.forName ( " com.microsoft.jdbc.sqlserver.SQLServerDriver") .newInstance () ;
dbConn = DriverManager.getConnection (" jdbc:microsoft:
sqlserver://localhost:1433;DatabaseName =tj" , " swm" , "
admin") ;
statement = dbConn.createStatement (ResultSet.
TYPE_SCROLL_INSENSITIVE,ResultSet.
CONCUR_UPDATABLE) ;
//以SQL 為參數,執行數據查詢
ResultSet rs = statement.executeQuery (sql) ;
int rowIndex = 4;
while (rs.next ())
{ List list = new ArrayList () ;
//將查詢得到的每行數據放入list 中
for (int i = 1;i <= columNumber;i++)
{list.add (rs.getString (i)) ; }
//調用createTableRow 把list 中數據寫入worksheet 的第rowIndex 行
createTableRow (worksheet,list, (short) rowIndex) ;
rowIndex++;}}
<! —-用list 數據創建當前工作表的第rowIndex 行,并將該行非String 數據累加到合計行行-->
public void createTableRow ( HSSFSheet worksheet1,List list,short rowIndex)
{//getRow (3) 取得工作表的第四行,即合計行(行數從0 開始)
HSSFRow sumrow = worksheet1.getRow (3) ;
for (short i = 0;i < list.size () ;i++)
{ HSSFCell cell = sumrow.getCell (i) ;
//將list 中1、2、3、4、6、7、8 列之外(這幾列為String 類型不進行合計),其它列數據累加到合計行的對應列單元中
if (! (i==0||i==1||i==2||i==3||i==5||i==6||i==7)) {
cell.setCellValue ( list.getNumericCellValue ( ) + ( double)
Integer.parseInt ((String) list.get (i))) ;
}}
//創建當前工作表的新行,等待放入數據
HSSFRow row = worksheet1.createRow ( ( short)rowIndex) ;
//在新創建行中創建各列單元格,并將list 中對應數據寫入
for (short i = 0;i < list.size () ;i++)
{HSSFCell cell = row.createCell ((short) i) ;
cell.setEncoding (HSSFCell.ENCODING_UTF_16) ;
cell.setCellValue ((String) list.get (i)) ; }
<! --該函數將存儲了數據的模板文件導出到輸出文件流,創建一個新的報表-->
public void exportExcel ( OutputStream os) throws
IOException
{worksheet.setGridsPrinted (true) ;
workbook.write (os) ;
}}
3 結語
對于一些要求非常苛刻的報表輸出可以借助于一些第三方插件,比如水晶報表等。在實際中可以隨心所欲地構建報表模板,而后通過程序控制將需要導出的數據導出到報表中,關鍵在于如何精確地控制數據導出的位置,保證數據在報表中的準確的位置,這是需要格外注意的。