diff --git a/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java b/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java index 3342efb4..a9fabae5 100644 --- a/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java +++ b/boot/src/main/java/com/zfoo/boot/StorageAutoConfiguration.java @@ -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() { diff --git a/boot/src/test/java/com/zfoo/boot/StorageTest.java b/boot/src/test/java/com/zfoo/boot/StorageTest.java deleted file mode 100644 index 7124036e..00000000 --- a/boot/src/test/java/com/zfoo/boot/StorageTest.java +++ /dev/null @@ -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) StorageContext.getStorageManager().getStorage(StudentResource.class); - for (StudentResource resource : storage.getAll()) { - logger.info(JsonUtils.object2String(resource)); - } - - } - -} diff --git a/boot/src/test/java/com/zfoo/boot/resource/StudentResource.java b/boot/src/test/java/com/zfoo/boot/resource/StudentResource.java deleted file mode 100644 index 8f2d1d2e..00000000 --- a/boot/src/test/java/com/zfoo/boot/resource/StudentResource.java +++ /dev/null @@ -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; - -} - diff --git a/boot/src/test/resources/excel/StudentResource.xlsx b/boot/src/test/resources/excel/StudentResource.xlsx deleted file mode 100644 index d7378b7a..00000000 Binary files a/boot/src/test/resources/excel/StudentResource.xlsx and /dev/null differ diff --git a/boot/src/test/resources/logback-test.xml b/boot/src/test/resources/logback-test.xml deleted file mode 100644 index fadb70c5..00000000 --- a/boot/src/test/resources/logback-test.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - com.zfoo.boot - - - - - - - - ${PATTERN_CONSOLE} - UTF-8 - - - - - - - - - - - - - - - - - - - - - - diff --git a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java index e01ed2e2..d6dda23d 100644 --- a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java +++ b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java @@ -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方法 diff --git a/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java b/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java index 90f9f2a1..6f002f7b 100644 --- a/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java @@ -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) { // 是一个基本类型变量 diff --git a/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java b/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java index 24fa8bf2..57f02130 100644 --- a/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java @@ -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 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(); diff --git a/storage/src/main/java/com/zfoo/storage/StorageContext.java b/storage/src/main/java/com/zfoo/storage/StorageContext.java index 08614ceb..aa6053a7 100644 --- a/storage/src/main/java/com/zfoo/storage/StorageContext.java +++ b/storage/src/main/java/com/zfoo/storage/StorageContext.java @@ -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 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) { // 只读取代码里写的字段 diff --git a/storage/src/main/java/com/zfoo/storage/interpreter/JsonReader.java b/storage/src/main/java/com/zfoo/storage/interpreter/JsonReader.java new file mode 100644 index 00000000..1368ba16 --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/interpreter/JsonReader.java @@ -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); + } + } + +} diff --git a/storage/src/main/java/com/zfoo/storage/interpreter/ResourceReader.java b/storage/src/main/java/com/zfoo/storage/interpreter/ResourceInterpreter.java similarity index 68% rename from storage/src/main/java/com/zfoo/storage/interpreter/ResourceReader.java rename to storage/src/main/java/com/zfoo/storage/interpreter/ResourceInterpreter.java index bf14b609..10a83200 100644 --- a/storage/src/main/java/com/zfoo/storage/interpreter/ResourceReader.java +++ b/storage/src/main/java/com/zfoo/storage/interpreter/ResourceInterpreter.java @@ -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 List read(InputStream inputStream, Class clazz, String suffix) throws IOException { + public static List read(InputStream inputStream, Class 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 getFieldInfos(Map 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 getFieldInfos(Map 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 getFieldMap(ResourceData resource, Class clazz) { + public static Map getFieldMap(ResourceData resource, Class clazz) { var header = resource.getHeaders(); if (header == null) { throw new RunException("无法获取资源[class:{}]的Excel文件的属性控制列", clazz.getSimpleName()); diff --git a/storage/src/main/java/com/zfoo/storage/manager/IStorageManager.java b/storage/src/main/java/com/zfoo/storage/manager/IStorageManager.java index 668c0d2d..02bf0bee 100644 --- a/storage/src/main/java/com/zfoo/storage/manager/IStorageManager.java +++ b/storage/src/main/java/com/zfoo/storage/manager/IStorageManager.java @@ -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, Storage> storageMap(); diff --git a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java index 5ace4841..420251c1 100644 --- a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java +++ b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java @@ -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(); diff --git a/storage/src/main/java/com/zfoo/storage/model/vo/Storage.java b/storage/src/main/java/com/zfoo/storage/model/vo/Storage.java index e5354b2c..c310f26c 100644 --- a/storage/src/main/java/com/zfoo/storage/model/vo/Storage.java +++ b/storage/src/main/java/com/zfoo/storage/model/vo/Storage.java @@ -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 { public void init(InputStream inputStream, Class resourceClazz, String suffix) { try { this.clazz = (Class) 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 { return Collections.unmodifiableMap(dataMap); } + public IdDef getIdDef() { + return idDef; + } + public boolean contain(K key) { return dataMap.containsKey(key); } diff --git a/storage/src/main/java/com/zfoo/storage/schema/StorageDefinitionParser.java b/storage/src/main/java/com/zfoo/storage/schema/StorageDefinitionParser.java index 18584be5..df4377e0 100644 --- a/storage/src/main/java/com/zfoo/storage/schema/StorageDefinitionParser.java +++ b/storage/src/main/java/com/zfoo/storage/schema/StorageDefinitionParser.java @@ -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) { diff --git a/storage/src/main/java/com/zfoo/storage/strategy/StringToClassConverter.java b/storage/src/main/java/com/zfoo/storage/strategy/StringToClassConverter.java index 1828ca99..7d41dbab 100644 --- a/storage/src/main/java/com/zfoo/storage/strategy/StringToClassConverter.java +++ b/storage/src/main/java/com/zfoo/storage/strategy/StringToClassConverter.java @@ -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> { 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)); } diff --git a/storage/src/main/java/com/zfoo/storage/util/ExportUtils.java b/storage/src/main/java/com/zfoo/storage/util/ExportUtils.java new file mode 100644 index 00000000..71c96883 --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/ExportUtils.java @@ -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 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 autoWrapData(Class clazz, Map, Storage> storageMap) { + var instance = ReflectionUtils.newInstance(clazz); + + var filedList = ReflectionUtils.notStaticAndTransientFields(clazz); + + var wrapClass = new HashSet>(); + + 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; + } + +} diff --git a/storage/src/test/java/com/zfoo/storage/excel/ExcelTest.java b/storage/src/test/java/com/zfoo/storage/excel/ExcelTest.java index 26780eba..04b97af1 100644 --- a/storage/src/test/java/com/zfoo/storage/excel/ExcelTest.java +++ b/storage/src/test/java/com/zfoo/storage/excel/ExcelTest.java @@ -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 diff --git a/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTest.java b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTest.java new file mode 100644 index 00000000..6d8d1282 --- /dev/null +++ b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTest.java @@ -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 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>(); + 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) storageManager.getStorage(StudentResource.class); + for (StudentResource resource : storage.getAll()) { + System.out.println(JsonUtils.object2String(resource)); + } + } + +} diff --git a/boot/src/test/java/com/zfoo/boot/resource/User.java b/storage/src/test/java/com/zfoo/storage/export/ExportCsvTest.java similarity index 59% rename from boot/src/test/java/com/zfoo/boot/resource/User.java rename to storage/src/test/java/com/zfoo/storage/export/ExportCsvTest.java index bb75693c..d26f6766 100644 --- a/boot/src/test/java/com/zfoo/boot/resource/User.java +++ b/storage/src/test/java/com/zfoo/storage/export/ExportCsvTest.java @@ -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); + } } diff --git a/storage/src/main/java/com/zfoo/storage/interpreter/IResourceReader.java b/storage/src/test/java/com/zfoo/storage/export/ExportJsonTest.java similarity index 57% rename from storage/src/main/java/com/zfoo/storage/interpreter/IResourceReader.java rename to storage/src/test/java/com/zfoo/storage/export/ExportJsonTest.java index a4c1737d..e332caff 100644 --- a/storage/src/main/java/com/zfoo/storage/interpreter/IResourceReader.java +++ b/storage/src/test/java/com/zfoo/storage/export/ExportJsonTest.java @@ -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; /** - * 解释器模式设计的文本解析器 - *

- * 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 { - List read(InputStream inputStream, Class 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); + } }