首先介绍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 setConditionMap(Object obj){
Map map = new HashMap();
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 mapMax = new HashMap();
//写入表头
row[0] = sheet.createRow(0);
for(int i=0;ishort)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//根据类获得的属性名值相对的map
Map, ?> map = ClassUtil.setConditionMap(list.get(j));
row[j] = sheet.createRow(j);
for(int i=0;ishort)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;ishort)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 list = userService.getUserList();
String[] sheetName = {"用户"};
ClassUtil.reportExport(list,sheetName,"d:user.xcl");
}