Excel导入导出
2016-03-08 08:12
260 查看
由于项目中经常需要进行数据的导入和导出。所以研究下Excel的导入导出技术并作出整理。采用的是Apache POI 对Excel的支持。
Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案(适用于Excel97-2008)。
其中 HSSF - 提供读写Microsoft Excel XLS格式档案的功能 。XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
网上搜索资料并进行了修改封装:
2、ExcelColumn.java 表头信息和ExcelHead.java列信息
ExcelHead.java 表头信息
3、ExcelHelper.java 导入导出的工具类(借鉴网上他人代码) 采用泛型方式可直接导入相应对象类型的数据
4、ExcelHelper.java 工厂化方法按Excel格式产生特定的Excel导入导出工具
最后实际应用例子:
// 1、Excel中每一行的信息
List<ExcelColumn> excelColumns = Lists.newArrayList();
excelColumns.add(new ExcelColumn(0, "strName", "机构名称"));
excelColumns.add(new ExcelColumn(1, "nlevel","机构级别"));
excelColumns.add(new ExcelColumn(2, "strCode", "机构号"));
excelColumns.add(new ExcelColumn(3, "strAddress","机构地址"));
excelColumns.add(new ExcelColumn(4, "parentOrg", "上级机构"));
// 2、机构级别中显示的名称-数据库中整数
Map<String, Integer> levelMap = new HashMap<String, Integer>(){
{
put("总行", 0); put("一级分行", 1); put("二级分行", 2);
put("直属支行", 3); put("支行", 4); put("办事处", 5);
put("经营支行", 6); put("分理处", 7); put("储蓄所",8);
}
};
// 3、excel中显示的信息转换为数据库中的值
Map<String, Map<?, ?>> excelColumnsConvertMap = Maps.newHashMap();
excelColumnsConvertMap.put("nlevel", levelMap);
// 4、组装excel信息
ExcelHead excelHead = new ExcelHead();
excelHead.setColumnCount(2);
excelHead.setColumns(excelColumns);
excelHead.setColumnsConvertMap(excelColumnsConvertMap);
// 5、Excel导入类使用
List<OrganizationDto> orgs = Lists.newArrayList();
ExcelHelper<OrganizationDto> excelHelper = ExcelHelperFactory.createExcelHelper(fileName);
orgs = excelHelper.importToObjectList(excelHead, orgFile, OrganizationDto.class);
Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案(适用于Excel97-2008)。
其中 HSSF - 提供读写Microsoft Excel XLS格式档案的功能 。XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
网上搜索资料并进行了修改封装:
1、ExcelBeanUtils.java 工具类
/** * <p>Excel导入数据时进行bean的复制</p> * -为Date类型注册类型转换器 * @version V1.0 */ public class ExcelBeanUtils extends org.apache.commons.beanutils.BeanUtils{ private static final String CONTEXT_KEY_FORMAT_DATE_VALUE = "yyyy-MM-dd"; private static final String CONTEXT_KEY_FORMAT_DATETIME_VALUE = "yyyy-MM-dd HH:mm:ss"; private static final String CONTEXT_KEY_FORMAT_TIME_VALUE = "HH:mm:ss"; static { DateConverter dateConverter = new DateConverter(null); dateConverter.setUseLocaleFormat(true); dateConverter.setPatterns(new String[]{CONTEXT_KEY_FORMAT_DATE_VALUE, CONTEXT_KEY_FORMAT_DATETIME_VALUE, CONTEXT_KEY_FORMAT_TIME_VALUE}); ConvertUtils.register(dateConverter, Date.class); } public static class DateConverter extends DateTimeConverter { public DateConverter() { } public DateConverter(Object defaultValue) { super(defaultValue); } @SuppressWarnings("rawtypes") protected Class getDefaultType() { return Date.class; } @SuppressWarnings("rawtypes") @Override protected Object convertToType(Class type, Object obj) throws Exception { if (obj == null) { return null; } String value = obj.toString().trim(); if (value.length() == 0) { return null; } return super.convertToType(type, obj); } } public static void populateBean(Object bean, Map<?, ?> properties) throws IllegalAccessException, InvocationTargetException{ populate(bean, properties); } }
2、ExcelColumn.java 表头信息和ExcelHead.java列信息
/** * <p>Excel列信息</p> * @author maxianming 2016-1-21 上午10:40:42 * @version V1.0 */ public class ExcelColumn { /** * 列索引 */ private Integer index; /** * 实际字段名称 */ private String fieldName; /** * 表格中的显示名称 */ private String fieldDispName; /** * 字段类型。数字类型还是日期等 */ private Integer type; public ExcelColumn() { } public ExcelColumn(int index, String fieldName, String fieldDispName) { this.index = index; this.fieldName = fieldName; this.fieldDispName = fieldDispName; } public ExcelColumn(int index, String fieldName, String fieldDispName, int type) { this.index = index; this.fieldName = fieldName; this.fieldDispName = fieldDispName; this.type = type; } public Integer getIndex() { return index; } public void setIndex(Integer index) { this.index = index; } public String getFieldName() { return fieldName; } public void setFieldName(String fieldName) { this.fieldName = fieldName; } public String getFieldDispName() { return fieldDispName; } public void setFieldDispName(String fieldDispName) { this.fieldDispName = fieldDispName; } public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } }
ExcelHead.java 表头信息
public class ExcelHead { /** * 列信息 */ private List<ExcelColumn> columns; /** * 需要转换的列 */ private Map<String, Map<?, ?>> columnsConvertMap; /** * 头部所占用的行数 */ private int rowCount; /** * 头部所占用的列数 */ private int columnCount; public List<ExcelColumn> getColumns() { return columns; } public int getRowCount() { return rowCount; } public int getColumnCount() { return columnCount; } public void setColumns(List<ExcelColumn> columns) { this.columns = columns; } public void setRowCount(int rowCount) { this.rowCount = rowCount; } public void setColumnCount(int columnCount) { this.columnCount = columnCount; } public Map<String, Map<?, ?>> getColumnsConvertMap() { return columnsConvertMap; } public void setColumnsConvertMap(Map<String, Map<?, ?>> columnsConvertMap) { this.columnsConvertMap = columnsConvertMap; } @Override public String toString() { return "ExcelHead [columnCount=" + columnCount + ", columns=" + columns + ", columnsConvertMap=" + columnsConvertMap + ", rowCount=" + rowCount + "]"; } }
3、ExcelHelper.java 导入导出的工具类(借鉴网上他人代码) 采用泛型方式可直接导入相应对象类型的数据
package com.hikvision.finance.isms.common.excel; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import com.google.common.collect.Lists; import com.hikvision.finance.core.util.BeanUtils; import com.hikvision.finance.core.util.DateUtils; import com.hikvision.finance.fwork.exception.ExpectedException; import com.hikvision.finance.isms.common.excel.model.ExcelColumn; import com.hikvision.finance.isms.common.excel.model.ExcelHead; import com.hikvision.finance.isms.common.excel.utils.ExcelBeanUtils; import com.hikvision.finance.isms.common.excel.utils.ExcelUtils; /** * <p>导入、导出的Excel帮助类</p> * -导入数据到相关泛型对象T中 * @author maxianming 2016-1-21 下午12:14:35 * @version V1.0 */ public class ExcelHelper<T> { private IPoiExcelOperation excelOperation; public IPoiExcelOperation getExcelOperation() { return excelOperation; } public void setExcelOperation(IPoiExcelOperation excelOperation) { this.excelOperation = excelOperation; } public ExcelHelper(IPoiExcelOperation excelOperation){ this.excelOperation = excelOperation; } /** * <p>将excel中数据导入到list中</p> * 文件读取失败会抛出ExpectedException * @author maxianming 2016-1-21 下午12:21:24 * @param head 文件头信息 * @param file 导入的数据源 * @param cls 保存当前数据的对象 * @return */ public List<T> importToObjectList(ExcelHead head, File file, Class<T> cls) { List<T> contents = null; FileInputStream fis; List<List<?>> rows = null; // 根据excel 每行 生成list类型的数据 try { fis = new FileInputStream(file); rows = excelFileConvertToList(fis); } catch (Exception ex) { ex.printStackTrace(); throw new ExpectedException("","读取文件失败"); } // 1.删除头信息 if(rows != null){ for (int i = 0; i < head.getRowCount(); i++) { rows.remove(0); } } // 2.将表结构转换成Map Map<Integer, String> excelHeadMap = convertExcelHeadToMap(head.getColumns()); // 3.构建为对象 contents = buildDataObject(excelHeadMap, head.getColumnsConvertMap(), rows, cls); return contents; } /** * 将Excel文件内容转换为List对象 * @author maxianming 2016-1-20 下午6:15:05 * @param fis excel文件 * @return List<List> list存放形式的内容 * @throws Exception */ public List<List<?>> excelFileConvertToList(FileInputStream fis) throws Exception{ Workbook wb = this.excelOperation.readExcel(fis); Sheet sheet = wb.getSheetAt(0); List<List<?>> rows = new ArrayList<List<?>>(); if(sheet != null){ for (Row row : sheet) { if(!ExcelUtils.isBlankRow(row)){ List<Object> cells = new ArrayList<Object>(); for (Cell cell : row) { Object obj = null; obj = this.getValue(cell); cells.add(obj); } rows.add(cells); } } } return rows; } /** * <p>将Excel中的数据类型进行转换</P> * @author maxianming 2016-1-21 下午6:27:54 * @param cell * @return */ private Object getValue(Cell cell) { Object value = null; if(cell != null){ switch (cell.getCellType()) { case Cell.CELL_TYPE_STRING: value = cell.getRichStringCellValue().getString(); break; case Cell.CELL_TYPE_NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { value = cell.getDateCellValue(); } else { BigDecimal big = new BigDecimal(cell.getNumericCellValue()); String strValue = big.toString(); // 解决1234.0 去掉后面的.0 if(null != strValue && !"".equals(strValue.trim())){ String[] item = strValue.split("[.]"); if(1 < item.length && "0".equals(item[1])){ strValue = item[0]; } }; value = strValue; } break; case Cell.CELL_TYPE_BOOLEAN: value = cell.getBooleanCellValue(); break; case Cell.CELL_TYPE_FORMULA: value = String.valueOf(cell.getNumericCellValue()); //读公式计算值 if (value.equals("NaN")) { // 如果获取的数据值为非法值,则转换为获取字符串 value = cell.getStringCellValue().toString(); } break; default: value = null; } } return value; } /** * <p>将报表结构转换成Map</p> * @author maxianming 2016-1-22 下午2:43:01 * @param excelColumns * @return */ private Map<Integer, String> convertExcelHeadToMap(List<ExcelColumn> excelColumns) { Map<Integer, String> excelHeadMap = new HashMap<Integer, String>(); for (ExcelColumn excelColumn : excelColumns) { if(StringUtils.isNotEmpty(excelColumn.getFieldName())) { excelHeadMap.put(excelColumn.getIndex(), excelColumn.getFieldName()); } } return excelHeadMap; } /** * <p>根据Excel生成数据对象</P> * @author maxianming 2016-1-21 下午1:42:22 * @param excelHeadMap 表头信息 * @param excelHeadConvertMap 需要特殊转换的单元 * @param rows Excel文件中数据的List对象 * @param cls 转换为的对象 * @return */ private List<T> buildDataObject(Map<Integer, String> excelHeadMap, Map<String, Map<?, ?>> excelHeadConvertMap, List<List<?>> rows, Class<T> cls) { List<T> contents = Lists.newArrayList(); for (List<?> list : rows) { // 1.如果当前第一列中无数据,则忽略当前行的数据 if(list == null || list.get(0) == null) { break; } // 2.当前行的数据放入map中,生成<fieldName, value>的形式 Map<String, Object> rowMap = rowListToMap(excelHeadMap, excelHeadConvertMap, list); // 3.将当前行转换成对应的对象 T obj = null; try { obj = cls.newInstance(); } catch (InstantiationException ex) { ex.printStackTrace(); } catch (IllegalAccessException ex) { ex.printStackTrace(); } try { ExcelBeanUtils.populateBean(obj, rowMap); } catch (IllegalAccessException e) { e.printStackTrace(); throw new ExpectedException("","导入文件内容有误!"); } catch (InvocationTargetException e) { e.printStackTrace(); throw new ExpectedException("","导入文件内容有误!"); } contents.add(obj); } return contents; } /** * <p>将行转行成map,生成<fieldName, value>的形式</p> * @author maxianming 2016-1-21 下午1:46:57 * @param excelHeadMap 表头信息 * @param excelHeadConvertMap 需要转换的信息 * @param list excel中的数据 * @throws ExpectedException 当导入文件不是按模板定义好的格式时,抛出异常。 * @return */ private Map<String, Object> rowListToMap(Map<Integer, String> excelHeadMap, Map<String, Map<?, ?>> excelHeadConvertMap, List<?> list) { Map<String, Object> rowMap = new HashMap<String, Object>(); if(excelHeadMap.size() > list.size()){ throw new ExpectedException("", "导入文件的内容格式有误!"); } for(int i = 0; i < list.size(); i++) { String fieldName = excelHeadMap.get(i); if(fieldName != null) { // 得到一行数据中每个单元格的value Object value = list.get(i); if(excelHeadConvertMap != null && excelHeadConvertMap.get(fieldName) != null) { value = excelHeadConvertMap.get(fieldName).get(value); } rowMap.put(fieldName, value); } } return rowMap; } /*--------------------------------导出功能还未完善-----------------------------------*/ /** * 导出数据至Excel文件 * @author maxianming 2016-1-20 下午6:41:30 * @param head 报表头信息 * @param modelFile 导出文件 * @param outputFile 导出文件 * @param dataList 导入excel报表的数据来源 */ public void exportExcelFile(ExcelHead head, File modelFile, File outputFile, List<?> dataList) { InputStream inp = null; Workbook wb = null; try { // 1.读取导出excel模板 inp = new FileInputStream(modelFile); wb = this.excelOperation.readExcel(inp); Sheet sheet = wb.getSheetAt(0); // 2.生成导出数据 buildExcelData(sheet, head, dataList); // 3.导出到文件中 FileOutputStream fileOut = new FileOutputStream(outputFile); wb.write(fileOut); fileOut.close(); } catch (FileNotFoundException ex) { ex.printStackTrace(); } catch (InvalidFormatException ex) { ex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } } /** * <p>生成导出至Excel文件的数据</p> * @author maxianming 2016-1-22 下午2:45:45 * @param sheet 工作区间 * @param head excel表头 * @param dataList 导入excel报表的数据来源 */ private void buildExcelData(Sheet sheet, ExcelHead head, List<?> dataList) { List<ExcelColumn> excelColumns = head.getColumns(); Map<String, Map<?, ?>> excelHeadConvertMap = head.getColumnsConvertMap(); // 1.将表结构转换成Map Map<Integer, String> excelHeadMap = convertExcelHeadToMap(excelColumns); // 2.从第几行开始插入数据 int startRow = head.getRowCount(); int order = 1; for (Object obj : dataList) { Row row = sheet.createRow(startRow++); for (int j = 0; j < excelColumns.size(); j++) { Cell cell = row.createCell(j); cell.setCellType(excelColumns.get(j).getType()); String fieldName = excelHeadMap.get(j); if(fieldName != null) { Object valueObject = null; try { valueObject = BeanUtils.getProperty(obj, fieldName); } catch (Exception e){ e.printStackTrace(); } /* * 如果存在需要转换的字段信息,则进行转换 */ if(excelHeadConvertMap != null && excelHeadConvertMap.get(fieldName) != null) { valueObject = excelHeadConvertMap.get(fieldName).get(valueObject); } if(valueObject == null) { cell.setCellValue(""); } else if (valueObject instanceof Integer) { cell.setCellValue((Integer)valueObject); } else if (valueObject instanceof String) { cell.setCellValue((String)valueObject); } else if (valueObject instanceof Date) { cell.setCellValue(DateUtils.getStringDateTime((Date)valueObject)); } else { cell.setCellValue(valueObject.toString()); } } else { cell.setCellValue(order++); } } } } }
4、ExcelHelper.java 工厂化方法按Excel格式产生特定的Excel导入导出工具
** * <p>产生一个ExcelHelper工具类</p> * @author maxianming 2016-1-22 下午4:28:35 * @version V1.0 */ public class ExcelHelperFactory { /** * <p>根据后缀名类型产生一个ExcelHelper类</p> * @author maxianming 2016-1-22 下午4:30:41 * @param cls */ public static <T> ExcelHelper<T> createExcelHelper(String fileName){ ExcelHelper<T> excelHelper = null; if(StringUtils.isNotBlank(fileName)){ String type = fileName.substring(fileName.lastIndexOf(".") + 1); if("xls".equals(type)){ excelHelper = new ExcelHelper<T>(new HSSFExcel()); } else if("xlsx".equals(type)){ excelHelper = new ExcelHelper<T>(new XSSFExcel()); } else{ throw new ExpectedException("","不支持Excel文件的扩展名【" + type +"】"); } } return excelHelper; } }
最后实际应用例子:
// 1、Excel中每一行的信息
List<ExcelColumn> excelColumns = Lists.newArrayList();
excelColumns.add(new ExcelColumn(0, "strName", "机构名称"));
excelColumns.add(new ExcelColumn(1, "nlevel","机构级别"));
excelColumns.add(new ExcelColumn(2, "strCode", "机构号"));
excelColumns.add(new ExcelColumn(3, "strAddress","机构地址"));
excelColumns.add(new ExcelColumn(4, "parentOrg", "上级机构"));
// 2、机构级别中显示的名称-数据库中整数
Map<String, Integer> levelMap = new HashMap<String, Integer>(){
{
put("总行", 0); put("一级分行", 1); put("二级分行", 2);
put("直属支行", 3); put("支行", 4); put("办事处", 5);
put("经营支行", 6); put("分理处", 7); put("储蓄所",8);
}
};
// 3、excel中显示的信息转换为数据库中的值
Map<String, Map<?, ?>> excelColumnsConvertMap = Maps.newHashMap();
excelColumnsConvertMap.put("nlevel", levelMap);
// 4、组装excel信息
ExcelHead excelHead = new ExcelHead();
excelHead.setColumnCount(2);
excelHead.setColumns(excelColumns);
excelHead.setColumnsConvertMap(excelColumnsConvertMap);
// 5、Excel导入类使用
List<OrganizationDto> orgs = Lists.newArrayList();
ExcelHelper<OrganizationDto> excelHelper = ExcelHelperFactory.createExcelHelper(fileName);
orgs = excelHelper.importToObjectList(excelHead, orgFile, OrganizationDto.class);
相关文章推荐
- VMware与Windows主机交换文件
- 部分JAVA设计模式在Android中的体现。
- 4200: [Noi2015]小园丁与老司机 DP+有源汇上下界最小流
- java,作业张三李四,运用类的继承
- Ubuntu 16.04 为更好支持容器化而采用 ZFS
- 线段树——I hate it
- 程序中写数据到文件
- 互联网面试总结(三) : 算法
- 《数据结构》顺序栈
- ATEN宏正盛装出席Infocomm China 2016
- 互联网面试总结(二) : 概述题
- HTML 5 视频使用
- 正则表达式
- 前端性能优化--能用css的地方尽量不要用js
- [leetcode] 167. Two Sum II - Input array is sorted 解题报告
- 软件第二次作业
- 作业
- oracle GROUPING函数
- Linux用户和用户组基本概念
- andriod VideoView