mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-08-17 02:24:00 +00:00
perf[storage]: 优化了配置表读取功能
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
package com.zfoo.boot;
|
||||
|
||||
import com.zfoo.storage.StorageContext;
|
||||
import com.zfoo.storage.interpreter.ExcelResourceReader;
|
||||
import com.zfoo.storage.manager.StorageManager;
|
||||
import com.zfoo.storage.model.config.StorageConfig;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
|
||||
@@ -27,6 +27,6 @@ import java.util.List;
|
||||
*/
|
||||
public interface IResourceReader {
|
||||
|
||||
<T> List<T> read(InputStream inputStream, Class<T> clazz);
|
||||
<T> List<T> read(InputStream inputStream, Class<T> clazz, String suffix);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
package com.zfoo.storage.interpreter;
|
||||
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.JsonUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.model.anno.Id;
|
||||
import com.zfoo.storage.strategy.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.context.support.ConversionServiceFactoryBean;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JsonResourceReader implements IResourceReader {
|
||||
|
||||
private static final TypeDescriptor TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
|
||||
|
||||
private static final ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
|
||||
|
||||
static {
|
||||
var converters = new HashSet<>();
|
||||
converters.add(new JsonToArrayConverter());
|
||||
converters.add(new JsonToMapConverter());
|
||||
converters.add(new JsonToObjectConverter());
|
||||
converters.add(new StringToClassConverter());
|
||||
converters.add(new StringToDateConverter());
|
||||
converters.add(new StringToMapConverter());
|
||||
conversionServiceFactoryBean.setConverters(converters);
|
||||
conversionServiceFactoryBean.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> read(InputStream inputStream, Class<T> clazz) {
|
||||
String txt = readTxt(inputStream, clazz);
|
||||
JsonResource JsonResource = JsonUtils.string2Object(txt, JsonResource.class);
|
||||
|
||||
var result = new ArrayList<T>();
|
||||
|
||||
// 默认取到第一个sheet页
|
||||
var fieldInfos = getFieldInfos(JsonResource, clazz);
|
||||
|
||||
var iterator = JsonResource.getData().iterator();
|
||||
// 从ROW_SERVER这行开始读取数据
|
||||
while (iterator.hasNext()) {
|
||||
var row = iterator.next();
|
||||
var instance = ReflectionUtils.newInstance(clazz);
|
||||
|
||||
for (var fieldInfo : fieldInfos) {
|
||||
var content = row.get(fieldInfo.index);
|
||||
if (StringUtils.isNotEmpty(content) || fieldInfo.field.getType() == String.class) {
|
||||
inject(instance, fieldInfo.field, content);
|
||||
}
|
||||
}
|
||||
result.add(instance);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void inject(Object instance, Field field, String content) {
|
||||
try {
|
||||
var targetType = new TypeDescriptor(field);
|
||||
var value = conversionServiceFactoryBean.getObject().convert(content, TYPE_DESCRIPTOR, targetType);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, instance, value);
|
||||
} catch (Exception e) {
|
||||
throw new RunException(e, "无法将Excel资源[class:{}]中的[content:{}]转换为属性[field:{}]", instance.getClass().getSimpleName(), content, field.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 只读取代码里写的字段
|
||||
private Collection<FieldInfo> getFieldInfos(JsonResource resource, Class<?> clazz) {
|
||||
var fieldRow = resource.getColumns();
|
||||
if (fieldRow == null) {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", clazz.getSimpleName());
|
||||
}
|
||||
|
||||
var cellFieldMap = new HashMap<String, Integer>();
|
||||
for (var i = 0; i < fieldRow.size(); i++) {
|
||||
var cell = fieldRow.get(i);
|
||||
if (Objects.isNull(cell)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = cell.getName();
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(name, i);
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("资源[class:{}]的Excel文件出现重复的属性控制列[field:{}]", clazz.getSimpleName(), name);
|
||||
}
|
||||
}
|
||||
|
||||
var fieldList = Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(it -> !Modifier.isTransient(it.getModifiers()))
|
||||
.filter(it -> !Modifier.isStatic(it.getModifiers()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (var field : fieldList) {
|
||||
if (!cellFieldMap.containsKey(field.getName())) {
|
||||
throw new RunException("资源类[class:{}]的声明属性[filed:{}]无法获取,请检查配置表的格式", clazz, field.getName());
|
||||
}
|
||||
|
||||
if (field.isAnnotationPresent(Id.class)) {
|
||||
var cellIndex = cellFieldMap.get(field.getName());
|
||||
if (cellIndex != 0) {
|
||||
throw new RunException("资源类[class:{}]的主键[Id:{}]必须放在Excel配置表的第一列,请检查配置表的格式", clazz, field.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (Modifier.isPublic(field.getModifiers())) {
|
||||
throw new RunException("因为静态资源类是不能被修改的,所以资源类[class:{}]的属性[filed:{}]不能被public修饰,请改为private修饰", clazz, field.getName());
|
||||
}
|
||||
|
||||
var setMethodName = StringUtils.EMPTY;
|
||||
try {
|
||||
setMethodName = ReflectionUtils.fieldToSetMethod(clazz, field);
|
||||
} catch (Exception e) {
|
||||
// 没有setMethod是正确的
|
||||
}
|
||||
if (StringUtils.isNotBlank(setMethodName)) {
|
||||
throw new RunException("因为静态资源类是不能被修改的,所以资源类[class:{}]的属性[filed:{}]不能含有set方法[{}]", clazz, field.getName(), setMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
return fieldList.stream().map(it -> new FieldInfo(cellFieldMap.get(it.getName()), it)).collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
private String readTxt(InputStream input, Class<?> clazz) {
|
||||
try {
|
||||
return IOUtils.toString(input, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RunException("静态资源[{}]异常,无法读取文件", clazz.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private static class FieldInfo {
|
||||
public final int index;
|
||||
public final Field field;
|
||||
|
||||
public FieldInfo(int index, Field field) {
|
||||
this.index = index;
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -7,11 +7,11 @@ import java.util.List;
|
||||
* 配置文件资源
|
||||
*
|
||||
*/
|
||||
public class JsonResource {
|
||||
public class ResourceConfig {
|
||||
// 文件名
|
||||
private String name;
|
||||
//配置表字段名
|
||||
private List<ColumnMeta> columns = new ArrayList<>();
|
||||
private List<Header> header = new ArrayList<>();
|
||||
// 配置表数据
|
||||
private List<List<String>> data = new ArrayList<>();
|
||||
|
||||
@@ -23,12 +23,12 @@ public class JsonResource {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<ColumnMeta> getColumns() {
|
||||
return columns;
|
||||
public List<Header> getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setColumns(List<ColumnMeta> columns) {
|
||||
this.columns = columns;
|
||||
public void setHeader(List<Header> header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public List<List<String>> getData() {
|
||||
@@ -39,7 +39,7 @@ public class JsonResource {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static class ColumnMeta {
|
||||
public static class Header {
|
||||
//字段名
|
||||
private String name;
|
||||
//类型
|
||||
@@ -47,10 +47,10 @@ public class JsonResource {
|
||||
//列
|
||||
private int index;
|
||||
|
||||
public ColumnMeta() {
|
||||
public Header() {
|
||||
}
|
||||
|
||||
public ColumnMeta(String name, String type, int index) {
|
||||
public Header(String name, String type, int index) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
+134
-60
@@ -14,12 +14,15 @@
|
||||
package com.zfoo.storage.interpreter;
|
||||
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.JsonUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.interpreter.ResourceConfig.Header;
|
||||
import com.zfoo.storage.model.anno.Id;
|
||||
import com.zfoo.storage.strategy.*;
|
||||
import com.zfoo.storage.util.CellUtils;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
@@ -30,6 +33,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -37,7 +41,7 @@ import java.util.stream.Collectors;
|
||||
* @author jaysunxiao
|
||||
* @version 3.0
|
||||
*/
|
||||
public class ExcelResourceReader implements IResourceReader {
|
||||
public class ResourceReader implements IResourceReader {
|
||||
|
||||
private static final TypeDescriptor TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
|
||||
|
||||
@@ -56,33 +60,27 @@ public class ExcelResourceReader implements IResourceReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> read(InputStream inputStream, Class<T> clazz) {
|
||||
var wb = createWorkbook(inputStream, clazz);
|
||||
public <T> List<T> read(InputStream inputStream, Class<T> clazz, String suffix) {
|
||||
ResourceConfig resource = null;
|
||||
if (suffix.equals("txt")) {
|
||||
resource = readJson(inputStream, clazz.getSimpleName());
|
||||
} else {
|
||||
resource = readExcel(inputStream, clazz.getSimpleName());
|
||||
}
|
||||
|
||||
var result = new ArrayList<T>();
|
||||
//获取所有字段
|
||||
var cellFieldMap = getFieldMap(resource, clazz);
|
||||
var fieldInfos = getFieldInfos(cellFieldMap, clazz);
|
||||
|
||||
// 默认取到第一个sheet页
|
||||
var sheet = wb.getSheetAt(0);
|
||||
var fieldInfos = getFieldInfos(sheet, clazz);
|
||||
|
||||
var iterator = sheet.iterator();
|
||||
// 行数定位到有效数据行,默认是第四行为有效数据行
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
|
||||
var iterator = resource.getData().iterator();
|
||||
// 从ROW_SERVER这行开始读取数据
|
||||
while (iterator.hasNext()) {
|
||||
var row = iterator.next();
|
||||
var instance = ReflectionUtils.newInstance(clazz);
|
||||
|
||||
var idCell = row.getCell(0);
|
||||
if (StringUtils.isBlank(CellUtils.getCellStringValue(idCell))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var fieldInfo : fieldInfos) {
|
||||
var cell = row.getCell(fieldInfo.index);
|
||||
var content = CellUtils.getCellStringValue(cell);
|
||||
var content = row.get(fieldInfo.index);
|
||||
if (StringUtils.isNotEmpty(content) || fieldInfo.field.getType() == String.class) {
|
||||
inject(instance, fieldInfo.field, content);
|
||||
}
|
||||
@@ -91,7 +89,81 @@ public class ExcelResourceReader implements IResourceReader {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResourceConfig readExcel(InputStream inputStream, String name) {
|
||||
var wb = createWorkbook(inputStream, name);
|
||||
var resource = new ResourceConfig();
|
||||
resource.setName(name);
|
||||
// 默认取到第一个sheet页
|
||||
var sheet = wb.getSheetAt(0);
|
||||
//设置所有列
|
||||
var headers = getHeaders(sheet, name);
|
||||
resource.setHeader(headers);
|
||||
|
||||
// 行数定位到有效数据行,默认是第四行为有效数据行
|
||||
var iterator = sheet.iterator();
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
// 从ROW_SERVER这行开始读取数据
|
||||
List<List<String>> data = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
var row = iterator.next();
|
||||
List<String> rowData = new ArrayList<>();
|
||||
for (var header : headers) {
|
||||
var cell = row.getCell(header.getIndex());
|
||||
var content = CellUtils.getCellStringValue(cell);
|
||||
rowData.add(content);
|
||||
}
|
||||
data.add(rowData);
|
||||
}
|
||||
resource.setData(data);
|
||||
return resource;
|
||||
}
|
||||
|
||||
// 只读取代码里写的字段
|
||||
private List<Header> getHeaders(Sheet sheet, String fileName) {
|
||||
var iterator = sheet.iterator();
|
||||
// 获取配置表的有效列名称,默认第一行就是字段名称
|
||||
var fieldRow = iterator.next();
|
||||
if (fieldRow == null) {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", fileName);
|
||||
}
|
||||
//默认第二行字段类型
|
||||
var typeRow = iterator.next();
|
||||
if (typeRow == null) {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的类型控制列", fileName);
|
||||
}
|
||||
|
||||
var headerList = new ArrayList<Header>();
|
||||
var cellFieldMap = new HashMap<String, Integer>();
|
||||
for (var i = 0; i < fieldRow.getLastCellNum(); i++) {
|
||||
var fieldCell = fieldRow.getCell(i);
|
||||
if (Objects.isNull(fieldCell)) {
|
||||
continue;
|
||||
}
|
||||
var typeCell = typeRow.getCell(i);
|
||||
if (Objects.isNull(typeCell)) {
|
||||
continue;
|
||||
}
|
||||
var fieldName = CellUtils.getCellStringValue(fieldCell);
|
||||
if (StringUtils.isEmpty(fieldName)) {
|
||||
continue;
|
||||
}
|
||||
var typeName = CellUtils.getCellStringValue(typeCell);
|
||||
if (StringUtils.isEmpty(typeName)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(fieldName, i);
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("资源[class:{}]的Excel文件出现重复的属性控制列[field:{}]", fileName, fieldName);
|
||||
}
|
||||
headerList.add(new Header(fieldName, typeName, i));
|
||||
}
|
||||
return headerList;
|
||||
}
|
||||
|
||||
|
||||
private void inject(Object instance, Field field, String content) {
|
||||
try {
|
||||
var targetType = new TypeDescriptor(field);
|
||||
@@ -103,43 +175,20 @@ public class ExcelResourceReader implements IResourceReader {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 只读取代码里写的字段
|
||||
private Collection<FieldInfo> getFieldInfos(Sheet sheet, Class<?> clazz) {
|
||||
var fieldRow = getFieldRow(sheet);
|
||||
if (fieldRow == null) {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", clazz.getSimpleName());
|
||||
}
|
||||
|
||||
var cellFieldMap = new HashMap<String, Integer>();
|
||||
for (var i = 0; i < fieldRow.getLastCellNum(); i++) {
|
||||
var cell = fieldRow.getCell(i);
|
||||
if (Objects.isNull(cell)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = CellUtils.getCellStringValue(cell);
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(name, i);
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("资源[class:{}]的Excel文件出现重复的属性控制列[field:{}]", clazz.getSimpleName(), name);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<FieldInfo> getFieldInfos(Map<String, Integer> fieldMap, Class<?> clazz) {
|
||||
var fieldList = Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(it -> !Modifier.isTransient(it.getModifiers()))
|
||||
.filter(it -> !Modifier.isStatic(it.getModifiers()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (var field : fieldList) {
|
||||
if (!cellFieldMap.containsKey(field.getName())) {
|
||||
if (!fieldMap.containsKey(field.getName())) {
|
||||
throw new RunException("资源类[class:{}]的声明属性[filed:{}]无法获取,请检查配置表的格式", clazz, field.getName());
|
||||
}
|
||||
|
||||
if (field.isAnnotationPresent(Id.class)) {
|
||||
var cellIndex = cellFieldMap.get(field.getName());
|
||||
var cellIndex = fieldMap.get(field.getName());
|
||||
if (cellIndex != 0) {
|
||||
throw new RunException("资源类[class:{}]的主键[Id:{}]必须放在Excel配置表的第一列,请检查配置表的格式", clazz, field.getName());
|
||||
}
|
||||
@@ -160,27 +209,17 @@ public class ExcelResourceReader implements IResourceReader {
|
||||
}
|
||||
}
|
||||
|
||||
return fieldList.stream().map(it -> new FieldInfo(cellFieldMap.get(it.getName()), it)).collect(Collectors.toList());
|
||||
|
||||
return fieldList.stream().map(it -> new FieldInfo(fieldMap.get(it.getName()), it)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 获取配置表的有效列名称,默认第一行就是字段名称
|
||||
private Row getFieldRow(Sheet sheet) {
|
||||
var iterator = sheet.iterator();
|
||||
var row = iterator.next();
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
private Workbook createWorkbook(InputStream input, Class<?> clazz) {
|
||||
private Workbook createWorkbook(InputStream input, String name) {
|
||||
try {
|
||||
return WorkbookFactory.create(input);
|
||||
} catch (IOException e) {
|
||||
throw new RunException("静态资源[{}]异常,无法读取文件", clazz.getSimpleName());
|
||||
throw new RunException("静态资源[{}]异常,无法读取文件", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class FieldInfo {
|
||||
public final int index;
|
||||
public final Field field;
|
||||
@@ -190,4 +229,39 @@ public class ExcelResourceReader implements IResourceReader {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Integer> getFieldMap(ResourceConfig resource, Class<?> clazz) {
|
||||
var header = resource.getHeader();
|
||||
if (header == null) {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", clazz.getSimpleName());
|
||||
}
|
||||
|
||||
var cellFieldMap = new HashMap<String, Integer>();
|
||||
for (var i = 0; i < header.size(); i++) {
|
||||
var cell = header.get(i);
|
||||
if (Objects.isNull(cell)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = cell.getName();
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
continue;
|
||||
}
|
||||
var previousValue = cellFieldMap.put(name, i);
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("资源[class:{}]的Excel文件出现重复的属性控制列[field:{}]", clazz.getSimpleName(), name);
|
||||
}
|
||||
}
|
||||
return cellFieldMap;
|
||||
}
|
||||
|
||||
private ResourceConfig readJson(InputStream input, String name) {
|
||||
try {
|
||||
var jsonStr = IOUtils.toString(input, StandardCharsets.UTF_8);
|
||||
//将json字符转换成对象
|
||||
return JsonUtils.string2Object(jsonStr, ResourceConfig.class);
|
||||
} catch (IOException e) {
|
||||
throw new RunException("静态资源[{}]异常,无法读取文件", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ package com.zfoo.storage.manager;
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.exception.ExceptionUtils;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.FileUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.StorageContext;
|
||||
@@ -98,8 +99,10 @@ public class StorageManager implements IStorageManager {
|
||||
try {
|
||||
for (var definition : resourceDefinitionMap.values()) {
|
||||
var clazz = definition.getClazz();
|
||||
var resource = definition.getResource();
|
||||
var fileExtName = FileUtils.fileExtName(resource.getFilename());
|
||||
Storage<?, ?> storage = new Storage<>();
|
||||
storage.init(definition.getResource().getInputStream(), definition.getClazz());
|
||||
storage.init(resource.getInputStream(), definition.getClazz(), fileExtName);
|
||||
storageMap.putIfAbsent(clazz, storage);
|
||||
allStorageUsableMap.put(clazz, false);
|
||||
}
|
||||
@@ -224,7 +227,7 @@ public class StorageManager implements IStorageManager {
|
||||
try {
|
||||
var resourceList = new ArrayList<Resource>();
|
||||
|
||||
var packageSearchPath = StringUtils.format("{}/**/{}.{}", storageConfig.getResourceLocation(), clazz.getSimpleName(), storageConfig.getResourceSuffix());
|
||||
var packageSearchPath = StringUtils.format("{}/**/{}.*", storageConfig.getResourceLocation(), clazz.getSimpleName());
|
||||
packageSearchPath = packageSearchPath.replaceAll("//", "/");
|
||||
try {
|
||||
resourceList.addAll(Arrays.asList(resourcePatternResolver.getResources(packageSearchPath)));
|
||||
@@ -234,7 +237,7 @@ public class StorageManager implements IStorageManager {
|
||||
|
||||
// 通配符无法匹配根目录,所以如果找不到,再从根目录查找一遍
|
||||
if (CollectionUtils.isEmpty(resourceList)) {
|
||||
packageSearchPath = StringUtils.format("{}/{}.{}", storageConfig.getResourceLocation(), clazz.getSimpleName(), storageConfig.getResourceSuffix());
|
||||
packageSearchPath = StringUtils.format("{}/{}.*", storageConfig.getResourceLocation(), clazz.getSimpleName());
|
||||
packageSearchPath = packageSearchPath.replaceAll("//", "/");
|
||||
resourceList.addAll(Arrays.asList(resourcePatternResolver.getResources(packageSearchPath)));
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ public class StorageConfig {
|
||||
|
||||
private String resourceLocation;
|
||||
|
||||
private String resourceSuffix;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -50,12 +48,4 @@ public class StorageConfig {
|
||||
public void setResourceLocation(String resourceLocation) {
|
||||
this.resourceLocation = resourceLocation;
|
||||
}
|
||||
|
||||
public String getResourceSuffix() {
|
||||
return resourceSuffix;
|
||||
}
|
||||
|
||||
public void setResourceSuffix(String resourceSuffix) {
|
||||
this.resourceSuffix = resourceSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ public class Storage<K, V> {
|
||||
public Storage() {
|
||||
}
|
||||
|
||||
public void init(InputStream inputStream, Class<?> resourceClazz) {
|
||||
public void init(InputStream inputStream, Class<?> resourceClazz, String suffix) {
|
||||
try {
|
||||
this.clazz = (Class<V>) resourceClazz;
|
||||
var reader = StorageContext.getResourceReader();
|
||||
idDef = IdDef.valueOf(resourceClazz);
|
||||
indexDefMap = IndexDef.createResourceIndexes(resourceClazz);
|
||||
|
||||
var list = reader.read(inputStream, resourceClazz);
|
||||
var list = reader.read(inputStream, resourceClazz, suffix);
|
||||
|
||||
dataMap.clear();
|
||||
indexMap.clear();
|
||||
|
||||
@@ -16,8 +16,7 @@ package com.zfoo.storage.schema;
|
||||
import com.zfoo.protocol.util.DomUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.StorageContext;
|
||||
import com.zfoo.storage.interpreter.ExcelResourceReader;
|
||||
import com.zfoo.storage.interpreter.JsonResourceReader;
|
||||
import com.zfoo.storage.interpreter.ResourceReader;
|
||||
import com.zfoo.storage.manager.StorageManager;
|
||||
import com.zfoo.storage.model.config.StorageConfig;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
@@ -70,20 +69,9 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
|
||||
resolvePlaceholder("id", "id", builder, element, parserContext);
|
||||
resolvePlaceholder("package", "scanPackage", builder, scanElement, parserContext);
|
||||
resolvePlaceholder("location", "resourceLocation", builder, resourceElement, parserContext);
|
||||
resolvePlaceholder("suffix", "resourceSuffix", builder, resourceElement, parserContext);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(clazz.getCanonicalName(), builder.getBeanDefinition());
|
||||
|
||||
// 注册ExcelResourceReader
|
||||
Class<?> readerClazz = ExcelResourceReader.class;
|
||||
var resourceSuffix = resourceElement.getAttribute("suffix");
|
||||
if (resourceSuffix.equals("txt")) {
|
||||
readerClazz = JsonResourceReader.class;
|
||||
}
|
||||
|
||||
var readerName = StringUtils.uncapitalize(readerClazz.getName());
|
||||
builder = BeanDefinitionBuilder.rootBeanDefinition(readerClazz);
|
||||
parserContext.getRegistry().registerBeanDefinition(readerName, builder.getBeanDefinition());
|
||||
|
||||
}
|
||||
|
||||
private void registerBeanDefinition(ParserContext parserContext) {
|
||||
@@ -99,11 +87,11 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
|
||||
builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
|
||||
registry.registerBeanDefinition(name, builder.getBeanDefinition());
|
||||
|
||||
// 注册ExcelResourceReader
|
||||
// clazz = ExcelResourceReader.class;
|
||||
// name = StringUtils.uncapitalize(clazz.getName());
|
||||
// builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
|
||||
// registry.registerBeanDefinition(name, builder.getBeanDefinition());
|
||||
// 注册ResourceReader
|
||||
clazz = ResourceReader.class;
|
||||
name = StringUtils.uncapitalize(clazz.getName());
|
||||
builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
|
||||
registry.registerBeanDefinition(name, builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void resolvePlaceholder(String attributeName, String fieldName, BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
|
||||
@@ -16,8 +16,8 @@ package com.zfoo.storage.util;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.JsonUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.interpreter.JsonResource;
|
||||
import com.zfoo.storage.interpreter.JsonResource.ColumnMeta;
|
||||
import com.zfoo.storage.interpreter.ResourceConfig;
|
||||
import com.zfoo.storage.interpreter.ResourceConfig.Header;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -34,15 +34,13 @@ import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
|
||||
/**
|
||||
* @author jaysunxiao
|
||||
* @author meiwei666
|
||||
* @version 3.0
|
||||
*/
|
||||
public class ExcelToJsonUtils {
|
||||
|
||||
public static void main(String[] args) throws Exception{
|
||||
File inputDir = new File("E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel");
|
||||
String outputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
|
||||
var listFiles = FileUtils.listFiles(inputDir, new String[] { "xls", "xlsx"}, true);
|
||||
public static void excelConvertJson(String inputDir, String outputDir) throws Exception{
|
||||
var listFiles = FileUtils.listFiles(new File(inputDir), new String[] { "xls", "xlsx"}, true);
|
||||
for (var file : listFiles) {
|
||||
var fileName = getFileName(file);
|
||||
var inputStream = FileUtils.openInputStream(file);
|
||||
@@ -51,7 +49,7 @@ public class ExcelToJsonUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeJsonFile(String outDir, String jsonStr, String name) {
|
||||
private static void writeJsonFile(String outDir, String jsonStr, String name) {
|
||||
System.out.println("resource: " + name + ".txt");
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
@@ -79,13 +77,13 @@ public class ExcelToJsonUtils {
|
||||
|
||||
public static String read(InputStream inputStream, String fileName) {
|
||||
var wb = createWorkbook(inputStream, fileName);
|
||||
var resource = new JsonResource();
|
||||
var resource = new ResourceConfig();
|
||||
resource.setName(fileName);
|
||||
// 默认取到第一个sheet页
|
||||
var sheet = wb.getSheetAt(0);
|
||||
//设置所有列
|
||||
var columns = getColumnMetas(sheet, fileName);
|
||||
resource.setColumns(columns);
|
||||
var headers = getHeaders(sheet, fileName);
|
||||
resource.setHeader(headers);
|
||||
|
||||
// 行数定位到有效数据行,默认是第四行为有效数据行
|
||||
var iterator = sheet.iterator();
|
||||
@@ -97,8 +95,8 @@ public class ExcelToJsonUtils {
|
||||
while (iterator.hasNext()) {
|
||||
var row = iterator.next();
|
||||
List<String> rowData = new ArrayList<>();
|
||||
for (var column : columns) {
|
||||
var cell = row.getCell(column.getIndex());
|
||||
for (var header : headers) {
|
||||
var cell = row.getCell(header.getIndex());
|
||||
var content = CellUtils.getCellStringValue(cell);
|
||||
rowData.add(content);
|
||||
}
|
||||
@@ -109,7 +107,7 @@ public class ExcelToJsonUtils {
|
||||
}
|
||||
|
||||
// 只读取代码里写的字段
|
||||
private static List<ColumnMeta> getColumnMetas(Sheet sheet, String fileName) {
|
||||
private static List<Header> getHeaders(Sheet sheet, String fileName) {
|
||||
var iterator = sheet.iterator();
|
||||
// 获取配置表的有效列名称,默认第一行就是字段名称
|
||||
var fieldRow = iterator.next();
|
||||
@@ -122,7 +120,7 @@ public class ExcelToJsonUtils {
|
||||
throw new RunException("无法获取资源[class:{}]的Excel文件的类型控制列", fileName);
|
||||
}
|
||||
|
||||
var columnMetaList = new ArrayList<ColumnMeta>();
|
||||
var headerList = new ArrayList<Header>();
|
||||
var cellFieldMap = new HashMap<String, Integer>();
|
||||
for (var i = 0; i < fieldRow.getLastCellNum(); i++) {
|
||||
var fieldCell = fieldRow.getCell(i);
|
||||
@@ -145,9 +143,9 @@ public class ExcelToJsonUtils {
|
||||
if (Objects.nonNull(previousValue)) {
|
||||
throw new RunException("资源[class:{}]的Excel文件出现重复的属性控制列[field:{}]", fileName, fieldName);
|
||||
}
|
||||
columnMetaList.add(new ColumnMeta(fieldName, typeName, i));
|
||||
headerList.add(new Header(fieldName, typeName, i));
|
||||
}
|
||||
return columnMetaList;
|
||||
return headerList;
|
||||
}
|
||||
|
||||
private static Workbook createWorkbook(InputStream input, String fileName) {
|
||||
@@ -157,6 +155,5 @@ public class ExcelToJsonUtils {
|
||||
throw new RunException("静态资源[{}]异常,无法读取文件", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
<xsd:complexType name="resource">
|
||||
<!-- 本地资源路径 -->
|
||||
<xsd:attribute name="location" type="xsd:string" use="required"/>
|
||||
<!-- 资源文件后缀 -->
|
||||
<xsd:attribute name="suffix" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="configType">
|
||||
|
||||
@@ -45,35 +45,6 @@ public class ApplicationTest {
|
||||
// Excel的映射内容需要在被Spring管理的bean的方法上加上@ResInjection注解,即可自动注入Excel对应的对象
|
||||
// 参考StudentManager中的标准用法
|
||||
|
||||
var studentManager = context.getBean(StudentManager.class);
|
||||
var studentResources = studentManager.studentResources;
|
||||
// 类名称和Excel名称必须完全一致,Excel的列名称必须对应对象的属性名称
|
||||
for (StudentResource resource : studentResources.getAll()) {
|
||||
logger.info(JsonUtils.object2String(resource));
|
||||
}
|
||||
System.out.println(StringUtils.MULTIPLE_HYPHENS);
|
||||
|
||||
// 通过id找到对应的行
|
||||
var id = 1000;
|
||||
var valueById = studentResources.get(id);
|
||||
logger.info(JsonUtils.object2String(valueById));
|
||||
System.out.println(StringUtils.MULTIPLE_HYPHENS);
|
||||
|
||||
// 通过索引找对应的行
|
||||
var valuesByIndex = studentResources.getIndex("name", "james0");
|
||||
logger.info(JsonUtils.object2String(valuesByIndex));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startStorageTestTxt() {
|
||||
// 加载配置文件,配置文件中必须引入storage
|
||||
// 配置文件中scan,需要映射Excel的类所在位置,会自动搜索文件夹下的Excel文件,Excel文件可以放在指定文件夹的任意目录
|
||||
// 配置文件中resource,需要映射Excel的文件所在位置
|
||||
var context = new ClassPathXmlApplicationContext("application.xml");
|
||||
|
||||
// Excel的映射内容需要在被Spring管理的bean的方法上加上@ResInjection注解,即可自动注入Excel对应的对象
|
||||
// 参考StudentManager中的标准用法
|
||||
|
||||
var studentManager = context.getBean(StudentManager.class);
|
||||
var studentResources = studentManager.studentResources;
|
||||
// 类名称和Excel名称必须完全一致,Excel的列名称必须对应对象的属性名称
|
||||
@@ -92,16 +63,6 @@ public class ApplicationTest {
|
||||
// 通过索引找对应的行
|
||||
var valuesByIndex = studentResources.getIndex("name", "james0");
|
||||
logger.info(JsonUtils.object2String(valuesByIndex));
|
||||
}
|
||||
|
||||
|
||||
// storage教程
|
||||
@Test
|
||||
public void startStorageTestTxt2() {
|
||||
// 加载配置文件,配置文件中必须引入storage
|
||||
// 配置文件中scan,需要映射Excel的类所在位置,会自动搜索文件夹下的Excel文件,Excel文件可以放在指定文件夹的任意目录
|
||||
// 配置文件中resource,需要映射Excel的文件所在位置
|
||||
var context = new ClassPathXmlApplicationContext("application.xml");
|
||||
|
||||
// Excel的映射内容需要在被Spring管理的bean的方法上加上@ResInjection注解,即可自动注入Excel对应的对象
|
||||
var testManager = context.getBean(TestManager.class);
|
||||
@@ -112,9 +73,10 @@ public class ApplicationTest {
|
||||
logger.info(JsonUtils.object2String(resource));
|
||||
}
|
||||
// 通过id找到对应的行
|
||||
var id = 2;
|
||||
var valueById = testResources.get(id);
|
||||
logger.info(JsonUtils.object2String(valueById));
|
||||
id = 2;
|
||||
var resource = testResources.get(id);
|
||||
logger.info(JsonUtils.object2String(resource));
|
||||
System.out.println(StringUtils.MULTIPLE_HYPHENS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.stereotype.Component;
|
||||
* @author jaysunxiao
|
||||
* @version 3.0
|
||||
*/
|
||||
//@Component
|
||||
@Component
|
||||
public class TestManager {
|
||||
|
||||
@ResInjection
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
package com.zfoo.storage.excel;
|
||||
|
||||
import com.zfoo.storage.util.ExcelToJsonUtils;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
@@ -32,6 +33,13 @@ import java.util.Iterator;
|
||||
@Ignore
|
||||
public class ExcelTest {
|
||||
|
||||
@Test
|
||||
public void excelConvertJson() throws Exception{
|
||||
String inputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
|
||||
String outputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
|
||||
ExcelToJsonUtils.excelConvertJson(inputDir, outputDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createExcelTest() throws IOException {
|
||||
//第一步创建workbook
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.zfoo.storage.model.anno.Resource;
|
||||
* @author jaysunxiao
|
||||
* @version 3.0
|
||||
*/
|
||||
//@Resource
|
||||
@Resource
|
||||
public class TestResource {
|
||||
|
||||
@Id
|
||||
|
||||
@@ -49,9 +49,8 @@
|
||||
<storage:storage id="resourceManager">
|
||||
<storage:scan package="com.zfoo.**.resource"/>
|
||||
<!-- 如果是类路径一classpath开头,如果是其它目录则以file开头-->
|
||||
<storage:resource location="classpath:/excel" suffix="txt"/>
|
||||
<!--<storage:resource location="classpath:/excel" suffix="xlsx"/>-->
|
||||
<!-- <storage:resource location="file:C:\Users\jaysunxiao\Desktop\excel" suffix="xlsx"/>-->
|
||||
<storage:resource location="classpath:/excel"/>
|
||||
<!-- <storage:resource location="file:C:\Users\jaysunxiao\Desktop\excel"/>-->
|
||||
</storage:storage>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user