第一版华为obs的starter完成

This commit is contained in:
2023-03-02 14:56:41 +08:00
parent a94c9543bf
commit 4a2ba3c236
20 changed files with 584 additions and 0 deletions

3
.gitignore vendored
View File

@@ -24,3 +24,6 @@
hs_err_pid*
replay_pid*
/huawei-obs-springboot-starter.iml
/huawei-obs-springboot-starter.ipr
/huawei-obs-springboot-starter.iws

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

13
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="huawei-obs-springboot-starter" />
</profile>
</annotationProcessing>
</component>
</project>

8
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

25
.idea/jarRepositories.xml generated Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="nexus" />
<option name="name" value="nexus" />
<option name="url" value="http://192.168.1.13:8001/nexus/content/groups/public/" />
</remote-repository>
</component>
</project>

13
.idea/junitgenerator-prj-settings.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JUnitGeneratorProjectSettings">
<option name="outputFilePattern" value="${SOURCEPATH}/../../test/java/${PACKAGE}/${FILENAME}" />
<option name="selectedTemplateKey" value="JUnit 4" />
<option name="vmTemplates">
<map>
<entry key="JUnit 3" value="######################################################################################## &#10;## &#10;## Available variables: &#10;## $entryList.methodList - List of method composites &#10;## $entryList.privateMethodList - List of private method composites &#10;## $entryList.fieldList - ArrayList of class scope field names &#10;## $entryList.className - class name &#10;## $entryList.packageName - package name &#10;## $today - Todays date in MM/dd/yyyy format &#10;## &#10;## MethodComposite variables: &#10;## $method.name - Method Name &#10;## $method.signature - Full method signature in String form &#10;## $method.reflectionCode - list of strings representing commented out reflection code to access method (Private Methods) &#10;## $method.paramNames - List of Strings representing the method's parameters' names &#10;## $method.paramClasses - List of Strings representing the method's parameters' classes &#10;## &#10;## You can configure the output class name using &quot;testClass&quot; variable below. &#10;## Here are some examples: &#10;## Test${entry.ClassName} - will produce TestSomeClass &#10;## ${entry.className}Test - will produce SomeClassTest &#10;## &#10;######################################################################################## &#10;## &#10;#macro (cap $strIn)$strIn.valueOf($strIn.charAt(0)).toUpperCase()$strIn.substring(1)#end &#10;## Iterate through the list and generate testcase for every entry. &#10;#foreach ($entry in $entryList) &#10;#set( $testClass=&quot;${entry.className}Test&quot;) &#10;## &#10;package test.$entry.packageName; &#10;&#10;import junit.framework.Test; &#10;import junit.framework.TestSuite; &#10;import junit.framework.TestCase; &#10;&#10;/** &#10;* ${entry.className} Tester. &#10;* &#10;* @author &lt;Authors name&gt; &#10;* @since &lt;pre&gt;$today&lt;/pre&gt; &#10;* @version 1.0 &#10;*/ &#10;public class $testClass extends TestCase { &#10;public $testClass(String name) { &#10;super(name); &#10;} &#10;&#10;public void setUp() throws Exception { &#10;super.setUp(); &#10;} &#10;&#10;public void tearDown() throws Exception { &#10;super.tearDown(); &#10;} &#10;&#10;#foreach($method in $entry.methodList) &#10;/** &#10;* &#10;* Method: $method.signature &#10;* &#10;*/ &#10;public void test#cap(${method.name})() throws Exception { &#10;//TODO: Test goes here... &#10;} &#10;&#10;#end &#10;&#10;#foreach($method in $entry.privateMethodList) &#10;/** &#10;* &#10;* Method: $method.signature &#10;* &#10;*/ &#10;public void test#cap(${method.name})() throws Exception { &#10;//TODO: Test goes here... &#10;#foreach($string in $method.reflectionCode) &#10;$string &#10;#end &#10;} &#10;&#10;#end &#10;&#10;public static Test suite() { &#10;return new TestSuite(${testClass}.class); &#10;} &#10;} &#10;#end" />
<entry key="JUnit 4" value="######################################################################################## &#10;## &#10;## Available variables: &#10;## $entryList.methodList - List of method composites &#10;## $entryList.privateMethodList - List of private method composites &#10;## $entryList.fieldList - ArrayList of class scope field names &#10;## $entryList.className - class name &#10;## $entryList.packageName - package name &#10;## $today - Todays date in MM/dd/yyyy format &#10;## &#10;## MethodComposite variables: &#10;## $method.name - Method Name &#10;## $method.signature - Full method signature in String form &#10;## $method.reflectionCode - list of strings representing commented out reflection code to access method (Private Methods) &#10;## $method.paramNames - List of Strings representing the method's parameters' names &#10;## $method.paramClasses - List of Strings representing the method's parameters' classes &#10;## &#10;## You can configure the output class name using &quot;testClass&quot; variable below. &#10;## Here are some examples: &#10;## Test${entry.ClassName} - will produce TestSomeClass &#10;## ${entry.className}Test - will produce SomeClassTest &#10;## &#10;######################################################################################## &#10;## &#10;#macro (cap $strIn)$strIn.valueOf($strIn.charAt(0)).toUpperCase()$strIn.substring(1)#end &#10;## Iterate through the list and generate testcase for every entry. &#10;#foreach ($entry in $entryList) &#10;#set( $testClass=&quot;${entry.className}Test&quot;) &#10;## &#10;package $entry.packageName; &#10;&#10;import org.junit.Test; &#10;import org.junit.Before; &#10;import org.junit.After; &#10;import org.junit.runner.RunWith;&#10;import org.springframework.boot.test.context.SpringBootTest;&#10;import org.springframework.test.context.junit4.SpringRunner;&#10;&#10;/** &#10;* ${entry.className} Tester. &#10;* &#10;* @author hongawen&#10;* @since $today &#10;* @version 1.0 &#10;*/ &#10;@RunWith(SpringRunner.class)&#10;@SpringBootTest(classes = UserBootMain.class)&#10;public class $testClass { &#10;&#10;@Before&#10;public void before() throws Exception { &#10;} &#10;&#10;@After&#10;public void after() throws Exception { &#10;} &#10;&#10;#foreach($method in $entry.methodList) &#10;&#10;@Test&#10;public void test#cap(${method.name})() throws Exception { &#10;//TODO: Test goes here... &#10;} &#10;&#10;#end &#10;&#10;#foreach($method in $entry.privateMethodList) &#10;&#10;@Test&#10;public void test#cap(${method.name})() throws Exception { &#10;//TODO: Test goes here... &#10;#foreach($string in $method.reflectionCode) &#10;$string &#10;#end &#10;} &#10;&#10;#end &#10;} &#10;#end" />
</map>
</option>
</component>
</project>

