mirror of https://github.com/halo-dev/halo
refactor: the naming method of uploaded attachments (#1500)
* feat: Refactor the naming method of uploaded attachments
* refactor: attachment upload parameter
* refactor: 重构文件名称是否重复的判断方式
* refactor: the usage of file path descriptor
* fix: remove blank line
* feat: add more test case
* fix: file base name in FilePathDescriptor
* Revert "refactor: the usage of file path descriptor"
This reverts commit b46ff3b4
pull/1509/head
parent
44d740b760
commit
1d91450505
|
@ -18,8 +18,8 @@ import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.AliOssProperties;
|
import run.halo.app.model.properties.AliOssProperties;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,7 @@ import run.halo.app.utils.ImageUtils;
|
||||||
*
|
*
|
||||||
* @author MyFaith
|
* @author MyFaith
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-04-04
|
* @date 2019-04-04
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -34,9 +35,12 @@ import run.halo.app.utils.ImageUtils;
|
||||||
public class AliOssFileHandler implements FileHandler {
|
public class AliOssFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public AliOssFileHandler(OptionService optionService) {
|
public AliOssFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,30 +83,21 @@ public class AliOssFileHandler implements FileHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final String basename =
|
FilePathDescriptor uploadFilePath = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(basePath.toString())
|
||||||
final String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
final String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
final StringBuilder upFilePath = new StringBuilder();
|
.setRenamePredicate(relativePath ->
|
||||||
|
attachmentRepository
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.countByFileKeyAndType(relativePath, AttachmentType.ALIOSS) > 0)
|
||||||
upFilePath.append(source)
|
.setOriginalName(file.getOriginalFilename())
|
||||||
.append(URL_SEPARATOR);
|
.build();
|
||||||
}
|
|
||||||
|
|
||||||
upFilePath.append(basename)
|
|
||||||
.append("_")
|
|
||||||
.append(timestamp)
|
|
||||||
.append(".")
|
|
||||||
.append(extension);
|
|
||||||
|
|
||||||
String filePath = StringUtils.join(basePath.toString(), upFilePath.toString());
|
|
||||||
|
|
||||||
log.info(basePath.toString());
|
log.info(basePath.toString());
|
||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
final PutObjectResult putObjectResult = ossClient.putObject(bucketName,
|
final PutObjectResult putObjectResult = ossClient.putObject(bucketName,
|
||||||
upFilePath.toString(),
|
uploadFilePath.getRelativePath(),
|
||||||
file.getInputStream());
|
file.getInputStream());
|
||||||
|
|
||||||
if (putObjectResult == null) {
|
if (putObjectResult == null) {
|
||||||
|
@ -111,21 +106,22 @@ public class AliOssFileHandler implements FileHandler {
|
||||||
|
|
||||||
// Response result
|
// Response result
|
||||||
final UploadResult uploadResult = new UploadResult();
|
final UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(basename);
|
uploadResult.setFilename(uploadFilePath.getName());
|
||||||
|
String fullPath = uploadFilePath.getFullPath();
|
||||||
uploadResult
|
uploadResult
|
||||||
.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
|
.setFilePath(StringUtils.isBlank(styleRule) ? fullPath : fullPath + styleRule);
|
||||||
uploadResult.setKey(upFilePath.toString());
|
uploadResult.setKey(uploadFilePath.getRelativePath());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(uploadFilePath.getExtension());
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
handleImageMetadata(file, uploadResult, () -> {
|
handleImageMetadata(file, uploadResult, () -> {
|
||||||
if (ImageUtils.EXTENSION_ICO.equals(extension)) {
|
if (ImageUtils.EXTENSION_ICO.equals(uploadFilePath.getExtension())) {
|
||||||
return filePath;
|
return fullPath;
|
||||||
} else {
|
} else {
|
||||||
return StringUtils.isBlank(thumbnailStyleRule) ? filePath :
|
return StringUtils.isBlank(thumbnailStyleRule) ? fullPath :
|
||||||
filePath + thumbnailStyleRule;
|
fullPath + thumbnailStyleRule;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package run.halo.app.handler.file;
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
|
|
||||||
import com.baidubce.auth.DefaultBceCredentials;
|
import com.baidubce.auth.DefaultBceCredentials;
|
||||||
import com.baidubce.services.bos.BosClient;
|
import com.baidubce.services.bos.BosClient;
|
||||||
import com.baidubce.services.bos.BosClientConfiguration;
|
import com.baidubce.services.bos.BosClientConfiguration;
|
||||||
|
@ -16,8 +15,8 @@ import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.BaiduBosProperties;
|
import run.halo.app.model.properties.BaiduBosProperties;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,9 +31,12 @@ import run.halo.app.utils.ImageUtils;
|
||||||
public class BaiduBosFileHandler implements FileHandler {
|
public class BaiduBosFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public BaiduBosFileHandler(OptionService optionService) {
|
public BaiduBosFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,40 +71,42 @@ public class BaiduBosFileHandler implements FileHandler {
|
||||||
domain = protocol + domain;
|
domain = protocol + domain;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String basename =
|
FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(domain)
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
String upFilePath = StringUtils.join(basename, "_", timestamp, ".", extension);
|
.setRenamePredicate(relativePath ->
|
||||||
String filePath = StringUtils.join(
|
attachmentRepository
|
||||||
StringUtils.appendIfMissing(StringUtils.isNotBlank(domain) ? domain : source, "/"),
|
.countByFileKeyAndType(relativePath, AttachmentType.BAIDUBOS) > 0)
|
||||||
upFilePath);
|
.setOriginalName(file.getOriginalFilename())
|
||||||
|
.build();
|
||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
PutObjectResponse putObjectResponseFromInputStream =
|
PutObjectResponse putObjectResponseFromInputStream =
|
||||||
client.putObject(bucketName, upFilePath, file.getInputStream());
|
client.putObject(bucketName, pathDescriptor.getFullName(), file.getInputStream());
|
||||||
if (putObjectResponseFromInputStream == null) {
|
if (putObjectResponseFromInputStream == null) {
|
||||||
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到百度云失败 ");
|
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到百度云失败 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response result
|
// Response result
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(basename);
|
uploadResult.setFilename(pathDescriptor.getFullName());
|
||||||
|
String fullPath = pathDescriptor.getFullPath();
|
||||||
uploadResult
|
uploadResult
|
||||||
.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
|
.setFilePath(StringUtils.isBlank(styleRule) ? fullPath : fullPath + styleRule);
|
||||||
uploadResult.setKey(upFilePath);
|
uploadResult.setKey(pathDescriptor.getRelativePath());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(pathDescriptor.getExtension());
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
// Handle thumbnail
|
// Handle thumbnail
|
||||||
handleImageMetadata(file, uploadResult, () -> {
|
handleImageMetadata(file, uploadResult, () -> {
|
||||||
if (ImageUtils.EXTENSION_ICO.equals(extension)) {
|
if (ImageUtils.EXTENSION_ICO.equals(pathDescriptor.getExtension())) {
|
||||||
return filePath;
|
return fullPath;
|
||||||
} else {
|
} else {
|
||||||
return StringUtils.isBlank(thumbnailStyleRule) ? filePath :
|
return StringUtils.isBlank(thumbnailStyleRule) ? fullPath :
|
||||||
filePath + thumbnailStyleRule;
|
fullPath + thumbnailStyleRule;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import run.halo.app.utils.FilenameUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File path descriptor.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2021-10-21
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public final class FilePathDescriptor {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String extension;
|
||||||
|
private String relativePath;
|
||||||
|
private String basePath;
|
||||||
|
private String fullName;
|
||||||
|
private String fullPath;
|
||||||
|
private String subPath;
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String extension;
|
||||||
|
private String subPath;
|
||||||
|
private String basePath;
|
||||||
|
private String nameSuffix = StringUtils.EMPTY;
|
||||||
|
private String separator = "/";
|
||||||
|
private boolean automaticRename;
|
||||||
|
private Predicate<String> renamePredicate;
|
||||||
|
private String relativePath;
|
||||||
|
|
||||||
|
public Builder setSubPath(String subPath) {
|
||||||
|
this.subPath = StringUtils.removeEnd(subPath, separator);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAutomaticRename(Boolean automaticRename) {
|
||||||
|
this.automaticRename = automaticRename != null && automaticRename;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRenamePredicate(Predicate<String> predicate) {
|
||||||
|
this.renamePredicate = predicate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set path separator, <code>NULL</code> value is not allowed.
|
||||||
|
*
|
||||||
|
* @param separator path separator
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setSeparator(String separator) {
|
||||||
|
if (separator == null) {
|
||||||
|
throw new IllegalArgumentException("The separator must not be null.");
|
||||||
|
}
|
||||||
|
this.separator = separator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set original file name.
|
||||||
|
*
|
||||||
|
* @param originalFileName original file name
|
||||||
|
* @return file path builder
|
||||||
|
*/
|
||||||
|
public Builder setOriginalName(String originalFileName) {
|
||||||
|
Assert.notNull(originalFileName, "The originalFileName must not be null.");
|
||||||
|
this.name = FilenameUtils.getBasename(originalFileName);
|
||||||
|
this.extension = FilenameUtils.getExtension(originalFileName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setBasePath(String basePath) {
|
||||||
|
this.basePath = StringUtils.removeEnd(basePath, separator);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set file base name suffix.
|
||||||
|
*
|
||||||
|
* @param nameSuffix file base name suffix
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setNameSuffix(String nameSuffix) {
|
||||||
|
if (nameSuffix == null) {
|
||||||
|
nameSuffix = StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
this.nameSuffix = nameSuffix;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String buildName() {
|
||||||
|
StringBuilder sb = new StringBuilder()
|
||||||
|
.append(this.name);
|
||||||
|
if (shouldRename()) {
|
||||||
|
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||||
|
sb.append('-').append(timestamp);
|
||||||
|
}
|
||||||
|
sb.append(this.nameSuffix);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFullName() {
|
||||||
|
// eg. hello.jpg -> hello-uuid-thumbnail.jpg
|
||||||
|
if (StringUtils.isNotBlank(this.extension)) {
|
||||||
|
return this.name + '.' + this.extension;
|
||||||
|
}
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFullPath() {
|
||||||
|
if (StringUtils.isNotBlank(this.basePath)) {
|
||||||
|
return getPath(this.basePath, this.subPath, this.getFullName());
|
||||||
|
}
|
||||||
|
return getPath(this.subPath, this.getFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String getRelativePath() {
|
||||||
|
return getPath(this.subPath, getFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldRename() {
|
||||||
|
if (!automaticRename) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// automaticRename is true
|
||||||
|
if (renamePredicate == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// renamePredicate not null
|
||||||
|
return renamePredicate.test(this.relativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPath(String first, String... more) {
|
||||||
|
String path;
|
||||||
|
if (more.length == 0) {
|
||||||
|
path = first;
|
||||||
|
} else {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(first);
|
||||||
|
for (String segment : more) {
|
||||||
|
if (StringUtils.isNotBlank(segment)) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append(separator);
|
||||||
|
}
|
||||||
|
sb.append(segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path = sb.toString();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build file path object.
|
||||||
|
*
|
||||||
|
* @return file path
|
||||||
|
*/
|
||||||
|
public FilePathDescriptor build() {
|
||||||
|
// build relative path first, used to determine if it needs to be renamed
|
||||||
|
this.relativePath = getRelativePath();
|
||||||
|
// then build name, returns a new name if the relative path exists
|
||||||
|
this.name = buildName();
|
||||||
|
|
||||||
|
FilePathDescriptor descriptor = new FilePathDescriptor()
|
||||||
|
.setBasePath(this.basePath)
|
||||||
|
.setSubPath(this.subPath)
|
||||||
|
// regenerate relative path
|
||||||
|
.setRelativePath(getRelativePath())
|
||||||
|
.setName(this.name)
|
||||||
|
.setExtension(extension)
|
||||||
|
.setFullPath(getFullPath())
|
||||||
|
.setFullName(getFullName());
|
||||||
|
log.info("FilePathDescriptor: [{}]", descriptor);
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,14 +17,15 @@ import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.HuaweiObsProperties;
|
import run.halo.app.model.properties.HuaweiObsProperties;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Huawei obs file handler.
|
* Huawei obs file handler.
|
||||||
*
|
*
|
||||||
* @author qilin
|
* @author qilin
|
||||||
|
* @author guqing
|
||||||
* @date 2020-04-03
|
* @date 2020-04-03
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -32,9 +33,12 @@ import run.halo.app.utils.ImageUtils;
|
||||||
public class HuaweiObsFileHandler implements FileHandler {
|
public class HuaweiObsFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public HuaweiObsFileHandler(OptionService optionService) {
|
public HuaweiObsFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,51 +81,44 @@ public class HuaweiObsFileHandler implements FileHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String basename =
|
FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(domain)
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
StringBuilder upFilePath = new StringBuilder();
|
.setRenamePredicate(relativePath ->
|
||||||
|
attachmentRepository
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.countByFileKeyAndType(relativePath, AttachmentType.HUAWEIOBS) > 0)
|
||||||
upFilePath.append(source)
|
.setOriginalName(file.getOriginalFilename())
|
||||||
.append(URL_SEPARATOR);
|
.build();
|
||||||
}
|
|
||||||
|
|
||||||
upFilePath.append(basename)
|
|
||||||
.append("_")
|
|
||||||
.append(timestamp)
|
|
||||||
.append(".")
|
|
||||||
.append(extension);
|
|
||||||
|
|
||||||
String filePath = StringUtils.join(basePath.toString(), upFilePath.toString());
|
|
||||||
|
|
||||||
log.info(basePath.toString());
|
log.info(basePath.toString());
|
||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
PutObjectResult putObjectResult =
|
PutObjectResult putObjectResult =
|
||||||
obsClient.putObject(bucketName, upFilePath.toString(), file.getInputStream());
|
obsClient.putObject(bucketName, pathDescriptor.getRelativePath(),
|
||||||
|
file.getInputStream());
|
||||||
if (putObjectResult == null) {
|
if (putObjectResult == null) {
|
||||||
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到华为云失败 ");
|
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到华为云失败 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response result
|
// Response result
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(basename);
|
uploadResult.setFilename(pathDescriptor.getName());
|
||||||
|
String fullPath = pathDescriptor.getFullPath();
|
||||||
uploadResult
|
uploadResult
|
||||||
.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
|
.setFilePath(StringUtils.isBlank(styleRule) ? fullPath : fullPath + styleRule);
|
||||||
uploadResult.setKey(upFilePath.toString());
|
uploadResult.setKey(pathDescriptor.getRelativePath());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(pathDescriptor.getExtension());
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
handleImageMetadata(file, uploadResult, () -> {
|
handleImageMetadata(file, uploadResult, () -> {
|
||||||
if (ImageUtils.EXTENSION_ICO.equals(extension)) {
|
if (ImageUtils.EXTENSION_ICO.equals(pathDescriptor.getExtension())) {
|
||||||
return filePath;
|
return fullPath;
|
||||||
} else {
|
} else {
|
||||||
return StringUtils.isBlank(thumbnailStyleRule) ? filePath :
|
return StringUtils.isBlank(thumbnailStyleRule) ? fullPath :
|
||||||
filePath + thumbnailStyleRule;
|
fullPath + thumbnailStyleRule;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Objects;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.coobird.thumbnailator.Thumbnails;
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
@ -20,9 +21,8 @@ import run.halo.app.config.properties.HaloProperties;
|
||||||
import run.halo.app.exception.FileOperationException;
|
import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
import run.halo.app.utils.FilenameUtils;
|
||||||
import run.halo.app.utils.HaloUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,7 @@ import run.halo.app.utils.ImageUtils;
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-03-27
|
* @date 2019-03-27
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -53,13 +54,13 @@ public class LocalFileHandler implements FileHandler {
|
||||||
*/
|
*/
|
||||||
private static final int THUMB_HEIGHT = 256;
|
private static final int THUMB_HEIGHT = 256;
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
private final String workDir;
|
private final String workDir;
|
||||||
|
|
||||||
public LocalFileHandler(OptionService optionService,
|
public LocalFileHandler(AttachmentRepository attachmentRepository,
|
||||||
HaloProperties haloProperties) {
|
HaloProperties haloProperties) {
|
||||||
this.optionService = optionService;
|
this.attachmentRepository = attachmentRepository;
|
||||||
|
|
||||||
// Get work dir
|
// Get work dir
|
||||||
workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir());
|
workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir());
|
||||||
|
@ -83,57 +84,39 @@ public class LocalFileHandler implements FileHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public UploadResult upload(MultipartFile file) {
|
public UploadResult upload(@NonNull MultipartFile file) {
|
||||||
Assert.notNull(file, "Multipart file must not be null");
|
Assert.notNull(file, "Multipart file must not be null");
|
||||||
|
|
||||||
// Get current time
|
FilePathDescriptor uploadFilePath = new FilePathDescriptor.Builder()
|
||||||
Calendar current = Calendar.getInstance(optionService.getLocale());
|
.setBasePath(workDir)
|
||||||
// Get month and day of month
|
.setSubPath(generatePath())
|
||||||
int year = current.get(Calendar.YEAR);
|
.setSeparator(FILE_SEPARATOR)
|
||||||
int month = current.get(Calendar.MONTH) + 1;
|
.setAutomaticRename(true)
|
||||||
|
.setRenamePredicate(relativePath ->
|
||||||
String monthString = month < 10 ? "0" + month : String.valueOf(month);
|
attachmentRepository
|
||||||
|
.countByFileKeyAndType(relativePath, AttachmentType.LOCAL) > 0)
|
||||||
// Build directory
|
.setOriginalName(file.getOriginalFilename())
|
||||||
String subDir = UPLOAD_SUB_DIR + year + FILE_SEPARATOR + monthString + FILE_SEPARATOR;
|
.build();
|
||||||
|
log.info("Uploading file: [{}] to directory: [{}]", file.getOriginalFilename(),
|
||||||
String originalBasename =
|
uploadFilePath.getRelativePath());
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
Path localFileFullPath = Paths.get(uploadFilePath.getFullPath());
|
||||||
|
|
||||||
// Get basename
|
|
||||||
String basename = originalBasename + '-' + HaloUtils.randomUUIDWithoutDash();
|
|
||||||
|
|
||||||
// Get extension
|
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
|
||||||
|
|
||||||
log.debug("Base name: [{}], extension: [{}] of original filename: [{}]", basename,
|
|
||||||
extension, file.getOriginalFilename());
|
|
||||||
|
|
||||||
// Build sub file path
|
|
||||||
String subFilePath = subDir + basename + '.' + extension;
|
|
||||||
|
|
||||||
// Get upload path
|
|
||||||
Path uploadPath = Paths.get(workDir, subFilePath);
|
|
||||||
|
|
||||||
log.info("Uploading file: [{}]to directory: [{}]", file.getOriginalFilename(),
|
|
||||||
uploadPath.toString());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO Synchronize here
|
// TODO Synchronize here
|
||||||
// Create directory
|
// Create directory
|
||||||
Files.createDirectories(uploadPath.getParent());
|
Files.createDirectories(localFileFullPath.getParent());
|
||||||
Files.createFile(uploadPath);
|
Files.createFile(localFileFullPath);
|
||||||
|
|
||||||
// Upload this file
|
// Upload this file
|
||||||
file.transferTo(uploadPath);
|
file.transferTo(localFileFullPath);
|
||||||
|
|
||||||
// Build upload result
|
// Build upload result
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(originalBasename);
|
uploadResult.setFilename(uploadFilePath.getName());
|
||||||
uploadResult.setFilePath(subFilePath);
|
uploadResult.setFilePath(uploadFilePath.getRelativePath());
|
||||||
uploadResult.setKey(subFilePath);
|
uploadResult.setKey(uploadFilePath.getRelativePath());
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(uploadFilePath.getExtension());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
@ -141,28 +124,35 @@ public class LocalFileHandler implements FileHandler {
|
||||||
// TODO refactor this: if image is svg ext. extension
|
// TODO refactor this: if image is svg ext. extension
|
||||||
handleImageMetadata(file, uploadResult, () -> {
|
handleImageMetadata(file, uploadResult, () -> {
|
||||||
// Upload a thumbnail
|
// Upload a thumbnail
|
||||||
final String thumbnailBasename = basename + THUMBNAIL_SUFFIX;
|
FilePathDescriptor thumbnailFilePath = new FilePathDescriptor.Builder()
|
||||||
final String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
.setBasePath(workDir)
|
||||||
final Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
.setSubPath(uploadFilePath.getSubPath())
|
||||||
|
.setSeparator(FILE_SEPARATOR)
|
||||||
|
.setOriginalName(uploadFilePath.getFullName())
|
||||||
|
.setNameSuffix(THUMBNAIL_SUFFIX)
|
||||||
|
.build();
|
||||||
|
final Path thumbnailPath = Paths.get(thumbnailFilePath.getFullPath());
|
||||||
try (InputStream is = file.getInputStream()) {
|
try (InputStream is = file.getInputStream()) {
|
||||||
// Generate thumbnail
|
// Generate thumbnail
|
||||||
BufferedImage originalImage = ImageUtils.getImageFromFile(is, extension);
|
BufferedImage originalImage =
|
||||||
boolean result = generateThumbnail(originalImage, thumbnailPath, extension);
|
ImageUtils.getImageFromFile(is, uploadFilePath.getExtension());
|
||||||
|
boolean result = generateThumbnail(originalImage, thumbnailPath,
|
||||||
|
uploadFilePath.getExtension());
|
||||||
if (result) {
|
if (result) {
|
||||||
// Set thumb path
|
// Set thumb path
|
||||||
return thumbnailSubFilePath;
|
return thumbnailFilePath.getRelativePath();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.warn("Failed to open image file.", e);
|
log.warn("Failed to open image file.", e);
|
||||||
}
|
}
|
||||||
return subFilePath;
|
return uploadFilePath.getRelativePath();
|
||||||
});
|
});
|
||||||
|
|
||||||
log.info("Uploaded file: [{}] to directory: [{}] successfully",
|
log.info("Uploaded file: [{}] to directory: [{}] successfully",
|
||||||
file.getOriginalFilename(), uploadPath.toString());
|
file.getOriginalFilename(), uploadFilePath.getFullPath());
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new FileOperationException("上传附件失败").setErrorData(uploadPath);
|
throw new FileOperationException("上传附件失败").setErrorData(uploadFilePath.getFullPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +195,19 @@ public class LocalFileHandler implements FileHandler {
|
||||||
return AttachmentType.LOCAL;
|
return AttachmentType.LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String generatePath() {
|
||||||
|
// Get current time
|
||||||
|
Calendar current = Calendar.getInstance();
|
||||||
|
// Get month and day of month
|
||||||
|
int year = current.get(Calendar.YEAR);
|
||||||
|
int month = current.get(Calendar.MONTH) + 1;
|
||||||
|
|
||||||
|
String monthString = month < 10 ? "0" + month : String.valueOf(month);
|
||||||
|
|
||||||
|
// Build directory
|
||||||
|
return UPLOAD_SUB_DIR + year + FILE_SEPARATOR + monthString + FILE_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean generateThumbnail(BufferedImage originalImage, Path thumbPath,
|
private boolean generateThumbnail(BufferedImage originalImage, Path thumbPath,
|
||||||
String extension) {
|
String extension) {
|
||||||
Assert.notNull(originalImage, "Image must not be null");
|
Assert.notNull(originalImage, "Image must not be null");
|
||||||
|
@ -215,11 +218,10 @@ public class LocalFileHandler implements FileHandler {
|
||||||
try {
|
try {
|
||||||
Files.createFile(thumbPath);
|
Files.createFile(thumbPath);
|
||||||
// Convert to thumbnail and copy the thumbnail
|
// Convert to thumbnail and copy the thumbnail
|
||||||
log.debug("Trying to generate thumbnail: [{}]", thumbPath.toString());
|
log.debug("Trying to generate thumbnail: [{}]", thumbPath);
|
||||||
Thumbnails.of(originalImage).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true)
|
Thumbnails.of(originalImage).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true)
|
||||||
.toFile(thumbPath.toFile());
|
.toFile(thumbPath.toFile());
|
||||||
log.info("Generated thumbnail image, and wrote the thumbnail to [{}]",
|
log.info("Generated thumbnail image, and wrote the thumbnail to [{}]", thumbPath);
|
||||||
thumbPath.toString());
|
|
||||||
result = true;
|
result = true;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
// Ignore the error
|
// Ignore the error
|
||||||
|
|
|
@ -16,14 +16,14 @@ import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.MinioProperties;
|
import run.halo.app.model.properties.MinioProperties;
|
||||||
import run.halo.app.model.support.HaloConst;
|
import run.halo.app.model.support.HaloConst;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MinIO file handler.
|
* MinIO file handler.
|
||||||
*
|
*
|
||||||
* @author Wh1te
|
* @author Wh1te
|
||||||
|
* @author guqing
|
||||||
* @date 2020-10-03
|
* @date 2020-10-03
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -31,9 +31,12 @@ import run.halo.app.utils.FilenameUtils;
|
||||||
public class MinioFileHandler implements FileHandler {
|
public class MinioFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public MinioFileHandler(OptionService optionService) {
|
public MinioFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -62,36 +65,36 @@ public class MinioFileHandler implements FileHandler {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String basename =
|
FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(endpoint + bucketName)
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
String upFilePath = StringUtils
|
.setRenamePredicate(relativePath ->
|
||||||
.join(StringUtils.isNotBlank(source) ? source + HaloConst.URL_SEPARATOR : "",
|
attachmentRepository
|
||||||
basename, "_", timestamp, ".", extension);
|
.countByFileKeyAndType(relativePath, AttachmentType.MINIO) > 0)
|
||||||
String filePath =
|
.setOriginalName(file.getOriginalFilename())
|
||||||
StringUtils.join(endpoint, bucketName, HaloConst.URL_SEPARATOR, upFilePath);
|
.build();
|
||||||
|
|
||||||
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
|
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
|
||||||
.contentType(file.getContentType())
|
.contentType(file.getContentType())
|
||||||
.bucket(bucketName)
|
.bucket(bucketName)
|
||||||
.stream(file.getInputStream(), file.getSize(), -1)
|
.stream(file.getInputStream(), file.getSize(), -1)
|
||||||
.object(upFilePath)
|
.object(pathDescriptor.getRelativePath())
|
||||||
.build();
|
.build();
|
||||||
minioClient.ignoreCertCheck();
|
minioClient.ignoreCertCheck();
|
||||||
minioClient.putObject(putObjectArgs);
|
minioClient.putObject(putObjectArgs);
|
||||||
|
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(basename);
|
uploadResult.setFilename(pathDescriptor.getName());
|
||||||
uploadResult.setFilePath(filePath);
|
uploadResult.setFilePath(pathDescriptor.getFullPath());
|
||||||
uploadResult.setKey(upFilePath);
|
uploadResult.setKey(pathDescriptor.getRelativePath());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(pathDescriptor.getExtension());
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
// Handle thumbnail
|
// Handle thumbnail
|
||||||
handleImageMetadata(file, uploadResult, () -> filePath);
|
handleImageMetadata(file, uploadResult, pathDescriptor::getFullPath);
|
||||||
|
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -30,8 +30,8 @@ import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.QiniuOssProperties;
|
import run.halo.app.model.properties.QiniuOssProperties;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
import run.halo.app.utils.JsonUtils;
|
import run.halo.app.utils.JsonUtils;
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ import run.halo.app.utils.JsonUtils;
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author guqing
|
||||||
* @date 2019-03-27
|
* @date 2019-03-27
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -47,9 +48,12 @@ import run.halo.app.utils.JsonUtils;
|
||||||
public class QiniuOssFileHandler implements FileHandler {
|
public class QiniuOssFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public QiniuOssFileHandler(OptionService optionService) {
|
public QiniuOssFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,20 +100,15 @@ public class QiniuOssFileHandler implements FileHandler {
|
||||||
.append(URL_SEPARATOR);
|
.append(URL_SEPARATOR);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String basename =
|
FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(basePath.toString())
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
StringBuilder upFilePath = new StringBuilder();
|
.setRenamePredicate(relativePath ->
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
attachmentRepository
|
||||||
upFilePath.append(source)
|
.countByFileKeyAndType(relativePath, AttachmentType.QINIUOSS) > 0)
|
||||||
.append(URL_SEPARATOR);
|
.setOriginalName(file.getOriginalFilename())
|
||||||
}
|
.build();
|
||||||
upFilePath.append(basename)
|
|
||||||
.append("_")
|
|
||||||
.append(timestamp)
|
|
||||||
.append(".")
|
|
||||||
.append(extension);
|
|
||||||
|
|
||||||
// Get file recorder for temp directory
|
// Get file recorder for temp directory
|
||||||
FileRecorder fileRecorder = new FileRecorder(tmpPath.toFile());
|
FileRecorder fileRecorder = new FileRecorder(tmpPath.toFile());
|
||||||
|
@ -117,7 +116,8 @@ public class QiniuOssFileHandler implements FileHandler {
|
||||||
UploadManager uploadManager = new UploadManager(configuration, fileRecorder);
|
UploadManager uploadManager = new UploadManager(configuration, fileRecorder);
|
||||||
// Put the file
|
// Put the file
|
||||||
Response response = uploadManager
|
Response response = uploadManager
|
||||||
.put(file.getInputStream(), upFilePath.toString(), uploadToken, null, null);
|
.put(file.getInputStream(), pathDescriptor.getRelativePath(), uploadToken, null,
|
||||||
|
null);
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Qiniu oss response: [{}]", response.toString());
|
log.debug("Qiniu oss response: [{}]", response.toString());
|
||||||
|
@ -128,25 +128,26 @@ public class QiniuOssFileHandler implements FileHandler {
|
||||||
PutSet putSet = JsonUtils.jsonToObject(response.bodyString(), PutSet.class);
|
PutSet putSet = JsonUtils.jsonToObject(response.bodyString(), PutSet.class);
|
||||||
|
|
||||||
// Get file full path
|
// Get file full path
|
||||||
String filePath = StringUtils.join(basePath.toString(), upFilePath.toString());
|
String fullPath = pathDescriptor.getFullPath();
|
||||||
|
|
||||||
// Build upload result
|
// Build upload result
|
||||||
UploadResult result = new UploadResult();
|
UploadResult result = new UploadResult();
|
||||||
result.setFilename(basename);
|
result.setFilename(pathDescriptor.getName());
|
||||||
result.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
|
|
||||||
result.setKey(upFilePath.toString());
|
result.setFilePath(StringUtils.isBlank(styleRule) ? fullPath : fullPath + styleRule);
|
||||||
result.setSuffix(extension);
|
result.setKey(pathDescriptor.getRelativePath());
|
||||||
|
result.setSuffix(pathDescriptor.getExtension());
|
||||||
result.setWidth(putSet.getWidth());
|
result.setWidth(putSet.getWidth());
|
||||||
result.setHeight(putSet.getHeight());
|
result.setHeight(putSet.getHeight());
|
||||||
result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
result.setSize(file.getSize());
|
result.setSize(file.getSize());
|
||||||
|
|
||||||
if (isImageType(file)) {
|
if (isImageType(file)) {
|
||||||
if (ImageUtils.EXTENSION_ICO.equals(extension)) {
|
if (ImageUtils.EXTENSION_ICO.equals(pathDescriptor.getExtension())) {
|
||||||
result.setThumbPath(filePath);
|
result.setThumbPath(fullPath);
|
||||||
} else {
|
} else {
|
||||||
result.setThumbPath(StringUtils.isBlank(thumbnailStyleRule) ? filePath :
|
result.setThumbPath(StringUtils.isBlank(thumbnailStyleRule) ? fullPath :
|
||||||
filePath + thumbnailStyleRule);
|
fullPath + thumbnailStyleRule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class SmmsFileHandler implements FileHandler {
|
||||||
|
|
||||||
// Check status
|
// Check status
|
||||||
if (mapResponseEntity.getStatusCode().isError()) {
|
if (mapResponseEntity.getStatusCode().isError()) {
|
||||||
log.error("Server response detail: [{}]", mapResponseEntity.toString());
|
log.error("Server response detail: [{}]", mapResponseEntity);
|
||||||
throw new FileOperationException(
|
throw new FileOperationException(
|
||||||
"SM.MS 服务状态异常,状态码: " + mapResponseEntity.getStatusCodeValue());
|
"SM.MS 服务状态异常,状态码: " + mapResponseEntity.getStatusCodeValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package run.halo.app.handler.file;
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
|
|
||||||
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||||
|
|
||||||
import com.qcloud.cos.COSClient;
|
import com.qcloud.cos.COSClient;
|
||||||
|
@ -21,8 +20,8 @@ import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.model.enums.AttachmentType;
|
import run.halo.app.model.enums.AttachmentType;
|
||||||
import run.halo.app.model.properties.TencentCosProperties;
|
import run.halo.app.model.properties.TencentCosProperties;
|
||||||
import run.halo.app.model.support.UploadResult;
|
import run.halo.app.model.support.UploadResult;
|
||||||
|
import run.halo.app.repository.AttachmentRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,9 +36,12 @@ import run.halo.app.utils.ImageUtils;
|
||||||
public class TencentCosFileHandler implements FileHandler {
|
public class TencentCosFileHandler implements FileHandler {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
private final AttachmentRepository attachmentRepository;
|
||||||
|
|
||||||
public TencentCosFileHandler(OptionService optionService) {
|
public TencentCosFileHandler(OptionService optionService,
|
||||||
|
AttachmentRepository attachmentRepository) {
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.attachmentRepository = attachmentRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,24 +90,15 @@ public class TencentCosFileHandler implements FileHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String basename =
|
FilePathDescriptor pathDescriptor = new FilePathDescriptor.Builder()
|
||||||
FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
|
.setBasePath(basePath.toString())
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
.setSubPath(source)
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
.setAutomaticRename(true)
|
||||||
StringBuilder upFilePath = new StringBuilder();
|
.setRenamePredicate(relativePath ->
|
||||||
|
attachmentRepository
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.countByFileKeyAndType(relativePath, AttachmentType.TENCENTCOS) > 0)
|
||||||
upFilePath.append(source)
|
.setOriginalName(file.getOriginalFilename())
|
||||||
.append(URL_SEPARATOR);
|
.build();
|
||||||
}
|
|
||||||
|
|
||||||
upFilePath.append(basename)
|
|
||||||
.append("_")
|
|
||||||
.append(timestamp)
|
|
||||||
.append(".")
|
|
||||||
.append(extension);
|
|
||||||
|
|
||||||
String filePath = StringUtils.join(basePath.toString(), upFilePath.toString());
|
|
||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||||
|
@ -114,31 +107,31 @@ public class TencentCosFileHandler implements FileHandler {
|
||||||
// 设置 Content type, 默认是 application/octet-stream
|
// 设置 Content type, 默认是 application/octet-stream
|
||||||
objectMetadata.setContentType(file.getContentType());
|
objectMetadata.setContentType(file.getContentType());
|
||||||
PutObjectResult putObjectResponseFromInputStream = cosClient
|
PutObjectResult putObjectResponseFromInputStream = cosClient
|
||||||
.putObject(bucketName, upFilePath.toString(), file.getInputStream(),
|
.putObject(bucketName, pathDescriptor.getRelativePath(), file.getInputStream(),
|
||||||
objectMetadata);
|
objectMetadata);
|
||||||
if (putObjectResponseFromInputStream == null) {
|
if (putObjectResponseFromInputStream == null) {
|
||||||
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到腾讯云失败 ");
|
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到腾讯云失败 ");
|
||||||
}
|
}
|
||||||
|
String fullPath = pathDescriptor.getFullPath();
|
||||||
// Response result
|
// Response result
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(basename);
|
uploadResult.setFilename(pathDescriptor.getName());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
|
.setFilePath(StringUtils.isBlank(styleRule) ? fullPath : fullPath + styleRule);
|
||||||
uploadResult.setKey(upFilePath.toString());
|
uploadResult.setKey(pathDescriptor.getRelativePath());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
uploadResult.setSuffix(extension);
|
uploadResult.setSuffix(pathDescriptor.getExtension());
|
||||||
uploadResult.setSize(file.getSize());
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
// Handle thumbnail
|
// Handle thumbnail
|
||||||
handleImageMetadata(file, uploadResult, () -> {
|
handleImageMetadata(file, uploadResult, () -> {
|
||||||
if (ImageUtils.EXTENSION_ICO.equals(extension)) {
|
if (ImageUtils.EXTENSION_ICO.equals(pathDescriptor.getExtension())) {
|
||||||
uploadResult.setThumbPath(filePath);
|
uploadResult.setThumbPath(fullPath);
|
||||||
return filePath;
|
return fullPath;
|
||||||
} else {
|
} else {
|
||||||
return StringUtils.isBlank(thumbnailStyleRule) ? filePath :
|
return StringUtils.isBlank(thumbnailStyleRule) ? fullPath :
|
||||||
filePath + thumbnailStyleRule;
|
fullPath + thumbnailStyleRule;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
|
|
|
@ -107,6 +107,7 @@ public class UpOssFileHandler implements FileHandler {
|
||||||
filePath + thumbnailStyleRule;
|
filePath + thumbnailStyleRule;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
result.close();
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到又拍云失败", e);
|
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到又拍云失败", e);
|
||||||
|
|
|
@ -41,4 +41,13 @@ public interface AttachmentRepository
|
||||||
* @return count of the given path
|
* @return count of the given path
|
||||||
*/
|
*/
|
||||||
long countByPath(@NonNull String path);
|
long countByPath(@NonNull String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts by attachment file key and type.
|
||||||
|
*
|
||||||
|
* @param fileKey attachment file key must not be blank
|
||||||
|
* @param type attachment type must not be null
|
||||||
|
* @return count of the given path and type
|
||||||
|
*/
|
||||||
|
long countByFileKeyAndType(@NonNull String fileKey, @NonNull AttachmentType type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File path descriptor test case.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2021-10-21
|
||||||
|
*/
|
||||||
|
public class FilePathDescriptorTest {
|
||||||
|
|
||||||
|
private FilePathDescriptor.Builder descriptorBuilder;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
descriptorBuilder = new FilePathDescriptor.Builder()
|
||||||
|
.setBasePath("/home/halo")
|
||||||
|
.setSubPath("2021/10/")
|
||||||
|
.setSeparator(FILE_SEPARATOR)
|
||||||
|
.setAutomaticRename(false)
|
||||||
|
.setRenamePredicate(builder -> true)
|
||||||
|
.setOriginalName("hello.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void build() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.build();
|
||||||
|
assertEquals("/home/halo/2021/10/hello.jpg", descriptor.getFullPath());
|
||||||
|
assertEquals("2021/10/hello.jpg", descriptor.getRelativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void autoRename() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.setAutomaticRename(true).build();
|
||||||
|
assertNotEquals("/home/halo/2021/10/hello.jpg", descriptor.getFullPath());
|
||||||
|
assertNotEquals("2021/10/hello.jpg", descriptor.getRelativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void autoRenameWithPredicate() {
|
||||||
|
FilePathDescriptor descriptor1 = descriptorBuilder.setAutomaticRename(true)
|
||||||
|
.setRenamePredicate(path -> false).build();
|
||||||
|
assertEquals("/home/halo/2021/10/hello.jpg", descriptor1.getFullPath());
|
||||||
|
assertEquals("2021/10/hello.jpg", descriptor1.getRelativePath());
|
||||||
|
|
||||||
|
FilePathDescriptor descriptor2 = descriptorBuilder.setAutomaticRename(true)
|
||||||
|
.setRenamePredicate(path -> true).build();
|
||||||
|
assertNotEquals("/home/halo/2021/10/hello.jpg", descriptor2.getFullPath());
|
||||||
|
assertNotEquals("2021/10/hello.jpg", descriptor2.getRelativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void separator() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.setSeparator("->").build();
|
||||||
|
assertEquals("/home/halo->2021/10->hello.jpg", descriptor.getFullPath());
|
||||||
|
assertEquals("2021/10->hello.jpg", descriptor.getRelativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nameSuffix() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.setNameSuffix("_thumbnail").build();
|
||||||
|
assertEquals("/home/halo/2021/10/hello_thumbnail.jpg", descriptor.getFullPath());
|
||||||
|
assertEquals("hello_thumbnail", descriptor.getName());
|
||||||
|
assertEquals("hello_thumbnail.jpg", descriptor.getFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withoutExtension() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.setOriginalName("hello").build();
|
||||||
|
assertEquals("hello", descriptor.getName());
|
||||||
|
assertEquals("", descriptor.getExtension());
|
||||||
|
assertEquals("hello", descriptor.getFullName());
|
||||||
|
assertEquals("2021/10/hello", descriptor.getRelativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void otherName() {
|
||||||
|
FilePathDescriptor descriptor = descriptorBuilder.setOriginalName("1.4.9.png").build();
|
||||||
|
assertEquals("1.4.9", descriptor.getName());
|
||||||
|
assertEquals("1.4.9.png", descriptor.getFullName());
|
||||||
|
assertEquals("/home/halo/2021/10/1.4.9.png", descriptor.getFullPath());
|
||||||
|
assertEquals("2021/10/1.4.9.png", descriptor.getRelativePath());
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ class FilenameUtilsTest {
|
||||||
assertEquals("", FilenameUtils.getBasename("a/b/c/"));
|
assertEquals("", FilenameUtils.getBasename("a/b/c/"));
|
||||||
assertEquals("o", FilenameUtils.getBasename("he/ll/o.tar.gz"));
|
assertEquals("o", FilenameUtils.getBasename("he/ll/o.tar.gz"));
|
||||||
assertEquals("i", FilenameUtils.getBasename("h/i.tar.bz2"));
|
assertEquals("i", FilenameUtils.getBasename("h/i.tar.bz2"));
|
||||||
|
assertEquals("1.4.9", FilenameUtils.getBasename("1.4.9.png"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// foo.txt --> "txt"
|
// foo.txt --> "txt"
|
||||||
|
|
Loading…
Reference in New Issue