| @@ -38,6 +38,11 @@ public @interface Excel { | |||||
| * 导出的时间格式,以这个是否为空来判断是否需要格式化日期 | * 导出的时间格式,以这个是否为空来判断是否需要格式化日期 | ||||
| */ | */ | ||||
| public String exportFormat() default ""; | public String exportFormat() default ""; | ||||
| /** | |||||
| * 导入的时间格式,以这个是否为空来判断是否需要格式化日期 | |||||
| */ | |||||
| public String importFormat() default ""; | |||||
| /** | /** | ||||
| * 时间格式,相当于同时设置了exportFormat 和 importFormat | * 时间格式,相当于同时设置了exportFormat 和 importFormat | ||||
| @@ -50,7 +55,9 @@ public @interface Excel { | |||||
| /** | /** | ||||
| * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 | * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 | ||||
| * 优先选择@ExcelEntity中的 height | |||||
| */ | */ | ||||
| @Deprecated | |||||
| public double height() default 10; | public double height() default 10; | ||||
| /** | /** | ||||
| @@ -58,11 +65,6 @@ public @interface Excel { | |||||
| */ | */ | ||||
| public int imageType() default 1; | public int imageType() default 1; | ||||
| /** | |||||
| * 导入的时间格式,以这个是否为空来判断是否需要格式化日期 | |||||
| */ | |||||
| public String importFormat() default ""; | |||||
| /** | /** | ||||
| * 文字后缀,如% 90 变成90% | * 文字后缀,如% 90 变成90% | ||||
| */ | */ | ||||
| @@ -22,7 +22,6 @@ import java.lang.annotation.Target; | |||||
| /** | /** | ||||
| * 标记是不是导出excel 标记为实体类 | * 标记是不是导出excel 标记为实体类 | ||||
| * | |||||
| * @author JueYue | * @author JueYue | ||||
| * | * | ||||
| */ | */ | ||||
| @@ -40,4 +39,5 @@ public @interface ExcelEntity { | |||||
| * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 | * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 | ||||
| */ | */ | ||||
| public String name() default ""; | public String name() default ""; | ||||
| } | } | ||||
| @@ -33,4 +33,15 @@ public @interface ExcelTarget { | |||||
| * 定义excel导出ID 来限定导出字段 | * 定义excel导出ID 来限定导出字段 | ||||
| */ | */ | ||||
| public String value(); | public String value(); | ||||
| /** | |||||
| * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 | |||||
| * 全局设置,优先使用 | |||||
| */ | |||||
| public double height() default 10; | |||||
| /** | |||||
| * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 | |||||
| * 全局设置,优先使用 | |||||
| */ | |||||
| public short fontSize() default 11; | |||||
| } | } | ||||
| @@ -85,7 +85,8 @@ public class ExcelImportUtil { | |||||
| } | } | ||||
| /** | /** | ||||
| * Excel 导入 数据源IO流,返回校验结果 字段类型 Integer,Long,Double,Date,String,Boolean | |||||
| * Excel 导入 数据源IO流 字段类型 Integer,Long,Double,Date,String,Boolean | |||||
| * 支持校验,支持Key-Value | |||||
| * | * | ||||
| * @param inputstream | * @param inputstream | ||||
| * @param pojoClass | * @param pojoClass | ||||
| @@ -93,21 +94,21 @@ public class ExcelImportUtil { | |||||
| * @return | * @return | ||||
| * @throws Exception | * @throws Exception | ||||
| */ | */ | ||||
| public static <T> ExcelImportResult<T> importExcelVerify(InputStream inputstream, | |||||
| public static <T> ExcelImportResult<T> importExcelMore(InputStream inputstream, | |||||
| Class<?> pojoClass, | Class<?> pojoClass, | ||||
| ImportParams params) throws Exception { | ImportParams params) throws Exception { | ||||
| return new ExcelImportServer().importExcelByIs(inputstream, pojoClass, params); | return new ExcelImportServer().importExcelByIs(inputstream, pojoClass, params); | ||||
| } | } | ||||
| /** | /** | ||||
| * Excel 导入 数据源本地文件,返回校验结果 字段类型 Integer,Long,Double,Date,String,Boolean | |||||
| * | |||||
| * Excel 导入 数据源本地文件 字段类型 Integer,Long,Double,Date,String,Boolean | |||||
| * 支持校验,支持Key-Value | |||||
| * @param file | * @param file | ||||
| * @param pojoClass | * @param pojoClass | ||||
| * @param params | * @param params | ||||
| * @return | * @return | ||||
| */ | */ | ||||
| public static <T> ExcelImportResult<T> importExcelVerify(File file, Class<?> pojoClass, | |||||
| public static <T> ExcelImportResult<T> importExcelMore(File file, Class<?> pojoClass, | |||||
| ImportParams params) { | ImportParams params) { | ||||
| FileInputStream in = null; | FileInputStream in = null; | ||||
| try { | try { | ||||
| @@ -44,7 +44,7 @@ public class ImportParams extends ExcelBaseParams { | |||||
| * 大家不理解,去掉这个 | * 大家不理解,去掉这个 | ||||
| */ | */ | ||||
| private Integer keyIndex = null; | |||||
| private Integer keyIndex = 0; | |||||
| /** | /** | ||||
| * 开始读取的sheet位置,默认为0 | * 开始读取的sheet位置,默认为0 | ||||
| */ | */ | ||||
| @@ -82,6 +82,15 @@ public class ImportParams extends ExcelBaseParams { | |||||
| * 导入时校验数据模板,是不是正确的Excel | * 导入时校验数据模板,是不是正确的Excel | ||||
| */ | */ | ||||
| private String[] importFields; | private String[] importFields; | ||||
| /** | |||||
| * Key-Value 读取标记,以这个为Key,后面一个Cell 为Value,多个改为ArrayList | |||||
| */ | |||||
| private String keyMark = ":"; | |||||
| /** | |||||
| * 按照Key-Value 规则读取全局扫描Excel,但是跳过List读取范围提升性能 | |||||
| * 仅仅支持titleRows + headRows + startRows 以及 lastOfInvalidRow | |||||
| */ | |||||
| private boolean readSingleCell = false; | |||||
| public int getHeadRows() { | public int getHeadRows() { | ||||
| return headRows; | return headRows; | ||||
| @@ -188,5 +197,19 @@ public class ImportParams extends ExcelBaseParams { | |||||
| return keyIndex; | return keyIndex; | ||||
| } | } | ||||
| public String getKeyMark() { | |||||
| return keyMark; | |||||
| } | |||||
| public void setKeyMark(String keyMark) { | |||||
| this.keyMark = keyMark; | |||||
| } | |||||
| public boolean isReadSingleCell() { | |||||
| return readSingleCell; | |||||
| } | |||||
| public void setReadSingleCell(boolean readSingleCell) { | |||||
| this.readSingleCell = readSingleCell; | |||||
| } | |||||
| } | } | ||||
| @@ -16,6 +16,7 @@ | |||||
| package cn.afterturn.easypoi.excel.entity.result; | package cn.afterturn.easypoi.excel.entity.result; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Map; | |||||
| import org.apache.poi.ss.usermodel.Workbook; | import org.apache.poi.ss.usermodel.Workbook; | ||||
| @@ -42,6 +43,8 @@ public class ExcelImportResult<T> { | |||||
| */ | */ | ||||
| private Workbook workbook; | private Workbook workbook; | ||||
| private Map<String,Object> map; | |||||
| public ExcelImportResult() { | public ExcelImportResult() { | ||||
| } | } | ||||
| @@ -76,4 +79,11 @@ public class ExcelImportResult<T> { | |||||
| this.workbook = workbook; | this.workbook = workbook; | ||||
| } | } | ||||
| public Map<String, Object> getMap() { | |||||
| return map; | |||||
| } | |||||
| public void setMap(Map<String, Object> map) { | |||||
| this.map = map; | |||||
| } | |||||
| } | } | ||||
| @@ -110,13 +110,6 @@ public class ExcelExportServer extends ExcelExportBase { | |||||
| } | } | ||||
| try { | try { | ||||
| List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>(); | List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>(); | ||||
| /** | |||||
| * createSheetMap 中也会判断index字段,会导致重复添加,出现null 情况 | |||||
| * 这里的代码注释掉 @date 2016-05-27 by xfworld | |||||
| */ | |||||
| // if (entity.isAddIndex()) { | |||||
| // excelParams.add(indexExcelEntity(entity)); | |||||
| // } | |||||
| // 得到所有字段 | // 得到所有字段 | ||||
| Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); | Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); | ||||
| ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); | ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); | ||||
| @@ -126,7 +119,6 @@ public class ExcelExportServer extends ExcelExportBase { | |||||
| //获取所有参数后,后面的逻辑判断就一致了 | //获取所有参数后,后面的逻辑判断就一致了 | ||||
| createSheetForMap(workbook, entity, excelParams, dataSet); | createSheetForMap(workbook, entity, excelParams, dataSet); | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| LOGGER.error(e.getMessage(), e); | |||||
| LOGGER.error(e.getMessage(), e); | LOGGER.error(e.getMessage(), e); | ||||
| throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); | throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); | ||||
| } | } | ||||
| @@ -29,6 +29,7 @@ import java.util.List; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.apache.commons.lang3.builder.ReflectionToStringBuilder; | |||||
| import org.apache.poi.POIXMLDocument; | import org.apache.poi.POIXMLDocument; | ||||
| import org.apache.poi.hssf.usermodel.HSSFSheet; | import org.apache.poi.hssf.usermodel.HSSFSheet; | ||||
| import org.apache.poi.hssf.usermodel.HSSFWorkbook; | import org.apache.poi.hssf.usermodel.HSSFWorkbook; | ||||
| @@ -226,9 +227,13 @@ public class ExcelImportServer extends ImportBaseService { | |||||
| collection.add(object); | collection.add(object); | ||||
| } | } | ||||
| } catch (ExcelImportException e) { | } catch (ExcelImportException e) { | ||||
| LOGGER.error("excel import error , row num:{},obj:{}",readRow, ReflectionToStringBuilder.toString(object)); | |||||
| if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) { | if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) { | ||||
| throw new ExcelImportException(e.getType(), e); | throw new ExcelImportException(e.getType(), e); | ||||
| } | } | ||||
| } catch (Exception e) { | |||||
| LOGGER.error("excel import error , row num:{},obj:{}",readRow, ReflectionToStringBuilder.toString(object)); | |||||
| throw new RuntimeException(e); | |||||
| } | } | ||||
| } | } | ||||
| readRow++; | readRow++; | ||||
| @@ -374,6 +379,7 @@ public class ExcelImportServer extends ImportBaseService { | |||||
| } else if (DocumentFactoryHelper.hasOOXMLHeader(inputstream)) { | } else if (DocumentFactoryHelper.hasOOXMLHeader(inputstream)) { | ||||
| book = new XSSFWorkbook(OPCPackage.open(inputstream)); | book = new XSSFWorkbook(OPCPackage.open(inputstream)); | ||||
| } | } | ||||
| ExcelImportResult importResult = new ExcelImportResult(result, verfiyFail, book); | |||||
| createErrorCellStyle(book); | createErrorCellStyle(book); | ||||
| Map<String, PictureData> pictures; | Map<String, PictureData> pictures; | ||||
| for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex() | for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex() | ||||
| @@ -395,11 +401,58 @@ public class ExcelImportServer extends ImportBaseService { | |||||
| if (LOGGER.isDebugEnabled()) { | if (LOGGER.isDebugEnabled()) { | ||||
| LOGGER.debug(" end to read excel list by pos ,endTime is {}", new Date().getTime()); | LOGGER.debug(" end to read excel list by pos ,endTime is {}", new Date().getTime()); | ||||
| } | } | ||||
| if(params.isReadSingleCell()){ | |||||
| readSingleCell(importResult, book.getSheetAt(i),params); | |||||
| if (LOGGER.isDebugEnabled()) { | |||||
| LOGGER.debug(" read Key-Value ,endTime is {}", new Date().getTime()); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| if (params.isNeedSave()) { | if (params.isNeedSave()) { | ||||
| saveThisExcel(params, pojoClass, isXSSFWorkbook, book); | saveThisExcel(params, pojoClass, isXSSFWorkbook, book); | ||||
| } | } | ||||
| return new ExcelImportResult(result, verfiyFail, book); | |||||
| importResult.setVerfiyFail(verfiyFail); | |||||
| return importResult; | |||||
| } | |||||
| /** | |||||
| * 按照键值对的方式取得Excel里面的数据 | |||||
| * @param result | |||||
| * @param sheet | |||||
| * @param params | |||||
| */ | |||||
| private void readSingleCell(ExcelImportResult result, Sheet sheet, ImportParams params) { | |||||
| if(result.getMap() == null){ | |||||
| result.setMap(new HashMap<String, Object>()); | |||||
| } | |||||
| for (int i = 0; i < params.getTitleRows() + params.getHeadRows() + params.getStartRows(); i++) { | |||||
| getSingleCellValueForRow(result,sheet.getRow(i),params); | |||||
| } | |||||
| for (int i = sheet.getLastRowNum() - params.getLastOfInvalidRow(); i < sheet.getLastRowNum(); i++) { | |||||
| getSingleCellValueForRow(result,sheet.getRow(i),params); | |||||
| } | |||||
| } | |||||
| private void getSingleCellValueForRow(ExcelImportResult result, Row row, ImportParams params) { | |||||
| for (int j = row.getFirstCellNum(), le = row.getLastCellNum(); j < le; j++) { | |||||
| String text = PoiCellUtil.getCellValue(row.getCell(j)); | |||||
| if(StringUtils.isNoneBlank(text) && text.endsWith(params.getKeyMark())){ | |||||
| if(result.getMap().containsKey(text)){ | |||||
| if(result.getMap().get(text) instanceof String){ | |||||
| List<String> list = new ArrayList<String>(); | |||||
| list.add((String)result.getMap().get(text)); | |||||
| result.getMap().put(text,list); | |||||
| } | |||||
| ((List)result.getMap().get(text)).add(PoiCellUtil.getCellValue(row.getCell(++j))); | |||||
| }else{ | |||||
| result.getMap().put(text,PoiCellUtil.getCellValue(row.getCell(++j))); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -27,7 +27,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 纵向合并相同内容的单元格 | * 纵向合并相同内容的单元格 | ||||
| * | |||||
| * | |||||
| * @param sheet | * @param sheet | ||||
| * @param startRow 开始行 | * @param startRow 开始行 | ||||
| * @param columns 需要处理的列 | * @param columns 需要处理的列 | ||||
| @@ -45,7 +45,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 纵向合并相同内容的单元格 | * 纵向合并相同内容的单元格 | ||||
| * | |||||
| * | |||||
| * @param sheet | * @param sheet | ||||
| * @param mergeMap key--列,value--依赖的列,没有传空 | * @param mergeMap key--列,value--依赖的列,没有传空 | ||||
| * @param startRow 开始行 | * @param startRow 开始行 | ||||
| @@ -56,7 +56,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 纵向合并相同内容的单元格 | * 纵向合并相同内容的单元格 | ||||
| * | |||||
| * | |||||
| * @param sheet | * @param sheet | ||||
| * @param mergeMap key--列,value--依赖的列,没有传空 | * @param mergeMap key--列,value--依赖的列,没有传空 | ||||
| * @param startRow 开始行 | * @param startRow 开始行 | ||||
| @@ -94,8 +94,10 @@ public final class PoiMergeCellUtil { | |||||
| } | } | ||||
| if (mergeDataMap.size() > 0) { | if (mergeDataMap.size() > 0) { | ||||
| for (Integer index : mergeDataMap.keySet()) { | for (Integer index : mergeDataMap.keySet()) { | ||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| if(mergeDataMap.get(index).getEndRow() > mergeDataMap.get(index).getStartRow()) { | |||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -103,7 +105,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 处理合并单元格 | * 处理合并单元格 | ||||
| * | |||||
| * | |||||
| * @param index | * @param index | ||||
| * @param rowNum | * @param rowNum | ||||
| * @param text | * @param text | ||||
| @@ -119,8 +121,10 @@ public final class PoiMergeCellUtil { | |||||
| if (checkIsEqualByCellContents(mergeDataMap.get(index), text, cell, delys, rowNum)) { | if (checkIsEqualByCellContents(mergeDataMap.get(index), text, cell, delys, rowNum)) { | ||||
| mergeDataMap.get(index).setEndRow(rowNum); | mergeDataMap.get(index).setEndRow(rowNum); | ||||
| } else { | } else { | ||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| if(mergeDataMap.get(index).getEndRow() > mergeDataMap.get(index).getStartRow()){ | |||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| } | |||||
| mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys)); | mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys)); | ||||
| } | } | ||||
| } else { | } else { | ||||
| @@ -130,7 +134,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 字符为空的情况下判断 | * 字符为空的情况下判断 | ||||
| * | |||||
| * | |||||
| * @param index | * @param index | ||||
| * @param mergeDataMap | * @param mergeDataMap | ||||
| * @param sheet | * @param sheet | ||||
| @@ -139,8 +143,12 @@ public final class PoiMergeCellUtil { | |||||
| Sheet sheet) { | Sheet sheet) { | ||||
| if (mergeDataMap.containsKey(index) | if (mergeDataMap.containsKey(index) | ||||
| && mergeDataMap.get(index).getEndRow() != mergeDataMap.get(index).getStartRow()) { | && mergeDataMap.get(index).getEndRow() != mergeDataMap.get(index).getStartRow()) { | ||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| try { | |||||
| sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), | |||||
| mergeDataMap.get(index).getEndRow(), index, index)); | |||||
| } catch (Exception e) { | |||||
| } | |||||
| mergeDataMap.remove(index); | mergeDataMap.remove(index); | ||||
| } | } | ||||
| } | } | ||||
| @@ -179,7 +187,7 @@ public final class PoiMergeCellUtil { | |||||
| /** | /** | ||||
| * 获取一个单元格的值,确保这个单元格必须有值,不然向上查询 | * 获取一个单元格的值,确保这个单元格必须有值,不然向上查询 | ||||
| * | |||||
| * | |||||
| * @param cell | * @param cell | ||||
| * @param index | * @param index | ||||
| * @param rowNum | * @param rowNum | ||||