14
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/huawei-obs-springboot-starter.iml" filepath="$PROJECT_DIR$/huawei-obs-springboot-starter.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

51
pom.xml Normal file
View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.njcn</groupId>
<artifactId>huawei-obs-springboot-starter</artifactId>
<version>1.0.0</version>
<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Release Repository</name>
<url>http://192.168.1.13:8001/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://192.168.1.13:8001/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<description>灿能针对河北pms项目的华为obs组件提取的starter模块</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>common-core</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.huaweicloud/esdk-obs-java -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java</artifactId>
<version>3.20.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>2.3.12.RELEASE</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,12 @@
package com.njcn;
/**
* @author hongawen
* @version 1.0.0
* @date ${YEAR}年${MONTH}月${DAY}日 ${HOUR}:${MINUTE}
*/
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

View File

@@ -0,0 +1,104 @@
package com.njcn.huawei.obs.config;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.Objects;
/**
* @author hongawen
* @version 1.0.0
* @date 2023年03月01日 13:56
*/
@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = HuaweiObsProperties.OBS_PREFIX)
public class HuaweiObsProperties implements InitializingBean {
static final String OBS_PREFIX = "huawei";
private Obs obs;
/***
* 华为云访问请求ak
*/
private String accessKey;
/***
* 华为云访问请求sk
*/
private String securityKey;
@Data
public static class Obs{
/***
* 华为云OBS的桶名称
*/
private String bucket;
/***
* 华为云OBS的终端节点访问路径
*/
private String endpoint;
/***
* 文件对应url的生命周期单位为秒
*/
private Long expire;
}
/***
* 初始化连接客户端
* @author hongawen
* @date 2023/3/2 9:58
* @return ObsClient
*/
public ObsClient getInstance(){
return new ObsClient(accessKey, securityKey, getObs().getEndpoint());
}
/***
* 销毁客户端
* @author hongawen
* @date 2023/3/2 9:59
*/
public void destroy(ObsClient obsClient){
if(Objects.isNull(obsClient)){
return;
}
try {
obsClient.close();
} catch (ObsException e) {
log.error("obs销毁异常", e);
} catch (Exception e) {
log.error("obs销毁发生非obs内部异常", e);
}
}
/***
* 构建对象前,断言属性是否配置信息
* @author hongawen
* @date 2023/3/2 14:29
*/
@Override
public void afterPropertiesSet() {
Assert.hasText(accessKey, "华为云accessKey信息必填");
Assert.hasText(securityKey, "华为云securityKey信息必填");
Assert.notNull(getObs(),"obs相关信息必填");
Assert.hasText(getObs().bucket, "obs桶信息必填");
Assert.hasText(getObs().endpoint, "obs终端节点访问路径必填");
Assert.notNull(getObs().expire, "obs_url生命周期必填");
}
}

