/** * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). *

* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.gnu.org/licenses/lgpl.html *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springblade.core.oss; import com.aliyun.oss.OSSClient; import com.aliyun.oss.common.utils.BinaryUtil; import com.aliyun.oss.model.MatchMode; import com.aliyun.oss.model.ObjectMetadata; import com.aliyun.oss.model.PolicyConditions; import com.aliyun.oss.model.PutObjectResult; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import org.springblade.core.oss.model.BladeFile; import org.springblade.core.oss.model.OssFile; import org.springblade.core.oss.props.OssProperties; import org.springblade.core.oss.rule.OssRule; import org.springblade.core.tool.jackson.JsonUtil; import org.springblade.core.tool.utils.StringPool; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * AliossTemplate * * @author Chill */ @AllArgsConstructor public class AliossTemplate { private OSSClient ossClient; private OssProperties ossProperties; private OssRule ossRule; @SneakyThrows public void makeBucket(String bucketName) { if (!bucketExists(bucketName)) { ossClient.createBucket(getBucketName(bucketName)); } } @SneakyThrows public void removeBucket(String bucketName) { ossClient.deleteBucket(getBucketName(bucketName)); } @SneakyThrows public boolean bucketExists(String bucketName) { return ossClient.doesBucketExist(getBucketName(bucketName)); } @SneakyThrows public void copyFile(String bucketName, String fileName, String destBucketName) { ossClient.copyObject(getBucketName(bucketName), fileName, getBucketName(destBucketName), fileName); } @SneakyThrows public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) { ossClient.copyObject(getBucketName(bucketName), fileName, getBucketName(destBucketName), destFileName); } @SneakyThrows public OssFile statFile(String fileName) { return statFile(ossProperties.getBucketName(), fileName); } @SneakyThrows public OssFile statFile(String bucketName, String fileName) { ObjectMetadata stat = ossClient.getObjectMetadata(getBucketName(bucketName), fileName); OssFile ossFile = new OssFile(); ossFile.setName(fileName); ossFile.setLink(fileLink(ossFile.getName())); ossFile.setHash(stat.getContentMD5()); ossFile.setLength(stat.getContentLength()); ossFile.setPutTime(stat.getLastModified()); ossFile.setContentType(stat.getContentType()); return ossFile; } @SneakyThrows public String filePath(String fileName) { return getOssHost().concat(StringPool.SLASH).concat(fileName); } @SneakyThrows public String filePath(String bucketName, String fileName) { return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName); } @SneakyThrows public String fileLink(String fileName) { return getOssHost().concat(StringPool.SLASH).concat(fileName); } @SneakyThrows public String fileLink(String bucketName, String fileName) { return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName); } /** * 文件对象 * * @param file 上传文件类 * @return */ @SneakyThrows public BladeFile putFile(MultipartFile file) { return putFile(ossProperties.getBucketName(), file.getOriginalFilename(), file); } /** * @param fileName 上传文件名 * @param file 上传文件类 * @return */ @SneakyThrows public BladeFile putFile(String fileName, MultipartFile file) { return putFile(ossProperties.getBucketName(), fileName, file); } @SneakyThrows public BladeFile putFile(String bucketName, String fileName, MultipartFile file) { return putFile(bucketName, fileName, file.getInputStream()); } @SneakyThrows public BladeFile putFile(String fileName, InputStream stream) { return putFile(ossProperties.getBucketName(), fileName, stream); } @SneakyThrows public BladeFile putFile(String bucketName, String fileName, InputStream stream) { return put(bucketName, stream, fileName, false); } @SneakyThrows public BladeFile put(String bucketName, InputStream stream, String key, boolean cover) { makeBucket(bucketName); String originalName = key; key = getFileName(key); // 覆盖上传 if (cover) { ossClient.putObject(getBucketName(bucketName), key, stream); } else { PutObjectResult response = ossClient.putObject(getBucketName(bucketName), key, stream); int retry = 0; int retryCount = 5; while (StringUtils.isEmpty(response.getETag()) && retry < retryCount) { response = ossClient.putObject(getBucketName(bucketName), key, stream); retry++; } } BladeFile file = new BladeFile(); file.setOriginalName(originalName); file.setName(key); file.setLink(fileLink(bucketName, key)); return file; } @SneakyThrows public void removeFile(String fileName) { ossClient.deleteObject(getBucketName(), fileName); } @SneakyThrows public void removeFile(String bucketName, String fileName) { ossClient.deleteObject(getBucketName(bucketName), fileName); } @SneakyThrows public void removeFiles(List fileNames) { fileNames.forEach(this::removeFile); } @SneakyThrows public void removeFiles(String bucketName, List fileNames) { fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName)); } /** * 根据规则生成存储桶名称规则 * * @return String */ private String getBucketName() { return getBucketName(ossProperties.getBucketName()); } /** * 根据规则生成存储桶名称规则 * * @param bucketName 存储桶名称 * @return String */ private String getBucketName(String bucketName) { return ossRule.bucketName(bucketName); } /** * 根据规则生成文件名称规则 * * @param originalFilename 原始文件名 * @return string */ private String getFileName(String originalFilename) { return ossRule.fileName(originalFilename); } public String getUploadToken() { return getUploadToken(ossProperties.getBucketName()); } /** * TODO 过期时间 *

* 获取上传凭证,普通上传 */ public String getUploadToken(String bucketName) { // 默认过期时间2小时 return getUploadToken(bucketName, ossProperties.getArgs().get("expireTime", 3600L)); } /** * TODO 上传大小限制、基础路径 *

* 获取上传凭证,普通上传 */ public String getUploadToken(String bucketName, long expireTime) { String baseDir = "upload"; long expireEndTime = System.currentTimeMillis() + expireTime * 1000; Date expiration = new Date(expireEndTime); PolicyConditions policyConds = new PolicyConditions(); // 默认大小限制10M policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, ossProperties.getArgs().get("contentLengthRange", 10485760)); policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, baseDir); String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); String encodedPolicy = BinaryUtil.toBase64String(binaryData); String postSignature = ossClient.calculatePostSignature(postPolicy); Map respMap = new LinkedHashMap<>(16); respMap.put("accessid", ossProperties.getAccessKey()); respMap.put("policy", encodedPolicy); respMap.put("signature", postSignature); respMap.put("dir", baseDir); respMap.put("host", getOssHost(bucketName)); respMap.put("expire", String.valueOf(expireEndTime / 1000)); return JsonUtil.toJson(respMap); } public String getOssHost(String bucketName) { String prefix = ossProperties.getEndpoint().contains("https://") ? "https://" : "http://"; return prefix + getBucketName(bucketName) + StringPool.DOT + ossProperties.getEndpoint().replaceFirst(prefix, StringPool.EMPTY); } public String getOssHost() { return getOssHost(ossProperties.getBucketName()); } }