近期看了下POI,写了一些小例子,结合反射技术对EXCEL的导入到出进行了简单封装,主要实现功能如下:
(1)导入EXCEL文档到List<Map<String,String>>中
(2)导出List<Map<String,String>>类型数据到EXCEL中
(3)导出List<Object>类型的数据到EXCEL中
其中第(3)个方法使用了相应的格式规范加反射,具体使用时只要配置好List中对象的取值方法名,可以实现很大程度上的复用
注:支持对象的深度导出,即List中存放对象的取值方法返回值是另一个对象的引用,最终需要的值在这个引用对象中
多余的话就不说了,上代码(Demo工程放到了文章后面的附件中):
POI封装类(主类)MyPOI.java
package com.lightgjc1.poi;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
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.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class MyPOI {
/**
* 导入Excel文件
* 内容以List<Map<String K,String V>>的方式存放
* @param excelFile : Excel文件对象
* @param strKeys : Map的Key列表,Value为相应的sheet一行中各列的值
* @return
*/
public static List<Map<String,String>> importExcelToMap(File excelFile, String strKeys) {
String[] strKey = strKeys.split(",");
List<Map<String,String>> listMap = new ArrayList<Map<String,String>>();
int i = 1;
try {
HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(excelFile));
HSSFSheet sheet = workbook.getSheetAt(0);
while (true) {
HSSFRow row = sheet.getRow(i);
if (row == null)
break;
Map<String,String> map = new HashMap<String,String>();
for(int keyIndex = 0; keyIndex < strKey.length; keyIndex++){
map.put(strKey[keyIndex], row.getCell(keyIndex).getStringCellValue());
}
listMap.add(map);
i++;
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("导入中断,错误位置:第"+ i +"行数据!");
}
return listMap;
}
/**
* 导出Excel文件
* 数据源的数据格式为List<Map<String K,String V>>
* @param objList : Excel数据源
* @param title : 新建Sheet的名称
* @param strTitle : Sheet各列的标题(第一行各列的名称)
* @param strBody : Sheet各列的取值方法名(各列的值在objClass中get方法名称)
* @param outputPath: Excel文档保存路径
*/
public static void exportExcelByMap(List<Map<String,String>> objList, String title, String strTitle, String strBody, String outputPath) {
// 创建工作簿(Excel文件)
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建Excel工作簿的第一个Sheet页
HSSFSheet sheet = workbook.createSheet(title);
// 创建Sheet页的文件头(第一行)
createTitle(sheet, strTitle);
// 创建Sheet页的文件体(后续行)
String[] strArray = strBody.split(",");
for(int objIndex = 0; objIndex < objList.size(); objIndex++) {
Map map = objList.get(objIndex);
HSSFRow row = sheet.createRow(objIndex + 1);
for(int i = 0; i < strArray.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(map.get(strArray[i]).toString());
}
}
// 保存Excel文件
saveExcelFile(workbook, outputPath);
}
/**
* 导出Excle文档
*
* @param objList : Excel数据源
* @param objClass : Excel数据源中的数据类型
* @param title : 新建Sheet的名称
* ex: title = "员工表";
* @param strTitle : Sheet各列的标题(第一行各列的名称)
* ex: strTitle = "员工代码,员工姓名,性别,出生日期,籍贯,所属机构,联系电话,电子邮件,助记码";
* @param strBody : Sheet各列的取值方法名(各列的值在objClass中get方法名称)
* ex: strBody = "getCode,getName,getSex,getBirthday,getHomeplace.getName,getOrg.getShortName,getContactTel,getEmail,getZjm";
* @param outputPath: Excel文档保存路径
*/
public static void exportExcelByObject(List objList, Class objClass, String title, String strTitle, String strBody, String outputPath) {
// 初始化工作簿
HSSFWorkbook workbook = initWorkbook(objList, objClass, title, strTitle, strBody);
// 保存Excel文件
saveExcelFile(workbook, outputPath);
}
/**
* 初始化工作簿
*
* @param objList : Excel数据源
* @param objClass : Excel数据源中的数据类型
* @param title : 新建Sheet的名称
* @param strTitle : Sheet各列的标题(第一行各列的名称)
* @param strBody : Sheet各列的取值方法名(各列的值在objClass中get方法名称)
*/
private static HSSFWorkbook initWorkbook(List objList, Class objClass, String title, String strTitle, String strBody){
// 创建工作簿(Excel文件)
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建Excel工作簿的第一个Sheet页
HSSFSheet sheet = workbook.createSheet(title);
// 创建Sheet页的文件头(第一行)
createTitle(sheet, strTitle);
// 创建Sheet页的文件体(后续行)
createBody(objList, objClass, sheet, strBody);
return workbook;
}
/**
* 创建Excel当前sheet页的头信息
*
* @param sheet : Excel工作簿的一个sheet
* @param strTitle : sheet头信息列表(sheet第一行各列值)
*/
private static void createTitle(HSSFSheet sheet, String strTitle){
HSSFRow row = sheet.createRow(0); // 创建该页的一行
HSSFCell cell = null;
String[] strArray = strTitle.split(",");
for(int i = 0; i < strArray.length; i++) {
cell = row.createCell(i); // 创建该行的一列
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(strArray[i]);
}
}
/**
* 创建Excel当前sheet页的体信息
*
* @param objList : Excel数据源
* @param objClass : Excel数据源中的数据类型
* @param sheet : Excel工作簿的sheet页
* @param strBody : Sheet各列的取值方法名(各列的值在objClass中get方法名称)
*/
private static void createBody(List objList, Class objClass, HSSFSheet sheet, String strBody){
String[] targetMethod = strBody.split(",");
Method[] ms = objClass.getMethods();
// 循环objList对象列表(生成sheet的行)
for(int objIndex = 0; objIndex < objList.size(); objIndex++){
Object obj = objList.get(objIndex);
HSSFRow row = sheet.createRow(objIndex + 1);
// 循环strBody目标方法数组(生成sheet的列)
for(int strIndex = 0; strIndex < targetMethod.length; strIndex++) {
String targetMethodName = targetMethod[strIndex];
// 循环ms方法数组,找到目标方法(strBody中指定的方法)并调用
for(int i = 0; i < ms.length; i++) {
Method srcMethod = ms[i];
int len = targetMethodName.indexOf(".") < 0 ? targetMethodName.length() : targetMethodName.indexOf(".");
if (srcMethod.getName().equals(targetMethodName.substring(0, len))) {
HSSFCell cell = row.createCell(strIndex);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
try {
// 如果方法返回一个引用类型的值
if (targetMethodName.contains(".")) {
cell.setCellValue(referenceInvoke(targetMethodName, obj));
// 如果方法返回一个普通属性
} else {
cell.setCellValue((srcMethod.invoke(obj)).toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 方法返回的是一个对象的引用(如:getHomeplace.getName类型的方法序列)
* 按方法序列逐层调用直到最后放回基本类型的值
*
* @param targetMethod : obj对象所包含的方法列
* @param obj : 待处理的对象
* @return
*/ //getHomeplace.getName emp(obj)
private static String referenceInvoke(String targetMethod, Object obj) {
// 截取方法序列的第一个方法(即截取属于obj对象的方法:getHomeplace())
String refMethod = targetMethod.substring(0, targetMethod.indexOf("."));
// 获得后续方法序列(getName())
targetMethod = targetMethod.substring(targetMethod.indexOf(".") + 1);
try {
// 获得第一个方法的执行结果(即obj方法执行的结果:obj.getHomeplace())
obj = obj.getClass().getMethod(refMethod).invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
// 如果方法序列没到最后一节
if (targetMethod.contains(".")) {
return referenceInvoke(targetMethod, obj);
// 如果方法序列到达最后一节
} else {
try {
// 通过obj对象获得该方法链的最后一个方法并调用
Method tarMethod = obj.getClass().getMethod(targetMethod);
return tarMethod.invoke(obj).toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
/**
* 保存Excel文件
*
* @param workbook : Excel工作簿
* @param outputPath: Excel文件保存路径
*/
private static void saveExcelFile(HSSFWorkbook workbook, String outputPath) {
try {
FileOutputStream fos = new FileOutputStream(outputPath);
workbook.write(fos);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试类POITest.java
package com.lightgjc1.test;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
import com.lightgjc1.domain.Area;
import com.lightgjc1.domain.Employee;
import com.lightgjc1.domain.OrgType;
import com.lightgjc1.domain.Organization;
import com.lightgjc1.poi.MyPOI;
public class POITest extends TestCase {
public void testImportAndExportExcel(){
String strKeys = "setCode,setName,setSex,setBirthday,setHomeplace,setOrg,setContactTel";
List<Map<String,String>> listMap = MyPOI.importExcelToMap(new File("D:\\employee.xls"), strKeys);
String[] keys = strKeys.split(",");
for(Map map : listMap) {
for(int i = 0; i < keys.length; i++) {
System.out.print(map.get(keys[i]) +" ");
}
System.out.println();
System.out.println("----------------");
}
String title = "员工表";
String strTitle = "员工代码,员工姓名,性别,出生日期,籍贯,所属机构,机构类型";
String strBody = "setCode,setName,setSex,setBirthday,setHomeplace,setOrg,setContactTel";
String outputPath = "D:\\employee2.xls";
MyPOI.exportExcelByMap(listMap, title, strTitle, strBody, outputPath);
}
public void testExportExcel(){
List objList = initData();
Class objClass = Employee.class;
String title = "员工表";
String strTitle = "员工代码,员工姓名,性别,出生日期,籍贯,所属机构,机构类型";
String strBody = "getCode,getName,getSex,getBirthday,getHomeplace.getName,getOrg.getShortName,getOrg.getOrgType.getName";
String outputPath = "D:\\employee.xls";
MyPOI.exportExcelByObject(objList, objClass, title, strTitle, strBody, outputPath);
}
private List initData(){
List empList = new ArrayList();
Employee emp = null;
for(int i = 0; i < 10; i++) {
emp = new Employee();
emp.setCode(i +"号");
emp.setName(i +"号");
emp.setSex(i % 2 == 0 ? "女" : "男");
emp.setBirthday(new Date());
Area area = new Area();
area.setName(i +"市");
emp.setHomeplace(area);
OrgType orgType = new OrgType();
orgType.setName("机构类型"+ i);
Organization org = new Organization();
org.setOrgType(orgType);
org.setShortName("机构"+ i);
emp.setOrg(org);
empList.add(emp);
}
return empList;
}
}
其他工具类(存放数据的实体类)
Employee.java
用来存放员工数据
package com.lightgjc1.domain;
import java.util.Date;
public class Employee {
private String id;
private String code;
private String name;
private String sex;
private Date birthday;
private String email;
private String contactTel;
private String zjm;
private Organization org = new Organization();
private Area homeplace;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContactTel() {
return contactTel;
}
public void setContactTel(String contactTel) {
this.contactTel = contactTel;
}
public String getZjm() {
return zjm;
}
public void setZjm(String zjm) {
this.zjm = zjm;
}
public Organization getOrg() {
return org;
}
public void setOrg(Organization org) {
this.org = org;
}
public Area getHomeplace() {
return homeplace;
}
public void setHomeplace(Area homeplace) {
this.homeplace = homeplace;
}
}
Organization.java
用来存放员工所属的组织部门
package com.lightgjc1.domain;
import java.util.Set;
public class Organization {
private String id;
private String code;
private String fullName;
private String shortName;
private String manager;
private String desc;
//*-----1
private OrgType orgType;
//*-----1
private Organization parent;
//1-----*
private Set<Organization> children;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getManager() {
return manager;
}
public void setManager(String manager) {
this.manager = manager;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public OrgType getOrgType() {
return orgType;
}
public void setOrgType(OrgType orgType) {
this.orgType = orgType;
}
public Organization getParent() {
return parent;
}
public void setParent(Organization parent) {
this.parent = parent;
}
public Set<Organization> getChildren() {
return children;
}
public void setChildren(Set<Organization> children) {
this.children = children;
}
}
OrgType.java
用来存放员工所属组织部门的部门类型
package com.lightgjc1.domain;
public class OrgType {
private String id;
//如果使用数值类型作为主键,建议使用包装类
//private Integer id;
//private int id;
private String code;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Area.java
用来存放员工的籍贯信息
package com.lightgjc1.domain;
import java.util.Set;
public class Area {
private String id;
private String code;
private String name;
private Area parent;
private Set<Area> children;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Area getParent() {
return parent;
}
public void setParent(Area parent) {
this.parent = parent;
}
public Set<Area> getChildren() {
return children;
}
public void setChildren(Set<Area> children) {
this.children = children;
}
}