mirror of https://github.com/halo-dev/halo
refactor: attachment upload parameter
parent
d8116c8557
commit
68b4614cf6
|
@ -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,20 @@ 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(builder ->
|
||||||
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.setOriginalName(file.getOriginalFilename())
|
||||||
upFilePath.append(source)
|
.build();
|
||||||
.append(URL_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 +105,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,41 @@ 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(builder ->
|
||||||
String filePath = StringUtils.join(
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
StringUtils.appendIfMissing(StringUtils.isNotBlank(domain) ? domain : source, "/"),
|
.setOriginalName(file.getOriginalFilename())
|
||||||
upFilePath);
|
.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,175 @@
|
||||||
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import run.halo.app.utils.FilenameUtils;
|
||||||
|
import run.halo.app.utils.HaloUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File path descriptor.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2021-10-21
|
||||||
|
*/
|
||||||
|
@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 path;
|
||||||
|
private String basePath;
|
||||||
|
private String nameSuffix = StringUtils.EMPTY;
|
||||||
|
private String separator = "/";
|
||||||
|
private boolean automaticRename;
|
||||||
|
private Predicate<Builder> renamePredicate;
|
||||||
|
|
||||||
|
public Builder setSubPath(String subPath) {
|
||||||
|
this.path = StringUtils.removeEnd(subPath, separator);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAutomaticRename(Boolean automaticRename) {
|
||||||
|
this.automaticRename = automaticRename != null && automaticRename;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRenamePredicate(Predicate<Builder> 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 = basePath;
|
||||||
|
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 getName() {
|
||||||
|
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 getName() + '.' + this.extension;
|
||||||
|
}
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFullPath() {
|
||||||
|
if (StringUtils.isNotBlank(this.basePath)) {
|
||||||
|
return getPath(this.basePath, this.path, this.getFullName());
|
||||||
|
}
|
||||||
|
return getPath(this.path, this.getFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldRename() {
|
||||||
|
if (!automaticRename) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// automaticRename is true
|
||||||
|
if (renamePredicate == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// renamePredicate not null
|
||||||
|
return renamePredicate.test(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
return new FilePathDescriptor()
|
||||||
|
.setBasePath(this.basePath)
|
||||||
|
.setSubPath(this.path)
|
||||||
|
.setRelativePath(getPath(this.path, getFullName()))
|
||||||
|
.setName(FilenameUtils.getBasename(getName()))
|
||||||
|
.setExtension(extension)
|
||||||
|
.setFullPath(getFullPath())
|
||||||
|
.setFullName(getFullName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,43 @@ 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(builder ->
|
||||||
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.setOriginalName(file.getOriginalFilename())
|
||||||
upFilePath.append(source)
|
.build();
|
||||||
.append(URL_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,23 +10,19 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.coobird.thumbnailator.Thumbnails;
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
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;
|
||||||
import run.halo.app.config.properties.HaloProperties;
|
import run.halo.app.config.properties.HaloProperties;
|
||||||
import run.halo.app.exception.FileOperationException;
|
import run.halo.app.exception.FileOperationException;
|
||||||
import run.halo.app.handler.file.LocalFileHandler.FilePath.Builder;
|
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,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
|
||||||
|
@ -57,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());
|
||||||
|
@ -87,31 +84,37 @@ 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");
|
||||||
|
|
||||||
FilePath uploadFilePath = new Builder()
|
FilePathDescriptor uploadFilePath = new FilePathDescriptor.Builder()
|
||||||
.setBasePath(workDir)
|
.setBasePath(workDir)
|
||||||
|
.setSubPath(generatePath())
|
||||||
|
.setSeparator(FILE_SEPARATOR)
|
||||||
|
.setAutomaticRename(true)
|
||||||
|
.setRenamePredicate(builder ->
|
||||||
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
.setOriginalName(file.getOriginalFilename())
|
.setOriginalName(file.getOriginalFilename())
|
||||||
.build();
|
.build();
|
||||||
log.info("Uploading file: [{}] to directory: [{}]", file.getOriginalFilename(),
|
log.info("Uploading file: [{}] to directory: [{}]", file.getOriginalFilename(),
|
||||||
uploadFilePath.getSubPath());
|
uploadFilePath.getRelativePath());
|
||||||
|
Path localFileFullPath = Paths.get(uploadFilePath.getFullPath());
|
||||||
try {
|
try {
|
||||||
// TODO Synchronize here
|
// TODO Synchronize here
|
||||||
// Create directory
|
// Create directory
|
||||||
Files.createDirectories(uploadFilePath.getFullPath().getParent());
|
Files.createDirectories(localFileFullPath.getParent());
|
||||||
Files.createFile(uploadFilePath.getFullPath());
|
Files.createFile(localFileFullPath);
|
||||||
|
|
||||||
// Upload this file
|
// Upload this file
|
||||||
file.transferTo(uploadFilePath.getFullPath());
|
file.transferTo(localFileFullPath);
|
||||||
|
|
||||||
// Build upload result
|
// Build upload result
|
||||||
UploadResult uploadResult = new UploadResult();
|
UploadResult uploadResult = new UploadResult();
|
||||||
uploadResult.setFilename(uploadFilePath.getName());
|
uploadResult.setFilename(uploadFilePath.getName());
|
||||||
uploadResult.setFilePath(uploadFilePath.getSubPath());
|
uploadResult.setFilePath(uploadFilePath.getRelativePath());
|
||||||
uploadResult.setKey(uploadFilePath.getSubPath());
|
uploadResult.setKey(uploadFilePath.getRelativePath());
|
||||||
uploadResult.setSuffix(uploadFilePath.getExtension());
|
uploadResult.setSuffix(uploadFilePath.getExtension());
|
||||||
uploadResult
|
uploadResult
|
||||||
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||||
|
@ -120,11 +123,14 @@ 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
|
||||||
FilePath thumbnailFilePath = new Builder()
|
FilePathDescriptor thumbnailFilePath = new FilePathDescriptor.Builder()
|
||||||
.setBasePath(workDir)
|
.setBasePath(workDir)
|
||||||
.setOriginalName(THUMBNAIL_SUFFIX + uploadFilePath.getFullName())
|
.setSubPath(uploadFilePath.getSubPath())
|
||||||
|
.setSeparator(FILE_SEPARATOR)
|
||||||
|
.setOriginalName(uploadFilePath.getFullName())
|
||||||
|
.setNameSuffix(THUMBNAIL_SUFFIX)
|
||||||
.build();
|
.build();
|
||||||
final Path thumbnailPath = thumbnailFilePath.getFullPath();
|
final Path thumbnailPath = Paths.get(thumbnailFilePath.getFullPath());
|
||||||
try (InputStream is = file.getInputStream()) {
|
try (InputStream is = file.getInputStream()) {
|
||||||
// Generate thumbnail
|
// Generate thumbnail
|
||||||
BufferedImage originalImage =
|
BufferedImage originalImage =
|
||||||
|
@ -133,110 +139,19 @@ public class LocalFileHandler implements FileHandler {
|
||||||
uploadFilePath.getExtension());
|
uploadFilePath.getExtension());
|
||||||
if (result) {
|
if (result) {
|
||||||
// Set thumb path
|
// Set thumb path
|
||||||
return thumbnailFilePath.getSubFilePath();
|
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 uploadFilePath.getSubFilePath();
|
return uploadFilePath.getRelativePath();
|
||||||
});
|
});
|
||||||
|
|
||||||
log.info("Uploaded file: [{}] to directory: [{}] successfully",
|
log.info("Uploaded file: [{}] to directory: [{}] successfully",
|
||||||
file.getOriginalFilename(), uploadFilePath.getFullPath().toString());
|
file.getOriginalFilename(), uploadFilePath.getFullPath());
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new FileOperationException("上传附件失败").setErrorData(uploadFilePath);
|
throw new FileOperationException("上传附件失败").setErrorData(uploadFilePath.getFullPath());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public static final class FilePath {
|
|
||||||
String name;
|
|
||||||
String extension;
|
|
||||||
String subPath;
|
|
||||||
String subFilePath;
|
|
||||||
String basePath;
|
|
||||||
String fullName;
|
|
||||||
Path fullPath;
|
|
||||||
|
|
||||||
public static final class Builder {
|
|
||||||
String name;
|
|
||||||
String extension;
|
|
||||||
String path;
|
|
||||||
String basePath;
|
|
||||||
|
|
||||||
public Builder() {
|
|
||||||
this.path = generatePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = basePath;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getFullName() {
|
|
||||||
if (!hasExtension()) {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
return this.name + '.' + this.extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path getFullPath() {
|
|
||||||
if (StringUtils.isNotBlank(this.basePath)) {
|
|
||||||
return Paths.get(this.basePath, this.path, this.getFullName());
|
|
||||||
}
|
|
||||||
return Paths.get(this.path, this.getFullName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build file path object.
|
|
||||||
*
|
|
||||||
* @return file path
|
|
||||||
*/
|
|
||||||
public FilePath build() {
|
|
||||||
if (Files.exists(getFullPath())) {
|
|
||||||
this.name = this.name + '-' + HaloUtils.simpleUUID();
|
|
||||||
}
|
|
||||||
return new FilePath()
|
|
||||||
.setBasePath(this.basePath)
|
|
||||||
.setSubPath(this.path)
|
|
||||||
.setSubFilePath(this.path + getFullName())
|
|
||||||
.setName(this.name)
|
|
||||||
.setExtension(extension)
|
|
||||||
.setFullPath(getFullPath())
|
|
||||||
.setFullName(getFullName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasExtension() {
|
|
||||||
return StringUtils.isNotBlank(this.extension);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +194,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");
|
||||||
|
@ -289,11 +217,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,35 @@ 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(builder ->
|
||||||
.join(StringUtils.isNotBlank(source) ? source + HaloConst.URL_SEPARATOR : "",
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
basename, "_", timestamp, ".", extension);
|
.setOriginalName(file.getOriginalFilename())
|
||||||
String filePath =
|
.build();
|
||||||
StringUtils.join(endpoint, bucketName, HaloConst.URL_SEPARATOR, upFilePath);
|
|
||||||
|
|
||||||
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,6 +30,7 @@ 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.FilenameUtils;
|
||||||
import run.halo.app.utils.ImageUtils;
|
import run.halo.app.utils.ImageUtils;
|
||||||
|
@ -40,6 +41,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 +49,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 +101,14 @@ 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(builder ->
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
upFilePath.append(source)
|
.setOriginalName(file.getOriginalFilename())
|
||||||
.append(URL_SEPARATOR);
|
.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,14 @@ 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(builder ->
|
||||||
|
attachmentRepository.countByPath(builder.getFullPath()) > 0)
|
||||||
if (StringUtils.isNotEmpty(source)) {
|
.setOriginalName(file.getOriginalFilename())
|
||||||
upFilePath.append(source)
|
.build();
|
||||||
.append(URL_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 +106,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;
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
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(builder -> false).build();
|
||||||
|
assertEquals("/home/halo/2021/10/hello.jpg", descriptor1.getFullPath());
|
||||||
|
assertEquals("2021/10/hello.jpg", descriptor1.getRelativePath());
|
||||||
|
|
||||||
|
FilePathDescriptor descriptor2 = descriptorBuilder.setAutomaticRename(true)
|
||||||
|
.setRenamePredicate(builder -> 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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue