Java泛型導出Excel表格數據

 

目前網頁導出文件的功能比較常見並且實用,所以個人也遇到了導出Excel表格的需求。關於導出表格數據,其實前端也能進行導出操作,不過一般前端進行的導出操作適用於數據量少的時候,普通來說,數據條數少於600行,前端導出效率也能行;如果數據量偏大,那麼後端導出是最好的選擇。

對於後端導出,請求類型筆者是用的GET請求,因爲使用POST請求,導出數據會是亂碼,也不能導出到文件,至於原因也沒有進行深究,如果有哪位大佬瞭解,煩請告知。

因爲需要導出的表格比較多,而每個表格的數據模型又是不同的模型,所以在這裏,筆者採用了Java泛型技術來達到導出方法的通用性。話不多說,下面就是整個導出方法的代碼。

爲了便於讀者閱讀,註釋比較多,並且筆者在這裏先舉一個實例,方便讀者理解。

一、前端導出頁面

姓名 工號 性別 年齡 工資
張三 1 19 1000
李四 2 11 1234

 

比如前端有一個這樣的表格,當然,真正的肯定不是這種簡陋的,這只是方便說明隨便提供的表格。

這張表格的數據其實可以分爲兩部分:一部分是表頭信息(下面代碼中的表頭信息,tableHeaders參數的value),就是如姓名、工號、性別這種,指示了這列數據的含義;二部分就是一條條數據了(下面代碼中的List<T> datas參數)。這些數據,其實是後端返回的一個List<PeopleInfo>集合,每一條數據就是一個PeopleInfo對象。因爲數據模型PeopleInfo的屬性不會用中文表示,所以,爲了將數據模型的每個字段對應上表頭的信息字段,就用到了KeyValueVO這個模型,這個模型的key就是數據模型的字段,value就是表頭的字段。

這裏,用戶可以選擇是否顯示某一列,比如,我不想看工資,年齡,性別,我只關注員工的姓名和工號,那麼在前端,用戶可以設置這幾列不可見,對應的這種設置就會保存在後端數據庫中。這個時候用戶再導出數據,就只會導出員工的姓名和工號了,其他數據就不會導出了(對應下面代碼的需要導出的字段exportFields)

所以,最後,當用戶點擊導出按鈕時,前端會傳一個請求過來,到時候,後端經過搜索,將需要導出的數據,需要導出的字段,以及數據模型和表頭字段的對應關係當做參數傳入方法,這樣就能導出數據了,並且導出的excel也會有表頭信息,即:姓名、工號這種信息。

1.使用的模型類

package sora.test.exampl;

/**
 * 鍵值對模型
 * @author sora
 *
 */
public class KeyValueVO {
	
	private String key;
	
	private String value;

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}
	
}

 2.到處Excel泛型方法

package sora.test.exampl;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import org.ietf.jgss.Oid;

/**
 * Excel文件導出工具類
 * 因爲環境限制,有一些類沒有導入進來,望讀者注意!!!!!!
 * @author sora
 *
 */
public class ExcelExportUtil {
	
	private static final int TWO_HUNDRED_FIFTY_SIX = 256;
	
	private static final int EIGHT = 8;
	
	private static final int FOUR = 4;
	
	private static final int THREE = 3;
	
	private static final int TWO = 2;
	
