feat: 添加 spring-boot-storage starter.

This commit is contained in:
lijiahang
2023-07-03 11:09:29 +08:00
parent f18cba1cb6
commit f1959946f5
14 changed files with 484 additions and 0 deletions

View File

@@ -107,6 +107,11 @@
<artifactId>orion-ops-spring-boot-starter-log</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.orion.ops</groupId>
<artifactId>orion-ops-spring-boot-starter-storage</artifactId>
<version>${revision}</version>
</dependency>
<!-- websocket -->
<dependency>

View File

@@ -0,0 +1,31 @@
<?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">
<parent>
<groupId>com.orion.ops</groupId>
<artifactId>orion-ops-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>orion-ops-spring-boot-starter-storage</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<description>项目存储层配置包</description>
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
<dependencies>
<dependency>
<groupId>com.orion.ops</groupId>
<artifactId>orion-ops-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,32 @@
package com.orion.ops.framework.storage.config;
import com.orion.ops.framework.storage.core.client.FileClient;
import com.orion.ops.framework.storage.core.client.local.LocalFileClient;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
/**
* 存储配置类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 16:21
* <p>
* TODO 后续添加 FAST MINIO OSS 等
*/
@AutoConfiguration
@EnableConfigurationProperties(StorageConfig.class)
public class OrionStorageAutoConfiguration {
/**
* 本地文件客户端
*/
@Bean
@Primary
public FileClient localFileClient(StorageConfig config) {
return new LocalFileClient(config.getLocal());
}
}

View File

@@ -0,0 +1,23 @@
package com.orion.ops.framework.storage.config;
import com.orion.ops.framework.storage.core.client.local.LocalFileClientConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 存储配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 18:40
*/
@Data
@ConfigurationProperties(prefix = "orion.storage")
public class StorageConfig {
/**
* 本地文件客户端 配置
*/
private LocalFileClientConfig local;
}

View File

@@ -0,0 +1,126 @@
package com.orion.ops.framework.storage.core.client;
import com.orion.lang.id.UUIds;
import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.io.Streams;
import com.orion.ops.framework.common.meta.TraceIdHolder;
import java.io.InputStream;
/**
* 文件客户端 基类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 17:24
*/
public abstract class AbstractFileClient<Config extends FileClientConfig> implements FileClient {
protected Config config;
public AbstractFileClient(Config config) {
this.config = config;
}
@Override
public String upload(String path, byte[] content) throws Exception {
return this.doUpload(path, Streams.toInputStream(content), true, true);
}
@Override
public String upload(String path, byte[] content, boolean overrideIfExist) throws Exception {
return this.doUpload(path, Streams.toInputStream(content), true, overrideIfExist);
}
@Override
public String upload(String path, InputStream in) throws Exception {
return this.doUpload(path, in, false, true);
}
@Override
public String upload(String path, InputStream in, boolean autoClose) throws Exception {
return this.doUpload(path, in, autoClose, true);
}
@Override
public String upload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception {
return this.doUpload(path, in, autoClose, overrideIfExist);
}
@Override
public byte[] getContent(String path) throws Exception {
try (InputStream in = this.doDownload(path)) {
return Streams.toByteArray(in);
}
}
@Override
public InputStream getContentInputStream(String path) throws Exception {
return this.doDownload(path);
}
/**
* 执行上传操作
*
* @param path path
* @param in in
* @param autoClose autoClose
* @param overrideIfExist 文件存在是否覆盖
* @return path
* @throws Exception Exception
*/
protected abstract String doUpload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception;
/**
* 执行下载操作
*
* @param path path
* @return stream
* @throws Exception Exception
*/
protected abstract InputStream doDownload(String path) throws Exception;
/**
* 获取返回路径 用于客户端返回
*
* @param path path
* @return returnPath
*/
protected abstract String getReturnPath(String path);
/**
* 获取实际存储路径 用于服务端的存储
*
* @param returnPath returnPath
* @return absolutePath
*/
protected abstract String getAbsolutePath(String returnPath);
/**
* 获取文件路径 拼接前缀
*
* @param path 路径
* @return 文件名称
*/
protected String getFilePath(String path) {
// 无需拼接
if (!config.isNameAppendTraceId()) {
return path;
}
// 名称前缀
String traceId = TraceIdHolder.get();
if (traceId == null) {
traceId = UUIds.random32();
}
String prefix = traceId + "_";
String name = Files1.getFileName(path);
// 只是文件名
if (name.equals(path)) {
return prefix + name;
}
// 包含路径
String parentPath = Files1.getParentPath(path);
return parentPath + prefix + name;
}
}

View File

