Fix file upload exception (#581)

* Refactor FileHandler and related implementations

* Add more friendly error throw

* Make tmp directory as default location for multipart file

* Change error message in Chinese
pull/583/head
John Niang 2020-02-20 14:47:57 +08:00 committed by GitHub
parent 594923ebd8
commit 50af1ec1aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 65 additions and 54 deletions

View File

@ -69,7 +69,7 @@ public class AliOssFileHandler implements FileHandler {
} }
try { try {
String basename = FilenameUtils.getBasename(file.getOriginalFilename()); String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
String timestamp = String.valueOf(System.currentTimeMillis()); String timestamp = String.valueOf(System.currentTimeMillis());
StringBuilder upFilePath = new StringBuilder(); StringBuilder upFilePath = new StringBuilder();
@ -116,19 +116,13 @@ public class AliOssFileHandler implements FileHandler {
} }
} }
log.info("Uploaded file: [{}] successfully", file.getOriginalFilename());
return uploadResult; return uploadResult;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到阿里云失败 ", e).setErrorData(file.getOriginalFilename());
} finally { } finally {
ossClient.shutdown(); ossClient.shutdown();
} }
// Build result
UploadResult result = new UploadResult();
log.info("File: [{}] uploaded successfully", file.getOriginalFilename());
return result;
} }
@Override @Override
@ -154,7 +148,7 @@ public class AliOssFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.ALIOSS.equals(type); return AttachmentType.ALIOSS.name().equalsIgnoreCase(type);
} }
} }

View File

@ -64,7 +64,7 @@ public class BaiduBosFileHandler implements FileHandler {
domain = protocol + domain; domain = protocol + domain;
try { try {
String basename = FilenameUtils.getBasename(file.getOriginalFilename()); String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
String timestamp = String.valueOf(System.currentTimeMillis()); String timestamp = String.valueOf(System.currentTimeMillis());
String upFilePath = StringUtils.join(basename, "_", timestamp, ".", extension); String upFilePath = StringUtils.join(basename, "_", timestamp, ".", extension);
@ -132,7 +132,7 @@ public class BaiduBosFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.BAIDUBOS.equals(type); return AttachmentType.BAIDUBOS.name().equalsIgnoreCase(type);
} }
} }

View File

@ -77,7 +77,7 @@ public interface FileHandler {
* Checks if the given type is supported. * Checks if the given type is supported.
* *
* @param type attachment type * @param type attachment type
* @return true if supported; false or else * @return true if supported; false otherwise
*/ */
boolean supportType(@Nullable AttachmentType type); boolean supportType(@Nullable String type);
} }

View File

