mirror of https://github.com/halo-dev/halo
Complete uploadQnYun service
parent
e042d83baf
commit
3c56b60b95
|
@ -0,0 +1,17 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ package cc.ryanc.halo.model.enums;
|
|||
* @author : RYAN0UP
|
||||
* @date : 2019-03-17
|
||||
*/
|
||||
public enum BlogProperties implements PropertyEnum<String> {
|
||||
public enum BlogProperties implements PropertyEnum {
|
||||
|
||||
/**
|
||||
* 博客语言
|
||||
|
@ -149,13 +149,7 @@ public enum BlogProperties implements PropertyEnum<String> {
|
|||
/**
|
||||
* 附件存储位置
|
||||
*/
|
||||
ATTACH_LOC("attach_loc", String.class),
|
||||
|
||||
/**
|
||||
* 七牛云 Zone.
|
||||
*/
|
||||
QINIU_ZONE("qiniu_zone", String.class);
|
||||
|
||||
ATTACHMENT_TYPE("attachment_type", String.class);
|
||||
|
||||
private String value;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.springframework.util.Assert;
|
|||
* @author johnniang
|
||||
* @date 3/26/19
|
||||
*/
|
||||
public interface PropertyEnum<T> extends ValueEnum<T> {
|
||||
public interface PropertyEnum extends ValueEnum<String> {
|
||||
|
||||
/**
|
||||
* Get property type.
|
||||
|
@ -67,7 +67,26 @@ public interface PropertyEnum<T> extends ValueEnum<T> {
|
|||
}
|
||||
|
||||
// Should never happen
|
||||
throw new UnsupportedOperationException("Unsupported blog property type:" + type.getName() + " provided");
|
||||
throw new UnsupportedOperationException("Unsupported convention for blog property type:" + type.getName() + " provided");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to enum.
|
||||
*
|
||||
* @param value string value must not be null
|
||||
* @param type propertye value enum type must not be null
|
||||
* @param <T> property value enum type
|
||||
* @return property enum value or null
|
||||
*/
|
||||
static <T extends Enum<T>> T convertToEnum(@NonNull String value, @NonNull Class<T> type) {
|
||||
Assert.hasText(value, "Property value must not be blank");
|
||||
|
||||
try {
|
||||
return Enum.valueOf(type, value);
|
||||
} catch (Exception e) {
|
||||
// Ignore this exception
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,6 +106,7 @@ public interface PropertyEnum<T> extends ValueEnum<T> {
|
|||
|| type.isAssignableFrom(Byte.class)
|
||||
|| type.isAssignableFrom(Double.class)
|
||||
|| type.isAssignableFrom(Float.class)
|
||||
|| type.isAssignableFrom(Enum.class)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package cc.ryanc.halo.model.enums;
|
||||
|
||||
/**
|
||||
* Qi niu yun properties.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/26/19
|
||||
*/
|
||||
public enum QnYunProperties implements PropertyEnum {
|
||||
|
||||
ZONE("qiniu_zone", String.class),
|
||||
ACCESS_KEY("qiniu_access_key", String.class),
|
||||
SECRET_KEY("qiniu_secret_key", String.class),
|
||||
DOMAIN("qiniu_domain", String.class),
|
||||
BUCKET("qiniu_bucket", String.class),
|
||||
SMALL_URL("qiniu_small_url", String.class);
|
||||
|
||||
private String value;
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
QnYunProperties(String value, Class<?> type) {
|
||||
if (!PropertyEnum.isSupportedType(type)) {
|
||||
throw new IllegalArgumentException("Unsupported blog property type: " + type);
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,15 @@ import lombok.Data;
|
|||
@Data
|
||||
public class QiNiuPutSet {
|
||||
|
||||
/**
|
||||
* 文件hash值
|
||||
*/
|
||||
public String hash;
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
public String key;
|
||||
|
||||
/**
|
||||
* 图片大小
|
||||
*/
|
||||
|
@ -21,10 +30,10 @@ public class QiNiuPutSet {
|
|||
/**
|
||||
* 长
|
||||
*/
|
||||
private Integer w;
|
||||
private Integer width;
|
||||
|
||||
/**
|
||||
* 宽
|
||||
*/
|
||||
private Integer h;
|
||||
private Integer height;
|
||||
}
|
||||
|
|
|
@ -35,4 +35,22 @@ public interface FileService {
|
|||
*/
|
||||
@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);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package cc.ryanc.halo.service;
|
|||
import cc.ryanc.halo.exception.MissingPropertyValueException;
|
||||
import cc.ryanc.halo.model.dto.OptionOutputDTO;
|
||||
import cc.ryanc.halo.model.entity.Option;
|
||||
import cc.ryanc.halo.model.enums.BlogProperties;
|
||||
import cc.ryanc.halo.model.enums.PropertyEnum;
|
||||
import cc.ryanc.halo.model.params.OptionParam;
|
||||
import cc.ryanc.halo.service.base.CrudService;
|
||||
|
@ -60,7 +59,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @param properties blog properties
|
||||
* @param source source
|
||||
*/
|
||||
void saveProperties(@NonNull Map<? extends PropertyEnum<String>, String> properties, String source);
|
||||
void saveProperties(@NonNull Map<? extends PropertyEnum, String> properties, String source);
|
||||
|
||||
/**
|
||||
* Get all options
|
||||
|
@ -110,7 +109,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @return an option value
|
||||
*/
|
||||
@Nullable
|
||||
String getByPropertyOfNullable(@NonNull PropertyEnum<String> property);
|
||||
String getByPropertyOfNullable(@NonNull PropertyEnum property);
|
||||
|
||||
/**
|
||||
* Gets option value by blog property.
|
||||
|
@ -120,7 +119,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @throws MissingPropertyValueException throws when property value dismisses
|
||||
*/
|
||||
@NonNull
|
||||
String getByPropertyOfNonNull(@NonNull PropertyEnum<String> property);
|
||||
String getByPropertyOfNonNull(@NonNull PropertyEnum property);
|
||||
|
||||
/**
|
||||
* Gets option value by blog property.
|
||||
|
@ -129,7 +128,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @return an optional option value
|
||||
*/
|
||||
@NonNull
|
||||
Optional<String> getByProperty(@NonNull PropertyEnum<String> property);
|
||||
Optional<String> getByProperty(@NonNull PropertyEnum property);
|
||||
|
||||
/**
|
||||
* Gets property value by blog property.
|
||||
|
@ -140,7 +139,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @param <T> property type
|
||||
* @return property value
|
||||
*/
|
||||
<T> T getByProperty(@NonNull PropertyEnum<String> property, @NonNull Class<T> propertyType, T defaultValue);
|
||||
<T> T getByProperty(@NonNull PropertyEnum property, @NonNull Class<T> propertyType, T defaultValue);
|
||||
|
||||
/**
|
||||
* Gets property value by blog property.
|
||||
|
@ -150,7 +149,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
* @param <T> property type
|
||||
* @return property value
|
||||
*/
|
||||
<T> Optional<T> getByProperty(@NonNull PropertyEnum<String> property, @NonNull Class<T> propertyType);
|
||||
<T> Optional<T> getByProperty(@NonNull PropertyEnum property, @NonNull Class<T> propertyType);
|
||||
|
||||
/**
|
||||
* Gets value by key.
|
||||
|
@ -195,12 +194,12 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
int getRssPageSize();
|
||||
|
||||
/**
|
||||
* Get quniu zone.
|
||||
* Get qi niu yun zone.
|
||||
*
|
||||
* @return qiniu zone
|
||||
*/
|
||||
@NonNull
|
||||
Zone getQiniuZone();
|
||||
Zone getQnYunZone();
|
||||
|
||||
/**
|
||||
* Gets locale.
|
||||
|
|
|
@ -1,12 +1,24 @@
|
|||
package cc.ryanc.halo.service.impl;
|
||||
|
||||
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||
import cc.ryanc.halo.exception.FileUploadException;
|
||||
import cc.ryanc.halo.exception.ServiceException;
|
||||
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.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.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;
|
||||
|
@ -26,6 +38,7 @@ 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.
|
||||
|
@ -58,10 +71,8 @@ public class FileServiceImpl implements FileService {
|
|||
|
||||
/**
|
||||
* Check work directory.
|
||||
*
|
||||
* @throws URISyntaxException throws when work directory is not a uri
|
||||
*/
|
||||
private void checkWorkDir() throws URISyntaxException {
|
||||
private void checkWorkDir() {
|
||||
// Get work path
|
||||
Path workPath = Paths.get(workDir);
|
||||
|
||||
|
@ -131,7 +142,7 @@ public class FileServiceImpl implements FileService {
|
|||
uploadResult.setFilename(basename);
|
||||
uploadResult.setFilePath(subFilePath);
|
||||
uploadResult.setSuffix(extension);
|
||||
uploadResult.setMediaType(MediaType.valueOf(file.getContentType()));
|
||||
uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||
uploadResult.setSize(file.getSize());
|
||||
|
||||
// Check file type
|
||||
|
@ -165,6 +176,82 @@ public class FileServiceImpl implements FileService {
|
|||
}
|
||||
}
|
||||
|
||||
@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.setThumbPath(StringUtils.isBlank(smallUrl) ? filePath : filePath + smallUrl);
|
||||
result.setSuffix(FilenameUtils.getExtension(file.getOriginalFilename()));
|
||||
result.setWidth(putSet.getWidth());
|
||||
result.setHeight(putSet.getHeight());
|
||||
result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
|
||||
|
||||
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");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates thumbnail image.
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@ import cc.ryanc.halo.model.dto.OptionOutputDTO;
|
|||
import cc.ryanc.halo.model.entity.Option;
|
||||
import cc.ryanc.halo.model.enums.BlogProperties;
|
||||
import cc.ryanc.halo.model.enums.PropertyEnum;
|
||||
import cc.ryanc.halo.model.enums.QnYunProperties;
|
||||
import cc.ryanc.halo.model.params.OptionParam;
|
||||
import cc.ryanc.halo.repository.OptionRepository;
|
||||
import cc.ryanc.halo.service.OptionService;
|
||||
|
@ -86,8 +87,6 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
return;
|
||||
}
|
||||
|
||||
// (Not recommended) Don't write "this::save" here
|
||||
// Types of key and value are String
|
||||
options.forEach((key, value) -> save(key, value, source));
|
||||
}
|
||||
|
||||
|
@ -102,7 +101,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public void saveProperties(Map<? extends PropertyEnum<String>, String> properties, String source) {
|
||||
public void saveProperties(Map<? extends PropertyEnum, String> properties, String source) {
|
||||
if (CollectionUtils.isEmpty(properties)) {
|
||||
return;
|
||||
}
|
||||
|
@ -151,33 +150,33 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getByPropertyOfNullable(PropertyEnum<String> property) {
|
||||
public String getByPropertyOfNullable(PropertyEnum property) {
|
||||
return getByProperty(property).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getByPropertyOfNonNull(PropertyEnum<String> property) {
|
||||
public String getByPropertyOfNonNull(PropertyEnum property) {
|
||||
Assert.notNull(property, "Blog property must not be null");
|
||||
|
||||
return getByKeyOfNonNull(property.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getByProperty(PropertyEnum<String> property) {
|
||||
public Optional<String> getByProperty(PropertyEnum property) {
|
||||
Assert.notNull(property, "Blog property must not be null");
|
||||
|
||||
return getByKey(property.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getByProperty(PropertyEnum<String> property, Class<T> propertyType, T defaultValue) {
|
||||
public <T> T getByProperty(PropertyEnum property, Class<T> propertyType, T defaultValue) {
|
||||
Assert.notNull(property, "Blog property must not be null");
|
||||
|
||||
return getByProperty(property, propertyType).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getByProperty(PropertyEnum<String> property, Class<T> propertyType) {
|
||||
public <T> Optional<T> getByProperty(PropertyEnum property, Class<T> propertyType) {
|
||||
return getByProperty(property).map(propertyValue -> PropertyEnum.convertTo(propertyValue, propertyType));
|
||||
}
|
||||
|
||||
|
@ -222,8 +221,8 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public Zone getQiniuZone() {
|
||||
return getByProperty(BlogProperties.QINIU_ZONE).map(qiniuZone -> {
|
||||
public Zone getQnYunZone() {
|
||||
return getByProperty(QnYunProperties.ZONE).map(qiniuZone -> {
|
||||
|
||||
Zone zone;
|
||||
switch (qiniuZone) {
|
||||
|
@ -262,5 +261,4 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
}).orElseGet(Locale::getDefault);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ public class InstallController {
|
|||
properties.put(BlogProperties.NEW_COMMENT_NOTICE, Boolean.FALSE.toString());
|
||||
properties.put(BlogProperties.COMMENT_PASS_NOTICE, Boolean.FALSE.toString());
|
||||
properties.put(BlogProperties.COMMENT_REPLY_NOTICE, Boolean.FALSE.toString());
|
||||
properties.put(BlogProperties.ATTACH_LOC, AttachmentType.SERVER.getValue().toString());
|
||||
properties.put(BlogProperties.ATTACHMENT_TYPE, AttachmentType.SERVER.getValue().toString());
|
||||
|
||||
// Create properties
|
||||
optionService.saveProperties(properties, "system");
|
||||
|
@ -261,7 +261,7 @@ public class InstallController {
|
|||
//// options.put(BlogProperties.NEW_COMMENT_NOTICE, TrueFalseEnum.FALSE.getDesc());
|
||||
//// options.put(BlogProperties.COMMENT_PASS_NOTICE, TrueFalseEnum.FALSE.getDesc());
|
||||
//// options.put(BlogProperties.COMMENT_REPLY_NOTICE, TrueFalseEnum.FALSE.getDesc());
|
||||
//// options.put(BlogProperties.ATTACH_LOC, AttachLocationEnum.SERVER.getDesc());
|
||||
//// options.put(BlogProperties.ATTACHMENT_TYPE, AttachLocationEnum.SERVER.getDesc());
|
||||
//// optionService.saveOptions(options);
|
||||
//
|
||||
// //更新日志
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cc.ryanc.halo.service.impl;
|
||||
|
||||
import cc.ryanc.halo.model.entity.Option;
|
||||
import cc.ryanc.halo.model.enums.BlogProperties;
|
||||
import cc.ryanc.halo.model.enums.QnYunProperties;
|
||||
import cc.ryanc.halo.repository.OptionRepository;
|
||||
import com.qiniu.common.Zone;
|
||||
import org.junit.Test;
|
||||
|
@ -73,13 +73,13 @@ public class OptionServiceImplTest {
|
|||
}
|
||||
|
||||
private void getQiniuZoneTest(Zone actualZone, Option option) {
|
||||
BlogProperties zoneProperty = BlogProperties.QINIU_ZONE;
|
||||
QnYunProperties zoneProperty = QnYunProperties.ZONE;
|
||||
|
||||
// Given
|
||||
given(optionRepository.findByOptionKey(zoneProperty.getValue())).willReturn(Optional.ofNullable(option));
|
||||
|
||||
// When
|
||||
Zone zone = optionService.getQiniuZone();
|
||||
Zone zone = optionService.getQnYunZone();
|
||||
|
||||
// Then
|
||||
then(optionRepository).should().findByOptionKey(zoneProperty.getValue());
|
||||
|
|
Loading…
Reference in New Issue