From 5e60db381905bdc0d810275c2368a365604df197 Mon Sep 17 00:00:00 2001 From: johnniang Date: Wed, 27 Mar 2019 11:22:38 +0800 Subject: [PATCH] Replace FileService with FileHandlers --- .../cc/ryanc/halo/service/FileService.java | 45 --- .../halo/service/impl/FileServiceImpl.java | 340 ------------------ .../halo/service/upload/FileHandler.java | 42 +++ .../halo/service/upload/LocalFileHandler.java | 154 +++++++- .../halo/service/upload/QnYunFileHandler.java | 95 ++++- .../halo/service/upload/UpYunFileHandler.java | 79 +++- 6 files changed, 366 insertions(+), 389 deletions(-) diff --git a/src/main/java/cc/ryanc/halo/service/FileService.java b/src/main/java/cc/ryanc/halo/service/FileService.java index 40d9bd37a..ff9359c8f 100644 --- a/src/main/java/cc/ryanc/halo/service/FileService.java +++ b/src/main/java/cc/ryanc/halo/service/FileService.java @@ -1,9 +1,5 @@ package cc.ryanc.halo.service; -import cc.ryanc.halo.model.support.UploadResult; -import org.springframework.lang.NonNull; -import org.springframework.web.multipart.MultipartFile; - /** * File service interface. * @@ -12,45 +8,4 @@ import org.springframework.web.multipart.MultipartFile; */ public interface FileService { - /** - * Upload sub directory. - */ - String UPLOAD_SUB_DIR = "upload"; - - /** - * Thumbnail width. - */ - int THUMB_WIDTH = 256; - - /** - * Thumbnail height. - */ - int THUMB_HEIGHT = 256; - - /** - * Uploads file to local storage. - * - * @param file multipart file must not be null - * @return upload result - */ - @NonNull - UploadResult uploadToLocal(@NonNull MultipartFile file); - - /** - * Uploads file to qi niu yun. - * - * @param file multipart file must not be null - * @return upload result - */ - @NonNull - UploadResult uploadToQnYun(@NonNull MultipartFile file); - - /** - * Uploads file to you pai yun. - * - * @param file multipart file must not be null - * @return upload result - */ - @NonNull - UploadResult uploadToYpYun(@NonNull MultipartFile file); } diff --git a/src/main/java/cc/ryanc/halo/service/impl/FileServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/FileServiceImpl.java index c5a323120..da5d9139d 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/FileServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/FileServiceImpl.java @@ -1,47 +1,8 @@ package cc.ryanc.halo.service.impl; -import cc.ryanc.halo.config.properties.HaloProperties; -import cc.ryanc.halo.exception.FileUploadException; -import cc.ryanc.halo.exception.PropertyFormatException; -import cc.ryanc.halo.exception.ServiceException; -import cc.ryanc.halo.model.enums.QnYunProperties; -import cc.ryanc.halo.model.enums.UpYunProperties; -import cc.ryanc.halo.model.support.QiNiuPutSet; -import cc.ryanc.halo.model.support.UploadResult; import cc.ryanc.halo.service.FileService; -import cc.ryanc.halo.service.OptionService; -import cc.ryanc.halo.utils.FilenameUtils; -import cc.ryanc.halo.utils.HaloUtils; -import cc.ryanc.halo.utils.JsonUtils; -import com.UpYun; -import com.qiniu.common.QiniuException; -import com.qiniu.common.Zone; -import com.qiniu.http.Response; -import com.qiniu.storage.Configuration; -import com.qiniu.storage.UploadManager; -import com.qiniu.storage.persistent.FileRecorder; -import com.qiniu.util.Auth; -import com.qiniu.util.StringMap; import lombok.extern.slf4j.Slf4j; -import net.coobird.thumbnailator.Thumbnails; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.MediaType; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import org.springframework.util.DigestUtils; -import org.springframework.web.multipart.MultipartFile; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Calendar; -import java.util.Objects; /** * File service implementation. @@ -53,305 +14,4 @@ import java.util.Objects; @Service public class FileServiceImpl implements FileService { - private final OptionService optionService; - - private final String workDir; - - private final MediaType imageType = MediaType.valueOf("image/*"); - - public FileServiceImpl(HaloProperties haloProperties, - OptionService optionService) { - this.optionService = optionService; - - // Get work dir - workDir = normalizeDirectory(haloProperties.getWorkDir()); - - // Check directory - checkWorkDir(); - - log.info("Work directory: [{}]", workDir); - } - - /** - * Check work directory. - */ - private void checkWorkDir() { - // Get work path - Path workPath = Paths.get(workDir); - - // Check file type - Assert.isTrue(Files.isDirectory(workPath), workDir + " isn't a directory"); - - // Check readable - Assert.isTrue(Files.isReadable(workPath), workDir + " isn't readable"); - - // Check writable - Assert.isTrue(Files.isWritable(workPath), workDir + " isn't writable"); - } - - /** - * Normalize directory full name, ensure the end path separator. - * - * @param dir directory full name must not be blank - * @return normalized directory full name with end path separator - */ - @NonNull - private String normalizeDirectory(@NonNull String dir) { - Assert.hasText(dir, "Directory full name must not be blank"); - - return StringUtils.appendIfMissing(dir, File.separator); - } - - @Override - public UploadResult uploadToLocal(MultipartFile file) { - Assert.notNull(file, "Multipart file must not be null"); - - // Get current time - Calendar current = Calendar.getInstance(optionService.getLocale()); - // Get month and day of month - int year = current.get(Calendar.YEAR); - int month = current.get(Calendar.MONTH) + 1; - - // Build directory - String subDir = UPLOAD_SUB_DIR + File.separator + year + File.separator + month + File.separator; - - // Get basename - String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash(); - - // Get extension - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - - log.debug("Base name: [{}], extension: [{}] of original filename: [{}]", basename, extension, file.getOriginalFilename()); - - // Build sub file path - String subFilePath = subDir + basename + '.' + extension; - - // Get upload path - Path uploadPath = Paths.get(workDir + subFilePath); - - log.info("Uploading to directory: [{}]", uploadPath.getFileName()); - - try { - // TODO Synchronize here - // Create directory - Files.createDirectories(uploadPath.getParent()); - Files.createFile(uploadPath); - - // Upload this file - file.transferTo(uploadPath); - - // Build upload result - UploadResult uploadResult = new UploadResult(); - uploadResult.setFilename(basename); - uploadResult.setFilePath(subFilePath); - uploadResult.setSuffix(extension); - uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); - uploadResult.setSize(file.getSize()); - - // Check file type - if (isImageType(uploadResult.getMediaType())) { - // Upload a thumbnail - String thumbnailBasename = basename + '-' + "thumbnail"; - String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension; - Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath); - - // Create the thumbnail - Files.createFile(thumbnailPath); - - // Generate thumbnail - generateThumbnail(uploadPath, thumbnailPath); - - // Set thumb path - uploadResult.setThumbPath(thumbnailSubFilePath); - - // Read as image - BufferedImage image = ImageIO.read(Files.newInputStream(uploadPath)); - - // Set width and height - uploadResult.setWidth(image.getWidth()); - uploadResult.setHeight(image.getHeight()); - } - - return uploadResult; - } catch (IOException e) { - log.error("Failed to upload file to local: " + uploadPath.getFileName(), e); - throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath.getFileName()); - } - } - - @Override - public UploadResult uploadToQnYun(MultipartFile file) { - Assert.notNull(file, "Multipart file must not be null"); - - // Get all config - Zone zone = optionService.getQnYunZone(); - String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.ACCESS_KEY); - String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.SECRET_KEY); - String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.BUCKET); - String domain = optionService.getByPropertyOfNonNull(QnYunProperties.DOMAIN); - String smallUrl = optionService.getByPropertyOfNullable(QnYunProperties.SMALL_URL); - - // Create configuration - Configuration configuration = new Configuration(zone); - - // Create auth - Auth auth = Auth.create(accessKey, secretKey); - // Build put plicy - StringMap putPolicy = new StringMap(); - putPolicy.put("returnBody", "{\"size\":$(fsize), " + - "\"width\":$(imageInfo.width), " + - "\"height\":$(imageInfo.height)," + - " \"key\":\"$(key)\", " + - "\"hash\":\"$(etag)\"}"); - // Get upload token - String uploadToken = auth.uploadToken(bucket, null, 3600, putPolicy); - - // Create temp path - Path tmpPath = Paths.get(System.getProperty("java.io.tmpdir"), bucket); - - try { - // Get file recorder for temp directory - FileRecorder fileRecorder = new FileRecorder(tmpPath.toFile()); - // Get upload manager - UploadManager uploadManager = new UploadManager(configuration, fileRecorder); - // Put the file - // TODO May need to set key manually - Response response = uploadManager.put(file.getInputStream(), null, uploadToken, null, null); - - log.debug("QnYun response: [{}]", response.toString()); - log.debug("QnYun response body: [{}]", response.bodyString()); - - response.jsonToObject(QiNiuPutSet.class); - - // Convert response - QiNiuPutSet putSet = JsonUtils.jsonToObject(response.bodyString(), QiNiuPutSet.class); - - // Get file full path - String filePath = StringUtils.appendIfMissing(domain, "/") + putSet.getHash(); - - // Build upload result - UploadResult result = new UploadResult(); - result.setFilename(putSet.getHash()); - result.setFilePath(filePath); - result.setSuffix(FilenameUtils.getExtension(file.getOriginalFilename())); - result.setWidth(putSet.getWidth()); - result.setHeight(putSet.getHeight()); - result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); - - if (isImageType(result.getMediaType())) { - result.setThumbPath(StringUtils.isBlank(smallUrl) ? filePath : filePath + smallUrl); - } - - return result; - } catch (IOException e) { - if (e instanceof QiniuException) { - log.error("QnYun error response: [{}]", ((QiniuException) e).response); - } - - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e); - } - } - - @Override - public UploadResult uploadToYpYun(MultipartFile file) { - Assert.notNull(file, "Multipart file must not be null"); - - String ossSource = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_SOURCE); - - if (StringUtils.startsWith(ossSource, "/")) { - throw new PropertyFormatException(UpYunProperties.OSS_SOURCE.getValue() + ": " + ossSource + " doesn't start with '/'"); - } - - String ossPassword = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_PASSWORD); - String ossBucket = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_BUCKET); - String ossDomain = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_DOMAIN); - String ossOperator = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_OPERATOR); - // small url can be null - String ossSmallUrl = optionService.getByPropertyOfNullable(UpYunProperties.OSS_SMALL_URL); - - // Create up yun - UpYun upYun = new UpYun(ossBucket, ossOperator, ossPassword); - upYun.setDebug(log.isDebugEnabled()); - upYun.setTimeout(60); - // TODO Provide a property for choosing - upYun.setApiDomain(UpYun.ED_AUTO); - - try { - // Get file basename - String basename = FilenameUtils.getBasename(file.getOriginalFilename()); - // Get file extension - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - // Get md5 value of the file - String md5OfFile = DigestUtils.md5DigestAsHex(file.getInputStream()); - // Build file path - String upFilePath = ossSource + md5OfFile + '.' + extension; - // Set md5Content - upYun.setContentMD5(md5OfFile); - // Write file - boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null); - if (!uploadSuccess) { - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath); - } - - String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath; - - // Build upload result - UploadResult uploadResult = new UploadResult(); - uploadResult.setFilename(basename); - uploadResult.setFilePath(filePath); - uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); - uploadResult.setSuffix(extension); - uploadResult.setSize(file.getSize()); - - // Handle thumbnail - if (isImageType(uploadResult.getMediaType())) { - BufferedImage image = ImageIO.read(file.getInputStream()); - uploadResult.setWidth(image.getWidth()); - uploadResult.setHeight(image.getHeight()); - uploadResult.setThumbPath(StringUtils.isBlank(ossSmallUrl) ? filePath : filePath + ossSmallUrl); - } - - return uploadResult; - } catch (Exception e) { - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e); - } - } - - /** - * Generates thumbnail image. - * - * @param imagePath image path must not be null - * @param thumbPath thumbnail path must not be null - * @throws IOException throws if image provided is not valid - */ - private void generateThumbnail(@NonNull Path imagePath, @NonNull Path thumbPath) throws IOException { - Assert.notNull(imagePath, "Image path must not be null"); - Assert.notNull(thumbPath, "Thumb path must not be null"); - - log.info("Generating thumbnail: [{}] for image: [{}]", thumbPath.getFileName(), imagePath.getFileName()); - - // Convert to thumbnail and copy the thumbnail - Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile()); - } - - /** - * Check whether media type provided is an image type. - * - * @param mediaType media type provided - * @return true if it is an image type - */ - private boolean isImageType(@Nullable String mediaType) { - return mediaType != null && imageType.includes(MediaType.valueOf(mediaType)); - } - - - /** - * Check whether media type provided is an image type. - * - * @param mediaType media type provided - * @return true if it is an image type - */ - private boolean isImageType(@Nullable MediaType mediaType) { - return mediaType != null && imageType.includes(mediaType); - } } diff --git a/src/main/java/cc/ryanc/halo/service/upload/FileHandler.java b/src/main/java/cc/ryanc/halo/service/upload/FileHandler.java index 11c3559d3..b5644649a 100644 --- a/src/main/java/cc/ryanc/halo/service/upload/FileHandler.java +++ b/src/main/java/cc/ryanc/halo/service/upload/FileHandler.java @@ -2,9 +2,15 @@ package cc.ryanc.halo.service.upload; import cc.ryanc.halo.exception.FileUploadException; import cc.ryanc.halo.model.support.UploadResult; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; +import java.io.File; + /** * File handler interface. * @@ -13,6 +19,8 @@ import org.springframework.web.multipart.MultipartFile; */ public interface FileHandler { + MediaType IMAGE_TYPE = MediaType.valueOf("image/*"); + /** * Uploads file. * @@ -30,4 +38,38 @@ public interface FileHandler { */ boolean delete(@NonNull String key); + + /** + * Check whether media type provided is an image type. + * + * @param mediaType media type provided + * @return true if it is an image type + */ + static boolean isImageType(@Nullable String mediaType) { + return mediaType != null && IMAGE_TYPE.includes(MediaType.valueOf(mediaType)); + } + + + /** + * Check whether media type provided is an image type. + * + * @param mediaType media type provided + * @return true if it is an image type + */ + static boolean isImageType(@Nullable MediaType mediaType) { + return mediaType != null && IMAGE_TYPE.includes(mediaType); + } + + /** + * Normalize directory full name, ensure the end path separator. + * + * @param dir directory full name must not be blank + * @return normalized directory full name with end path separator + */ + @NonNull + static String normalizeDirectory(@NonNull String dir) { + Assert.hasText(dir, "Directory full name must not be blank"); + + return StringUtils.appendIfMissing(dir, File.separator); + } } diff --git a/src/main/java/cc/ryanc/halo/service/upload/LocalFileHandler.java b/src/main/java/cc/ryanc/halo/service/upload/LocalFileHandler.java index b8743ddbf..9f80f1a45 100644 --- a/src/main/java/cc/ryanc/halo/service/upload/LocalFileHandler.java +++ b/src/main/java/cc/ryanc/halo/service/upload/LocalFileHandler.java @@ -1,30 +1,180 @@ package cc.ryanc.halo.service.upload; +import cc.ryanc.halo.config.properties.HaloProperties; +import cc.ryanc.halo.exception.ServiceException; import cc.ryanc.halo.model.support.UploadResult; import cc.ryanc.halo.service.OptionService; +import cc.ryanc.halo.utils.FilenameUtils; +import cc.ryanc.halo.utils.HaloUtils; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Calendar; +import java.util.Objects; + +import static cc.ryanc.halo.service.upload.FileHandler.isImageType; + /** * Local file handler. * * @author johnniang * @date 3/27/19 */ +@Slf4j public class LocalFileHandler implements FileHandler { + /** + * Upload sub directory. + */ + private final static String UPLOAD_SUB_DIR = "upload"; + + /** + * Thumbnail width. + */ + private final static int THUMB_WIDTH = 256; + + /** + * Thumbnail height. + */ + private final static int THUMB_HEIGHT = 256; + private final OptionService optionService; - public LocalFileHandler(OptionService optionService) { + private final String workDir; + + public LocalFileHandler(OptionService optionService, + HaloProperties haloProperties) { this.optionService = optionService; + + // Get work dir + workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir()); + + } + + /** + * Check work directory. + */ + private void checkWorkDir() { + // Get work path + Path workPath = Paths.get(workDir); + + // Check file type + Assert.isTrue(Files.isDirectory(workPath), workDir + " isn't a directory"); + + // Check readable + Assert.isTrue(Files.isReadable(workPath), workDir + " isn't readable"); + + // Check writable + Assert.isTrue(Files.isWritable(workPath), workDir + " isn't writable"); } @Override public UploadResult upload(MultipartFile file) { - return null; + Assert.notNull(file, "Multipart file must not be null"); + + // Get current time + Calendar current = Calendar.getInstance(optionService.getLocale()); + // Get month and day of month + int year = current.get(Calendar.YEAR); + int month = current.get(Calendar.MONTH) + 1; + + // Build directory + String subDir = UPLOAD_SUB_DIR + File.separator + year + File.separator + month + File.separator; + + // Get basename + String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash(); + + // Get extension + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + + log.debug("Base name: [{}], extension: [{}] of original filename: [{}]", basename, extension, file.getOriginalFilename()); + + // Build sub file path + String subFilePath = subDir + basename + '.' + extension; + + // Get upload path + Path uploadPath = Paths.get(workDir + subFilePath); + + log.info("Uploading to directory: [{}]", uploadPath.getFileName()); + + try { + // TODO Synchronize here + // Create directory + Files.createDirectories(uploadPath.getParent()); + Files.createFile(uploadPath); + + // Upload this file + file.transferTo(uploadPath); + + // Build upload result + UploadResult uploadResult = new UploadResult(); + uploadResult.setFilename(basename); + uploadResult.setFilePath(subFilePath); + uploadResult.setSuffix(extension); + uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); + uploadResult.setSize(file.getSize()); + + // Check file type + if (isImageType(uploadResult.getMediaType())) { + // Upload a thumbnail + String thumbnailBasename = basename + '-' + "thumbnail"; + String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension; + Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath); + + // Create the thumbnail + Files.createFile(thumbnailPath); + + // Generate thumbnail + generateThumbnail(uploadPath, thumbnailPath); + + // Read as image + BufferedImage image = ImageIO.read(Files.newInputStream(uploadPath)); + + // Set width and height + uploadResult.setWidth(image.getWidth()); + uploadResult.setHeight(image.getHeight()); + + // Set thumb path + uploadResult.setThumbPath(thumbnailSubFilePath); + } + + return uploadResult; + } catch (IOException e) { + log.error("Failed to upload file to local: " + uploadPath.getFileName(), e); + throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath.getFileName()); + } } @Override public boolean delete(String key) { return false; } + + /** + * Generates thumbnail image. + * + * @param imagePath image path must not be null + * @param thumbPath thumbnail path must not be null + * @throws IOException throws if image provided is not valid + */ + private void generateThumbnail(@NonNull Path imagePath, @NonNull Path thumbPath) throws IOException { + Assert.notNull(imagePath, "Image path must not be null"); + Assert.notNull(thumbPath, "Thumb path must not be null"); + + log.info("Generating thumbnail: [{}] for image: [{}]", thumbPath.getFileName(), imagePath.getFileName()); + + // Convert to thumbnail and copy the thumbnail + Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile()); + } } diff --git a/src/main/java/cc/ryanc/halo/service/upload/QnYunFileHandler.java b/src/main/java/cc/ryanc/halo/service/upload/QnYunFileHandler.java index 1ad6bfff7..27b35456a 100644 --- a/src/main/java/cc/ryanc/halo/service/upload/QnYunFileHandler.java +++ b/src/main/java/cc/ryanc/halo/service/upload/QnYunFileHandler.java @@ -1,15 +1,40 @@ package cc.ryanc.halo.service.upload; +import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.model.enums.QnYunProperties; +import cc.ryanc.halo.model.support.QiNiuPutSet; import cc.ryanc.halo.model.support.UploadResult; import cc.ryanc.halo.service.OptionService; +import cc.ryanc.halo.utils.FilenameUtils; +import cc.ryanc.halo.utils.JsonUtils; +import com.qiniu.common.QiniuException; +import com.qiniu.common.Zone; +import com.qiniu.http.Response; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.storage.persistent.FileRecorder; +import com.qiniu.util.Auth; +import com.qiniu.util.StringMap; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +import static cc.ryanc.halo.service.upload.FileHandler.isImageType; + /** * Qi niu yun file handler. * * @author johnniang * @date 3/27/19 */ +@Slf4j public class QnYunFileHandler implements FileHandler { private final OptionService optionService; @@ -20,7 +45,75 @@ public class QnYunFileHandler implements FileHandler { @Override public UploadResult upload(MultipartFile file) { - return null; + Assert.notNull(file, "Multipart file must not be null"); + + // Get all config + Zone zone = optionService.getQnYunZone(); + String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.ACCESS_KEY); + String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.SECRET_KEY); + String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.BUCKET); + String domain = optionService.getByPropertyOfNonNull(QnYunProperties.DOMAIN); + String smallUrl = optionService.getByPropertyOfNullable(QnYunProperties.SMALL_URL); + + // Create configuration + Configuration configuration = new Configuration(zone); + + // Create auth + Auth auth = Auth.create(accessKey, secretKey); + // Build put plicy + StringMap putPolicy = new StringMap(); + putPolicy.put("returnBody", "{\"size\":$(fsize), " + + "\"width\":$(imageInfo.width), " + + "\"height\":$(imageInfo.height)," + + " \"key\":\"$(key)\", " + + "\"hash\":\"$(etag)\"}"); + // Get upload token + String uploadToken = auth.uploadToken(bucket, null, 3600, putPolicy); + + // Create temp path + Path tmpPath = Paths.get(System.getProperty("java.io.tmpdir"), bucket); + + try { + // Get file recorder for temp directory + FileRecorder fileRecorder = new FileRecorder(tmpPath.toFile()); + // Get upload manager + UploadManager uploadManager = new UploadManager(configuration, fileRecorder); + // Put the file + // TODO May need to set key manually + Response response = uploadManager.put(file.getInputStream(), null, uploadToken, null, null); + + log.debug("QnYun response: [{}]", response.toString()); + log.debug("QnYun response body: [{}]", response.bodyString()); + + response.jsonToObject(QiNiuPutSet.class); + + // Convert response + QiNiuPutSet putSet = JsonUtils.jsonToObject(response.bodyString(), QiNiuPutSet.class); + + // Get file full path + String filePath = StringUtils.appendIfMissing(domain, "/") + putSet.getHash(); + + // Build upload result + UploadResult result = new UploadResult(); + result.setFilename(putSet.getHash()); + result.setFilePath(filePath); + result.setSuffix(FilenameUtils.getExtension(file.getOriginalFilename())); + result.setWidth(putSet.getWidth()); + result.setHeight(putSet.getHeight()); + result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); + + if (isImageType(result.getMediaType())) { + result.setThumbPath(StringUtils.isBlank(smallUrl) ? filePath : filePath + smallUrl); + } + + return result; + } catch (IOException e) { + if (e instanceof QiniuException) { + log.error("QnYun error response: [{}]", ((QiniuException) e).response); + } + + throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e); + } } @Override diff --git a/src/main/java/cc/ryanc/halo/service/upload/UpYunFileHandler.java b/src/main/java/cc/ryanc/halo/service/upload/UpYunFileHandler.java index de0c637d5..abfbbe447 100644 --- a/src/main/java/cc/ryanc/halo/service/upload/UpYunFileHandler.java +++ b/src/main/java/cc/ryanc/halo/service/upload/UpYunFileHandler.java @@ -1,15 +1,32 @@ package cc.ryanc.halo.service.upload; +import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.PropertyFormatException; +import cc.ryanc.halo.model.enums.UpYunProperties; import cc.ryanc.halo.model.support.UploadResult; import cc.ryanc.halo.service.OptionService; +import cc.ryanc.halo.utils.FilenameUtils; +import com.UpYun; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.DigestUtils; import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.util.Objects; + +import static cc.ryanc.halo.service.upload.FileHandler.isImageType; + /** * Up Yun file handler. * * @author johnniang * @date 3/27/19 */ +@Slf4j public class UpYunFileHandler implements FileHandler { private final OptionService optionService; @@ -20,7 +37,67 @@ public class UpYunFileHandler implements FileHandler { @Override public UploadResult upload(MultipartFile file) { - return null; + Assert.notNull(file, "Multipart file must not be null"); + + String ossSource = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_SOURCE); + + if (StringUtils.startsWith(ossSource, "/")) { + throw new PropertyFormatException(UpYunProperties.OSS_SOURCE.getValue() + ": " + ossSource + " doesn't start with '/'"); + } + + String ossPassword = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_PASSWORD); + String ossBucket = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_BUCKET); + String ossDomain = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_DOMAIN); + String ossOperator = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_OPERATOR); + // small url can be null + String ossSmallUrl = optionService.getByPropertyOfNullable(UpYunProperties.OSS_SMALL_URL); + + // Create up yun + UpYun upYun = new UpYun(ossBucket, ossOperator, ossPassword); + upYun.setDebug(log.isDebugEnabled()); + upYun.setTimeout(60); + // TODO Provide a property for choosing + upYun.setApiDomain(UpYun.ED_AUTO); + + try { + // Get file basename + String basename = FilenameUtils.getBasename(file.getOriginalFilename()); + // Get file extension + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + // Get md5 value of the file + String md5OfFile = DigestUtils.md5DigestAsHex(file.getInputStream()); + // Build file path + String upFilePath = ossSource + md5OfFile + '.' + extension; + // Set md5Content + upYun.setContentMD5(md5OfFile); + // Write file + boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null); + if (!uploadSuccess) { + throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath); + } + + String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath; + + // Build upload result + UploadResult uploadResult = new UploadResult(); + uploadResult.setFilename(basename); + uploadResult.setFilePath(filePath); + uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); + uploadResult.setSuffix(extension); + uploadResult.setSize(file.getSize()); + + // Handle thumbnail + if (isImageType(uploadResult.getMediaType())) { + BufferedImage image = ImageIO.read(file.getInputStream()); + uploadResult.setWidth(image.getWidth()); + uploadResult.setHeight(image.getHeight()); + uploadResult.setThumbPath(StringUtils.isBlank(ossSmallUrl) ? filePath : filePath + ossSmallUrl); + } + + return uploadResult; + } catch (Exception e) { + throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e); + } } @Override