首先介紹POI:
Apache POI是Apache軟件基金會的開放源碼函式庫,POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能。
結構:
HSSF - 提供讀寫Microsoft Excel格式檔案的功能。
XSSF - 提供讀寫Microsoft Excel OOXML格式檔案的功能。
HWPF - 提供讀寫Microsoft Word格式檔案的功能。
HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。
HDGF - 提供讀寫Microsoft Visio格式檔案的功能。
一些基本的讀取excel,把數據導出到excel的創建文件和爲表格填充數據都可以查看:
百度百科:https://baike.baidu.com/item/POI/8886826
這裏講一下如何封裝一個方法傳入一個任意的list集合,然後根據該類的屬性動態生成集合所有屬性的excel數據。
然後說一下反射:這裏用到的就是通過反射在運行時動態獲取傳來的類的屬性值,主要用到兩個jar包:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
主要的方法就是獲取到運行時加載進內存的類的屬性名:class.getDeclaredFields()方法,以及該類聲明的方法;
class.getMethod();
一下獻上源碼:
package com.nms.common;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.awt.Font;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.Format;
import java.text.SimpleDateFormat;
public class ClassUtil {
/**
* @Description:將一個類的所有聲明屬性和值存入map(屬性值爲int型時,0時不加入,
* 屬性值爲String型或Long時爲null和“”不加入)
* @param Object object 是需要將其所有聲明屬性和值存入單個map的對象
* @Date:2018/3/20
* @return 屬性名和值對應的map
*/
public static Map<String, Object> setConditionMap(Object obj){
Map<String, Object> map = new HashMap<String, Object>();
if(obj==null){
return null;
}
try {
//獲取該類的所有聲明的屬性的名字
Field[] fields = obj.getClass().getDeclaredFields();
//循環遍歷以屬性名作爲key以boject的get方法獲取的值作爲value存入map
for(Field field : fields){
String fieldName = field.getName();
if(getValueByFieldName(fieldName,obj)!=null)
map.put(fieldName, getValueByFieldName(fieldName,obj));
}
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
return map;
}
/**
* 根據屬性名獲取該類此屬性的值
* @param fieldName
* @param object
* @return get方法的返回值
*/
private static Object getValueByFieldName(String fieldName,Object object){
//拼接get方法
String firstLetter=fieldName.substring(0,1).toUpperCase();
String getter = "get"+firstLetter+fieldName.substring(1);
try {
//從實體類中獲取該get方法
Method method = object.getClass().getMethod(getter, new Class[]{});
//利用該實體類對象執行該get方法
Object value = method.invoke(object, new Object[] {});
//如果是時間格式化
if(value.getClass().equals(Date.class)){
Date date = new Date(((Date)value).getTime());
SimpleDateFormat time=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return time.format(date);
}
return value;
} catch (Exception e) {
return null;
}
}
/**成功打印出excel表格的方法
* @Description: 根據數據集合以及要生成的表名和存儲路徑在該路徑下生成數據集合導出的excel文件
* @param: list 要導出的數據集合
* @param: sheetName 要生成的excel sheet的名字集合
* @param: path 要保存的文件路徑
* @Date:2018/3/20
* */
@SuppressWarnings("deprecation")
public static void reportExport(List<?> list,String[] sheetName,String path){
int size = list.size();
//獲取一個對象爲填入表頭提供信息
Object object = list.get(0);
//獲取該類的所有聲明即表頭
Field[] fields = object.getClass().getDeclaredFields();
//每一行的列數
int columnSize = fields.length;
//在Excel工作簿中建一工作表,其名爲缺省值。
HSSFWorkbook workbook = new HSSFWorkbook();
//如要新建一名爲sheetName[0]的工作表
HSSFSheet sheet = workbook.createSheet(sheetName[0]);
//在索引的位置創建行(根據記錄數添加)
HSSFRow[] row = new HSSFRow[size];
//每一行創建列(根據樹形字段)
HSSFCell[] cell = new HSSFCell[columnSize];
//單元格式
HSSFCellStyle cellStyle= workbook.createCellStyle();
//字體
HSSFFont font = workbook.createFont();
font.setFontName("宋體");
cellStyle.setFont(font);
//存儲列字段值最大值
Map<String,Short> mapMax = new HashMap();
//寫入表頭
row[0] = sheet.createRow(0);
for(int i=0;i<columnSize;i++){
mapMax.put(fields[i].getName(), (short)3000);
cell[i] = row[0].createCell((short)i);
cell[i].setCellType(HSSFCell.CELL_TYPE_STRING);
cell[i].setCellStyle(cellStyle);
cell[i].setCellValue(fields[i].getName());
}
//寫入具體數據
for(int j=1;j<size;j++){
//根據類獲得的屬性名值相對的map
Map<?, ?> map = ClassUtil.setConditionMap(list.get(j));
row[j] = sheet.createRow(j);
for(int i=0;i<columnSize;i++){
cell[i] = row[j].createCell((short)i);
cell[i].setCellType(HSSFCell.CELL_TYPE_STRING);
if(map.get(fields[i].getName())==null){
cell[i].setCellValue("");
} else {
cell[i].setCellValue(map.get(fields[i].getName()).toString());
//比較最大值並且更新
if(mapMax.get(fields[i].getName())>map.get(fields[i].getName()).toString().length())
mapMax.put(fields[i].getName(), (short)(map.get(fields[i].getName()).toString().length()*280+1000));
}
}
}
//設置列寬度
for(int i=0;i<fields.length;i++){
sheet.setColumnWidth((short)i, (short)mapMax.get(fields[i].getName()));
}
try {
FileOutputStream outputStream = new FileOutputStream(path);
workbook.write(outputStream);
outputStream.flush();
//操作結束,關閉文件
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
!!!!!要注意的地方是
1,傳入的是list對象,要獲取fields集合需要從中取出一個實例化的類然後再獲取屬性;
2,class.getMethod方法區分有參數和無參數的區別,有參數的要加上參數的類型比如參數是String那麼 class.getMethod(”setName”,String.class);無參數的可以用null也可以使用 new Class[]{}代替;
3,method.invoke()方法是對獲取的類的方法的一次執行,執行實例化的User類的無參數方法getName()的時候必須傳出該實例化的User對象作爲Object參數,否則getName()方法執行也獲取不到結果,會返回NULl. //利用該實體類對象執行該get方法,即 Object value = method.invoke(object, new Object[] {}); 此處的Object要是實例化的一個具體的User.
4,實現excel列寬度的自適應:在遍歷列的頭的時候維護一個Map存入每個屬性的基本列寬爲(short)3000,然後在填入數據的時候比較最長的一條記錄的長度經過相應的計算我這邊大概估計了一下用獲得的value的值(short)(vakue*280+1000)就是最終的列寬度,最後在循環一下設置列寬度即可。
測試 代碼:
@SuppressWarnings("deprecation")
@Test
public void test () throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
List<User> list = userService.getUserList();
String[] sheetName = {"用戶"};
ClassUtil.reportExport(list,sheetName,"d:user.xcl");
}
運行結果: