mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-05-23 20:27:39 +00:00
Merge pull request #41 from Yuao-github/main
feat[storage] Add @ExcelFieldName to specify the column name of the r…
This commit is contained in:
@@ -23,7 +23,9 @@ import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author meiwei666
|
||||
@@ -31,14 +33,14 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class ExcelReader {
|
||||
|
||||
public static ResourceData readResourceDataFromExcel(InputStream inputStream, String fileName) {
|
||||
public static ResourceData readResourceDataFromExcel(InputStream inputStream, String resourceClassName) {
|
||||
// 只读取代码里写的字段
|
||||
var wb = createWorkbook(inputStream, fileName);
|
||||
var wb = createWorkbook(inputStream, resourceClassName);
|
||||
// 默认取到第一个sheet页
|
||||
var sheet = wb.getSheetAt(0);
|
||||
var iterator = sheet.iterator();
|
||||
//设置所有列
|
||||
var headers = getHeaders(iterator, fileName);
|
||||
var headers = getHeaders(iterator, resourceClassName);
|
||||
|
||||
var rows = new ArrayList<List<String>>();
|
||||
while (iterator.hasNext()) {
|
||||
@@ -57,19 +59,19 @@ public abstract class ExcelReader {
|
||||
}
|
||||
rows.add(columns);
|
||||
}
|
||||
return ResourceData.valueOf(fileName, headers, rows);
|
||||
return ResourceData.valueOf(resourceClassName, headers, rows);
|
||||
}
|
||||
|
||||
private static List<ResourceHeader> getHeaders(Iterator<Row> iterator, String fileName) {
|
||||
private static List<ResourceHeader> getHeaders(Iterator<Row> iterator, String resourceClassName) {
|
||||
// 获取配置表的有效列名称,默认第一行就是字段名称
|
||||
var fieldRow = iterator.next();
|
||||
if (fieldRow == null) {
|
||||
throw new RunException("Failed to get attribute control column from excel file of resource [class:{}]", fileName);
|
||||
throw new RunException("Failed to get attribute control column from excel file of resource [class:{}]", resourceClassName);
|
||||
}
|
||||
// 默认第二行字段类型
|
||||
var typeRow = iterator.next();
|
||||
if (typeRow == null) {
|
||||
throw new RunException("Failed to get type control column from excel file of resource [class:{}]", fileName);
|
||||
throw new RunException("Failed to get type control column from excel file of resource [class:{}]", resourceClassName);
|
||||
}
|
||||
// 默认第三行为描述,需要的时候再使用
|
||||
var desRow = iterator.next();
|
||||
@@ -84,19 +86,19 @@ public abstract class ExcelReader {
|
||||
if (Objects.isNull(typeCell)) {
|
||||
continue;
|
||||
}
|
||||
var fieldName = CellUtils.getCellStringValue(fieldCell);
|
||||
if (StringUtils.isEmpty(fieldName)) {
|
||||
var excelFieldName = CellUtils.getCellStringValue(fieldCell);
|
||||
if (StringUtils.isEmpty(excelFieldName)) {
|
||||
continue;
|
||||
}
|
||||
var typeName = CellUtils.getCellStringValue(typeCell);
|
||||
if (StringUtils.isEmpty(typeName)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(fieldName, i);
|
||||
var previousValue = cellFieldMap.put(excelFieldName, i);
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("There are duplicate attribute control columns [field:{}] in the Excel file of the resource [class:{}]", fieldName,fileName);
|
||||
throw new RunException("There are duplicate attribute control columns [field:{}] in the Excel file of the resource [class:{}]", excelFieldName,resourceClassName);
|
||||
}
|
||||
headerList.add(ResourceHeader.valueOf(fieldName, typeName, i));
|
||||
headerList.add(ResourceHeader.valueOf(excelFieldName, typeName, i));
|
||||
}
|
||||
return headerList;
|
||||
}
|
||||
@@ -108,5 +110,4 @@ public abstract class ExcelReader {
|
||||
throw new RunException(e, "Static resource [{}] is abnormal, and the file cannot be read", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,11 @@ public abstract class JsonReader {
|
||||
|
||||
public static ResourceData readResourceDataFromCSV(InputStream input) {
|
||||
try {
|
||||
return JsonUtils.string2Object(StringUtils.bytesToString(IOUtils.toByteArray(input)), ResourceData.class);
|
||||
var resourceData= JsonUtils.string2Object(StringUtils.bytesToString(IOUtils.toByteArray(input)), ResourceData.class);
|
||||
for(int i=0;i<resourceData.getHeaders().size();i++) {
|
||||
resourceData.getHeaders().get(i).setIndex(i);
|
||||
}
|
||||
return resourceData;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ package com.zfoo.storage.interpreter;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.model.anno.ExcelFieldName;
|
||||
import com.zfoo.storage.model.anno.Id;
|
||||
import com.zfoo.storage.model.resource.ResourceData;
|
||||
import com.zfoo.storage.model.resource.ResourceEnum;
|
||||
@@ -101,10 +102,6 @@ public class ResourceInterpreter {
|
||||
private static Collection<FieldInfo> getFieldInfos(Map<String, Integer> fieldMap, Class<?> clazz) {
|
||||
var fieldList = ReflectionUtils.notStaticAndTransientFields(clazz);
|
||||
for (var field : fieldList) {
|
||||
if (!fieldMap.containsKey(field.getName())) {
|
||||
throw new RunException("The declaration attribute [filed:{}] of the resource class [class:{}] cannot be obtained, please check the format of the configuration table", field.getName(), clazz);
|
||||
}
|
||||
|
||||
if (field.isAnnotationPresent(Id.class)) {
|
||||
var cellIndex = fieldMap.get(field.getName());
|
||||
if (cellIndex != 0) {
|
||||
@@ -112,7 +109,26 @@ public class ResourceInterpreter {
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldList.stream().map(it -> new FieldInfo(fieldMap.get(it.getName()), it)).collect(Collectors.toList());
|
||||
return fieldList.stream().filter(it1->
|
||||
fieldMap.keySet().stream().anyMatch(it->{
|
||||
var ans=false;
|
||||
if(it1.isAnnotationPresent(ExcelFieldName.class)){
|
||||
ans|=it.equals(it1.getAnnotation(ExcelFieldName.class).value());
|
||||
}
|
||||
ans|=it.equals(it1.getName());
|
||||
return ans;
|
||||
})).map(it1->{
|
||||
String excelFieldName;
|
||||
List<String> list=null;
|
||||
if(it1.isAnnotationPresent(ExcelFieldName.class)){
|
||||
list=fieldMap.keySet().stream().filter(it->it.equals(it1.getAnnotation(ExcelFieldName.class).value())).collect(Collectors.toList());
|
||||
}
|
||||
if(list==null||list.size()==0){
|
||||
list=fieldMap.keySet().stream().filter(it->it.equals(it1.getName())).collect(Collectors.toList());
|
||||
}
|
||||
excelFieldName=list.get(0);
|
||||
return new FieldInfo(fieldMap.get(excelFieldName), it1);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static class FieldInfo {
|
||||
@@ -142,7 +158,7 @@ public class ResourceInterpreter {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(name, i);
|
||||
var previousValue = cellFieldMap.put(name, cell.getIndex());
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("There are duplicate attribute control columns [field:{}] in the Excel file of the resource [class:{}]", name, clazz.getSimpleName());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.zfoo.storage.model.anno;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
*指定文件列名,不指定则默认列名与字段名一致
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface ExcelFieldName {
|
||||
String value();
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public enum ResourceEnum {
|
||||
static {
|
||||
for (var resourceEnum : ResourceEnum.values()) {
|
||||
var previousValue = typeMap.putIfAbsent(resourceEnum.type, resourceEnum);
|
||||
AssertionUtils.isNull(previousValue, "ResourceEnum中不应该含有重复type的枚举类[{}]和[{}]", resourceEnum, previousValue);
|
||||
AssertionUtils.isNull(previousValue, "ResourceEnum should not contain enumeration classes [{}] and [{}] of repeated type", resourceEnum, previousValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ public class IdDef {
|
||||
public static IdDef valueOf(Class<?> clazz) {
|
||||
var fields = ReflectionUtils.getFieldsByAnnoInPOJOClass(clazz, Id.class);
|
||||
if (fields.length <= 0) {
|
||||
throw new RunException("class[{}]没有被Id注解标识的主键(如果确实已经被Id注解标注,注意不要使用ORM的Id注解)", clazz.getName());
|
||||
throw new RunException("There is no a primary key identified by the Id annotation in class[{}](if it has indeed been annotated by the Id annotation, be careful not to use the ORM Id annotation)", clazz.getName());
|
||||
}
|
||||
if (fields.length > 1) {
|
||||
throw new RunException("类[{}]的主键Id注解重复", clazz.getName());
|
||||
throw new RunException("The primary key Id annotation of class [{}] is duplicated", clazz.getName());
|
||||
}
|
||||
if (fields[0] == null) {
|
||||
throw new RunException("不合法的Id资源映射对象:" + clazz.getName());
|
||||
throw new RunException("Illegal Id resource mapping object:" + clazz.getName());
|
||||
}
|
||||
var idField = fields[0];
|
||||
ReflectionUtils.makeAccessible(idField);
|
||||
|
||||
@@ -48,7 +48,7 @@ public class IndexDef {
|
||||
|
||||
var ormIndexes = ReflectionUtils.getFieldsByAnnoNameInPOJOClass(clazz, "com.zfoo.orm.model.anno.Index");
|
||||
if (ArrayUtils.isNotEmpty(ormIndexes)) {
|
||||
throw new RunException("在Storage中只能使用Storage的Index注解,不能使用Orm的Index注解,为了避免不必要的误解和增强项目的健壮性,禁止这样使用");
|
||||
throw new RunException("Only the Index annotation of Storage can be used, and the Index annotation of Orm cannot be used in Storage. In order to avoid unnecessary misunderstanding and enhance the robustness of the project, such use is prohibited");
|
||||
}
|
||||
|
||||
for (var field : fields) {
|
||||
@@ -60,7 +60,7 @@ public class IndexDef {
|
||||
for (var index : indexes) {
|
||||
var indexName = index.field.getName();
|
||||
if (result.put(indexName, index) != null) {
|
||||
throw new RuntimeException(StringUtils.format("资源类[{}]索引名称重复,索引名[}|]", clazz.getName(), indexName));
|
||||
throw new RuntimeException(StringUtils.format("The index name[{}] of resource class [{}] is duplicated.", indexName, clazz.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@ public class Storage<K, V> {
|
||||
|
||||
public V get(K id) {
|
||||
V result = dataMap.get(id);
|
||||
AssertionUtils.notNull(result, "静态资源[resource:{}]中表示为[id:{}]的静态资源不存在", clazz.getSimpleName(), id);
|
||||
AssertionUtils.notNull(result, "The static resource represented as [id:{}] in the static resource [resource:{}] does not exist", id, clazz.getSimpleName());
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<V> getIndex(String indexName, Object key) {
|
||||
var indexValues = indexMap.get(indexName);
|
||||
AssertionUtils.notNull(indexValues, "静态资源[resource:{}]不存在为[indexName:{}]的索引", clazz.getSimpleName(), indexName);
|
||||
AssertionUtils.notNull(indexValues, "The index of [indexName:{}] does not exist in the static resource [resource:{}]", indexName, clazz.getSimpleName());
|
||||
var values = indexValues.get(key);
|
||||
if (CollectionUtils.isEmpty(values)) {
|
||||
return Collections.emptyList();
|
||||
@@ -118,7 +118,7 @@ public class Storage<K, V> {
|
||||
@Nullable
|
||||
public V getUniqueIndex(String uniqueIndexName, Object key) {
|
||||
var indexValueMap = uniqueIndexMap.get(uniqueIndexName);
|
||||
AssertionUtils.notNull(indexValueMap, "静态资源[resource:{}]不存在为[uniqueIndexName:{}]的唯一索引", clazz.getSimpleName(), uniqueIndexName);
|
||||
AssertionUtils.notNull(indexValueMap, "There is no a unique index for [uniqueIndexName:{}] in the static resource [resource:{}]", uniqueIndexName, clazz.getSimpleName());
|
||||
var value = indexValueMap.get(key);
|
||||
return value;
|
||||
}
|
||||
@@ -128,11 +128,11 @@ public class Storage<K, V> {
|
||||
var key = (K) ReflectionUtils.getField(idDef.getField(), value);
|
||||
|
||||
if (key == null) {
|
||||
throw new RuntimeException("静态资源存在id未配置的项");
|
||||
throw new RuntimeException("There is an item with an unconfigured id in the static resource");
|
||||
}
|
||||
|
||||
if (dataMap.containsKey(key)) {
|
||||
throw new RuntimeException(StringUtils.format("静态资源[resource:{}]的[id:{}]重复", clazz.getSimpleName(), key));
|
||||
throw new RuntimeException(StringUtils.format("Duplicate [id:{}] of static resource [resource:{}]", key, clazz.getSimpleName()));
|
||||
}
|
||||
|
||||
// 添加资源
|
||||
@@ -146,7 +146,7 @@ public class Storage<K, V> {
|
||||
if (def.isUnique()) {// 唯一索引
|
||||
var index = uniqueIndexMap.computeIfAbsent(indexKey, k -> new HashMap<>());
|
||||
if (index.put(indexValue, value) != null) {
|
||||
throw new RuntimeException(StringUtils.format("静态资源[class:{}]的唯一索引重复[index:{}][value:{}]", clazz.getName(), indexKey, indexValue));
|
||||
throw new RuntimeException(StringUtils.format("Duplicate unique index [index:{}][value:{}] of static resource [class:{}]", indexKey, indexValue, clazz.getName()));
|
||||
}
|
||||
} else {// 不是唯一索引
|
||||
var index = indexMap.computeIfAbsent(indexKey, k -> new HashMap<>());
|
||||
|
||||
@@ -58,11 +58,11 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
var scanElement = DomUtils.getFirstChildElementByTagName(element, "scan");
|
||||
if (scanElement == null) {
|
||||
throw new RuntimeException("XML文件缺少[scan]元素定义");
|
||||
throw new RuntimeException("The XML file is missing a [scan] element definition");
|
||||
}
|
||||
var resourceElement = DomUtils.getFirstChildElementByTagName(element, "resource");
|
||||
if (resourceElement == null) {
|
||||
throw new RuntimeException("XML文件缺少[resource]元素定义");
|
||||
throw new RuntimeException("The XML file is missing a [resource] element definition");
|
||||
}
|
||||
|
||||
resolvePlaceholder("id", "id", builder, element, parserContext);
|
||||
|
||||
@@ -33,7 +33,7 @@ public class StringToClassConverter implements Converter<String, Class<?>> {
|
||||
try {
|
||||
return Class.forName(source, true, ClassUtils.getDefaultClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException(StringUtils.format("无法将字符串[{}]转换为Class对象", source));
|
||||
throw new IllegalArgumentException(StringUtils.format("Unable to convert string [{}] to Class object", source));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class StringToDateConverter implements Converter<String, Date> {
|
||||
try {
|
||||
return df.parse(source);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException(StringUtils.format("字符串[{}]不符合格式要求:[yyyy-MM-dd HH:mm:ss]", source));
|
||||
throw new IllegalArgumentException(StringUtils.format("The string [{}] does not meet the format requirements: [yyyy-MM-dd HH:mm:ss]", source));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public abstract class ExportUtils {
|
||||
for (var field : filedList) {
|
||||
var fieldType = field.getType();
|
||||
if (!fieldType.equals(Map.class)) {
|
||||
throw new RunException("[class:{}]类型声明不正确,导出的storage必须为Map接口类型", clazz.getCanonicalName());
|
||||
throw new RunException("[class:{}] type declaration is incorrect, the exported storage must be a Map interface type", clazz.getCanonicalName());
|
||||
}
|
||||
|
||||
var type = field.getGenericType();
|
||||
@@ -121,13 +121,13 @@ public abstract class ExportUtils {
|
||||
} else if (idFieldType.equals(short.class) && keyType.equals(Short.class)) {
|
||||
} else if (idFieldType.equals(byte.class) && keyType.equals(Byte.class)) {
|
||||
} else {
|
||||
throw new RunException("[class:{}]中的[field:{}]类型声明不正确,类型需要改为[Map<{}, {}>]", clazz.getSimpleName(), field.getName(), idFieldType, valueClass.getSimpleName());
|
||||
throw new RunException("The [field:{}] type declaration in [class:{}] is incorrect, the type needs to be changed to [Map<{}, {}>]", field.getName(), clazz.getSimpleName(), idFieldType, valueClass.getSimpleName());
|
||||
}
|
||||
} else if (!keyType.equals(idFieldType)) {
|
||||
throw new RunException("[class:{}]中的[field:{}]类型声明不正确,类型需要改为[Map<{}, {}>]", clazz.getSimpleName(), field.getName(), idFieldType, valueClass.getSimpleName());
|
||||
throw new RunException("The [field:{}] type declaration in [class:{}] is incorrect, the type needs to be changed to [Map<{}, {}>]", field.getName(), clazz.getSimpleName(), idFieldType, valueClass.getSimpleName());
|
||||
}
|
||||
if (!wrapClass.add(valueClass)) {
|
||||
throw new RunException("[class:{}]中含有重复的类型[{}]", clazz.getCanonicalName(), valueType);
|
||||
throw new RunException("[class:{}] contains duplicate type [{}]", clazz.getCanonicalName(), valueType);
|
||||
}
|
||||
ReflectionUtils.setField(field, instance, storage.getData());
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class ApplicationTest {
|
||||
var studentManager = context.getBean(StudentManager.class);
|
||||
var studentResources = studentManager.studentResources;
|
||||
var studentCsvResources = studentManager.studentCsvResources;
|
||||
// @Resource注解没指定别名,类名称和Excel名称必须完全一致,Excel的列名称必须对应对象的属性名称
|
||||
// @Resource注解没指定别名,类名称和Excel名称必须完全一致,没有使用@ExcelFieldName对象属性名会自动对应同名的资源文件列名
|
||||
for (StudentResource resource : studentResources.getAll()) {
|
||||
logger.info(JsonUtils.object2String(resource));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
package com.zfoo.storage.resource;
|
||||
|
||||
import com.zfoo.storage.model.anno.ExcelFieldName;
|
||||
import com.zfoo.storage.model.anno.Id;
|
||||
import com.zfoo.storage.model.anno.Index;
|
||||
import com.zfoo.storage.model.anno.Resource;
|
||||
@@ -35,13 +36,13 @@ public class StudentResource {
|
||||
@Index
|
||||
private String name;
|
||||
|
||||
@ExcelFieldName("年龄")
|
||||
private int age;
|
||||
private float score;
|
||||
private String[] courses;
|
||||
private User[] users;
|
||||
private List<User> userList;
|
||||
private User user;
|
||||
|
||||
/**
|
||||
* 不想映射的字段必须加上transient关键字,这样就不会从Excel中去找对应的列
|
||||
*/
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user