1. 程式人生 > >POI匯出excel表格優化

POI匯出excel表格優化

package com.ywj.excel;

import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

public class Excel {

	/**
	 * 
	* @Title: export
	* @Description: (通用匯出excel)
	* @param excelName   檔名
	* @param list    資料集合
	* @param fieldMap     資料庫欄位和表頭的值
	* @param response
	* @return void
	 */
	   public static  void export(String excelName,List<Map<String, Object>> list,LinkedHashMap<String, String> fieldMap,HttpServletResponse response){
		   // 設定預設檔名為當前時間:年月日時分秒
	        if (excelName==null || excelName=="") {
	            excelName = new SimpleDateFormat("yyyyMMddhhmmss").format(
	                    new Date()).toString();
	        }
	        int total=list.size();  //總記錄數
	        int  excelBig=10000;    //excel劃分的大小

	        //判斷需要分成多少個excel
	        int excelCount=(total%excelBig==0)?(total/excelBig):(total/excelBig+1);
           
	        //定義一個excel集合
	        List<HSSFWorkbook>  excelList=new ArrayList<HSSFWorkbook>();
	        
	        HSSFWorkbook wb=null;  //excel工作表
	        int begin = 0;   //資料來源的開始位置
	        int end = 0;      //資料來源的結束位置
		   
		   
	        //迴圈得到excel集合
	        for(int i=0;i<excelCount;i++){
	            //第一次begin從零開始,否則從結束位置加1開始
	            if(end!=0){
	                begin=end;
	            }
	            end=begin+excelBig;
	            //判斷如果最後的位置大於總記錄數,則修改為總記錄數
	            if(end>list.size()){
	                end=list.size();
	            }
	            //生成excel
	            wb=createExcel(excelName+(i+1), list,begin,end, fieldMap);
	            //將生成的excel新增到集合
	            excelList.add(wb);
	        } 
		   
	        //生成壓縮檔案,並匯出
	        toZipOut(excelName, excelList, response);   
	        
	   }
	   /**
	    * 
	   * @Title: toZipOut
	   * @Description: (壓縮檔案)
	   * @param excelName  檔案命
	   * @param excelList    wb工作簿集合
	   * @param response  將資料傳送到頁面上
	   * @return void
	    */
	    private static void toZipOut(String excelName, List<HSSFWorkbook> excelList, HttpServletResponse response) {
	
	    	 try {
	             //將壓縮包的名字預設為日期時間串
	             String fieldName=new SimpleDateFormat("yyyyMMddhhmmss").format(
	                     new Date()).toString();
	             /**設定response頭資訊**/
	             response.reset();  
	             //自己寫狀態碼
	             response.setStatus(HttpServletResponse.SC_OK);  
	             //使客戶端瀏覽器,區分不同種類的資料,並根據不同的MIME呼叫瀏覽器內不同的程式嵌入模組來處理相應的資料。
	             //ZIP與EXE檔案的MIME型別同為application/octet-stream
	             response.setContentType( "application/octet-stream "); 
	             //Content-disposition 是 MIME 協議的擴充套件,MIME 協議指示 MIME 使用者代理如何顯示附加的檔案。
	             //Content-disposition其實可以控制使用者請求所得的內容存為一個檔案的時候提供一個預設的檔名,檔案直接在瀏覽器上顯示或者在訪問時彈出檔案下載對話方塊。 
	             //此處設定下載檔案的格式為.zip
	             response.setHeader("Content-Disposition","attachment;filename=\""+fieldName+".zip"+"\"");  

	             //生成輸出流
	             OutputStream ouputStream = response.getOutputStream();
	             //生成壓縮包
	             ZipOutputStream zip = new ZipOutputStream(ouputStream);
//	             zip.setEncoding("GBK");//指定編碼為gbk,否則部署到linux下會出現亂碼
	             int i = 1;
	             String eName;
	             //迴圈檔案列表,新增到壓縮包中
	             for(HSSFWorkbook workbook:excelList){
	                 //給每個檔名加序號
	                 eName=excelName+String.valueOf(i);
	                 //例項化一個壓縮實體
	                 ZipEntry entry = new ZipEntry(eName+".xls");
	                 //將壓縮實體放入壓縮包
	                 zip.putNextEntry(entry);
	                 //將excel內容寫進壓縮實體
	                 workbook.write(zip);
	                 i++;
	             }
	             //將檔案輸出
	             zip.flush();
	             zip.close();
	             response.flushBuffer();  
	         } catch (Exception e) {
	        	 e.printStackTrace();
	         }
	    	
	    	
	    	
	    	
		
	}
		/**
	     * 生成Excel
	     * @param excelName   要匯出的excel名稱
	     * @param list       要匯出的資料集合
	     * @param begin   資料集合的開始位置
	     * @param end      資料集合的結束位置
	     * @param fieldMap 中英文欄位對應Map,即要匯出的excel表頭
	  
	     * @return
	     */ 
	    private static  HSSFWorkbook createExcel(String excelName,List<Map<String, Object>> list,Integer begin,Integer end,LinkedHashMap<String, String> fieldMap){

	        int sheetContent=2000;     //每個excel中sheet的容量

	        //計算sheet的數量
	        int sheetCount=0;
	        //如果總記錄數  正好整除 以每個sheet的容量
	        if ((end-begin)%sheetContent==0){
	            //sheet的數量=總記錄數 除以 每個sheet的容量
	            sheetCount=(end-begin)/sheetContent;
	        }else{
	            //sheet的數量=總記錄數 除以 每個sheet的容量 加1
	            sheetCount=(end-begin)/sheetContent+1;
	        }

	        //建立一個WorkBook,對應一個Excel檔案
	        HSSFWorkbook wb=new HSSFWorkbook();
	        //建立單元格,並設定值表頭 設定表頭居中
	        HSSFCellStyle style=wb.createCellStyle();
	        //建立一個居中格式
	        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);

