diff --git a/.gitignore b/.gitignore index 9154f4c..20f07e4 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ hs_err_pid* replay_pid* +/huawei-obs-springboot-starter.iml +/huawei-obs-springboot-starter.ipr +/huawei-obs-springboot-starter.iws diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -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 diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..85806bd --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63574ec --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..f0ebcd0 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/junitgenerator-prj-settings.xml b/.idea/junitgenerator-prj-settings.xml new file mode 100644 index 0000000..3001171 --- /dev/null +++ b/.idea/junitgenerator-prj-settings.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..132404b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ed01f68 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0265114 --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + com.njcn + huawei-obs-springboot-starter + 1.0.0 + + + nexus-releases + Nexus Release Repository + http://192.168.1.13:8001/nexus/content/repositories/releases/ + + + nexus-snapshots + Nexus Snapshot Repository + http://192.168.1.13:8001/nexus/content/repositories/snapshots/ + + + + + 8 + 8 + UTF-8 + + 灿能针对河北pms项目的华为obs组件提取的starter模块 + jar + + + com.njcn + common-core + 1.0.0 + + + + + com.huaweicloud + esdk-obs-java + 3.20.6.1 + + + + org.springframework.boot + spring-boot-configuration-processor + true + 2.3.12.RELEASE + + + + \ No newline at end of file diff --git a/src/main/java/com/njcn/Main.java b/src/main/java/com/njcn/Main.java new file mode 100644 index 0000000..8c7cdb1 --- /dev/null +++ b/src/main/java/com/njcn/Main.java @@ -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!"); + } +} \ No newline at end of file diff --git a/src/main/java/com/njcn/huawei/obs/config/HuaweiObsProperties.java b/src/main/java/com/njcn/huawei/obs/config/HuaweiObsProperties.java new file mode 100644 index 0000000..c3b7186 --- /dev/null +++ b/src/main/java/com/njcn/huawei/obs/config/HuaweiObsProperties.java @@ -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生命周期必填!!"); + } + +} diff --git a/src/main/java/com/njcn/huawei/obs/util/OBSUtil.java b/src/main/java/com/njcn/huawei/obs/util/OBSUtil.java new file mode 100644 index 0000000..39c4a3a --- /dev/null +++ b/src/main/java/com/njcn/huawei/obs/util/OBSUtil.java @@ -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 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 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()); + } + } + } + + +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..d03c39c --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,5 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.njcn.huawei.obs.config.HuaweiObsProperties,\ + com.njcn.huawei.obs.util.OBSUtil + + diff --git a/target/classes/META-INF/spring-configuration-metadata.json b/target/classes/META-INF/spring-configuration-metadata.json new file mode 100644 index 0000000..0bd4854 --- /dev/null +++ b/target/classes/META-INF/spring-configuration-metadata.json @@ -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": [] +} \ No newline at end of file diff --git a/target/classes/META-INF/spring.factories b/target/classes/META-INF/spring.factories new file mode 100644 index 0000000..d03c39c --- /dev/null +++ b/target/classes/META-INF/spring.factories @@ -0,0 +1,5 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.njcn.huawei.obs.config.HuaweiObsProperties,\ + com.njcn.huawei.obs.util.OBSUtil + + diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..c1e1dc9 --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -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 diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..40ab423 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -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 diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..87690a0 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -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 diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..e69de29