mirror of https://github.com/halo-dev/halo
Complete local file deletion service
parent
69b77ac245
commit
b6f1a29951
|
@ -0,0 +1,17 @@
|
||||||
|
package cc.ryanc.halo.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File operation exception.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/27/19
|
||||||
|
*/
|
||||||
|
public class FileOperationException extends ServiceException {
|
||||||
|
public FileOperationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileOperationException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
package cc.ryanc.halo.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File upload exception.
|
|
||||||
*
|
|
||||||
* @author johnniang
|
|
||||||
* @date 3/27/19
|
|
||||||
*/
|
|
||||||
public class FileUploadException extends ServiceException {
|
|
||||||
public FileUploadException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileUploadException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cc.ryanc.halo.filehandler;
|
package cc.ryanc.halo.filehandler;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.FileUploadException;
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.model.enums.AttachmentType;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.support.UploadResult;
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -27,7 +27,7 @@ public interface FileHandler {
|
||||||
*
|
*
|
||||||
* @param file multipart file must not be null
|
* @param file multipart file must not be null
|
||||||
* @return upload result
|
* @return upload result
|
||||||
* @throws FileUploadException throws when fail to upload the file
|
* @throws FileOperationException throws when fail to upload the file
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
UploadResult upload(@NonNull MultipartFile file);
|
UploadResult upload(@NonNull MultipartFile file);
|
||||||
|
@ -37,7 +37,7 @@ public interface FileHandler {
|
||||||
*
|
*
|
||||||
* @param key file key must not be null
|
* @param key file key must not be null
|
||||||
*/
|
*/
|
||||||
boolean delete(@NonNull String key);
|
void delete(@NonNull String key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given type is supported.
|
* Checks if the given type is supported.
|
||||||
|
@ -45,7 +45,7 @@ public interface FileHandler {
|
||||||
* @param type attachment type
|
* @param type attachment type
|
||||||
* @return true if supported; false or else
|
* @return true if supported; false or else
|
||||||
*/
|
*/
|
||||||
boolean supportType(AttachmentType type);
|
boolean supportType(@Nullable AttachmentType type);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cc.ryanc.halo.filehandler;
|
package cc.ryanc.halo.filehandler;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.FileUploadException;
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.model.enums.AttachmentType;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.support.UploadResult;
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -42,18 +42,19 @@ public class FileHandlers {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error("There is no available file handle for attachment type: [{}]", attachmentType);
|
log.error("There is no available file handle for attachment type: [{}]", attachmentType);
|
||||||
throw new FileUploadException("No available file handler to filehandler the file").setErrorData(attachmentType);
|
throw new FileOperationException("No available file handler to filehandler the file").setErrorData(attachmentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean delete(String key, AttachmentType attachmentType) {
|
public void delete(String key, AttachmentType attachmentType) {
|
||||||
for (FileHandler fileHandler : fileHandlers) {
|
for (FileHandler fileHandler : fileHandlers) {
|
||||||
if (fileHandler.supportType(attachmentType)) {
|
if (fileHandler.supportType(attachmentType)) {
|
||||||
return fileHandler.delete(key);
|
fileHandler.delete(key);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error("There is no available file handle for attachment type: [{}]", attachmentType);
|
log.error("There is no available file handle for attachment type: [{}]", attachmentType);
|
||||||
throw new FileUploadException("No available file handler to delete the file").setErrorData(attachmentType);
|
throw new FileOperationException("No available file handler to delete the file").setErrorData(attachmentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cc.ryanc.halo.filehandler;
|
package cc.ryanc.halo.filehandler;
|
||||||
|
|
||||||
import cc.ryanc.halo.config.properties.HaloProperties;
|
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||||
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.exception.ServiceException;
|
import cc.ryanc.halo.exception.ServiceException;
|
||||||
import cc.ryanc.halo.model.enums.AttachmentType;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.support.UploadResult;
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
|
@ -36,7 +37,9 @@ public class LocalFileHandler implements FileHandler {
|
||||||
/**
|
/**
|
||||||
* Upload sub directory.
|
* Upload sub directory.
|
||||||
*/
|
*/
|
||||||
private final static String UPLOAD_SUB_DIR = "upload";
|
private final static String UPLOAD_SUB_DIR = "upload/";
|
||||||
|
|
||||||
|
private final static String THUMBNAIL_SUFFIX = "-thumbnail";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thumbnail width.
|
* Thumbnail width.
|
||||||
|
@ -59,6 +62,8 @@ public class LocalFileHandler implements FileHandler {
|
||||||
// Get work dir
|
// Get work dir
|
||||||
workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir());
|
workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir());
|
||||||
|
|
||||||
|
// Check work directory
|
||||||
|
checkWorkDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +94,7 @@ public class LocalFileHandler implements FileHandler {
|
||||||
int month = current.get(Calendar.MONTH) + 1;
|
int month = current.get(Calendar.MONTH) + 1;
|
||||||
|
|
||||||
// Build directory
|
// Build directory
|
||||||
String subDir = UPLOAD_SUB_DIR + File.separator + year + File.separator + month + File.separator;
|
String subDir = UPLOAD_SUB_DIR + year + File.separator + month + File.separator;
|
||||||
|
|
||||||
// Get basename
|
// Get basename
|
||||||
String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash();
|
String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash();
|
||||||
|
@ -103,9 +108,9 @@ public class LocalFileHandler implements FileHandler {
|
||||||
String subFilePath = subDir + basename + '.' + extension;
|
String subFilePath = subDir + basename + '.' + extension;
|
||||||
|
|
||||||
// Get upload path
|
// Get upload path
|
||||||
Path uploadPath = Paths.get(workDir + subFilePath);
|
Path uploadPath = Paths.get(workDir, subFilePath);
|
||||||
|
|
||||||
log.info("Uploading to directory: [{}]", uploadPath.getFileName());
|
log.info("Uploading to directory: [{}]", uploadPath.toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO Synchronize here
|
// TODO Synchronize here
|
||||||
|
@ -128,7 +133,7 @@ public class LocalFileHandler implements FileHandler {
|
||||||
// Check file type
|
// Check file type
|
||||||
if (FileHandler.isImageType(uploadResult.getMediaType())) {
|
if (FileHandler.isImageType(uploadResult.getMediaType())) {
|
||||||
// Upload a thumbnail
|
// Upload a thumbnail
|
||||||
String thumbnailBasename = basename + '-' + "thumbnail";
|
String thumbnailBasename = basename + THUMBNAIL_SUFFIX;
|
||||||
String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
||||||
Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
||||||
|
|
||||||
|
@ -151,14 +156,44 @@ public class LocalFileHandler implements FileHandler {
|
||||||
|
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Failed to upload file to local: " + uploadPath.getFileName(), e);
|
log.error("Failed to upload file to local: " + uploadPath, e);
|
||||||
throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath.getFileName());
|
throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete(String key) {
|
public void delete(String key) {
|
||||||
return false;
|
Assert.hasText(key, "File key must not be blank");
|
||||||
|
// Get path
|
||||||
|
Path path = Paths.get(workDir, key);
|
||||||
|
|
||||||
|
|
||||||
|
// Delete the file key
|
||||||
|
try {
|
||||||
|
Files.delete(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileOperationException("Failed to delete " + key + " file", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete thumb if necessary
|
||||||
|
String basename = FilenameUtils.getBasename(key);
|
||||||
|
String extension = FilenameUtils.getExtension(key);
|
||||||
|
|
||||||
|
// Get thumbnail name
|
||||||
|
String thumbnailName = basename + THUMBNAIL_SUFFIX + '.' + extension;
|
||||||
|
|
||||||
|
// Get thumbnail path
|
||||||
|
Path thumbnailPath = Paths.get(path.getParent().toString(), thumbnailName);
|
||||||
|
|
||||||
|
// Delete thumbnail file
|
||||||
|
try {
|
||||||
|
boolean deleteResult = Files.deleteIfExists(thumbnailPath);
|
||||||
|
if (!deleteResult) {
|
||||||
|
log.warn("Thumbnail: [{}] way not exist", thumbnailPath.toString());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileOperationException("Failed to delete " + thumbnailName + " thumbnail", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,4 +217,5 @@ public class LocalFileHandler implements FileHandler {
|
||||||
// Convert to thumbnail and copy the thumbnail
|
// Convert to thumbnail and copy the thumbnail
|
||||||
Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile());
|
Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cc.ryanc.halo.filehandler;
|
package cc.ryanc.halo.filehandler;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.FileUploadException;
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.model.enums.AttachmentType;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.enums.QnYunProperties;
|
import cc.ryanc.halo.model.enums.QnYunProperties;
|
||||||
import cc.ryanc.halo.model.support.QiNiuPutSet;
|
import cc.ryanc.halo.model.support.QiNiuPutSet;
|
||||||
|
@ -118,13 +118,13 @@ public class QnYunFileHandler implements FileHandler {
|
||||||
log.error("QnYun error response: [{}]", ((QiniuException) e).response);
|
log.error("QnYun error response: [{}]", ((QiniuException) e).response);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e);
|
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete(String key) {
|
public void delete(String key) {
|
||||||
return false;
|
// TODO Handle file deletion
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cc.ryanc.halo.filehandler;
|
package cc.ryanc.halo.filehandler;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.FileUploadException;
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.exception.PropertyFormatException;
|
import cc.ryanc.halo.exception.PropertyFormatException;
|
||||||
import cc.ryanc.halo.model.enums.AttachmentType;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.enums.UpYunProperties;
|
import cc.ryanc.halo.model.enums.UpYunProperties;
|
||||||
|
@ -72,7 +72,7 @@ public class UpYunFileHandler implements FileHandler {
|
||||||
// Write file
|
// Write file
|
||||||
boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null);
|
boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null);
|
||||||
if (!uploadSuccess) {
|
if (!uploadSuccess) {
|
||||||
throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath);
|
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath;
|
String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath;
|
||||||
|
@ -96,13 +96,14 @@ public class UpYunFileHandler implements FileHandler {
|
||||||
|
|
||||||
return uploadResult;
|
return uploadResult;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e);
|
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete(String key) {
|
public void delete(String key) {
|
||||||
return false;
|
|
||||||
|
// TODO Handle file deletion
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cc.ryanc.halo.service;
|
package cc.ryanc.halo.service;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.FileUploadException;
|
import cc.ryanc.halo.exception.FileOperationException;
|
||||||
import cc.ryanc.halo.model.dto.AttachmentOutputDTO;
|
import cc.ryanc.halo.model.dto.AttachmentOutputDTO;
|
||||||
import cc.ryanc.halo.model.entity.Attachment;
|
import cc.ryanc.halo.model.entity.Attachment;
|
||||||
import cc.ryanc.halo.service.base.CrudService;
|
import cc.ryanc.halo.service.base.CrudService;
|
||||||
|
@ -30,7 +30,7 @@ public interface AttachmentService extends CrudService<Attachment, Integer> {
|
||||||
*
|
*
|
||||||
* @param file multipart file must not be null
|
* @param file multipart file must not be null
|
||||||
* @return attachment info
|
* @return attachment info
|
||||||
* @throws FileUploadException throws when failed to filehandler the file
|
* @throws FileOperationException throws when failed to filehandler the file
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
Attachment upload(@NonNull MultipartFile file);
|
Attachment upload(@NonNull MultipartFile file);
|
||||||
|
|
|
@ -66,4 +66,5 @@ public class FilenameUtils {
|
||||||
|
|
||||||
return filename.substring(dotLastIndex + 1);
|
return filename.substring(dotLastIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paths test.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/27/19
|
||||||
|
*/
|
||||||
|
public class PathsTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getTest() {
|
||||||
|
Path path = Paths.get("/home/test/", "/upload/test.txt");
|
||||||
|
assertThat(path.toString(), equalTo("/home/test/upload/test.txt"));
|
||||||
|
assertThat(path.getParent().toString(), equalTo("/home/test/upload"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue