diff --git a/build.gradle b/build.gradle index 149d7876c..01327f8dc 100644 --- a/build.gradle +++ b/build.gradle @@ -54,6 +54,7 @@ dependencies { implementation 'com.upyun:java-sdk:4.0.1' implementation 'com.qiniu:qiniu-java-sdk:7.2.18' implementation 'com.aliyun.oss:aliyun-sdk-oss:3.4.2' + implementation 'com.baidubce:bce-java-sdk:0.10.36' implementation 'net.coobird:thumbnailator:0.4.8' implementation 'io.springfox:springfox-swagger2:2.9.2' implementation 'io.springfox:springfox-swagger-ui:2.9.2' diff --git a/src/main/java/run/halo/app/handler/file/BaiDuYunFileHandler.java b/src/main/java/run/halo/app/handler/file/BaiDuYunFileHandler.java new file mode 100644 index 000000000..462141baa --- /dev/null +++ b/src/main/java/run/halo/app/handler/file/BaiDuYunFileHandler.java @@ -0,0 +1,137 @@ +package run.halo.app.handler.file; + + +import com.baidubce.auth.DefaultBceCredentials; +import com.baidubce.services.bos.BosClient; +import com.baidubce.services.bos.BosClientConfiguration; +import com.baidubce.services.bos.model.PutObjectResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.web.multipart.MultipartFile; +import run.halo.app.exception.FileOperationException; +import run.halo.app.model.enums.AttachmentType; +import run.halo.app.model.properties.BaiDuYunProperties; +import run.halo.app.model.support.UploadResult; +import run.halo.app.service.OptionService; +import run.halo.app.utils.FilenameUtils; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.util.Objects; + +/** + * BaiDuYun file handler. + * + * @author wangya + * @date 2019-07-20 + */ +@Slf4j +@Component +public class BaiDuYunFileHandler implements FileHandler { + + private final OptionService optionService; + + public BaiDuYunFileHandler(OptionService optionService) { + this.optionService = optionService; + } + + @Override + public UploadResult upload(MultipartFile file) { + Assert.notNull(file, "Multipart file must not be null"); + + // Get config + String ossEndPoint = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ENDPOINT).toString(); + String ossAccessKey = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ACCESS_KEY).toString(); + String ossAccessSecret = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ACCESS_SECRET).toString(); + String ossBucketName = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_BUCKET_NAME).toString(); + String ossStyleRule = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_STYLE_RULE).toString(); + String ossSource = StringUtils.join("https://", ossBucketName, "." + ossEndPoint); + + + BosClientConfiguration config = new BosClientConfiguration(); + config.setCredentials(new DefaultBceCredentials(ossAccessKey,ossAccessSecret)); + config.setEndpoint(ossEndPoint); + + // Init OSS client + BosClient client = new BosClient(config); + + try { + String basename = FilenameUtils.getBasename(file.getOriginalFilename()); + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + String timestamp = String.valueOf(System.currentTimeMillis()); + String upFilePath = StringUtils.join(basename, "_", timestamp, ".", extension); + String filePath = StringUtils.join(StringUtils.appendIfMissing(ossSource, "/"), upFilePath); + + // Upload + PutObjectResponse putObjectResponseFromInputStream = client.putObject(ossBucketName, upFilePath, file.getInputStream()); + if (putObjectResponseFromInputStream == null) { + throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到百度云失败 "); + } + + // Response result + UploadResult uploadResult = new UploadResult(); + uploadResult.setFilename(basename); + uploadResult.setFilePath(filePath); + uploadResult.setKey(upFilePath); + uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); + uploadResult.setSuffix(extension); + uploadResult.setSize(file.getSize()); + + // Handle thumbnail + if (FileHandler.isImageType(uploadResult.getMediaType())) { + BufferedImage image = ImageIO.read(file.getInputStream()); + uploadResult.setWidth(image.getWidth()); + uploadResult.setHeight(image.getHeight()); + uploadResult.setThumbPath(StringUtils.isBlank(ossStyleRule) ? filePath : filePath + ossStyleRule); + } + + return uploadResult; + } catch (Exception e) { + e.printStackTrace(); + } finally { + client.shutdown(); + } + + // Build result + UploadResult result = new UploadResult(); + + log.info("File: [{}] uploaded successfully", file.getOriginalFilename()); + + return result; + } + + @Override + public void delete(String key) { + Assert.notNull(key, "File key must not be blank"); + + // Get config + String ossEndPoint = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ENDPOINT).toString(); + String ossAccessKey = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ACCESS_KEY).toString(); + String ossAccessSecret = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_ACCESS_SECRET).toString(); + String ossBucketName = optionService.getByPropertyOfNonNull(BaiDuYunProperties.OSS_BUCKET_NAME).toString(); + String ossSource = StringUtils.join("https://", ossBucketName, "." + ossEndPoint); + + BosClientConfiguration config = new BosClientConfiguration(); + config.setCredentials(new DefaultBceCredentials(ossAccessKey,ossAccessSecret)); + config.setEndpoint(ossEndPoint); + + // Init OSS client + BosClient client = new BosClient(config); + + try { + client.deleteObject(ossBucketName,key); + } catch (Exception e) { + throw new FileOperationException("附件 " + key + " 从百度云删除失败", e); + } finally { + client.shutdown(); + } + } + + @Override + public boolean supportType(AttachmentType type) { + return AttachmentType.BAIDUYUN.equals(type); + } +} diff --git a/src/main/java/run/halo/app/model/enums/AttachmentType.java b/src/main/java/run/halo/app/model/enums/AttachmentType.java index db1626846..59fdd6482 100644 --- a/src/main/java/run/halo/app/model/enums/AttachmentType.java +++ b/src/main/java/run/halo/app/model/enums/AttachmentType.java @@ -31,7 +31,12 @@ public enum AttachmentType implements ValueEnum { /** * 阿里云 */ - ALIYUN(4); + ALIYUN(4), + + /** + * 百度云 + */ + BAIDUYUN(5); private Integer value; diff --git a/src/main/java/run/halo/app/model/properties/BaiDuYunProperties.java b/src/main/java/run/halo/app/model/properties/BaiDuYunProperties.java new file mode 100644 index 000000000..490c7fd67 --- /dev/null +++ b/src/main/java/run/halo/app/model/properties/BaiDuYunProperties.java @@ -0,0 +1,66 @@ +package run.halo.app.model.properties; + +/** + * BaiDuYun properties. + * + * @author wangya + * @date 2019-07-19 + */ +public enum BaiDuYunProperties implements PropertyEnum { + + /** + * BaiDuyun oss endpoint. + */ + OSS_ENDPOINT("oss_baiduyun_endpoint", String.class, ""), + + /** + * BaiDuyun oss bucket name. + */ + OSS_BUCKET_NAME("oss_baiduyun_bucket_name", String.class, ""), + + /** + * BaiDuyun oss access key. + */ + OSS_ACCESS_KEY("oss_baiduyun_access_key", String.class, ""), + + /** + * BaiDuyun oss access secret. + */ + OSS_ACCESS_SECRET("oss_baiduyun_access_secret", String.class, ""), + + /** + * BaiDuyun oss style rule + */ + OSS_STYLE_RULE("oss_baiduyun_style_rule", String.class, ""); + + private final String value; + + private final Class type; + + private final String defaultValue; + + BaiDuYunProperties(String value, Class type, String defaultValue) { + this.defaultValue = defaultValue; + if (!PropertyEnum.isSupportedType(type)) { + throw new IllegalArgumentException("Unsupported blog property type: " + type); + } + + this.value = value; + this.type = type; + } + + @Override + public Class getType() { + return type; + } + + @Override + public String defaultValue() { + return defaultValue; + } + + @Override + public String getValue() { + return value; + } +}