@ -34,6 +34,7 @@ public class FileHandlers {
public FileHandlers(ApplicationContext applicationContext) { public FileHandlers(ApplicationContext applicationContext) {
// Add all file handler // Add all file handler
addFileHandlers(applicationContext.getBeansOfType(FileHandler.class).values()); addFileHandlers(applicationContext.getBeansOfType(FileHandler.class).values());
log.info("Registered {} file handler(s)", fileHandlers.size());
} }
/** /**
@ -46,16 +47,30 @@ public class FileHandlers {
*/ */
@NonNull @NonNull
public UploadResult upload(@NonNull MultipartFile file, @NonNull AttachmentType attachmentType) { public UploadResult upload(@NonNull MultipartFile file, @NonNull AttachmentType attachmentType) {
Assert.notNull(file, "Multipart file must not be null");
Assert.notNull(attachmentType, "Attachment type must not be null"); Assert.notNull(attachmentType, "Attachment type must not be null");
return upload(file, attachmentType.name());
}
/**
* Uploads files.
*
* @param file multipart file must not be null
* @param type store type
* @return upload result
* @throws FileOperationException throws when fail to delete attachment or no available file handler to upload it
*/
@NonNull
public UploadResult upload(@NonNull MultipartFile file, @Nullable String type) {
Assert.notNull(file, "Multipart file must not be null");
for (FileHandler fileHandler : fileHandlers) { for (FileHandler fileHandler : fileHandlers) {
if (fileHandler.supportType(attachmentType)) { if (fileHandler.supportType(type)) {
return fileHandler.upload(file); return fileHandler.upload(file);
} }
} }
throw new FileOperationException("No available file handler to upload the file").setErrorData(attachmentType); throw new FileOperationException("No available file handlers to upload the file").setErrorData(type);
} }
/** /**
@ -67,15 +82,25 @@ public class FileHandlers {
public void delete(@NonNull Attachment attachment) { public void delete(@NonNull Attachment attachment) {
Assert.notNull(attachment, "Attachment must not be null"); Assert.notNull(attachment, "Attachment must not be null");
delete(attachment.getType().name(), attachment.getFileKey());
}
/**
* Deletes attachment.
*
* @param key file key
* @throws FileOperationException throws when fail to delete attachment or no available file handler to delete it
*/
public void delete(@Nullable String type, @NonNull String key) {
for (FileHandler fileHandler : fileHandlers) { for (FileHandler fileHandler : fileHandlers) {
if (fileHandler.supportType(attachment.getType())) { if (fileHandler.supportType(type)) {
// Delete the file // Delete the file
fileHandler.delete(attachment.getFileKey()); fileHandler.delete(key);
return; return;
} }
} }
throw new FileOperationException("No available file handler to delete the file").setErrorData(attachment); throw new FileOperationException("No available file handlers to delete the file").setErrorData(type);
} }
/** /**

View File

@ -8,7 +8,6 @@ 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.exception.ServiceException;
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.service.OptionService;
@ -101,7 +100,7 @@ public class LocalFileHandler implements FileHandler {
// Build directory // Build directory
String subDir = UPLOAD_SUB_DIR + year + FILE_SEPARATOR + month + FILE_SEPARATOR; String subDir = UPLOAD_SUB_DIR + year + FILE_SEPARATOR + month + FILE_SEPARATOR;
String originalBasename = FilenameUtils.getBasename(file.getOriginalFilename()); String originalBasename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
// Get basename // Get basename
String basename = originalBasename + '-' + HaloUtils.randomUUIDWithoutDash(); String basename = originalBasename + '-' + HaloUtils.randomUUIDWithoutDash();
@ -117,7 +116,7 @@ public class LocalFileHandler implements FileHandler {
// Get upload path // Get upload path
Path uploadPath = Paths.get(workDir, subFilePath); Path uploadPath = Paths.get(workDir, subFilePath);
log.info("Uploading to directory: [{}]", uploadPath.toString()); log.info("Uploading file: [{}]to directory: [{}]", file.getOriginalFilename(), uploadPath.toString());
try { try {
// TODO Synchronize here // TODO Synchronize here
@ -171,10 +170,10 @@ public class LocalFileHandler implements FileHandler {
uploadResult.setThumbPath(subFilePath); uploadResult.setThumbPath(subFilePath);
} }
log.info("Uploaded file: [{}] to directory: [{}] successfully", file.getOriginalFilename(), uploadPath.toString());
return uploadResult; return uploadResult;
} catch (IOException e) { } catch (IOException e) {
log.error("Failed to upload file to local: " + uploadPath, e); throw new FileOperationException("上传附件失败").setErrorData(uploadPath);
throw new ServiceException("上传附件失败").setErrorData(uploadPath);
} }
} }
@ -184,7 +183,6 @@ public class LocalFileHandler implements FileHandler {
// Get path // Get path
Path path = Paths.get(workDir, key); Path path = Paths.get(workDir, key);
// Delete the file key // Delete the file key
try { try {
Files.delete(path); Files.delete(path);
@ -214,8 +212,8 @@ public class LocalFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.LOCAL.equals(type); return AttachmentType.LOCAL.name().equalsIgnoreCase(type);
} }
private boolean generateThumbnail(BufferedImage originalImage, Path thumbPath, String extension) { private boolean generateThumbnail(BufferedImage originalImage, Path thumbPath, String extension) {

View File

@ -87,7 +87,7 @@ public class QiniuOssFileHandler implements FileHandler {
.append("/"); .append("/");
try { try {
String basename = FilenameUtils.getBasename(file.getOriginalFilename()); String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
String timestamp = String.valueOf(System.currentTimeMillis()); String timestamp = String.valueOf(System.currentTimeMillis());
StringBuilder upFilePath = new StringBuilder(); StringBuilder upFilePath = new StringBuilder();
@ -108,8 +108,10 @@ public class QiniuOssFileHandler implements FileHandler {
// Put the file // Put the file
Response response = uploadManager.put(file.getInputStream(), upFilePath.toString(), uploadToken, null, null); Response response = uploadManager.put(file.getInputStream(), upFilePath.toString(), uploadToken, null, null);
if (log.isDebugEnabled()) {
log.debug("QnYun response: [{}]", response.toString()); log.debug("QnYun response: [{}]", response.toString());
log.debug("QnYun response body: [{}]", response.bodyString()); log.debug("QnYun response body: [{}]", response.bodyString());
}
response.jsonToObject(QiNiuPutSet.class); response.jsonToObject(QiNiuPutSet.class);
@ -175,7 +177,7 @@ public class QiniuOssFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.QINIUOSS.equals(type); return AttachmentType.QINIUOSS.name().equalsIgnoreCase(type);
} }
} }

View File

@ -2,7 +2,6 @@ package run.halo.app.handler.file;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*; import org.springframework.http.*;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@ -123,7 +122,7 @@ public class SmmsFileHandler implements FileHandler {
// Build result // Build result
UploadResult result = new UploadResult(); UploadResult result = new UploadResult();
result.setFilename(FilenameUtils.getBasename(file.getOriginalFilename())); result.setFilename(FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename())));
result.setSuffix(FilenameUtils.getExtension(file.getOriginalFilename())); result.setSuffix(FilenameUtils.getExtension(file.getOriginalFilename()));
result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
@ -164,8 +163,8 @@ public class SmmsFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.SMMS.equals(type); return AttachmentType.SMMS.name().equalsIgnoreCase(type);
} }
/** /**
@ -179,7 +178,6 @@ public class SmmsFileHandler implements FileHandler {
} }
@Data @Data
@ToString
@NoArgsConstructor @NoArgsConstructor
private static class SmmsResponse { private static class SmmsResponse {
@ -195,7 +193,6 @@ public class SmmsFileHandler implements FileHandler {
} }
@Data @Data
@ToString(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
private static class SmmsResponseData { private static class SmmsResponseData {

View File

@ -78,7 +78,7 @@ public class TencentCosFileHandler implements FileHandler {
} }
try { try {
String basename = FilenameUtils.getBasename(file.getOriginalFilename()); String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
String timestamp = String.valueOf(System.currentTimeMillis()); String timestamp = String.valueOf(System.currentTimeMillis());
StringBuilder upFilePath = new StringBuilder(); StringBuilder upFilePath = new StringBuilder();
@ -163,7 +163,7 @@ public class TencentCosFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.TENCENTCOS.equals(type); return AttachmentType.TENCENTCOS.name().equalsIgnoreCase(type);
} }
} }

View File

@ -58,7 +58,7 @@ public class UpOssFileHandler implements FileHandler {
try { try {
// Get file basename // Get file basename
String basename = FilenameUtils.getBasename(file.getOriginalFilename()); String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename()));
// Get file extension // Get file extension
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
// Get md5 value of the file // Get md5 value of the file
@ -128,7 +128,7 @@ public class UpOssFileHandler implements FileHandler {
} }
@Override @Override
public boolean supportType(AttachmentType type) { public boolean supportType(String type) {
return AttachmentType.UPOSS.equals(type); return AttachmentType.UPOSS.name().equalsIgnoreCase(type);
} }
} }

View File

@ -234,6 +234,6 @@ public class AttachmentServiceImpl extends AbstractCrudService<Attachment, Integ
*/ */
@NonNull @NonNull
private AttachmentType getAttachmentType() { private AttachmentType getAttachmentType() {
return optionService.getEnumByPropertyOrDefault(AttachmentProperties.ATTACHMENT_TYPE, AttachmentType.class, AttachmentType.LOCAL); return Objects.requireNonNull(optionService.getEnumByPropertyOrDefault(AttachmentProperties.ATTACHMENT_TYPE, AttachmentType.class, AttachmentType.LOCAL));
} }
} }

View File

@ -20,12 +20,6 @@ spring:
username: admin username: admin
password: 123456 password: 123456
# MySQL database configuration.
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
# username: root
# password: 123456
h2: h2:
console: console:
settings: settings:
@ -43,6 +37,7 @@ spring:
multipart: multipart:
max-file-size: 10240MB max-file-size: 10240MB
max-request-size: 10240MB max-request-size: 10240MB
location: ${java.io.tmpdir}
management: management:
endpoints: endpoints:
web: web: