mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-08-05 12:24:17 +00:00
Merge pull request #36 from Yuao-github/main
feat[storage]:配置文件可以同时指定多个扫描路径和扫描包
This commit is contained in:
@@ -484,4 +484,39 @@ public abstract class StringUtils {
|
||||
public static boolean isStopChar(char ch) {
|
||||
return Character.isWhitespace(ch) || STOP_WORD.contains(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param str 待匹配字符串
|
||||
* @param matchStr 匹配的后缀
|
||||
* @return 是否成功匹配后缀
|
||||
*/
|
||||
public static boolean suffixMatch(final String str,final String matchStr){
|
||||
if(matchStr.length()>str.length())
|
||||
return false;
|
||||
for(int i=0;i<matchStr.length();i++){
|
||||
if(str.charAt(str.length()-1-i)!=matchStr.charAt(matchStr.length()-1-i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*把String数组展开成一个大的字符串
|
||||
* @param strings
|
||||
* @return
|
||||
*/
|
||||
public static String stringArrayToString(final String[] strings){
|
||||
StringBuilder stringBuilder=new StringBuilder();
|
||||
stringBuilder.append('[');
|
||||
for(var i=0;i<strings.length;i++){
|
||||
if(i!=0){
|
||||
stringBuilder.append(',');
|
||||
}
|
||||
stringBuilder.append(StringUtils.format("[{}]",i+1));
|
||||
stringBuilder.append(strings[i]);
|
||||
}
|
||||
stringBuilder.append(']');
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.zfoo.storage.StorageContext;
|
||||
import com.zfoo.storage.model.anno.Id;
|
||||
import com.zfoo.storage.model.anno.ResInjection;
|
||||
import com.zfoo.storage.model.config.StorageConfig;
|
||||
import com.zfoo.storage.model.resource.ResourceEnum;
|
||||
import com.zfoo.storage.model.vo.ResourceDef;
|
||||
import com.zfoo.storage.model.vo.Storage;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -75,7 +76,7 @@ public class StorageManager implements IStorageManager {
|
||||
var resourceDefinitionMap = new HashMap<Class<?>, ResourceDef>();
|
||||
|
||||
// 扫描Excel的class类文件
|
||||
var clazzNameSet = scanResourceAnno(storageConfig.getScanPackage());
|
||||
var clazzNameSet = scanResourceAnno(storageConfig.getScanPackages());
|
||||
|
||||
// 通过class类文件扫描excel文件地址
|
||||
for (var clazzName : clazzNameSet) {
|
||||
@@ -221,22 +222,24 @@ public class StorageManager implements IStorageManager {
|
||||
return getStorageConfig();
|
||||
}
|
||||
|
||||
private Set<String> scanResourceAnno(String scanLocation) {
|
||||
private Set<String> scanResourceAnno(String[] scanPackages) {
|
||||
var resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
var metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||
|
||||
try {
|
||||
var packageSearchPath = ResourceUtils.CLASSPATH_URL_PREFIX + scanLocation.replace(StringUtils.PERIOD, StringUtils.SLASH) + StringUtils.SLASH + SUFFIX_PATTERN;
|
||||
var resources = resourcePatternResolver.getResources(packageSearchPath);
|
||||
var result = new HashSet<String>();
|
||||
var name = com.zfoo.storage.model.anno.Resource.class.getName();
|
||||
for (var resource : resources) {
|
||||
if (resource.isReadable()) {
|
||||
var metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
||||
var annoMeta = metadataReader.getAnnotationMetadata();
|
||||
if (annoMeta.hasAnnotation(name)) {
|
||||
ClassMetadata clazzMeta = metadataReader.getClassMetadata();
|
||||
result.add(clazzMeta.getClassName());
|
||||
for(var scanPackage:scanPackages) {
|
||||
var packageSearchPath = ResourceUtils.CLASSPATH_URL_PREFIX + scanPackage.replace(StringUtils.PERIOD, StringUtils.SLASH) + StringUtils.SLASH + SUFFIX_PATTERN;
|
||||
var resources = resourcePatternResolver.getResources(packageSearchPath);
|
||||
var resourceName = com.zfoo.storage.model.anno.Resource.class.getName();
|
||||
for (var resource : resources) {
|
||||
if (resource.isReadable()) {
|
||||
var metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
||||
var annoMeta = metadataReader.getAnnotationMetadata();
|
||||
if (annoMeta.hasAnnotation(resourceName)) {
|
||||
ClassMetadata clazzMeta = metadataReader.getClassMetadata();
|
||||
result.add(clazzMeta.getClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,30 +254,48 @@ public class StorageManager implements IStorageManager {
|
||||
var metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||
|
||||
try {
|
||||
var resourceList = new ArrayList<Resource>();
|
||||
|
||||
var packageSearchPath = StringUtils.format("{}/**/{}.*", storageConfig.getResourceLocation(), clazz.getSimpleName());
|
||||
packageSearchPath = packageSearchPath.replaceAll("//", "/");
|
||||
try {
|
||||
resourceList.addAll(Arrays.asList(resourcePatternResolver.getResources(packageSearchPath)));
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// 通配符无法匹配根目录,所以如果找不到,再从根目录查找一遍
|
||||
if (CollectionUtils.isEmpty(resourceList)) {
|
||||
packageSearchPath = StringUtils.format("{}/{}.*", storageConfig.getResourceLocation(), clazz.getSimpleName());
|
||||
var resourceDefSet = new HashSet<ResourceDef>();
|
||||
for(var resourceLocation: storageConfig.getResourceLocations()) {
|
||||
var packageSearchPath = StringUtils.format("{}/**/{}.*", resourceLocation, clazz.getSimpleName());
|
||||
packageSearchPath = packageSearchPath.replaceAll("//", "/");
|
||||
resourceList.addAll(Arrays.asList(resourcePatternResolver.getResources(packageSearchPath)));
|
||||
try {
|
||||
for(var resource :resourcePatternResolver.getResources(packageSearchPath)){
|
||||
if(StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.CSV.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.EXCEL_XLS.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.EXCEL_XLSX.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.JSON.getType()))
|
||||
resourceDefSet.add(new ResourceDef(clazz,resource));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// 通配符无法匹配根目录,所以如果找不到,再从根目录查找一遍
|
||||
if (resourceDefSet.isEmpty()) {
|
||||
packageSearchPath = StringUtils.format("{}/{}.*", resourceLocation, clazz.getSimpleName());
|
||||
packageSearchPath = packageSearchPath.replaceAll("//", "/");
|
||||
for(var resource :resourcePatternResolver.getResources(packageSearchPath)){
|
||||
if(StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.CSV.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.EXCEL_XLS.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.EXCEL_XLSX.getType())
|
||||
||StringUtils.suffixMatch(resource.getFilename(), ResourceEnum.JSON.getType()))
|
||||
resourceDefSet.add(new ResourceDef(clazz,resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(resourceList)) {
|
||||
throw new RuntimeException(StringUtils.format("无法找到配置文件[{}]", clazz.getSimpleName()));
|
||||
} else if (resourceList.size() > 1) {
|
||||
var resourceNames = resourceList.stream().map(it -> it.getFilename()).collect(Collectors.joining(StringUtils.COMMA));
|
||||
throw new RuntimeException(StringUtils.format("资源类[class:{}]找到重复的配置文件[{}]", clazz.getSimpleName(), resourceNames));
|
||||
if (CollectionUtils.isEmpty(resourceDefSet)) {
|
||||
throw new RuntimeException(StringUtils.format("资源类[class:{}]无法找到配置文件", clazz.getSimpleName()));
|
||||
} else if (resourceDefSet.size() > 1) {
|
||||
var resourceNames=new String[resourceDefSet.size()];
|
||||
var index=0;
|
||||
for(var resourceDef:resourceDefSet){
|
||||
resourceNames[index++]=resourceDef.getResource().getFile().getAbsolutePath();
|
||||
}
|
||||
|
||||
throw new RuntimeException(StringUtils.format("资源类[class:{}]找到重复的配置文件{}", clazz.getSimpleName(),StringUtils.stringArrayToString(resourceNames)));
|
||||
} else {
|
||||
return resourceList.get(0);
|
||||
return ((ResourceDef)(resourceDefSet.toArray()[0])).getResource();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -21,9 +21,9 @@ public class StorageConfig {
|
||||
|
||||
private String id;
|
||||
|
||||
private String scanPackage;
|
||||
private String[] scanPackages;
|
||||
|
||||
private String resourceLocation;
|
||||
private String[] resourceLocations;
|
||||
|
||||
// 类的属性是否可写,如果为false则类的属性必须为private并且不能有set方法
|
||||
private boolean writeable;
|
||||
@@ -39,20 +39,20 @@ public class StorageConfig {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getScanPackage() {
|
||||
return scanPackage;
|
||||
public String[] getScanPackages() {
|
||||
return scanPackages;
|
||||
}
|
||||
|
||||
public void setScanPackage(String scanPackage) {
|
||||
this.scanPackage = scanPackage;
|
||||
public void setScanPackages(String[] scanPackages) {
|
||||
this.scanPackages = scanPackages;
|
||||
}
|
||||
|
||||
public String getResourceLocation() {
|
||||
return resourceLocation;
|
||||
public String[] getResourceLocations() {
|
||||
return resourceLocations;
|
||||
}
|
||||
|
||||
public void setResourceLocation(String resourceLocation) {
|
||||
this.resourceLocation = resourceLocation;
|
||||
public void setResourceLocations(String[] resourceLocations) {
|
||||
this.resourceLocations = resourceLocations;
|
||||
}
|
||||
|
||||
public boolean isWriteable() {
|
||||
|
||||
@@ -15,6 +15,9 @@ package com.zfoo.storage.model.vo;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
* @version 4.0
|
||||
@@ -38,4 +41,28 @@ public class ResourceDef {
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ResourceDef that = (ResourceDef) o;
|
||||
boolean equal= false;
|
||||
try {
|
||||
equal = this.resource.getFile().getAbsolutePath().equals(that.resource.getFile().getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode=0;
|
||||
try {
|
||||
hashCode=this.resource.getFile().getAbsolutePath().hashCode();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +66,10 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
resolvePlaceholder("id", "id", builder, element, parserContext);
|
||||
resolvePlaceholder("package", "scanPackage", builder, scanElement, parserContext);
|
||||
resolvePlaceholder("package", "scanPackages", builder, scanElement, parserContext);
|
||||
resolvePlaceholder("writeable", "writeable", builder, scanElement, parserContext);
|
||||
resolvePlaceholder("recycle", "recycle", builder, scanElement, parserContext);
|
||||
resolvePlaceholder("location", "resourceLocation", builder, resourceElement, parserContext);
|
||||
resolvePlaceholder("location", "resourceLocations", builder, resourceElement, parserContext);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(clazz.getCanonicalName(), builder.getBeanDefinition());
|
||||
}
|
||||
@@ -90,6 +90,8 @@ public class StorageDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private void resolvePlaceholder(String attributeName, String fieldName, BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
var attributeValue = element.getAttribute(attributeName);
|
||||
attributeValue=attributeValue.replaceAll(";",",");
|
||||
attributeValue=attributeValue.replaceAll(" ",",");
|
||||
var environment = parserContext.getReaderContext().getEnvironment();
|
||||
var placeholder = environment.resolvePlaceholders(attributeValue);
|
||||
builder.addPropertyValue(fieldName, placeholder);
|
||||
|
||||
@@ -78,8 +78,8 @@ public class ExportBinaryTest {
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
var config = new StorageConfig();
|
||||
config.setScanPackage("com.zfoo.storage.export");
|
||||
config.setResourceLocation("classpath:/excel");
|
||||
config.setScanPackages(new String[]{"com.zfoo.storage.export"});
|
||||
config.setResourceLocations(new String[]{"classpath:/excel"});
|
||||
config.setWriteable(true);
|
||||
config.setRecycle(false);
|
||||
var storageManager = new StorageManager();
|
||||
|
||||
@@ -47,9 +47,10 @@
|
||||
<context:component-scan base-package="com.zfoo.storage"/>
|
||||
|
||||
<storage:storage id="resourceManager">
|
||||
<!-- package以及location属性都支持同时指定多个路径,路径分隔符为, ;或者空格-->
|
||||
<storage:scan package="com.zfoo.**.resource"/>
|
||||
<!-- 如果是类路径一classpath开头,如果是其它目录则以file开头-->
|
||||
<storage:resource location="classpath:/excel"/>
|
||||
<!-- 如果是类路径一classpath开头,如果是其它目录则以file开头,-->
|
||||
<storage:resource location="classpath:/,classpath:/excel"/>
|
||||
<!-- <storage:resource location="file:C:\Users\godotg\Desktop\excel"/>-->
|
||||
</storage:storage>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user