From cad9a3524398c0a807e8779008af1f5a1e698128 Mon Sep 17 00:00:00 2001 From: jinqilin721 Date: Tue, 7 Apr 2020 19:35:03 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=84=E4=BB=B6=E4=B8=8A=E4=BC=A0=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=8D=8E=E4=B8=BA=E4=BA=91OBS=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../handler/file/HuaweiObsFileHandler.java | 164 ++++++++++++++++++ .../halo/app/model/enums/AttachmentType.java | 7 +- .../model/properties/HuaweiObsProperties.java | 88 ++++++++++ 4 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 src/main/java/run/halo/app/handler/file/HuaweiObsFileHandler.java create mode 100644 src/main/java/run/halo/app/model/properties/HuaweiObsProperties.java diff --git a/build.gradle b/build.gradle index 6d0f88b36..5eda9edd0 100644 --- a/build.gradle +++ b/build.gradle @@ -72,6 +72,7 @@ ext { jsonVersion = "20190722" fastJsonVersion = "1.2.67" annotationsVersion = "3.0.1" + huaweiObsVersion = "3.19.7" } dependencies { @@ -90,6 +91,7 @@ dependencies { implementation "com.aliyun.oss:aliyun-sdk-oss:$aliyunSdkVersion" implementation "com.baidubce:bce-java-sdk:$baiduSdkVersion" implementation "com.qcloud:cos_api:$qcloudSdkVersion" + implementation "com.huaweicloud:esdk-obs-java:$huaweiObsVersion" implementation "io.springfox:springfox-swagger2:$swaggerVersion" implementation "io.springfox:springfox-swagger-ui:$swaggerVersion" implementation "org.apache.commons:commons-lang3:$commonsLangVersion" diff --git a/src/main/java/run/halo/app/handler/file/HuaweiObsFileHandler.java b/src/main/java/run/halo/app/handler/file/HuaweiObsFileHandler.java new file mode 100644 index 000000000..83c6f29c8 --- /dev/null +++ b/src/main/java/run/halo/app/handler/file/HuaweiObsFileHandler.java @@ -0,0 +1,164 @@ +package run.halo.app.handler.file; + +import com.obs.services.ObsClient; +import com.obs.services.model.PutObjectResult; +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.HuaweiObsProperties; +import run.halo.app.model.support.UploadResult; +import run.halo.app.service.OptionService; +import run.halo.app.utils.FilenameUtils; +import run.halo.app.utils.ImageUtils; + +import javax.imageio.ImageReader; +import java.io.IOException; +import java.util.Objects; + +import static run.halo.app.model.support.HaloConst.URL_SEPARATOR; + +/** + * Huawei obs file handler. + * + * @author qilin + * @date 2020-04-03 + */ +@Slf4j +@Component +public class HuaweiObsFileHandler implements FileHandler { + + private final OptionService optionService; + + public HuaweiObsFileHandler(OptionService optionService) { + this.optionService = optionService; + } + + @Override + public UploadResult upload(MultipartFile file) { + Assert.notNull(file, "Multipart file must not be null"); + + // Get config + String protocol = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_PROTOCOL).toString(); + String domain = optionService.getByPropertyOrDefault(HuaweiObsProperties.OSS_DOMAIN, String.class, ""); + String source = optionService.getByPropertyOrDefault(HuaweiObsProperties.OSS_SOURCE, String.class, ""); + String endPoint = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ENDPOINT).toString(); + String accessKey = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ACCESS_KEY).toString(); + String accessSecret = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ACCESS_SECRET).toString(); + String bucketName = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_BUCKET_NAME).toString(); + String styleRule = optionService.getByPropertyOrDefault(HuaweiObsProperties.OSS_STYLE_RULE, String.class, ""); + String thumbnailStyleRule = optionService.getByPropertyOrDefault(HuaweiObsProperties.OSS_THUMBNAIL_STYLE_RULE, String.class, ""); + + // Init OSS client + final ObsClient obsClient = new ObsClient(accessKey, accessSecret, endPoint); + + StringBuilder basePath = new StringBuilder(protocol); + + if (StringUtils.isNotEmpty(domain)) { + basePath.append(domain) + .append(URL_SEPARATOR); + } else { + basePath.append(bucketName) + .append(".") + .append(endPoint) + .append(URL_SEPARATOR); + } + + try { + String basename = FilenameUtils.getBasename(Objects.requireNonNull(file.getOriginalFilename())); + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + String timestamp = String.valueOf(System.currentTimeMillis()); + StringBuilder upFilePath = new StringBuilder(); + + if (StringUtils.isNotEmpty(source)) { + upFilePath.append(source) + .append(URL_SEPARATOR); + } + + upFilePath.append(basename) + .append("_") + .append(timestamp) + .append(".") + .append(extension); + + String filePath = StringUtils.join(basePath.toString(), upFilePath.toString()); + + log.info(basePath.toString()); + + // Upload + PutObjectResult putObjectResult = obsClient.putObject(bucketName, upFilePath.toString(), file.getInputStream()); + if (putObjectResult == null) { + throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到华为云失败 "); + } + + // Response result + UploadResult uploadResult = new UploadResult(); + uploadResult.setFilename(basename); + uploadResult.setFilePath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule); + uploadResult.setKey(upFilePath.toString()); + uploadResult.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType()))); + uploadResult.setSuffix(extension); + uploadResult.setSize(file.getSize()); + + // Handle thumbnail + if (FileHandler.isImageType(uploadResult.getMediaType())) { + ImageReader image = ImageUtils.getImageReaderFromFile(file.getInputStream(), extension); + assert image != null; + uploadResult.setWidth(image.getWidth(0)); + uploadResult.setHeight(image.getHeight(0)); + if (ImageUtils.EXTENSION_ICO.equals(extension)) { + uploadResult.setThumbPath(filePath); + } else { + uploadResult.setThumbPath(StringUtils.isBlank(thumbnailStyleRule) ? filePath : filePath + thumbnailStyleRule); + } + } + + log.info("Uploaded file: [{}] successfully", file.getOriginalFilename()); + return uploadResult; + } catch (Exception e) { + throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到华为云失败 ", e).setErrorData(file.getOriginalFilename()); + } finally { + try { + obsClient.close(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + } + + @Override + public void delete(String key) { + Assert.notNull(key, "File key must not be blank"); + + // Get config + String endPoint = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ENDPOINT).toString(); + String accessKey = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ACCESS_KEY).toString(); + String accessSecret = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_ACCESS_SECRET).toString(); + String bucketName = optionService.getByPropertyOfNonNull(HuaweiObsProperties.OSS_BUCKET_NAME).toString(); + + // Init OSS client + final ObsClient obsClient = new ObsClient(accessKey, accessSecret, endPoint); + + try { + obsClient.deleteObject(bucketName, key); + } catch (Exception e) { + throw new FileOperationException("附件 " + key + " 从华为云删除失败", e); + } finally { + try { + obsClient.close(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + } + + @Override + public AttachmentType getAttachmentType() { + return AttachmentType.HUAWEIOBS; + } + +} 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 33371fea9..48bd63908 100644 --- a/src/main/java/run/halo/app/model/enums/AttachmentType.java +++ b/src/main/java/run/halo/app/model/enums/AttachmentType.java @@ -41,7 +41,12 @@ public enum AttachmentType implements ValueEnum { /** * 腾讯云 */ - TENCENTCOS(6); + TENCENTCOS(6), + + /** + * 华为云 + */ + HUAWEIOBS(7); private final Integer value; diff --git a/src/main/java/run/halo/app/model/properties/HuaweiObsProperties.java b/src/main/java/run/halo/app/model/properties/HuaweiObsProperties.java new file mode 100644 index 000000000..5ef6ff8bc --- /dev/null +++ b/src/main/java/run/halo/app/model/properties/HuaweiObsProperties.java @@ -0,0 +1,88 @@ +package run.halo.app.model.properties; + +import run.halo.app.model.support.HaloConst; + +/** + * Huawei obs properties. + * + * @author qilin + * @date 2020-04-03 + */ +public enum HuaweiObsProperties implements PropertyEnum { + + /** + * Huawei obs domain protocol + */ + OSS_PROTOCOL("obs_huawei_domain_protocol", String.class, HaloConst.PROTOCOL_HTTPS), + + /** + * Huawei obs domain + */ + OSS_DOMAIN("obs_huawei_domain", String.class, ""), + + /** + * Huawei obs endpoint. + */ + OSS_ENDPOINT("obs_huawei_endpoint", String.class, ""), + + /** + * Huawei obs bucket name. + */ + OSS_BUCKET_NAME("obs_huawei_bucket_name", String.class, ""), + + /** + * Huawei obs access key. + */ + OSS_ACCESS_KEY("obs_huawei_access_key", String.class, ""), + + /** + * Huawei obs access secret. + */ + OSS_ACCESS_SECRET("obs_huawei_access_secret", String.class, ""), + + /** + * Huawei obs source + */ + OSS_SOURCE("obs_huawei_source", String.class, ""), + + /** + * Huawei obs style rule. + */ + OSS_STYLE_RULE("obs_huawei_style_rule", String.class, ""), + + /** + * Huawei obs thumbnail style rule. + */ + OSS_THUMBNAIL_STYLE_RULE("obs_huawei_thumbnail_style_rule", String.class, ""); + + private final String value; + + private final Class type; + + private final String defaultValue; + + HuaweiObsProperties(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; + } +}