@@ -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% | |||
*/ | |||
@@ -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 ""; | |||
} |
@@ -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; | |||
} |
@@ -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 <T> ExcelImportResult<T> importExcelVerify(InputStream inputstream, | |||
public static <T> ExcelImportResult<T> 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 <T> ExcelImportResult<T> importExcelVerify(File file, Class<?> pojoClass, | |||
public static <T> ExcelImportResult<T> importExcelMore(File file, Class<?> pojoClass, | |||
ImportParams params) { | |||
FileInputStream in = null; | |||
try { | |||
@@ -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; | |||
} | |||
} |
@@ -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<T> { | |||
*/ | |||
private Workbook workbook; | |||
private Map<String,Object> map; | |||
public ExcelImportResult() { | |||
} | |||
@@ -76,4 +79,11 @@ public class ExcelImportResult<T> { | |||
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 { | |||
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); | |||
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()); | |||
} | |||
@@ -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<String, PictureData> 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<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 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 | |||