Complete local file deletion service

pull/137/head
johnniang 2019-03-27 19:19:54 +08:00
parent 69b77ac245
commit b6f1a29951
10 changed files with 111 additions and 46 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
/** /**

View File

@ -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);
} }
/** /**

View File

@ -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());
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -66,4 +66,5 @@ public class FilenameUtils {
return filename.substring(dotLastIndex + 1); return filename.substring(dotLastIndex + 1);
} }
} }

View File

@ -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"));
}
}