Replace FileService with FileHandlers

pull/137/head
johnniang 2019-03-27 11:22:38 +08:00
parent 88e0bc3099
commit 5e60db3819
6 changed files with 366 additions and 389 deletions

View File

@ -1,9 +1,5 @@
package cc.ryanc.halo.service; 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. * File service interface.
* *
@ -12,45 +8,4 @@ import org.springframework.web.multipart.MultipartFile;
*/ */
public interface FileService { 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);
} }

View File

@ -1,47 +1,8 @@
package cc.ryanc.halo.service.impl; 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.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 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.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. * File service implementation.
@ -53,305 +14,4 @@ import java.util.Objects;
@Service @Service
public class FileServiceImpl implements FileService { 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);
}
} }

View File

@ -2,9 +2,15 @@ package cc.ryanc.halo.service.upload;
import cc.ryanc.halo.exception.FileUploadException; import cc.ryanc.halo.exception.FileUploadException;
import cc.ryanc.halo.model.support.UploadResult; 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.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
/** /**
* File handler interface. * File handler interface.
* *
@ -13,6 +19,8 @@ import org.springframework.web.multipart.MultipartFile;
*/ */
public interface FileHandler { public interface FileHandler {
MediaType IMAGE_TYPE = MediaType.valueOf("image/*");
/** /**
* Uploads file. * Uploads file.
* *
@ -30,4 +38,38 @@ public interface FileHandler {
*/ */
boolean delete(@NonNull String key); 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);
}
} }

View File

@ -1,30 +1,180 @@
package cc.ryanc.halo.service.upload; 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.model.support.UploadResult;
import cc.ryanc.halo.service.OptionService; 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 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. * Local file handler.
* *
* @author johnniang * @author johnniang
* @date 3/27/19 * @date 3/27/19
*/ */
@Slf4j
public class LocalFileHandler implements FileHandler { 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; private final OptionService optionService;
public LocalFileHandler(OptionService optionService) { private final String workDir;
public LocalFileHandler(OptionService optionService,
HaloProperties haloProperties) {
this.optionService = optionService; 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 @Override
public UploadResult upload(MultipartFile file) { 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 @Override
public boolean delete(String key) { public boolean delete(String key) {
return false; 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());
}
} }

View File

@ -1,15 +1,40 @@
package cc.ryanc.halo.service.upload; 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.model.support.UploadResult;
import cc.ryanc.halo.service.OptionService; 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 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. * Qi niu yun file handler.
* *
* @author johnniang * @author johnniang
* @date 3/27/19 * @date 3/27/19
*/ */
@Slf4j
public class QnYunFileHandler implements FileHandler { public class QnYunFileHandler implements FileHandler {
private final OptionService optionService; private final OptionService optionService;
@ -20,7 +45,75 @@ public class QnYunFileHandler implements FileHandler {
@Override @Override
public UploadResult upload(MultipartFile file) { 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 @Override

View File

@ -1,15 +1,32 @@
package cc.ryanc.halo.service.upload; 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.model.support.UploadResult;
import cc.ryanc.halo.service.OptionService; 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 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. * Up Yun file handler.
* *
* @author johnniang * @author johnniang
* @date 3/27/19 * @date 3/27/19
*/ */
@Slf4j
public class UpYunFileHandler implements FileHandler { public class UpYunFileHandler implements FileHandler {
private final OptionService optionService; private final OptionService optionService;
@ -20,7 +37,67 @@ public class UpYunFileHandler implements FileHandler {
@Override @Override
public UploadResult upload(MultipartFile file) { 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 @Override