1. 程式人生 > >poi對Excel報表的自動化

poi對Excel報表的自動化

       工作中經常會有一些daily的報告,每次的格式都是一樣的,來源也基本都是資料庫的表,每次要自己去貼上很麻煩。

       嘗試過python以及sas等工具或者包,python的xlrd等系列不支援07以後的excel檔案,openpyxl在替換資料後容易莫名的失去cell的格式,sas第一是收費,第二也是隻支援03版本的excel。好在還是可以通過poi來處理。

       本篇主要只記錄下幾個函式,以及處理的思路,預設各位已經完成了Spring + Mybatis的搭。

       首先使用maybatis可以忽略ORM。因為如果是長期相同的sql給個對應的物件還可以,但是一旦經常欄位變動搞起來也很麻煩,mybatis是可以將查詢結果返回為一個HashMap的,所以我就直接使用LinkedHashMap。        

<select id="test" resultType="java.util.LinkedHashMap">
    sql語句
</select>
//流式資料,優先選用
	public static SXSSFWorkbook createWorkbookWithoutBean2(List<LinkedHashMap<String, Object>> list, Object adb){
			SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
			SXSSFSheet sheet = workbook.createSheet("sheet");
			SXSSFRow row = sheet.createRow(0); //從第一行開始寫入bean的具體資訊
			SXSSFCell cell = row.createCell(0);
			cell.setCellValue(adb.toString());
			row = sheet.createRow(1);
			if(list.size()!=0)
				try {
					//獲得所有的key值並將其匯入一個ArrayList中
					LinkedHashMap<String, Object> map = list.get(0);  //得到第一個map,然後獲得所有的key
					Set keySet = map.keySet();
					Iterator<String> iterator = keySet.iterator();
					ArrayList<String> keys = new ArrayList<String>();
					while(iterator.hasNext()){
						keys.add(iterator.next());
					}
					
										
					
					//寫入列名
					for(int i=0; i<keys.size(); i++){
						cell = row.createCell(i);
						cell.setCellValue(keys.get(i));
					}
					//寫入值
					int rowIndex = 2;
					Iterator<LinkedHashMap<String, Object>> iter1 = list.iterator();
					while(iter1.hasNext()){
						row = sheet.createRow(rowIndex++);
						map = iter1.next();
						for(int i=0; i<keys.size(); i++){
							cell = row.createCell(i);
							if(map.get(keys.get(i)) != null){
								String name = map.get(keys.get(i)).getClass().getName();
						        if(name.equals("java.math.BigDecimal")){
						        	BigDecimal bigDecimal = (BigDecimal) map.get(keys.get(i));
						        	cell.setCellValue(bigDecimal.doubleValue());
						        }else if(name.equals("java.sql.Timestamp")){
						        	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//定義格式,不顯示毫秒 
						        	String str = df.format((Timestamp)map.get(keys.get(i)));
						        	cell.setCellValue(str);
						        }else if(name.equals("java.lang.Integer")||name.equals("java.sql.Integer")){
						        	cell.setCellValue((Integer)map.get(keys.get(i)));
						        }else{
						        	cell.setCellValue((String)map.get(keys.get(i)));
								}
							}
							
						
						}

					}
					return workbook;
				}catch(Exception e){
					e.printStackTrace();
				}													
		return workbook;

上面這個函式假設你已經通過mabatis查詢的到一個返回的map物件,那麼呼叫後就可以直接得到一個新的SXSSFWorkBook物件,這是poi中用於大資料匯出的物件,接收也很簡單,在main裡面new一個XSSFWorkBook接收就可以了。

/**
	 * 
	 * @param wb
	 * @param sheetName
	 * @param sql  不是真正意義上的sql,而是你sql對應的mapper.xml檔案裡面的id
	 * @param start_line  excel如果是模板的話,資料要從第二行開始替換
	 * @param sqlParam 查詢的引數 Object物件,和mapper.xml裡面的對應
	 * @return
	 */
	public static synchronized XSSFWorkbook replaceSheet(XSSFWorkbook wb, String sheetName, String sql, int start_line, String sqlParam){
		try {
			XSSFSheet sheet = wb.getSheet(sheetName);
			int lastRow = sheet.getLastRowNum();
			XSSFRow row;
			XSSFCell cell;
			XSSFCellStyle style = wb.createCellStyle();
			row = sheet.getRow(start_line-1);
			int rowIndex = start_line-1;
			if(row.getCell(0)!=null){
				style = row.getCell(0).getCellStyle();
			}else{
				style.setBorderBottom(BorderStyle.THIN);
				style.setBorderTop(BorderStyle.THIN);
				style.setBorderLeft(BorderStyle.THIN);
				style.setBorderRight(BorderStyle.THIN);
			}
			
			for(int i=start_line-1; i<=lastRow; i++){
				row = sheet.getRow(i);
				if(row!=null){   
					myRemoveRow(sheet, row);  
	            }
			}//刪除完成			
			InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			SqlSession session = sqlSessionFactory.openSession();
			System.out.println(sql);
			System.out.println(sqlParam);
			List<LinkedHashMap<String,Object>> list = session.selectList(sql, sqlParam);
			System.out.println(list.size());
			if(list.size()!=0){
				LinkedHashMap<String, Object> map = list.get(0);
				Set keySet = map.keySet();
				Iterator<String> iterator = keySet.iterator();
				ArrayList<String> keys = new ArrayList<String>();
				while(iterator.hasNext()){
					keys.add(iterator.next());
				}
				
				//寫入列名
				Iterator<LinkedHashMap<String, Object>> iter1 = list.iterator();
				while(iter1.hasNext()){
					row = sheet.createRow(rowIndex++);
					map = iter1.next();
					for(int i=0; i<keys.size(); i++){
						cell = row.createCell(i);
						if(map.get(keys.get(i)) != null){
							String name = map.get(keys.get(i)).getClass().getName();
							if(name.equals("java.math.BigDecimal")){
					        	BigDecimal bigDecimal = (BigDecimal) map.get(keys.get(i));
					        	cell.setCellValue(bigDecimal.doubleValue());
					        }else if(name.equals("java.sql.Timestamp")){
					        	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//定義格式,不顯示毫秒 
					        	String str = df.format((Timestamp)map.get(keys.get(i)));
					        	cell.setCellValue(str);
					        }else if(name.equals("java.lang.Integer")||name.equals("java.sql.Integer")){
					        	cell.setCellValue((Integer)map.get(keys.get(i)));
					        }else{
					        	cell.setCellValue((String)map.get(keys.get(i)));
							}
						}
						cell.setCellStyle(style);
					}
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return wb;
	}
	
	private static synchronized void myRemoveRow(XSSFSheet sheet, Row row) {  
        sheet.removeRow(row);  
    } 

這個是用於替換模板裡面的sheet的,因為可能報表的形式不變,後面隱藏的sheet作為對映到前面的資料(就是顯示的sheet全是公式,實際的資料在後面hide的sheet裡面)。開始行選1就是全sheet替換,選2就是從第二行開始刪除替換,這裡有個style樣式的問題,建議使用模板的時候,第一行為欄位的名字,第二行為樣例的資料。返回的物件一樣用XSSFWorkbook接收。

最後資料重新整理了以後需要重新整理的是公式,poi自動生成資料後你開啟excel,很容易發現作為公式的數值並不會自己重新整理,所以還有一個函式用於重新整理公式

public static void updateFormula(Workbook wb){
			for(int sheet_index=0;sheet_index<wb.getNumberOfSheets();sheet_index++){
				Sheet s = wb.getSheetAt(sheet_index);
				int maxRow = s.getLastRowNum();
				Row r;
				for(int row_index=0; row_index<=maxRow; row_index++){
					r=s.getRow(row_index);
			        if(r!=null){
			        	Cell c=null;
			            XSSFFormulaEvaluator eval=null;
			            if(wb instanceof XSSFWorkbook)
			                eval=new XSSFFormulaEvaluator((XSSFWorkbook) wb);
			            else if(wb instanceof XSSFWorkbook)
			                eval=new XSSFFormulaEvaluator((XSSFWorkbook) wb);
			            for(int i=r.getFirstCellNum();i<r.getLastCellNum();i++){      	
			                c=r.getCell(i);
			                if(c != null)
			                	if(c.getCellType()==Cell.CELL_TYPE_FORMULA)
			                		eval.evaluateFormulaCell(c);
			            }
			        }
					
				}
			}
			

傳入一個XSSFWorkbook物件即可。

最後一個問題,如果你提前已經做好了ORM的對映,這個時候你不想寫一個新的方法而只想呼叫這種返回為HashMap的通用方法,就要把物件轉為一個Map。

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

public class BeanMapTrans {
	
	public static LinkedHashMap<String, Object> transBean2Map(Object obj){
		if(obj == null){  
            return null;  
        }          
        LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();  
        try {  
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());  
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
            for (PropertyDescriptor property : propertyDescriptors) {  
                String key = property.getName();  
                // 過濾class屬性  
                if (!key.equals("class")) {  
                    // 得到property對應的getter方法  
                    Method getter = property.getReadMethod();  
                    Object value = getter.invoke(obj);  
  
                    map.put(key, value);  
                }  
  
            }  
        } catch (Exception e) {  
            System.out.println("transBean2Map Error " + e);  
        }  
  
        return map;  
	} 

}

函式見上。

另外說一句在替換多個sheet,使用removeRow的時候會出現空指標異常,因為Row的儲存非執行緒安全的TreeMap,但是對於刪除操作不會影響,所以我只是將這個情況跳過了,如有大神明白具體原理請告知。

如果你還有對格式處理的要求,可以參考這一篇文章

相關推薦

poiExcel報表自動化

       工作中經常會有一些daily的報告,每次的格式都是一樣的,來源也基本都是資料庫的表,每次要自己去貼上很麻煩。       嘗試過python以及sas等工具或者包,python的xlrd等系列不支援07以後的excel檔案,openpyxl在替換資料後容易莫名的

POIExcel單元格進行顏色設置

dex .so nbsp set exceptio except www span 單元格 POI對Excel單元格進行顏色設置 學習了:http://www.myexception.cn/program/1932587.html HSSFWorkbook workboo

POIExcel自定義日期格式的讀取

大數 -i ride 字符串 所有 sfc ats http 錯誤 cell.getCellStyle().getDataFormat();根據這個值進行時間、日期格式的判斷;POI讀取出來的結果也是有些變化的;需要在實際項目中進行確認; 時間格式的遍歷:

POIExcel單元格內容修改

// XLSX版本 const in= new Packages.java.io.FileInputStream("C:\\LJT\\test.xlsx"); const wb= Packages.org.apache.poi.xssf.usermodel.XSSFWorkbook("in"

學以致用——Excel報表自動化方案 (Automation solution of complicated manual Excel Report)

經過整整兩年多的實踐加理論學習,總算實現了一套Excel報表自動化方案。思路總結如下: 1. 使用批處理檔案呼叫批處理檔案(call batch file through batch file) 2. 在batch檔案中呼叫sqlplus程式,同時指定要連線的資料庫及登入密碼,並指定co

Web使用Apache poiEXCEL操作(匯入)

第一次嘗試Web專案上傳Excel資料進行匯入 如果有哪裡做的不對不好或者有更好的方法請聯絡我,謝謝 pom.xml中新增         <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --&

使用Apache POI 進行Excel報表的匯出下載(GET 請求 && POST請求)

簡介:之前專案有這樣的需求:按各種條件進行篩選資料,然後匯出Excel到本地 針對條件條件很少的情況下,使用的是GET請求的方式,直接在URL上拼接請求引數,這種形式很簡單就能匯出Excel。但是當條件很多很複雜時,就不適合使用GET請求的方式了,所以我使用了

POIEXCEL的操作【重點:如何設定CELL格式為文字格式】

轉載至:http://javacrazyer.iteye.com/blog/894758 實際開發過程中通常用到的就是從資料庫匯出EXCEL表格了,JXL可以這樣做,其實POI也可以(關於JXL與POI的異同可訪問我之前總結的文章),之前寫過POI對七種文件(當然也

POIExcel進行讀取操作,工具類,便於操作資料

一:首先POI對Excel 操作進行了一系列的封裝,匯入,匯出Excel這裡藉助於POI提供的jar包 專案當中匯入POI提供的Jar包,這裡使用Maven管理   進行匯入jar包   <!-- https://mvnrepository.c

Java POIExcel操作,專案開發中遇到的問題,及解決方案

java POI官網地址,裡面有介紹POI的使用,以及各種例子程式碼:說下在專案開發中遇到的java操作Excel的棘手問題,以及解決方案:首先記下2007版及以上Excel版本(.xlsx)的檔案讀取、輸出程式碼:讀取:public static Workbook getT

學以致用——Excel報表自動化方案探索

準備進一步提高Excel報表的自動化生成程度。 看到一篇文章,收到了啟發,暫存一下。 '' --main.sql   set linesize 200 set term off verify of

POIEXCEL中時間格式資料的讀取

      1、Excel儲存日期、時間均以數值型別進行儲存,讀取時POI先判斷是是否是數值型別,再進行判斷,判斷數值:                 HSSFCell.CELL_TYPE_NUMERIC==cell.getCellType()        2.日期

POI excel表格基本操作Demo

今天熟悉了一下POI對excel的一些基本操作與大家分享一下 import java.io.FileOutputStream; import java.io.IOException; import org.apache.poi.hssf.usermodel.HSSFC

POIExcel的單元格格式區分

圖中的資料有數值、貨幣、時間、日期、文字等格式。這些資料格式在POI中的HSSFDataFormat類裡都有相應的定義。 HSSFDataFormat是HSSF子專案裡面定義的一個類。類HSSFDataFormat允許使用者新建資料格式型別。HSSFDataFormat類包含靜態方法static java.

使用poiexcel條件格式設定字型顏色使用自定義的顏色

在poi中設定條件格式也是使用如下程式碼 XSSFSheetConditionalFormatting scf = target.getSheetConditionalFormatting(); //獲得條件格式物件 //紅色格式 XSSFConditionalFo

使用poiExcel表的寫入修改,再匯出

本文介紹將一個Excel檔案上傳後,修改Excel表中資料,再從新寫入到新的Excel表 1.使用myeclipse建立web工程, 2.新增struts2 使用struts2的分裝工具將檔案 上傳 3.匯入poi-3.0.2-FINAL-20080204.jar 4

poi匯出Excel報表多表頭雙層表頭、合併單元格

效果圖: controller層方法:   /**      *      * 匯出Excel報表      * @param request      * @return      *      */     @RequestMapping("/export")  

POIExcel操作——java儲存資料到Excel

1、常見的java操作Excel API介紹 1.1 Java Aspose Cells Java Aspose Cells是一種純粹的Java授權的Excel API,開發和供應商Aspose釋出。這個API的最新版本是8.1.2,是一個豐富而厚重的API

接口自動化測試Python(2)_使用pythonexcel進行操作

pip安裝 print eight tps cell .com family logs 運行 如何使用Python對excel進行簡單的操作 一. 通過pip安裝xlwt, xlrd這兩個模塊 *pip install xlwt *pip insta

Java自動化——使用Selenium+POI實現Excel自動化批量查單詞

寫在最前 相信大家都對爬蟲非常熟悉,一般來說,利用HttpClient傳送請求並獲取響應以獲得想要提取的資料應該是最常用的方法。最近工作中頻繁使用了Selenium,在本文中,我們將使用Selenium和POI(讀寫Excel)來完成一個入門級的自動化程式,原始碼地址見附錄。 步驟一覽 使用Mav