	/**
	 * 導出excel表格數據
	 * @param datas 需要導出的數據模型集合
	 * @param exportFields 需要導出的字段顯示
	 * @param excelName 導出Excel文件名
	 * @param tableHeaders 表格數據模型與表頭信息鍵值對
	 * @param response 響應
	 */
	public static <T> void excelExport(List<T> datas, List<String> exportFields, String excelName, List<KeyValueVO> tableHeaders, HttpServletResponse response)
	{
		if (null == datas) 
		{
			return;
		}
		try 
		{
			excelName = new String(excelName.getBytes("UTF-8"),"ISO-8859-1");
		} 
		catch (Exception e1) 
		{
			e1.printStackTrace();
		}
		
		response.setCharacterEncoding("utf-8");
		
		try 
		{
			writeExcel(datas,exportFields,excelName,tableHeaders,response);
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
	
	/**
	 *  寫入數據
	 * @param datas 數據
	 * @param exportFields 導出字段
	 * @param excelName 導出Excel名字
	 * @param tableHeaders 表頭信息
	 * @param response 響應
	 * @throws Exception 
	 */
	public static <T> void writeExcel(List<T> datas, List<String> exportFields, String excelName, List<KeyValueVO> tableHeaders, HttpServletResponse response) 
			throws Exception
	{
		//創建一個excel文件
		HSSFWorkbook excel = new HSSFWorkbook();
		//excel文件裏面一張表格sheet
		HSSFSheet excelSheet = excel.createSheet("sheet1");
		//sheet中的行
		HSSFRow excelRow = null;
		//sheet中的單元格
		HSSFCell excelCell = null;
		//行下標,因爲表頭是用單獨的方法寫,所以直接從第二行開始寫數據
		Integer rowSubScript = 1;
		//單元格下標
		Integer cellSubScript = 0;
		
		//獲取數據模型的類對象
		Class<?> clazz = datas.get(0).getClass();
		//獲取模型聲明的所有字段
		Field[] modelFields = clazz.getDeclaredFields();
		
		exportFields = writeExcelFirstRowAndField(modelFields, exportFields, excelSheet, excelCell, tableHeaders);
		
		for (T data : datas) 
		{
			cellSubScript = 0;
			excelRow = excelSheet.createRow(rowSubScript);
			
			for (String exportField : exportFields) 
			{
				excelCell = excelRow.createCell(cellSubScript);
				
				String methodName = getInitialsUp(exportField);
				
				Method getMethod = null;
				
				getMethod = clazz.getMethod("get" + methodName);
				
				setExcelCellValue(getMethod, data, excelCell);
				cellSubScript++;
			}
			rowSubScript++;
		}
		OutputStream output = response.getOutPutStream();
		excel.write(output);
		output.flush();
		output.close();
		excel.close();
	}
	
	/**
	 * 寫入sheet表格第一行表頭信息,支持中文表頭
	 * @param modelFields 數據模型的字段
	 * @param exportFields 需要導出的表頭字段
	 * @param excelSheet sheet
	 * @param excelCell 單元格
	 * @param tableHeaders 表頭與模型字段的鍵值對
	 * @return List<Stirng> 實際需要導出的字段:因爲用戶可以設置某些字段不導出
	 * @throws Exception
	 */
	public static List<String> writeExcelFirstRowAndField(Field[] modelFields, List<String> exportFields, HSSFSheet excelSheet, HSSFCell excelCell, 
			List<KeyValueVO> tableHeaders) 
			throws Exception
	{
		HSSFRow excelRow = excelSheet.createRow(0);
		Integer cellSubScript = 0;
		List<String> actualExprtFields = new LinkedList<>();
		//如果導出字段爲Null或者爲空,那麼默認導出數據模型的所有字段
		if (null == exportFields || exportFields.isEmpty()) 
		{
			for (Field modelField : modelFields) 
			{
                //如果這個字段在數據模型中的聲明是靜態的,即static,那麼就是不需要導出的字段
				if (EIGHT == modelField.getModifiers()) 
				{
					continue;
				}
				excelCell = excelRow.createCell(cellSubScript);
				String resultName = fieldToTableHeader(tableHeaders, modelField.getName());
				if (resultName.isEmpty()) 
				{
					continue;
				}
				excelSheet.setCloumnWidth(cellSubScript, 
						resultName.getBytes("UTF-8").length * TWO * TWO_HUNDRED_FIFTY_SIX / THREE + FOUR * TWO_HUNDRED_FIFTY_SIX);
				
				excelCell.setCellValue(resultName);
				
				actualExprtFields.add(modelField.getName());
				cellSubScript++;
			}
		}
		else 
		{
			for (String exportField : exportFields) 
			{
				excelCell = excelRow.createCell(cellSubScript);
				String resultName = fieldToTableHeader(tableHeaders, modelField.getName());
				if (resultName.isEmpty()) 
				{
					continue;
				}
				excelSheet.setCloumnWidth(cellSubScript, 
						resultName.getBytes("UTF-8").length * TWO * TWO_HUNDRED_FIFTY_SIX / THREE + FOUR * TWO_HUNDRED_FIFTY_SIX);
				
				excelCell.setCellValue(resultName);
				
				actualExprtFields.add(modelField.getName());
				cellSubScript++;
			}
		}
		return actualExprtFields;
	}
	
	/**
	 *  設置單元格的值
	 * @param getMethod 類對象屬性的get方法
	 * @param data 數據
	 * @param excelCell 單元格
	 */
	public static <T> void setExcelCellValue(Method getMethod, T data, HSSFCell excelCell)
	{
		try 
		{
			if (null == getMethod.invoke(data)) 
			{
				excelCell.setCellValue("");
			}
			else 
			{
				excelCell.setCellValue(getMethod.invoke(data).toString());
			}
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
	
	/**
	 *  返回數據模型字段對應的表頭字段
	 * @param tableHeaders 表頭鍵值對
	 * @param modelField 模型字段
	 * @return 目標字符串
	 */
	public static String fieldToTableHeader(List<KeyValueVO> tableHeaders, String modelField)
	{
		for (KeyValueVO tableHeader : tableHeaders) 
		{
			if (modelField.equals(tableHeader.getKey())) 
			{
				return tableHeader.getValue();
			}
		}
		return "";
	}
	
	/**
	 *  將字符串首字母大寫,如:big → Big
	 * @param field 字符串
	 * @return 首字母大寫之後的字符串
	 */
	public static String getInitialsUp(String field)
	{
		byte[] items = null;
		try 
		{
			items = field.getBytes("UTF-8");
			items[0] = (byte) ((char)items[0] - 'a' + 'A');
			return new String(items, "UTF-8");
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
			return "";
		}
	}
	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章