<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
OSS_ACCESS_KEY_ID=xx
OSS_ACCESS_KEY_SECRET=xx
OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
OSS_REGION_NAME=cn-hangzhou
OSS_BUCKET_NAME=jieti11
UploadResult uploadFileResult = Aop.get(AliyunStorageService.class).uploadFile("document", uploadFile);
package com.litongjava.tio.boot.admin.services.storage;
import com.aliyun.oss.OSS;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.litongjava.db.TableInput;
import com.litongjava.db.TableResult;
import com.litongjava.db.activerecord.Row;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.model.body.RespBodyVo;
import com.litongjava.model.upload.UploadFile;
import com.litongjava.model.upload.UploadResult;
import com.litongjava.table.services.ApiTable;
import com.litongjava.tio.boot.admin.consts.StoragePlatformConst;
import com.litongjava.tio.boot.admin.costants.TioBootAdminTableNames;
import com.litongjava.tio.boot.admin.dao.SystemUploadFileDao;
import com.litongjava.tio.boot.admin.services.StorageService;
import com.litongjava.tio.boot.admin.services.system.SystemUploadFileService;
import com.litongjava.tio.boot.admin.utils.storage.AliyunOssUtils;
import com.litongjava.tio.utils.crypto.Md5Utils;
import com.litongjava.tio.utils.hutool.FilenameUtils;
import com.litongjava.tio.utils.snowflake.SnowflakeIdUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AliyunStorageService implements StorageService {
@Override
public RespBodyVo upload(UploadFile uploadFile) {
return upload(DEFAULT_CATEGORY, uploadFile);
}
@Override
public RespBodyVo upload(String category, UploadFile uploadFile) {
if (StrKit.isBlank(category)) {
category = DEFAULT_CATEGORY;
}
UploadResult uploadResultVo = uploadFile(category, uploadFile);
return RespBodyVo.ok(uploadResultVo);
}
@Override
public UploadResult uploadFile(String category, UploadFile uploadFile) {
long id = SnowflakeIdUtils.id();
return uploadFile(category, uploadFile, id);
}
@Override
public UploadResult uploadFile(String category, UploadFile uploadFile, Long id) {
String suffix = FilenameUtils.getSuffix(uploadFile.getName());
String newFilename = id + "." + suffix;
String targetName = category + "/" + newFilename;
return uploadFile(id, targetName, uploadFile, suffix);
}
@Override
public UploadResult uploadFile(long id, String targetName, UploadFile uploadFile, String suffix) {
String name = uploadFile.getName();
long size = uploadFile.getSize();
byte[] fileContent = uploadFile.getData();
String md5 = Md5Utils.md5Hex(fileContent);
Row record = Aop.get(SystemUploadFileDao.class).getFileBasicInfoByMd5(md5);
if (record != null) {
log.info("select table result: {}", record.toMap());
id = record.getLong("id");
String url = this.getUrl(record.getStr("bucket_name"), record.getStr("target_name"));
Kv kv = record.toKv();
kv.remove("target_name");
kv.remove("bucket_name");
kv.set("url", url);
kv.set("md5", md5);
return new UploadResult(id, name, size, url, md5);
} else {
log.info("not found from cache table: {}", md5);
}
String etag = null;
OSS client = null;
try {
client = AliyunOssUtils.buildClient();
etag = AliyunOssUtils.upload(client, AliyunOssUtils.bucketName, targetName, fileContent, suffix).getETag();
} catch (Exception e) {
log.error("Error uploading file", e);
throw new RuntimeException(e);
} finally {
if (client != null) {
client.shutdown();
}
}
log.info("Uploaded to Aliyun OSS with ETag: {}", etag);
TableInput kv = TableInput.create().set("name", name).set("size", size).set("md5", md5)
.set("platform", StoragePlatformConst.aliyun_oss).set("region_name", AliyunOssUtils.regionName)
.set("bucket_name", AliyunOssUtils.bucketName).set("target_name", targetName).set("file_id", etag);
TableResult<Kv> save = ApiTable.save(TioBootAdminTableNames.tio_boot_admin_system_upload_file, kv);
String downloadUrl = getUrl(AliyunOssUtils.bucketName, targetName);
return new UploadResult(save.getData().getLong("id"), name, size, downloadUrl, md5);
}
@Override
public String getUrl(String bucketName, String targetName) {
return AliyunOssUtils.getUrl(bucketName, targetName);
}
@Override
public String getUrl(String targetName) {
return AliyunOssUtils.getUrl(targetName);
}
@Override
public UploadResult getUrlById(String id) {
return Aop.get(SystemUploadFileService.class).getUrlById(id);
}
@Override
public UploadResult getUrlById(long id) {
return Aop.get(SystemUploadFileService.class).getUrlById(id);
}
@Override
public UploadResult getUrlByMd5(String md5) {
return Aop.get(SystemUploadFileService.class).getUrlByMd5(md5);
}
@Override
public String getPresignedDownloadUrl(String targetName) {
return AliyunOssUtils.getPresignedDownloadUrl(targetName);
}
@Override
public String getPresignedDownloadUrl(String bucket, String targetName) {
return AliyunOssUtils.getPresignedDownloadUrl(bucket, targetName);
}
@Override
public String getPresignedDownloadUrl(String region, String bucket, String targetName) {
return AliyunOssUtils.getPresignedDownloadUrl(region, bucket, targetName);
}
@Override
public UploadResult getPresignedDownloadUrl(Long id) {
return Aop.get(SystemUploadFileService.class).getPresignedDownloadUrl(id);
}
}
package com.litongjava.tio.boot.admin.utils.storage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Date;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.ResponseHeaderOverrides;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.http.ContentTypeUtils;
import com.litongjava.tio.utils.hutool.FilenameUtils;
* Aliyun OSS 工具类(对齐 AwsS3Utils 的能力)
* - upload(byte[] / File)
* - getUrl(公开 URL,仅当 bucket/object 允许公开访问或走自定义域名/CDN)
* - getPresignedDownloadUrl(私有桶可下载:预签名 GET URL)
* - buildClient(统一凭证/region/endpoint 构建)
*/
public class AliyunOssUtils {
* URL 模板: https://<bucket>.oss-<region>.aliyuncs.com/<objectKey>
* 说明:regionName 一般是类似 cn-hangzhou;endpoint 一般是 https://oss-cn-hangzhou.aliyuncs.com
*/
public static final String urlFormat = "https://%s.oss-%s.aliyuncs.com/%s";
public static final String bucketName = EnvUtils.get("OSS_BUCKET_NAME");
public static final String regionName = EnvUtils.get("OSS_REGION_NAME");
public static final String endpoint = EnvUtils.get("OSS_ENDPOINT");
public static final String accessKeyId = EnvUtils.get("OSS_ACCESS_KEY_ID");
public static final String accessKeySecret = EnvUtils.get("OSS_ACCESS_KEY_SECRET");
public static final String domain = EnvUtils.getStr("OSS_BUCKET_DOMAIN");
public static final Duration DEFAULT_PRESIGN_EXPIRES = Duration.ofMinutes(30);
public static PutObjectResult upload(OSS client, String targetName, byte[] fileContent, String suffix) {
return upload(client, bucketName, targetName, fileContent, suffix);
}
public static PutObjectResult upload(OSS client, String bucketName, String objectKey, byte[] bytes, String suffix) {
try {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(bytes.length);
if (suffix != null) {
metadata.setContentType(ContentTypeUtils.getContentType(suffix));
}
PutObjectRequest req = new PutObjectRequest(bucketName, objectKey, new ByteArrayInputStream(bytes), metadata);
return client.putObject(req);
} catch (Exception e) {
throw new RuntimeException("Aliyun OSS upload error", e);
}
}
public static PutObjectResult upload(OSS client, String objectKey, File file) {
return upload(client, bucketName, objectKey, file);
}
public static PutObjectResult upload(OSS client, String bucketName, String objectKey, File file) {
String name = file.getName();
long length = file.length();
String suffix = FilenameUtils.getSuffix(name);
String contentType = ContentTypeUtils.getContentType(suffix);
try {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(length);
if (suffix != null) {
metadata.setContentType(contentType);
}
PutObjectRequest req = new PutObjectRequest(bucketName, objectKey, file, metadata);
return client.putObject(req);
} catch (Exception e) {
throw new RuntimeException("Aliyun OSS upload error", e);
}
}
public static String getUrl(String objectKey) {
return getUrl(bucketName, objectKey);
}
public static String getUrl(String bucket, String objectKey) {
if (domain != null) {
return "https://" + domain + "/" + objectKey;
} else {
return String.format(urlFormat, bucket, regionName, objectKey);
}
}
public static String getUrl(String regionName, String bucket, String objectKey) {
if (domain != null) {
return "https://" + domain + "/" + objectKey;
} else {
return String.format(urlFormat, bucket, regionName, objectKey);
}
}
* 生成可下载的预签名 GET URL(默认 30 分钟)
*/
public static String getPresignedDownloadUrl(String targetUri) {
return getPresignedDownloadUrl(regionName, bucketName, targetUri, DEFAULT_PRESIGN_EXPIRES, null, null);
}
public static String getPresignedDownloadUrl(String bucket, String targetUri) {
return getPresignedDownloadUrl(regionName, bucket, targetUri, DEFAULT_PRESIGN_EXPIRES, null, null);
}
public static String getPresignedDownloadUrl(String regionName, String bucket, String targetUri) {
return getPresignedDownloadUrl(regionName, bucket, targetUri, DEFAULT_PRESIGN_EXPIRES, null, null);
}
* 生成可下载的预签名 URL(GET)。
*
* @param bucket bucket name
* @param objectKey object key(你的 targetName/targetUri)
* @param expires 过期时间
* @param downloadFilename 下载保存时显示的文件名(可选)
* @param contentType 响应 Content-Type(可选)
*/
public static String getPresignedDownloadUrl(String bucket, String objectKey, Duration expires,
String downloadFilename, String contentType) {
return getPresignedDownloadUrl(regionName, bucket, objectKey, expires, downloadFilename, contentType);
}
public static String getPresignedDownloadUrl(String regionName, String bucket, String targetUri,
String downloadFilename) {
String suffix = FilenameUtils.getSuffix(downloadFilename);
String contentType = ContentTypeUtils.getContentType(suffix);
return getPresignedDownloadUrl(regionName, bucket, targetUri, DEFAULT_PRESIGN_EXPIRES, downloadFilename,
contentType);
}
public static String getPresignedDownloadUrl(String region, String bucket, String objectKey, Duration expires,
String downloadFilename, String contentType) {
if (expires == null) {
expires = DEFAULT_PRESIGN_EXPIRES;
}
Date expiration = new Date(System.currentTimeMillis() + expires.toMillis());
OSS client = null;
try {
client = buildClient(region);
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucket, objectKey, HttpMethod.GET);
req.setExpiration(expiration);
ResponseHeaderOverrides overrides = new ResponseHeaderOverrides();
if (downloadFilename != null && downloadFilename.length() > 0) {
String safe = downloadFilename.replace("\"", "");
String encoded = URLEncoder.encode(downloadFilename, StandardCharsets.UTF_8).replace("+", "%20");
String disposition = "attachment; filename=\"" + safe + "\"; filename*=UTF-8''" + encoded;
overrides.setContentDisposition(disposition);
} else {
overrides.setContentDisposition("attachment");
}
if (contentType != null && contentType.length() > 0) {
overrides.setContentType(contentType);
}
req.setResponseHeaders(overrides);
URL url = client.generatePresignedUrl(req);
return url.toString();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (client != null) {
client.shutdown();
}
}
}
public static OSS buildClient() {
return buildClient(regionName);
}
public static OSS buildClient(String regionName) {
try {
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
conf.setSignatureVersion(SignVersion.V4);
DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
return OSSClientBuilder.create().endpoint(endpoint).credentialsProvider(credentialProvider)
.clientConfiguration(conf).region(regionName).build();
} catch (Exception e) {
throw new RuntimeException("Failed to build Aliyun OSS client", e);
}
}
public static String getBucketName() {
return bucketName;
}
public static String getRegionName() {
return regionName;
}
}