mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 19:03:56 +08:00
refactor(storage): 新增存储模块 - 本地和 S3 两种存储模式
This commit is contained in:
@@ -13,10 +13,10 @@
|
||||
<description>ContiNew Starter 存储模块 - 本地存储</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Web MVC 模块 -->
|
||||
<!--存储 - 核心模块-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-storage-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import top.continew.starter.storage.dao.StorageDao;
|
||||
import top.continew.starter.storage.dao.impl.StorageDaoDefaultImpl;
|
||||
|
||||
/**
|
||||
* 本地存储 - 存储自动配置
|
||||
*
|
||||
* @author echo
|
||||
* @date 2024/12/17 20:23
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class LocalStorageAutoconfigure {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public StorageDao storageDao() {
|
||||
return new StorageDaoDefaultImpl();
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.client;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.continew.starter.storage.model.req.StorageProperties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* 本地客户端
|
||||
*
|
||||
* @author echo
|
||||
* @date 2024/12/16 19:37
|
||||
*/
|
||||
public class LocalClient {
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalClient.class);
|
||||
|
||||
/**
|
||||
* 配置属性
|
||||
*/
|
||||
private final StorageProperties properties;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param properties 配置属性
|
||||
*/
|
||||
public LocalClient(StorageProperties properties) {
|
||||
this.properties = properties;
|
||||
// 判断是否是默认存储,若不存在桶目录,则创建
|
||||
if (Boolean.TRUE.equals(properties.getIsDefault())) {
|
||||
String bucketName = properties.getBucketName();
|
||||
if (bucketName != null && !bucketName.isEmpty()) {
|
||||
createBucketDirectory(bucketName);
|
||||
} else {
|
||||
log.info("默认存储-存储桶已存在 => {}", bucketName);
|
||||
}
|
||||
}
|
||||
log.info("加载 Local 存储 => {}", properties.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性
|
||||
*
|
||||
* @return {@link StorageProperties }
|
||||
*/
|
||||
public StorageProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建桶目录
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
*/
|
||||
private void createBucketDirectory(String bucketName) {
|
||||
Path bucketPath = Path.of(bucketName);
|
||||
try {
|
||||
if (Files.notExists(bucketPath)) {
|
||||
Files.createDirectories(bucketPath);
|
||||
log.info("默认存储-存储桶创建成功 : {}", bucketPath.toAbsolutePath());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("创建默认存储-存储桶失败 => 路径: {}", bucketPath.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.local.autoconfigure;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 本地文件自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@EnableWebMvc
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(LocalStorageProperties.class)
|
||||
@ConditionalOnProperty(prefix = PropertiesConstants.STORAGE_LOCAL, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public class LocalStorageAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalStorageAutoConfiguration.class);
|
||||
private final LocalStorageProperties properties;
|
||||
|
||||
public LocalStorageAutoConfiguration(LocalStorageProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
Map<String, LocalStorageProperties.LocalStorageMapping> mappingMap = properties.getMapping();
|
||||
for (Map.Entry<String, LocalStorageProperties.LocalStorageMapping> mappingEntry : mappingMap.entrySet()) {
|
||||
LocalStorageProperties.LocalStorageMapping mapping = mappingEntry.getValue();
|
||||
String pathPattern = mapping.getPathPattern();
|
||||
String location = mapping.getLocation();
|
||||
if (CharSequenceUtil.isBlank(location)) {
|
||||
throw new IllegalArgumentException("Path pattern [%s] location is null.".formatted(pathPattern));
|
||||
}
|
||||
registry.addResourceHandler(CharSequenceUtil.appendIfMissing(pathPattern, StringConstants.PATH_PATTERN))
|
||||
.addResourceLocations(!location.startsWith("file:")
|
||||
? "file:%s".formatted(this.format(location))
|
||||
: this.format(location))
|
||||
.setCachePeriod(0);
|
||||
}
|
||||
}
|
||||
|
||||
private String format(String location) {
|
||||
return location.replace(StringConstants.BACKSLASH, StringConstants.SLASH);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Storage-Local' completed initialization.");
|
||||
}
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.local.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 本地存储配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.STORAGE_LOCAL)
|
||||
public class LocalStorageProperties {
|
||||
|
||||
/**
|
||||
* 是否启用本地存储
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 存储映射
|
||||
*/
|
||||
private Map<String, LocalStorageMapping> mapping = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 本地存储映射
|
||||
*/
|
||||
public static class LocalStorageMapping {
|
||||
|
||||
/**
|
||||
* 路径模式
|
||||
*/
|
||||
private String pathPattern;
|
||||
|
||||
/**
|
||||
* 资源路径
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 单文件上传大小限制
|
||||
*/
|
||||
private DataSize maxFileSize = DataSize.ofMegabytes(1);
|
||||
|
||||
public String getPathPattern() {
|
||||
return pathPattern;
|
||||
}
|
||||
|
||||
public void setPathPattern(String pathPattern) {
|
||||
this.pathPattern = pathPattern;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public DataSize getMaxFileSize() {
|
||||
return maxFileSize;
|
||||
}
|
||||
|
||||
public void setMaxFileSize(DataSize maxFileSize) {
|
||||
this.maxFileSize = maxFileSize;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Map<String, LocalStorageMapping> getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public void setMapping(Map<String, LocalStorageMapping> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
}
|
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.strategy;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.core.exception.BusinessException;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.storage.client.LocalClient;
|
||||
import top.continew.starter.storage.constant.StorageConstant;
|
||||
import top.continew.starter.storage.dao.StorageDao;
|
||||
import top.continew.starter.storage.enums.FileTypeEnum;
|
||||
import top.continew.starter.storage.model.req.StorageProperties;
|
||||
import top.continew.starter.storage.model.resp.ThumbnailResp;
|
||||
import top.continew.starter.storage.model.resp.UploadResp;
|
||||
import top.continew.starter.storage.util.ImageThumbnailUtils;
|
||||
import top.continew.starter.storage.util.LocalUtils;
|
||||
import top.continew.starter.storage.util.StorageUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 本地存储策略
|
||||
*
|
||||
* @author echo
|
||||
* @date 2024/12/16 19:48
|
||||
*/
|
||||
public class LocalStorageStrategy implements StorageStrategy<LocalClient> {
|
||||
|
||||
private final LocalClient client;
|
||||
private final StorageDao storageDao;
|
||||
|
||||
public LocalStorageStrategy(LocalClient client, StorageDao storageDao) {
|
||||
this.client = client;
|
||||
this.storageDao = storageDao;
|
||||
}
|
||||
|
||||
private StorageProperties getStorageProperties() {
|
||||
return client.getProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bucketExists(String bucketName) {
|
||||
try {
|
||||
return Files.exists(Path.of(bucketName));
|
||||
} catch (RuntimeException e) {
|
||||
throw new BusinessException("local存储 查询桶 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createBucket(String bucketName) {
|
||||
if (!bucketExists(bucketName)) {
|
||||
try {
|
||||
Files.createDirectories(Path.of(bucketName));
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException("local存储 创建桶 失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadResp upload(String fileName, InputStream inputStream, String fileType) {
|
||||
String bucketName = getStorageProperties().getBucketName();
|
||||
return this.upload(bucketName, fileName, null, inputStream, fileType, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadResp upload(String fileName,
|
||||
String path,
|
||||
InputStream inputStream,
|
||||
String fileType,
|
||||
boolean isThumbnail) {
|
||||
String bucketName = getStorageProperties().getBucketName();
|
||||
return this.upload(bucketName, fileName, path, inputStream, fileType, isThumbnail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadResp upload(String bucketName,
|
||||
String fileName,
|
||||
String path,
|
||||
InputStream inputStream,
|
||||
String fileType,
|
||||
boolean isThumbnail) {
|
||||
try {
|
||||
// 可重复读流
|
||||
inputStream = StorageUtils.ensureByteArrayStream(inputStream);
|
||||
// 获取流大小
|
||||
byte[] originalBytes = IoUtil.readBytes(inputStream);
|
||||
ValidationUtils.throwIf(originalBytes.length == 0, "输入流内容长度不可用或无效");
|
||||
|
||||
// 获取文件扩展名
|
||||
String fileExtension = FileNameUtil.extName(fileName);
|
||||
// 格式化文件名 防止上传后重复
|
||||
String formatFileName = StorageUtils.formatFileName(fileName);
|
||||
// 判断文件路径是否为空 为空给默认路径 格式 2024/12/30/
|
||||
if (StrUtil.isEmpty(path)) {
|
||||
path = StorageUtils.defaultPath();
|
||||
}
|
||||
// 判断文件夹是否存在 不存在则创建
|
||||
Path folderPath = Paths.get(bucketName, path);
|
||||
if (!Files.exists(folderPath)) {
|
||||
Files.createDirectories(folderPath);
|
||||
}
|
||||
ThumbnailResp thumbnailResp = null;
|
||||
//判断是否需要上传缩略图 前置条件 文件必须为图片
|
||||
boolean contains = FileTypeEnum.IMAGE.getExtensions().contains(fileExtension);
|
||||
if (contains && isThumbnail) {
|
||||
try (InputStream thumbnailStream = new ByteArrayInputStream(originalBytes)) {
|
||||
thumbnailResp = this.uploadThumbnail(bucketName, formatFileName, path, thumbnailStream, fileType);
|
||||
}
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
try (InputStream uploadStream = new ByteArrayInputStream(originalBytes)) {
|
||||
this.upload(bucketName, formatFileName, path, uploadStream, fileType);
|
||||
}
|
||||
|
||||
// 构建文件 md5
|
||||
String eTag = LocalUtils.calculateMD5(inputStream);
|
||||
// 构建 上传后的文件路径地址 格式 xxx/xxx/xxx.jpg
|
||||
String filePath = Paths.get(path, formatFileName).toString();
|
||||
// 构建 文件上传记录 并返回
|
||||
return buildStorageRecord(bucketName, fileName, filePath, eTag, originalBytes.length, thumbnailResp);
|
||||
} catch (NoSuchAlgorithmException | IOException e) {
|
||||
throw new BusinessException("文件上传异常", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(String bucketName, String fileName, String path, InputStream inputStream, String fileType) {
|
||||
byte[] fileBytes = IoUtil.readBytes(inputStream);
|
||||
// 拼接完整地址
|
||||
String filePath = Paths.get(bucketName, path, fileName).toString();
|
||||
try {
|
||||
//上传文件
|
||||
File targetFile = new File(filePath);
|
||||
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
|
||||
fos.write(fileBytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException("文件上传异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThumbnailResp uploadThumbnail(String bucketName,
|
||||
String fileName,
|
||||
String path,
|
||||
InputStream inputStream,
|
||||
String fileType) {
|
||||
// 获取文件扩展名
|
||||
String fileExtension = FileNameUtil.extName(fileName);
|
||||
// 生成缩略图文件名
|
||||
String thumbnailFileName = StorageUtils.buildThumbnailFileName(fileName, StorageConstant.SMALL_SUFFIX);
|
||||
// 处理文件为缩略图
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
ImageThumbnailUtils.generateThumbnail(inputStream, outputStream, fileExtension);
|
||||
inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
// 上传文件
|
||||
this.upload(bucketName, thumbnailFileName, path, inputStream, null);
|
||||
|
||||
return new ThumbnailResp((long)outputStream.size(), Paths.get(path, thumbnailFileName).toString());
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException("缩略图处理异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream download(String bucketName, String fileName) {
|
||||
String fullPath = Paths.get(bucketName, fileName).toString();
|
||||
File file = new File(fullPath);
|
||||
try {
|
||||
return new FileInputStream(file);
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException("下载文件异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String bucketName, String fileName) {
|
||||
try {
|
||||
String fullPath = Paths.get(bucketName, fileName).toString();
|
||||
Files.delete(Paths.get(fullPath));
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("删除文件异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageBase64(String bucketName, String fileName) {
|
||||
try (InputStream inputStream = download(bucketName, fileName)) {
|
||||
if (ObjectUtil.isEmpty(inputStream)) {
|
||||
return null;
|
||||
}
|
||||
String extName = FileUtil.extName(fileName);
|
||||
CheckUtils.throwIf(!FileTypeEnum.IMAGE.getExtensions().contains(extName), "{} 不是图像格式", extName);
|
||||
return Base64.getEncoder().encodeToString(inputStream.readAllBytes());
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("无法查看图片", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建存储记录
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param fileName 原始文件名
|
||||
* @param filePath 文件路径 xx/xx/xxx.jpg
|
||||
* @param eTag 标签 - md5
|
||||
* @param size 文件大小
|
||||
* @param thumbnailResp 缩略图信息
|
||||
* @return {@link UploadResp }
|
||||
*/
|
||||
private UploadResp buildStorageRecord(String bucketName,
|
||||
String fileName,
|
||||
String filePath,
|
||||
String eTag,
|
||||
long size,
|
||||
ThumbnailResp thumbnailResp) {
|
||||
// 获取当前存储 code
|
||||
String code = client.getProperties().getCode();
|
||||
// 构建访问地址前缀
|
||||
String baseUrl = "http://" + getStorageProperties().getEndpoint() + StringConstants.SLASH;
|
||||
|
||||
UploadResp resp = new UploadResp();
|
||||
resp.setCode(code);
|
||||
resp.setUrl(baseUrl + filePath);
|
||||
resp.setBasePath(filePath);
|
||||
resp.setOriginalFilename(fileName);
|
||||
resp.setExt(FileNameUtil.extName(fileName));
|
||||
resp.setSize(size);
|
||||
resp.seteTag(eTag);
|
||||
resp.setPath(filePath);
|
||||
resp.setBucketName(bucketName);
|
||||
resp.setCreateTime(LocalDateTime.now());
|
||||
if (ObjectUtil.isNotEmpty(thumbnailResp)) {
|
||||
resp.setThumbnailUrl(baseUrl + thumbnailResp.getThumbnailPath());
|
||||
resp.setThumbnailSize(thumbnailResp.getThumbnailSize());
|
||||
}
|
||||
storageDao.add(resp);
|
||||
return resp;
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.continew.starter.storage.util;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import net.dreamlu.mica.core.utils.DigestUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* 本地存储工具
|
||||
*
|
||||
* @author echo
|
||||
* @date 2024/12/27 11:58
|
||||
*/
|
||||
public class LocalUtils {
|
||||
public LocalUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算MD5
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @return {@link String }
|
||||
* @throws NoSuchAlgorithmException 没有这样算法例外
|
||||
*/
|
||||
public static String calculateMD5(InputStream inputStream) throws NoSuchAlgorithmException {
|
||||
byte[] fileBytes = IoUtil.readBytes(inputStream);
|
||||
return DigestUtil.md5Hex(fileBytes);
|
||||
}
|
||||
}
|
@@ -1 +1 @@
|
||||
top.continew.starter.storage.local.autoconfigure.LocalStorageAutoConfiguration
|
||||
top.continew.starter.storage.autoconfigure.LocalStorageAutoconfigure
|
Reference in New Issue
Block a user