	        //定義sheet
	        HSSFSheet sheet=null;
	        //定義sheet的名稱
	        String sheetName=excelName+"-";
	        //sheet中的資料開始位置
	        int beginSheet=0;
	        //sheet中的資料結束位置
	        int endSheet=0;

	        //迴圈建立sheet
	        for (int i=0;i<sheetCount;i++){
	            //在Workbook中,建立一個sheet,對應Excel中的工作薄(sheet)
	            sheet=wb.createSheet(sheetName+(i+1));

	            //第一次beginSheet從begin開始,否則從結束位置加1開始
	            if(endSheet==0){
	                beginSheet=begin;
	            }else{
	                beginSheet=endSheet;
	            }
	            //sheet結束位置=sheet開始位置+每個sheet的容量
	            endSheet=beginSheet+sheetContent;
	            //判斷如果最後的位置大於總記錄數,則修改為總記錄數
	            if(endSheet>end){
	                endSheet=end;
	            }

	            // 填充工作表
	            try {
	            	  fillSheet(sheet,list,beginSheet,endSheet,fieldMap,style);
	            } catch (Exception e) {
                 e.printStackTrace();
	            }
	        }
	        //返回excel
	        return wb;
	    }
/**
 * 
* @Title: fillSheet
* @Description: (向每一個sheet頁中填充row)
* @param sheet 頁物件
* @param list  資料集合
* @param beginSheet   這一頁開始的資料
* @param endSheet  這一夜結束的資料
* @param fieldMap   表頭中文欄位和資料庫欄位  鍵為資料庫欄位 值為中文欄位
* @param style   表頭樣式
* @return void
 */
	    private static void fillSheet(HSSFSheet sheet, List<Map<String, Object>> list, int beginSheet, int endSheet,
				LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) {
	    	   // 定義存放英文欄位名和中文欄位名的陣列
	    	    //英文為鍵中文為值
	        String[] enFields = new String[fieldMap.size()];
	        String[] cnFields = new String[fieldMap.size()];
	        // 將值分別填入兩個陣列
	        int count = 0;
	        for (Entry<String, String> entry : fieldMap.entrySet()) {
	            enFields[count] = entry.getKey();
	            cnFields[count] = entry.getValue();
	            count++;
	        }
	        int   rowIndex=0;//行的數量
	        //在sheet中新增表頭第0行
	        HSSFRow row=sheet.createRow(rowIndex++);

	        // 填充表頭
	        for (int i = 0; i < cnFields.length; i++) {
	            HSSFCell cell=row.createCell(i);
	            cell.setCellValue(cnFields[i]);
	            cell.setCellStyle(style);
	            sheet.autoSizeColumn(20);
	        }

	        Map<String, Object> map=null;
      for(int i=beginSheet;i<endSheet;i++) {
	  row=sheet.createRow(rowIndex++);
		 map= list.get(i);//map集合可以理解為物件
	  for (int j = 0; j < enFields.length; j++) {
           String fieldValue=map.get(enFields[j]).toString();//用鍵取值
           row.createCell(j).setCellValue(fieldValue);//將值賦給單元格
      }
       }	    		
		}    
	   
}