1. 程式人生 > >優化poi 匯入匯出excel,不造成電腦卡死問題

優化poi 匯入匯出excel,不造成電腦卡死問題

其實生活中不乏很多需要從資料庫向excel匯入資料的情況,但是如果資料庫的東西很多且欄位很長,會造成卡宕機的狀態。 那麼如何解決這個一問題呢,其實網路上有一門技術叫做poi,官方介紹是: Apache POI是Apache軟體基金會的開放原始碼函式庫,POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。 其實可以把它理解為Java和Microsoft之間互相溝通的一門技術 Microsoft其實除了excel 還有ppt,word, 相互對應的列舉如下: 結構:

HSSF - 提供讀寫Microsoft Excel格式檔案的功能。

XSSF - 提供讀寫Microsoft Excel OOXML格式檔案的功能。

HWPF - 提供讀寫Microsoft Word格式檔案的功能。

HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。

HDGF - 提供讀寫Microsoft Visio格式檔案的功能。

那我今天為大家簡單的介紹一下如何優化poi匯出問題 1.常用類說明

類名 說明 HSSFWorkbook Excel的文件物件 HSSFSheet sheet頁 HSSFRow Excel的行 HSSFCell Excel的格子單元 HSSFFont Excel字型

HSSFDataFormat 格子單元的日期格式 HSSFHeader Excel文件Sheet的頁首 HSSFFooter Excel文件Sheet的頁尾 HSSFCellStyle 格子單元樣式 HSSFDateUtil 日期 HSSFPrintSetup 列印 HSSFErrorConstants 錯誤資訊表

1.2 .1新建一個表格 首先要將下載好的jar包,解壓將根目錄下的所有包,以及將lib目錄下的commons-logging-1.2.jar 和 junit-4.12.jar 以及 log4j1.2.17.jar 這三個通用包匯入到專案的lib的目錄下,poi-4.0.0.jar包是最重要的。 主要介紹HSSFWorkbook /** * 多型實現 * HSSFWorkbook 是對於xls進行操作 / Workbook wb=new HSSFWorkbook();//新建一個工作簿 /

* * 匯出所以用到輸出流 *引數為輸出的地址 */ FileOutputStream fout=new FileOutputStream(“E:\Demo\poi.xls”); wb.write(fout);//Workbook提供了write的方法 fout.close();//將輸出流關閉

1.1.2新建sheet頁 在新建工作簿的基礎上新建sheet頁,wb.createSheet() 返回一個Sheet()如果不進行操作不用接收 /** * 多型實現 * HSSFWorkbook 是對於xls進行操作 / Workbook wb=new HSSFWorkbook();//新建一個工作簿 /* * 匯出所以用到輸出流 / FileOutputStream fout=new FileOutputStream(“E:\Demo\poi.xls”); /* * 有有參和無引數兩種 * 引數為sheet頁的名字 * 不寫引數預設名字為sheet0到n */ Sheet sheet1 = wb.createSheet();//建立一個sheet頁 Sheet sheet2 = wb.createSheet(“第二個sheet頁”);//建立第二個sheet頁 wb.write(fout); fout.close();//將輸出流關閉 一些工作表的方法 workbook.setActiveSheet(工作表下標);//設定預設工作表 workbook.setSheetName(2(工作表下標), “1234”(新名字));//重新命名工作表 sheet1.setZoom(1,2);//50%顯示比例 sheet2.setZoom(2,1);//200%顯示比例 sheet3.setZoom(1,10);//10%顯示比例

優化之後的方法

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);//將值賦給單元格
      }
       }	    		
		}    
	   
}