|
@@ -3,8 +3,12 @@ package org.hswebframework.web.excel;
|
|
|
import io.swagger.annotations.ApiModelProperty;
|
|
|
import lombok.Getter;
|
|
|
import lombok.SneakyThrows;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.hswebframework.expands.office.excel.ExcelIO;
|
|
|
+import org.hswebframework.web.ApplicationContextHolder;
|
|
|
import org.hswebframework.web.bean.FastBeanCopier;
|
|
|
+import org.hswebframework.web.dict.EnumDict;
|
|
|
+import org.hswebframework.web.dict.ItemDefine;
|
|
|
import org.springframework.util.ClassUtils;
|
|
|
import org.springframework.util.ReflectionUtils;
|
|
|
|
|
@@ -19,11 +23,29 @@ import java.util.function.Supplier;
|
|
|
* @author zhouhao
|
|
|
* @since 3.0.0-RC
|
|
|
*/
|
|
|
+@Slf4j
|
|
|
+@SuppressWarnings("all")
|
|
|
public class DefaultExcelImporter implements ExcelImporter {
|
|
|
|
|
|
protected static Map<Class, Map<Class, HeaderMapper>> headerMappings = new ConcurrentHashMap<>();
|
|
|
|
|
|
- @SuppressWarnings("all")
|
|
|
+ protected static ExcelCellConverter DEFAULT_CONVERTER = new ExcelCellConverter() {
|
|
|
+ @Override
|
|
|
+ public Object convertFromCell(Object from) {
|
|
|
+ return from;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object convertToCell(Object from) {
|
|
|
+ if (from instanceof EnumDict) {
|
|
|
+ return ((EnumDict) from).getText();
|
|
|
+ }
|
|
|
+ return from;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ protected ExcelCellConverter defaultConvert = DEFAULT_CONVERTER;
|
|
|
+
|
|
|
protected Map<Class, HeaderMapper> createHeaderMapping(Class type) {
|
|
|
//一些基本类型不做处理
|
|
|
if (type == String.class
|
|
@@ -48,7 +70,6 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
mapping.header = header;
|
|
|
mapping.field = field.getName();
|
|
|
mapping.index = excel == null || excel.exportOrder() == -1 ? index.getAndAdd(1) : excel.exportOrder();
|
|
|
- mapping.converter = createConvert(field.getType());
|
|
|
if (null != excel) {
|
|
|
mapping.enableImport = excel.enableImport();
|
|
|
mapping.enableExport = excel.enableExport();
|
|
@@ -58,7 +79,9 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
.mappings
|
|
|
.add(mapping);
|
|
|
}
|
|
|
+ mapping.converter = createConvert(excel.converter(), field.getType());
|
|
|
} else {
|
|
|
+ mapping.converter = createConvert(ExcelCellConverter.class, field.getType());
|
|
|
mapping.children = () -> getHeaderMapper(field.getType());
|
|
|
headerMapperMap.computeIfAbsent(Void.class, DefaultHeaderMapper::new)
|
|
|
.mappings
|
|
@@ -70,19 +93,17 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
return (Map) headerMapperMap;
|
|
|
}
|
|
|
|
|
|
- protected <T> ExcelCellConverter<T> createConvert(Class<T> type) {
|
|
|
- // TODO: 18-6-12
|
|
|
- return new ExcelCellConverter<T>() {
|
|
|
- @Override
|
|
|
- public T convertFromCell(Object from) {
|
|
|
- return type.cast(from);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object convertToCell(T from) {
|
|
|
- return from;
|
|
|
+ @SneakyThrows
|
|
|
+ protected <T> ExcelCellConverter<T> createConvert(Class<ExcelCellConverter> converterClass, Class<T> type) {
|
|
|
+ if (converterClass != ExcelCellConverter.class) {
|
|
|
+ try {
|
|
|
+ return ApplicationContextHolder.get().getBean(converterClass);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("can not get bean ({}) from spring context.", converterClass, e);
|
|
|
+ return converterClass.newInstance();
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
+ return defaultConvert;
|
|
|
}
|
|
|
|
|
|
@Getter
|
|
@@ -147,11 +168,15 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
@Override
|
|
|
public Optional<HeaderMapping> getMapping(String key) {
|
|
|
return Optional.ofNullable(fastMapping.computeIfAbsent(key, k -> {
|
|
|
+ //尝试获取嵌套的属性
|
|
|
for (HeaderMapping mapping : mappings) {
|
|
|
String newKey = key;
|
|
|
+ //字段嵌套
|
|
|
if (newKey.startsWith(mapping.field)) {
|
|
|
newKey = newKey.substring(mapping.field.length());
|
|
|
- } else if (newKey.startsWith(mapping.header)) {
|
|
|
+ }
|
|
|
+ //表头嵌套
|
|
|
+ else if (newKey.startsWith(mapping.header)) {
|
|
|
newKey = newKey.substring(mapping.header.length());
|
|
|
} else {
|
|
|
continue;
|
|
@@ -162,6 +187,7 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
if (map != null) {
|
|
|
map = map.copy();
|
|
|
map.field = mapping.field.concat(".").concat(map.field);
|
|
|
+ map.header = mapping.header.concat(map.header);
|
|
|
return map;
|
|
|
}
|
|
|
}
|
|
@@ -208,31 +234,44 @@ public class DefaultExcelImporter implements ExcelImporter {
|
|
|
|
|
|
for (Map.Entry<String, Object> entry : mapValue.entrySet()) {
|
|
|
String key = entry.getKey();
|
|
|
- Object value = entry.getValue();
|
|
|
-
|
|
|
HeaderMapping mapping = headerMapper.getMapping(key).orElse(null);
|
|
|
|
|
|
if (mapping == null || !mapping.enableImport) {
|
|
|
continue;
|
|
|
}
|
|
|
+ Object value = mapping.getConverter().convertFromCell(entry.getValue());
|
|
|
|
|
|
- String field = mapping.field;
|
|
|
+ String field = mapping.getField();
|
|
|
//嵌套的字段
|
|
|
if (field.contains(".")) {
|
|
|
String tmpField = field;
|
|
|
Map<String, Object> nestMapValue = newValue;
|
|
|
+
|
|
|
while (tmpField.contains(".")) {
|
|
|
+
|
|
|
+ // nest.obj.name => [nest,obj.name]
|
|
|
String[] nestFields = tmpField.split("[.]", 2);
|
|
|
+
|
|
|
+ //nest
|
|
|
+ String nestField = nestFields[0];
|
|
|
+
|
|
|
+ //obj.name
|
|
|
tmpField = nestFields[1];
|
|
|
- Object nestValue = nestMapValue.get(nestFields[0]);
|
|
|
+
|
|
|
+ Object nestValue = nestMapValue.get(nestField);
|
|
|
+ //构造嵌套对象为map
|
|
|
if (nestValue == null) {
|
|
|
- nestMapValue.put(nestFields[0], nestMapValue = new HashMap<>());
|
|
|
+ nestMapValue.put(nestField, nestMapValue = new HashMap<>());
|
|
|
} else {
|
|
|
if (nestValue instanceof Map) {
|
|
|
nestMapValue = ((Map) nestValue);
|
|
|
+ } else {
|
|
|
+ //这里几乎不可能进入...
|
|
|
+ nestMapValue.put(nestField, nestMapValue = FastBeanCopier.copy(nestValue, new HashMap<>()));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ //最后nestMapValue就为最里层嵌套的对象了
|
|
|
nestMapValue.put(tmpField, value);
|
|
|
} else {
|
|
|
newValue.put(field, value);
|