View File

@@ -0,0 +1,248 @@
package com.njcn.huawei.obs.util;
import com.njcn.huawei.obs.config.HuaweiObsProperties;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author hongawen
* @version 1.0.0
* @date 2023年03月01日 14:10
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class OBSUtil {
private final HuaweiObsProperties huaweiObsProperties;
/**
* 上传注意事项:文件名不能以 / 开头,
* 比如错误名称:/comtrade/192.168.1.190/xxxx.dat
* 正确名称为comtrade/192.168.1.190/xxxx.dat
* 上述文件名在上传文件到obs桶中时会自动创建 comtrade、192.168.1.190两个文件夹
* 不同的业务功能可以通过文件夹去区分,比如稳态、暂态等报表、波形文件等等
* 前端form文件上传
*
* @author hongawen
* @date 2023/3/1 20:50
*/
public String multiFileUpload(MultipartFile uploadFile, String fileName) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
String bucketName = huaweiObsProperties.getObs().getBucket();
// 判断桶是否存在
judgeBucket(obsClient, bucketName);
InputStream inputStream = uploadFile.getInputStream();
long available = inputStream.available();
PutObjectRequest request = new PutObjectRequest(bucketName, fileName, inputStream);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(available);
request.setMetadata(objectMetadata);
// 设置对象访问权限为公共读
request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
PutObjectResult result = obsClient.putObject(request);
// 读取该已上传对象的URL
log.info("已上传对象的URL" + result.getObjectUrl());
return result.getObjectUrl();
} catch (ObsException e) {
log.error("obs上传失败", e);
} catch (IOException e) {
log.error("上传失败", e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return null;
}
/***
* 流式文件上传
* @author hongawen
* @date 2023/3/2 10:18
*/
public String streamUpload(FileInputStream inputStream, String fileName) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
String bucketName = huaweiObsProperties.getObs().getBucket();
// 判断桶是否存在
judgeBucket(obsClient, bucketName);
long available = inputStream.available();
PutObjectRequest request = new PutObjectRequest(bucketName, fileName, inputStream);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(available);
request.setMetadata(objectMetadata);
// 设置对象访问权限为公共读
request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
PutObjectResult result = obsClient.putObject(request);
// 读取该已上传对象的URL
log.info("已上传对象的URL" + result.getObjectUrl());
return result.getObjectUrl();
} catch (ObsException e) {
log.error("obs上传失败", e);
} catch (IOException e) {
log.error("上传失败", e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return null;
}
/***
* 获取文件上传后的url
* @author hongawen
* @date 2023/3/2 11:46
*/
public String getFileUrl(String fileName) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
// URL有效期3600秒
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/octet-stream");
TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.PUT, huaweiObsProperties.getObs().getExpire());
request.setBucketName(huaweiObsProperties.getObs().getBucket());
request.setObjectKey(fileName);
request.setHeaders(headers);
TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
return response.getSignedUrl();
} catch (Exception e) {
log.error("获取上传地址异常:{}", e.getMessage(), e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return null;
}
/***
* 判断对象是否存在
* @author hongawen
* @date 2023/3/2 13:35
*/
public boolean judgeObjectExist(String fileName) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
return obsClient.doesObjectExist(huaweiObsProperties.getObs().getBucket(), fileName);
} catch (Exception e) {
log.error("获取上传地址异常:{}", e.getMessage(), e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return false;
}
/***
* 以流的形式下载文件
* @author hongawen
* @date 2023/3/1 20:56
* @return InputStream
*/
public InputStream fileDownload(String fileName) {
ObsClient obsClient = null;
try {
String bucketName = huaweiObsProperties.getObs().getBucket();
ObsObject obsObject = obsClient.getObject(bucketName, fileName);
return obsObject.getObjectContent();
} catch (ObsException e) {
log.error("obs文件下载失败", e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return null;
}
/***
* 删除指定对象
* @author hongawen
* @date 2023/3/1 20:36
*/
public boolean delete(String fileName) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
// obs删除
obsClient.deleteObject(huaweiObsProperties.getObs().getBucket(), fileName);
} catch (ObsException e) {
log.error("obs删除保存失败", e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return true;
}
/***
* 批量删除指定对象
* @author hongawen
* @date 2023/3/1 20:36
*/
public boolean deleteBatch(List<String> fileNames) {
ObsClient obsClient = null;
try {
obsClient = huaweiObsProperties.getInstance();
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(huaweiObsProperties.getObs().getBucket());
// obs批量删除
fileNames.forEach(deleteObjectsRequest::addKeyAndVersion);
obsClient.deleteObjects(deleteObjectsRequest);
} catch (ObsException e) {
log.error("obs批量删除保存失败", e);
} finally {
huaweiObsProperties.destroy(obsClient);
}
return true;
}
/***
* 暂时未知河北现场的桶是否固定,将多个业务文件存在一个桶内也没问题
* 判断是否存在桶,不存在则创建通
* @author hongawen
* @date 2023/3/2 10:08
*/
public void judgeBucket(ObsClient obsClient, String bucketName) {
boolean exists = obsClient.headBucket(bucketName);
if (!exists) {
CreateBucketRequest request = new CreateBucketRequest();
request.setBucketName(bucketName);
// 设置桶访问权限为公共读,默认是私有读写
request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
// 设置桶的存储类型为归档存储
request.setBucketStorageClass(StorageClassEnum.COLD);
// 设置桶区域位置(以区域为华北-北京四为例)
request.setLocation("cn-east-3");
// 指定创建多AZ桶如果不设置默认创建单AZ桶
request.setAvailableZone(AvailableZoneEnum.MULTI_AZ);
// 创建桶
try {
// 创建桶成功
ObsBucket bucket = obsClient.createBucket(request);
log.info(bucket.getRequestId());
} catch (ObsException e) {
// 创建桶失败
log.info("HTTP Code: " + e.getResponseCode());
log.info("Error Code:" + e.getErrorCode());
log.info("Error Message: " + e.getErrorMessage());
log.info("Request ID:" + e.getErrorRequestId());
log.info("Host ID:" + e.getErrorHostId());
}
}
}
}

View File

@@ -0,0 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.njcn.huawei.obs.config.HuaweiObsProperties,\
com.njcn.huawei.obs.util.OBSUtil

View File

@@ -0,0 +1,48 @@
{
"groups": [
{
"name": "huawei",
"type": "com.njcn.huawei.obs.config.HuaweiObsProperties",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties"
},
{
"name": "huawei.obs",
"type": "com.njcn.huawei.obs.config.HuaweiObsProperties$Obs",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties",
"sourceMethod": "getObs()"
}
],
"properties": [
{
"name": "huawei.access-key",
"type": "java.lang.String",
"description": "华为云访问请求ak",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties"
},
{
"name": "huawei.obs.bucket",
"type": "java.lang.String",
"description": "华为云OBS的桶名称",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties$Obs"
},
{
"name": "huawei.obs.endpoint",
"type": "java.lang.String",
"description": "华为云OBS的终端节点访问路径",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties$Obs"
},
{
"name": "huawei.obs.expire",
"type": "java.lang.Long",
"description": "文件对应url的生命周期单位为秒",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties$Obs"
},
{
"name": "huawei.security-key",
"type": "java.lang.String",
"description": "华为云访问请求sk",
"sourceType": "com.njcn.huawei.obs.config.HuaweiObsProperties"
}
],
"hints": []
}

View File

@@ -0,0 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.njcn.huawei.obs.config.HuaweiObsProperties,\
com.njcn.huawei.obs.util.OBSUtil

View File

@@ -0,0 +1,5 @@
#Generated by Maven
#Thu Mar 02 13:52:05 CST 2023
version=1.0.0
groupId=com.njcn
artifactId=huawei-obs-springboot-starter

View File

@@ -0,0 +1,5 @@
com\njcn\huawei\obs\config\HuaweiObsProperties.class
com\njcn\Main.class
com\njcn\huawei\obs\util\OBSUtil.class
META-INF\spring-configuration-metadata.json
com\njcn\huawei\obs\config\HuaweiObsProperties$Obs.class

View File

@@ -0,0 +1,3 @@
E:\gitea\huawei-obs-springboot-starter\src\main\java\com\njcn\huawei\obs\util\OBSUtil.java
E:\gitea\huawei-obs-springboot-starter\src\main\java\com\njcn\Main.java
E:\gitea\huawei-obs-springboot-starter\src\main\java\com\njcn\huawei\obs\config\HuaweiObsProperties.java