@@ -0,0 +1,103 @@
package com.orion.ops.framework.storage.core.client;
import java.io.InputStream;
/**
* 文件客户端
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 16:51
*/
public interface FileClient {
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @return 路径
* @throws Exception Exception
*/
String upload(String path, byte[] content) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
String upload(String path, byte[] content, boolean overrideIfExist) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in, boolean autoClose) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception;
/**
* 检测文件是否存在
*
* @param path path
* @return 是否存在
*/
boolean isExists(String path);
/**
* 删除文件
*
* @param path 路径
* @return 是否删除
* @throws Exception Exception
*/
boolean delete(String path) throws Exception;
/**
* 获取文件内容
*
* @param path path
* @return bytes
* @throws Exception Exception
*/
byte[] getContent(String path) throws Exception;
/**
* 获取文件输入流
*
* @param path path
* @return stream
* @throws Exception Exception
*/
InputStream getContentInputStream(String path) throws Exception;
}

View File

@@ -0,0 +1,20 @@
package com.orion.ops.framework.storage.core.client;
import lombok.Data;
/**
* 文件客户端配置 基类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 17:21
*/
@Data
public class FileClientConfig {
/**
* 是否自动拼接 traceId 前缀. 没有则使用 UUID
*/
protected boolean nameAppendTraceId;
}

View File

@@ -0,0 +1,71 @@
package com.orion.ops.framework.storage.core.client.local;
import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.io.Streams;
import com.orion.ops.framework.storage.core.client.AbstractFileClient;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 本地文件客户端
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 17:21
*/
public class LocalFileClient extends AbstractFileClient<LocalFileClientConfig> {
public LocalFileClient(LocalFileClientConfig config) {
super(config);
}
@Override
protected String doUpload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception {
// 获取返回文件路径
String returnPath = this.getReturnPath(path);
// 检测文件是否存在
if (!overrideIfExist && this.isExists(returnPath)) {
return returnPath;
}
// 获取实际文件路径
String absolutePath = this.getAbsolutePath(returnPath);
// 上传文件
try (OutputStream out = Files1.openOutputStreamFast(absolutePath)) {
Streams.transfer(in, out);
} finally {
if (autoClose) {
Streams.close(in);
}
}
return returnPath;
}
@Override
protected InputStream doDownload(String path) throws Exception {
return Files1.openInputStreamFast(this.getAbsolutePath(path));
}
@Override
public boolean isExists(String path) {
return Files1.isFile(this.getAbsolutePath(path));
}
@Override
public boolean delete(String path) {
return Files1.delete(this.getAbsolutePath(path));
}
@Override
protected String getReturnPath(String path) {
// 拼接前缀
return Files1.getPath(config.getBasePath() + "/" + this.getFilePath(path));
}
@Override
protected String getAbsolutePath(String returnPath) {
// 拼接存储路径
return Files1.getPath(config.getStoragePath() + "/" + returnPath);
}
}

View File

@@ -0,0 +1,32 @@
package com.orion.ops.framework.storage.core.client.local;
import com.orion.ops.framework.storage.core.client.FileClientConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 本地文件客户端 配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 17:47
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class LocalFileClientConfig extends FileClientConfig {
/**
* 存储路径
* <p>
* 无需 / 结尾
*/
private String storagePath = "";
/**
* 基础路径
* <p>
* 无需 / 结尾
*/
private String basePath = "";
}

View File

@@ -0,0 +1,29 @@
{
"groups": [
{
"name": "orion.storage",
"type": "com.orion.ops.framework.storage.config.StorageConfig",
"sourceType": "com.orion.ops.framework.storage.config.StorageConfig"
}
],
"properties": [
{
"name": "orion.storage.local.nameAppendTraceId",
"type": "java.lang.Boolean",
"description": "是否自动拼接 traceId 前缀. 没有则使用 UUID.",
"defaultValue": false
},
{
"name": "orion.storage.local.storagePath",
"type": "java.lang.String",
"description": "存储路径.",
"defaultValue": ""
},
{
"name": "orion.storage.local.basePath",
"type": "java.lang.String",
"description": "基础路径.",
"defaultValue": ""
}
]
}

View File

@@ -0,0 +1 @@
com.orion.ops.framework.storage.config.OrionStorageAutoConfiguration

View File

@@ -27,6 +27,7 @@
<module>orion-ops-spring-boot-starter-redis</module>
<module>orion-ops-spring-boot-starter-desensitize</module>
<module>orion-ops-spring-boot-starter-log</module>
<module>orion-ops-spring-boot-starter-storage</module>
</modules>
</project>

View File

@@ -64,6 +64,11 @@
<groupId>com.orion.ops</groupId>
<artifactId>orion-ops-spring-boot-starter-log</artifactId>
</dependency>
<dependency>
<groupId>com.orion.ops</groupId>
<artifactId>orion-ops-spring-boot-starter-storage</artifactId>
<version>${revision}</version>
</dependency>
<!-- orion-ops biz-modules -->

View File

@@ -139,3 +139,8 @@ orion:
email: ljh1553488six@139.com
license: Apache-2.0
license-url: https://github.com/lijiahangmax/orion-ops-pro/blob/main/LICENSE
storage:
local:
nameAppendTraceId: true
storagePath: ${user.home}
basePath: /orion/storage/orion-ops-pro