refactor[storage]: storage code refactoring

This commit is contained in:
godotg committed 2022-10-27 20:11:09 +08:00
1 parent 356a96f787
commit e1c547c9d6
23 files changed
+351 -316

No files matched your search

@@ -13,7 +13,6 @@
package com.zfoo.boot;
import com.zfoo.storage.StorageContext;
import com.zfoo.storage.interpreter.ResourceReader;
import com.zfoo.storage.manager.StorageManager;
import com.zfoo.storage.model.config.StorageConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -38,12 +37,6 @@ public class StorageAutoConfiguration {
return storageManager;
}
@Bean
@ConditionalOnMissingBean
public ResourceReader excelResourceReader() {
return new ResourceReader();
}
@Bean
@ConditionalOnMissingBean
public StorageContext storageContext() {
@@ -1,75 +0,0 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.boot;
import com.zfoo.boot.resource.StudentResource;
import com.zfoo.protocol.ProtocolManager;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.storage.StorageContext;
import com.zfoo.storage.model.config.StorageConfig;
import com.zfoo.storage.model.vo.Storage;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
/**
* @author godotg
* @version 3.0
*/
@Ignore
@SpringBootApplication(exclude = {
// 排除MongoDB自动配置
MongoAutoConfiguration.class
})
public class StorageTest {
private static final Logger logger = LoggerFactory.getLogger(StorageTest.class);
@Bean
public StorageConfig storageConfig(Environment environment) {
var config = new StorageConfig();
config.setScanPackage("com.zfoo.boot");
config.setResourceLocation("classpath:/excel");
config.setWriteable(true);
config.setRecycle(false);
return config;
}
@Test
public void startApplication() {
var springBoot = new SpringApplicationBuilder();
springBoot.sources(StorageTest.class).web(WebApplicationType.NONE).run();
var protocols = StorageContext.getStorageManager().storageMap().keySet();
var operation = new GenerateOperation();
operation.getGenerateLanguages().add(CodeLanguage.GdScript);
ProtocolManager.initProtocolAuto(protocols, operation);
var storage = (Storage<Integer, StudentResource>) StorageContext.getStorageManager().getStorage(StudentResource.class);
for (StudentResource resource : storage.getAll()) {
logger.info(JsonUtils.object2String(resource));
}
}
}
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.boot.resource;
import com.zfoo.protocol.IPacket;
import com.zfoo.storage.model.anno.Id;
import com.zfoo.storage.model.anno.Resource;
/**
* @author godotg
* @version 4.0
*/
@Resource
public class StudentResource implements IPacket {
@Id
public int id;
public String name;
public int age;
public float score;
public String[] courses;
public User[] users;
public User user;
}
Binary file not shown.
-44
View File
@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" debug="false">
<contextName>com.zfoo.boot</contextName>
<property name="LOG_HOME" value="log/boot"/>
<property name="PATTERN_FILE"
value="%d{yyyy-MM-dd HH:mm:ss} [%5level] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
<property name="PATTERN_CONSOLE"
value="%d{yyyy-MM-dd HH:mm:ss} [%highlight(%5level)] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
<!-- 负责写日志,控制台日志,会打印所有的包的所有级别日志 -->
<appender name="zfoo_console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN_CONSOLE}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 根logger -->
<root level="info">
<appender-ref ref="zfoo_console"/>
</root>
<!--
- 1.name:包名或类名,用来指定受此logger约束的某一个包或者具体的某一个类
- 2.未设置打印级别,所以继承他的上级<root>的日志级别“DEBUG”
- 3.未设置additivity,默认为true,将此logger的打印信息向上级传递;
- 4.未设置appender,此logger本身不打印任何信息,级别为“DEBUG”及大于“DEBUG”的日志信息传递给root,
- root接到下级传递的信息,交给已经配置好的名为“STDOUT”的appender处理,“STDOUT”appender将信息打印到控制台;
-->
<logger name="ch.qos.logback" level="info"/>
<!--*******************************************Spring********************************************************-->
<!--logger中的name是指代码的包名或类名,路径要写全,可以配置不同包中的日志输出到不同的文件中。level是日志输出级别 -->
<!--过滤掉spring的一些无用的DEBUG信息-->
<logger name="org.springframework" level="info"/>
<!-- additivity="false"表示不继承父logger的配置和父类没有关系-->
<logger name="org.springframework.core" level="warn"/>
<!--*******************************************Netty*********************************************************-->
<logger name="io.netty" level="info"/>
</configuration>
@@ -467,10 +467,7 @@ public class OrmManager implements IOrmManager {
throw new RunException("在Orm中只能使用Orm的Index注解,不能使用Storage的Index注解,为了避免不必要的误解和增强项目的健壮性,禁止这样使用");
}
var filedList = Arrays.stream(clazz.getDeclaredFields())
.filter(it -> !Modifier.isTransient(it.getModifiers()))
.filter(it -> !Modifier.isStatic(it.getModifiers()))
.collect(Collectors.toList());
var filedList = ReflectionUtils.notStaticAndTransientFields(clazz);
for (var field : filedList) {
// entity必须包含属性的get和set方法
@@ -18,11 +18,12 @@ import com.zfoo.protocol.exception.RunException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author godotg
@@ -89,10 +90,7 @@ public abstract class ClassUtils {
// 必须要有一个空的构造器
ReflectionUtils.publicEmptyConstructor(clazz);
var filedList = Arrays.stream(clazz.getDeclaredFields())
.filter(it -> !Modifier.isTransient(it.getModifiers()))
.filter(it -> !Modifier.isStatic(it.getModifiers()))
.collect(Collectors.toList());
var filedList = ReflectionUtils.notStaticAndTransientFields(clazz);
for (var field : filedList) {
// 是一个基本类型变量
@@ -16,15 +16,19 @@ import com.zfoo.protocol.collection.ArrayUtils;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.exception.UnknownException;
import java.beans.Transient;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -319,6 +323,14 @@ public abstract class ReflectionUtils {
}
}
// 获取class中的普通field属性字段
public static List<Field> notStaticAndTransientFields(Class<?> clazz) {
return Arrays.stream(clazz.getDeclaredFields())
.filter(it -> !Modifier.isStatic(it.getModifiers()))
.filter(it -> !Modifier.isTransient(it.getModifiers()))
.filter(it -> !it.isAnnotationPresent(Transient.class))
.collect(Collectors.toList());
}
public static String fieldToGetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
@@ -14,7 +14,6 @@
package com.zfoo.storage;
import com.zfoo.scheduler.model.StopWatch;
import com.zfoo.storage.interpreter.IResourceReader;
import com.zfoo.storage.manager.IStorageManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,8 +36,6 @@ public class StorageContext implements ApplicationListener<ApplicationContextEve
private ApplicationContext applicationContext;
private IResourceReader resourceReader;
private IStorageManager storageManager;
public static StorageContext getStorageContext() {
@@ -49,14 +46,6 @@ public class StorageContext implements ApplicationListener<ApplicationContextEve
return instance.applicationContext;
}
public static StorageContext getInstance() {
return instance;
}
public static IResourceReader getResourceReader() {
return instance.resourceReader;
}
public static IStorageManager getStorageManager() {
return instance.storageManager;
}
@@ -69,7 +58,6 @@ public class StorageContext implements ApplicationListener<ApplicationContextEve
// 初始化上下文
StorageContext.instance = this;
instance.applicationContext = event.getApplicationContext();
instance.resourceReader = applicationContext.getBean(IResourceReader.class);
instance.storageManager = applicationContext.getBean(IStorageManager.class);
// 初始化,并读取配置表
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
@@ -11,7 +10,7 @@
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.util;
package com.zfoo.storage.interpreter;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.StringUtils;
@@ -32,7 +31,7 @@ import java.util.List;
* @author meiwei666
* @version 4.0
*/
public abstract class CsvReaderUtils {
public abstract class CsvReader {
public static ResourceData readResourceDataFromCSV(InputStream input, String fileName) {
var records = parseCsv(input, fileName);
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
@@ -11,48 +10,26 @@
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.util;
package com.zfoo.storage.interpreter;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.model.resource.ResourceData;
import com.zfoo.storage.model.resource.ResourceEnum;
import com.zfoo.storage.model.resource.ResourceHeader;
import com.zfoo.storage.util.CellUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author meiwei666
* @version 4.0
*/
public abstract class ExcelReaderUtils {
public static void excelConvertJson(String inputDir, String outputDir) throws IOException {
var listFiles = FileUtils.getAllReadableFiles(new File(inputDir))
.stream()
.filter(it -> ResourceEnum.isExcel(FileUtils.fileExtName(it.getName())))
.collect(Collectors.toList());
for (var file : listFiles) {
var fileSimpleName = FileUtils.fileSimpleName(file.getName());
var jsonFileName = StringUtils.format("{}.json", fileSimpleName);
var inputStream = FileUtils.openInputStream(file);
var resourceData = readResourceDataFromExcel(inputStream, file.getName());
var outputFilePath = FileUtils.joinPath(outputDir, jsonFileName);
FileUtils.deleteFile(new File(outputFilePath));
FileUtils.writeStringToFile(new File(outputFilePath), JsonUtils.object2String(resourceData), true);
}
}
public abstract class ExcelReader {
public static ResourceData readResourceDataFromExcel(InputStream inputStream, String fileName) {
// 只读取代码里写的字段
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.interpreter;
import com.zfoo.protocol.util.IOUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.model.resource.ResourceData;
import java.io.IOException;
import java.io.InputStream;
/**
* @author godotg
* @version 3.0
*/
public abstract class JsonReader {
public static ResourceData readResourceDataFromCSV(InputStream input) {
try {
return JsonUtils.string2Object(StringUtils.bytesToString(IOUtils.toByteArray(input)), ResourceData.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -13,26 +13,18 @@
package com.zfoo.storage.interpreter;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.IOUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.StorageContext;
import com.zfoo.storage.model.anno.Id;
import com.zfoo.storage.model.resource.ResourceData;
import com.zfoo.storage.model.resource.ResourceEnum;
import com.zfoo.storage.strategy.*;
import com.zfoo.storage.util.CsvReaderUtils;
import com.zfoo.storage.util.ExcelReaderUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
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.util.*;
import java.util.stream.Collectors;
@@ -40,7 +32,7 @@ import java.util.stream.Collectors;
* @author godotg
* @version 4.0
*/
public class ResourceReader implements IResourceReader {
public class ResourceInterpreter {
private static final TypeDescriptor TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
@@ -58,16 +50,15 @@ public class ResourceReader implements IResourceReader {
conversionServiceFactoryBean.afterPropertiesSet();
}
@Override
public <T> List<T> read(InputStream inputStream, Class<T> clazz, String suffix) throws IOException {
public static <T> List<T> read(InputStream inputStream, Class<T> clazz, String suffix) throws IOException {
ResourceData resource = null;
var resourceEnum = ResourceEnum.getResourceEnumByType(suffix);
if (resourceEnum == ResourceEnum.JSON) {
resource = JsonUtils.string2Object(StringUtils.bytesToString(IOUtils.toByteArray(inputStream)), ResourceData.class);
resource = JsonReader.readResourceDataFromCSV(inputStream);
} else if (resourceEnum == ResourceEnum.EXCEL_XLS || resourceEnum == ResourceEnum.EXCEL_XLSX) {
resource = ExcelReaderUtils.readResourceDataFromExcel(inputStream, clazz.getSimpleName());
resource = ExcelReader.readResourceDataFromExcel(inputStream, clazz.getSimpleName());
} else if (resourceEnum == ResourceEnum.CSV) {
resource = CsvReaderUtils.readResourceDataFromCSV(inputStream, clazz.getSimpleName());
resource = CsvReader.readResourceDataFromCSV(inputStream, clazz.getSimpleName());
} else {
throw new RunException("不支持文件[{}]的配置类型[{}]", clazz.getSimpleName(), suffix);
}
@@ -94,7 +85,7 @@ public class ResourceReader implements IResourceReader {
return result;
}
private void inject(Object instance, Field field, String content) {
private static void inject(Object instance, Field field, String content) {
try {
var targetType = new TypeDescriptor(field);
var value = conversionServiceFactoryBean.getObject().convert(content, TYPE_DESCRIPTOR, targetType);
@@ -106,12 +97,8 @@ public class ResourceReader implements IResourceReader {
}
// 只读取代码里写的字段
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());
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("资源类[class:{}]的声明属性[filed:{}]无法获取,请检查配置表的格式", clazz, field.getName());
@@ -123,35 +110,10 @@ public class ResourceReader implements IResourceReader {
throw new RunException("资源类[class:{}]的主键[Id:{}]必须放在Excel配置表的第一列,请检查配置表的格式", clazz, field.getName());
}
}
if (!StorageContext.getStorageManager().storageConfig().isWriteable()) {
if (Modifier.isPublic(field.getModifiers())) {
throw new RunException("因为静态资源类是不能被修改的,资源类[class:{}]的属性[filed:{}]不能被public修饰,用private修饰或者开启配置writeable属性", 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方法[{}],删除set方法或者开启配置writeable属性", clazz, field.getName(), setMethodName);
}
}
}
return fieldList.stream().map(it -> new FieldInfo(fieldMap.get(it.getName()), it)).collect(Collectors.toList());
}
private Workbook createWorkbook(InputStream input, String name) {
try {
return WorkbookFactory.create(input);
} catch (IOException e) {
throw new RunException("静态资源[{}]异常,无法读取文件", name);
}
}
private static class FieldInfo {
public final int index;
public final Field field;
@@ -162,7 +124,7 @@ public class ResourceReader implements IResourceReader {
}
}
public Map<String, Integer> getFieldMap(ResourceData resource, Class<?> clazz) {
public static Map<String, Integer> getFieldMap(ResourceData resource, Class<?> clazz) {
var header = resource.getHeaders();
if (header == null) {
throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", clazz.getSimpleName());
@@ -15,7 +15,6 @@ package com.zfoo.storage.manager;
import com.zfoo.storage.model.config.StorageConfig;
import com.zfoo.storage.model.vo.Storage;
import org.springframework.lang.Nullable;
import java.util.Map;
@@ -40,7 +39,6 @@ public interface IStorageManager {
*/
void initAfter();
@Nullable
Storage<?, ?> getStorage(Class<?> clazz);
Map<Class<?>, Storage<?, ?>> storageMap();
@@ -33,6 +33,7 @@ import org.springframework.util.ResourceUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
@@ -92,6 +93,29 @@ public class StorageManager implements IStorageManager {
resourceDefinitionMap.put(resourceClazz, resourceDef);
}
// 检查class字段是否合法
if (!storageConfig.isWriteable()) {
for (var definition : resourceDefinitionMap.values()) {
var clazz = definition.getClazz();
var fieldList = ReflectionUtils.notStaticAndTransientFields(clazz);
for (var field : fieldList) {
if (Modifier.isPublic(field.getModifiers())) {
throw new RunException("因为静态资源类是不能被修改的,资源类[class:{}]的属性[filed:{}]不能被public修饰,用private修饰或者开启配置writeable属性", 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方法[{}],删除set方法或者开启配置writeable属性", clazz, field.getName(), setMethodName);
}
}
}
}
try {
for (var definition : resourceDefinitionMap.values()) {
var clazz = definition.getClazz();
@@ -18,7 +18,7 @@ import com.zfoo.protocol.util.AssertionUtils;
import com.zfoo.protocol.util.IOUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.StorageContext;
import com.zfoo.storage.interpreter.ResourceInterpreter;
import org.springframework.lang.Nullable;
import java.io.InputStream;
@@ -47,11 +47,10 @@ public class Storage<K, V> {
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, suffix);
var list = ResourceInterpreter.read(inputStream, resourceClazz, suffix);
dataMap.clear();
indexMap.clear();
@@ -92,6 +91,10 @@ public class Storage<K, V> {
return Collections.unmodifiableMap(dataMap);
}
public IdDef getIdDef() {
return idDef;
}
public boolean contain(K key) {
return dataMap.containsKey(key);
}
@@ -16,7 +16,6 @@ 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.ResourceReader;
import com.zfoo.storage.manager.StorageManager;
import com.zfoo.storage.model.config.StorageConfig;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -40,7 +39,7 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
// 解析StorageConfig的配置
parseStorageConfig(element, parserContext);
// 注册StorageContext,ExcelResourceReader
// 注册StorageContext
registerBeanDefinition(parserContext);
// 注册StorageManager
@@ -87,12 +86,6 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
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) {
@@ -13,8 +13,8 @@
package com.zfoo.storage.strategy;
import com.zfoo.protocol.util.ClassUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.StorageContext;
import org.springframework.core.convert.converter.Converter;
/**
@@ -30,18 +30,8 @@ public class StringToClassConverter implements Converter<String, Class<?>> {
source = "java.lang." + source;
}
ClassLoader loader = null;
StorageContext context = StorageContext.getInstance();
if (context != null) {
loader = StorageContext.getApplicationContext().getClassLoader();
} else {
loader = Thread.currentThread().getContextClassLoader();
}
try {
return Class.forName(source, true, loader);
return Class.forName(source, true, ClassUtils.getDefaultClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(StringUtils.format("无法将字符串[{}]转换为Class对象", source));
}
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.util;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.interpreter.CsvReader;
import com.zfoo.storage.interpreter.ExcelReader;
import com.zfoo.storage.model.resource.ResourceEnum;
import com.zfoo.storage.model.vo.Storage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author godotg
* @version 3.0
*/
public abstract class ExportUtils {
public static void excel2Json(String inputDir, String outputDir) throws IOException {
var excelFiles = scanExcelFiles(inputDir);
for (var excel : excelFiles) {
var excelSimpleName = FileUtils.fileSimpleName(excel.getName());
var jsonFileName = StringUtils.format("{}.json", excelSimpleName);
var resourceData = ExcelReader.readResourceDataFromExcel(FileUtils.openInputStream(excel), excel.getName());
var outputFilePath = FileUtils.joinPath(outputDir, jsonFileName);
FileUtils.deleteFile(new File(outputFilePath));
FileUtils.writeStringToFile(new File(outputFilePath), JsonUtils.object2String(resourceData), true);
}
}
public static void excel2Csv(String inputDir, String outputDir) throws IOException {
var excelFiles = scanExcelFiles(inputDir);
for (var excel : excelFiles) {
var excelSimpleName = FileUtils.fileSimpleName(excel.getName());
var csvFileName = StringUtils.format("{}.csv", excelSimpleName);
var resourceData = CsvReader.readResourceDataFromCSV(FileUtils.openInputStream(excel), excel.getName());
var outputFilePath = FileUtils.joinPath(outputDir, csvFileName);
FileUtils.deleteFile(new File(outputFilePath));
FileUtils.writeStringToFile(new File(outputFilePath), JsonUtils.object2String(resourceData), true);
}
}
private static List<File> scanExcelFiles(String inputDir) {
return FileUtils.getAllReadableFiles(new File(inputDir))
.stream()
.filter(it -> ResourceEnum.isExcel(FileUtils.fileExtName(it.getName())))
.collect(Collectors.toList());
}
// 将class里的map自动赋值storage
public static <T> T autoWrapData(Class<T> clazz, Map<Class<?>, Storage<?, ?>> storageMap) {
var instance = ReflectionUtils.newInstance(clazz);
var filedList = ReflectionUtils.notStaticAndTransientFields(clazz);
var wrapClass = new HashSet<Class<?>>();
for (var field : filedList) {
var fieldType = field.getType();
if (!fieldType.equals(Map.class)) {
throw new RunException("[class:{}]类型声明不正确,导出的storage必须为Map接口类型", clazz.getCanonicalName());
}
var type = field.getGenericType();
var types = ((ParameterizedType) type).getActualTypeArguments();
var keyType = types[0];
var valueType = types[1];
var valueClass = (Class<?>) valueType;
var storage = storageMap.get(valueClass);
var idFieldType = storage.getIdDef().getField().getType();
if (idFieldType.isPrimitive()) {
if (idFieldType.equals(long.class) && keyType.equals(Long.class)) {
} else if (idFieldType.equals(int.class) && keyType.equals(Integer.class)) {
} 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());
}
} else if (!keyType.equals(idFieldType)) {
throw new RunException("[class:{}]中的[field:{}]类型声明不正确,类型需要改为[Map<{}, {}>]", clazz.getSimpleName(), field.getName(), idFieldType, valueClass.getSimpleName());
}
if (!wrapClass.add(valueClass)) {
throw new RunException("[class:{}]中含有重复的类型[{}]", clazz.getCanonicalName(), valueType);
}
ReflectionUtils.setField(field, instance, storage.getData());
}
return instance;
}
}
@@ -13,7 +13,6 @@
package com.zfoo.storage.excel;
import com.zfoo.storage.util.ExcelReaderUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
@@ -33,13 +32,6 @@ 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";
ExcelReaderUtils.excelConvertJson(inputDir, outputDir);
}
@Test
public void createExcelTest() throws IOException {
//第一步创建workbook
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.export;
import com.zfoo.protocol.IPacket;
import com.zfoo.protocol.ProtocolManager;
import com.zfoo.protocol.buffer.ByteBufUtils;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.storage.manager.StorageManager;
import com.zfoo.storage.model.anno.Id;
import com.zfoo.storage.model.anno.Resource;
import com.zfoo.storage.model.config.StorageConfig;
import com.zfoo.storage.model.vo.Storage;
import com.zfoo.storage.util.ExportUtils;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledHeapByteBuf;
import org.junit.Ignore;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
/**
* @author godotg
* @version 3.0
*/
@Ignore
public class ExportBinaryTest {
public static class User implements IPacket {
public String id;
public String name;
public String sex;
public int age;
}
@Resource
public static class StudentResource implements IPacket {
@Id
public int id;
public String name;
public int age;
public float score;
public String[] courses;
public User[] users;
public User user;
}
public static class ResourceData implements IPacket {
public Map<Integer, StudentResource> studentResources;
}
@Test
public void test() throws Exception {
var config = new StorageConfig();
config.setScanPackage("com.zfoo.storage.export");
config.setResourceLocation("classpath:/excel");
config.setWriteable(true);
config.setRecycle(false);
var storageManager = new StorageManager();
storageManager.setStorageConfig(config);
storageManager.initBefore();
storageManager.initAfter();
// 生成协议
var protocols = new HashSet<Class<?>>();
protocols.add(ResourceData.class);
protocols.addAll(storageManager.storageMap().keySet());
var operation = new GenerateOperation();
operation.getGenerateLanguages().add(CodeLanguage.GdScript);
ProtocolManager.initProtocolAuto(protocols, operation);
// 生成数据
var resourceData = ExportUtils.autoWrapData(ResourceData.class, storageManager.storageMap());
var buffer = new UnpooledHeapByteBuf(ByteBufAllocator.DEFAULT, 100, Integer.MAX_VALUE);
ProtocolManager.write(buffer, resourceData);
var bytes = ByteBufUtils.readAllBytes(buffer);
FileUtils.writeInputStreamToFile(new File("D:/github/godot-bird/binary_data.cfg"), new ByteArrayInputStream(bytes));
var storage = (Storage<Integer, StudentResource>) storageManager.getStorage(StudentResource.class);
for (StudentResource resource : storage.getAll()) {
System.out.println(JsonUtils.object2String(resource));
}
}
}
@@ -10,19 +10,24 @@
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.boot.resource;
package com.zfoo.storage.export;
import com.zfoo.protocol.IPacket;
import com.zfoo.storage.util.ExportUtils;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author godotg
* @version 3.0
*/
public class User implements IPacket {
@Ignore
public class ExportCsvTest {
public String id;
public String name;
public String sex;
public int age;
@Test
public void test() throws Exception {
var inputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
var outputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
ExportUtils.excel2Json(inputDir, outputDir);
}
}
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
@@ -11,23 +10,24 @@
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.storage.interpreter;
package com.zfoo.storage.export;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import com.zfoo.storage.util.ExportUtils;
import org.junit.Ignore;
import org.junit.Test;
/**
* 解释器模式设计的文本解析器
* <p>
* interpreter [in'ter·pret·er || ɪn'tɜrprɪtə(r) /-'tɜːp-]
* n. 直译程序, 翻译员, 解释者
*
* @author godotg
* @version 4.0
* @version 3.0
*/
public interface IResourceReader {
@Ignore
public class ExportJsonTest {
<T> List<T> read(InputStream inputStream, Class<T> clazz, String suffix) throws IOException;
@Test
public void test() throws Exception {
var inputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
var outputDir = "E:\\workspace\\zfoo\\storage\\src\\test\\resources\\excel";
ExportUtils.excel2Json(inputDir, outputDir);
}
}