diff --git a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/Excel.java b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/Excel.java index f72c14b..2bddea3 100644 --- a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/Excel.java +++ b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/Excel.java @@ -38,6 +38,11 @@ public @interface Excel { * 导出的时间格式,以这个是否为空来判断是否需要格式化日期 */ public String exportFormat() default ""; + /** + * 导入的时间格式,以这个是否为空来判断是否需要格式化日期 + */ + public String importFormat() default ""; + /** * 时间格式,相当于同时设置了exportFormat 和 importFormat @@ -50,7 +55,9 @@ public @interface Excel { /** * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 + * 优先选择@ExcelEntity中的 height */ + @Deprecated public double height() default 10; /** @@ -58,11 +65,6 @@ public @interface Excel { */ public int imageType() default 1; - /** - * 导入的时间格式,以这个是否为空来判断是否需要格式化日期 - */ - public String importFormat() default ""; - /** * 文字后缀,如% 90 变成90% */ diff --git a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelEntity.java b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelEntity.java index 06dfbcf..d28d5fa 100644 --- a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelEntity.java +++ b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelEntity.java @@ -22,7 +22,6 @@ import java.lang.annotation.Target; /** * 标记是不是导出excel 标记为实体类 - * * @author JueYue * */ @@ -40,4 +39,5 @@ public @interface ExcelEntity { * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 */ public String name() default ""; + } diff --git a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelTarget.java b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelTarget.java index 46dbf2e..467bf4e 100644 --- a/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelTarget.java +++ b/easypoi-annotation/src/main/java/cn/afterturn/easypoi/excel/annotation/ExcelTarget.java @@ -33,4 +33,15 @@ public @interface ExcelTarget { * 定义excel导出ID 来限定导出字段 */ public String value(); + + /** + * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 + * 全局设置,优先使用 + */ + public double height() default 10; + /** + * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 + * 全局设置,优先使用 + */ + public short fontSize() default 11; } diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/ExcelImportUtil.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/ExcelImportUtil.java index d9bf0ff..94d5f34 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/ExcelImportUtil.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/ExcelImportUtil.java @@ -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 pojoClass @@ -93,21 +94,21 @@ public class ExcelImportUtil { * @return * @throws Exception */ - public static ExcelImportResult importExcelVerify(InputStream inputstream, + public static ExcelImportResult importExcelMore(InputStream inputstream, Class pojoClass, ImportParams params) throws Exception { 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 pojoClass * @param params * @return */ - public static ExcelImportResult importExcelVerify(File file, Class pojoClass, + public static ExcelImportResult importExcelMore(File file, Class pojoClass, ImportParams params) { FileInputStream in = null; try { diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/ImportParams.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/ImportParams.java index 7f53101..fb63729 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/ImportParams.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/ImportParams.java @@ -44,7 +44,7 @@ public class ImportParams extends ExcelBaseParams { * 大家不理解,去掉这个 */ - private Integer keyIndex = null; + private Integer keyIndex = 0; /** * 开始读取的sheet位置,默认为0 */ @@ -82,6 +82,15 @@ public class ImportParams extends ExcelBaseParams { * 导入时校验数据模板,是不是正确的Excel */ 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() { return headRows; @@ -188,5 +197,19 @@ public class ImportParams extends ExcelBaseParams { 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; + } } diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/result/ExcelImportResult.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/result/ExcelImportResult.java index 3d92612..35e95a3 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/result/ExcelImportResult.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/entity/result/ExcelImportResult.java @@ -16,6 +16,7 @@ package cn.afterturn.easypoi.excel.entity.result; import java.util.List; +import java.util.Map; import org.apache.poi.ss.usermodel.Workbook; @@ -42,6 +43,8 @@ public class ExcelImportResult { */ private Workbook workbook; + private Map map; + public ExcelImportResult() { } @@ -76,4 +79,11 @@ public class ExcelImportResult { this.workbook = workbook; } + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } } diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/export/ExcelExportServer.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/export/ExcelExportServer.java index 59d5281..186ef6c 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/export/ExcelExportServer.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/export/ExcelExportServer.java @@ -110,13 +110,6 @@ public class ExcelExportServer extends ExcelExportBase { } try { List excelParams = new ArrayList(); - /** - * createSheetMap 中也会判断index字段,会导致重复添加,出现null 情况 - * 这里的代码注释掉 @date 2016-05-27 by xfworld - */ -// if (entity.isAddIndex()) { -// excelParams.add(indexExcelEntity(entity)); -// } // 得到所有字段 Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); @@ -126,7 +119,6 @@ public class ExcelExportServer extends ExcelExportBase { //获取所有参数后,后面的逻辑判断就一致了 createSheetForMap(workbook, entity, excelParams, dataSet); } catch (Exception e) { - LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e); throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); } diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/imports/ExcelImportServer.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/imports/ExcelImportServer.java index ff31939..2156d37 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/imports/ExcelImportServer.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/excel/imports/ExcelImportServer.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.poi.POIXMLDocument; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -226,9 +227,13 @@ public class ExcelImportServer extends ImportBaseService { collection.add(object); } } catch (ExcelImportException e) { + LOGGER.error("excel import error , row num:{},obj:{}",readRow, ReflectionToStringBuilder.toString(object)); if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) { 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++; @@ -374,6 +379,7 @@ public class ExcelImportServer extends ImportBaseService { } else if (DocumentFactoryHelper.hasOOXMLHeader(inputstream)) { book = new XSSFWorkbook(OPCPackage.open(inputstream)); } + ExcelImportResult importResult = new ExcelImportResult(result, verfiyFail, book); createErrorCellStyle(book); Map pictures; for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex() @@ -395,11 +401,58 @@ public class ExcelImportServer extends ImportBaseService { if (LOGGER.isDebugEnabled()) { 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()) { 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()); + } + 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 list = new ArrayList(); + 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))); + } + + } + + } } /** diff --git a/easypoi-base/src/main/java/cn/afterturn/easypoi/util/PoiMergeCellUtil.java b/easypoi-base/src/main/java/cn/afterturn/easypoi/util/PoiMergeCellUtil.java index e9fe1b4..70977fe 100644 --- a/easypoi-base/src/main/java/cn/afterturn/easypoi/util/PoiMergeCellUtil.java +++ b/easypoi-base/src/main/java/cn/afterturn/easypoi/util/PoiMergeCellUtil.java @@ -27,7 +27,7 @@ public final class PoiMergeCellUtil { /** * 纵向合并相同内容的单元格 - * + * * @param sheet * @param startRow 开始行 * @param columns 需要处理的列 @@ -45,7 +45,7 @@ public final class PoiMergeCellUtil { /** * 纵向合并相同内容的单元格 - * + * * @param sheet * @param mergeMap key--列,value--依赖的列,没有传空 * @param startRow 开始行 @@ -56,7 +56,7 @@ public final class PoiMergeCellUtil { /** * 纵向合并相同内容的单元格 - * + * * @param sheet * @param mergeMap key--列,value--依赖的列,没有传空 * @param startRow 开始行 @@ -94,8 +94,10 @@ public final class PoiMergeCellUtil { } if (mergeDataMap.size() > 0) { 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 rowNum * @param text @@ -119,8 +121,10 @@ public final class PoiMergeCellUtil { if (checkIsEqualByCellContents(mergeDataMap.get(index), text, cell, delys, rowNum)) { mergeDataMap.get(index).setEndRow(rowNum); } 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)); } } else { @@ -130,7 +134,7 @@ public final class PoiMergeCellUtil { /** * 字符为空的情况下判断 - * + * * @param index * @param mergeDataMap * @param sheet @@ -139,8 +143,12 @@ public final class PoiMergeCellUtil { Sheet sheet) { if (mergeDataMap.containsKey(index) && 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); } } @@ -179,7 +187,7 @@ public final class PoiMergeCellUtil { /** * 获取一个单元格的值,确保这个单元格必须有值,不然向上查询 - * + * * @param cell * @param index * @param rowNum