存储文件到 AW3 S3
添加依赖
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.17.100</version> <!-- 请检查并使用最新版本 -->
</dependency>
添加配置
AWS_S3_ACCESS_KEY_ID=
AWS_S3_SECRET_ACCESS_KEY=
AWS_S3_REGION_NAME=us-west-1
AWS_S3_BUCKET_NAME=rumiapp
AwsS3Utils 文件上传工具类
package com.litongjava.tio.boot.admin.utils;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.http.ContentTypeUtils;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
public class AwsS3Utils {
public static final String urlFormat = "https://%s.s3.us-west-1.amazonaws.com/%s";
public static final String bucketName = EnvUtils.get("AWS_S3_BUCKET_NAME");
public static final String regionName = EnvUtils.get("AWS_S3_REGION_NAME");
public static PutObjectResponse upload(S3Client client, String bucketName, String targetName, byte[] fileContent,
String suffix) {
try {
String contentType = ContentTypeUtils.getContentType(suffix);
PutObjectRequest putOb = PutObjectRequest.builder().bucket(bucketName).key(targetName).contentType(contentType)
.build();
PutObjectResponse putObject = client.putObject(putOb, RequestBody.fromBytes(fileContent));
return putObject;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
配置类
package com.litongjava.tio.boot.admin.config;
import com.litongjava.tio.utils.environment.EnvUtils;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
public class AwsS3Config {
public S3Client buildClient() {
String accessKeyId = EnvUtils.get("AWS_S3_ACCESS_KEY_ID");
String secretAccessKey = EnvUtils.get("AWS_S3_SECRET_ACCESS_KEY");
String regionName = EnvUtils.get("AWS_S3_REGION_NAME");
AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKeyId, secretAccessKey);
StaticCredentialsProvider staticCredentialsProvider = StaticCredentialsProvider.create(awsCreds);
Region region = Region.of(regionName);
// 创建S3客户端
S3ClientBuilder builder = S3Client.builder();
S3Client s3 = builder.region(region) //
.credentialsProvider(staticCredentialsProvider) //
.build();
return s3;
}
}
测试工具类
package com.litongjava.tio.boot.admin.utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Test;
import com.litongjava.tio.boot.admin.config.AwsS3Config;
import com.litongjava.tio.utils.environment.EnvUtils;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
public class AwsS3UtilsTest {
@Test
public void test() throws IOException {
EnvUtils.load();
Path path = java.nio.file.Paths.get("F:\\my_file\\my_photo\\kitty\\kitty-cat.jpg");
byte[] fileContent = Files.readAllBytes(path);
String targetName = "001.jpg"; // 上传到S3的文件名
String suffix = "jpg";
// 示例使用upload方法
try (S3Client client = new AwsS3Config().buildClient();) {
PutObjectResponse response = AwsS3Utils.upload(client, AwsS3Utils.bucketName, targetName, fileContent, suffix);
String url = String.format(AwsS3Utils.urlFormat, AwsS3Utils.bucketName, targetName);
System.out.println(url);
System.out.println(response.eTag());
}
}
}
接受文件上传,并经相关信息保存到数据库
package com.litongjava.open.chat.services;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.litongjava.data.model.DbJsonBean;
import com.litongjava.data.services.DbJsonService;
import com.litongjava.data.utils.SnowflakeIdGenerator;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.plugin.activerecord.Db;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.open.chat.config.AwsS3Config;
import com.litongjava.open.chat.constants.TableNames;
import com.litongjava.open.chat.utils.AwsS3Utils;
import com.litongjava.tio.boot.http.TioHttpContext;
import com.litongjava.tio.http.common.UploadFile;
import com.litongjava.tio.utils.crypto.Md5Utils;
import com.litongjava.tio.utils.hutool.FilenameUtils;
import com.litongjava.tio.utils.resp.RespVo;
import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
/**
* Created by Tong Li <https://github.com/litongjava>
*/
@Slf4j
public class AwsS3StorageService {
public RespVo upload(String category, UploadFile uploadFile) {
if (StrKit.isBlank(category)) {
category = "default";
}
String filename = uploadFile.getName();
int size = uploadFile.getSize();
byte[] fileContent = uploadFile.getData();
return upload(category, filename, size, fileContent);
}
public RespVo upload(String category, String filename, int size, byte[] fileContent) {
Kv kvResult = uploadReturnKv(category, filename, size, fileContent);
return RespVo.ok(kvResult);
}
public Kv uploadReturnKv(String category, String filename, int size, byte[] fileContent) {
// 上传文件
long threadId = Thread.currentThread().getId();
if (threadId > 31L) {
threadId %= 31L;
}
if (threadId < 0L) {
threadId = 0L;
}
long id = (new SnowflakeIdGenerator(threadId, 0L)).generateId();
String suffix = FilenameUtils.getSuffix(filename);
String newFilename = id + "." + suffix;
String targetName = category + "/" + newFilename;
Kv kvResult = uploadBytes(id, filename, targetName, fileContent, size, suffix);
return kvResult;
}
public Kv uploadBytes(long id, String filename, String targetName, byte[] fileContent, int size, String suffix) {
String etag = null;
// 示例使用upload方法
try (S3Client client = new AwsS3Config().buildClient();) {
PutObjectResponse response = AwsS3Utils.upload(client, AwsS3Utils.bucketName, targetName, fileContent, suffix);
etag = response.eTag();
} catch (Exception e) {
log.error("Error uploading file to Tencent COS", e);
throw new RuntimeException(e);
}
// Log and save to database
log.info("Uploaded with ETag: {}", etag);
String md5 = Md5Utils.digestHex(fileContent);
Kv kv = Kv.create().set("md5", md5).set("filename", filename).set("file_size", size)
//
.set("platform", "aws s3").set("region_name", AwsS3Utils.regionName).set("bucket_name", AwsS3Utils.bucketName)
//
.set("target_name", targetName).set("file_id", etag);
String userId = TioHttpContext.getUserId();
if (userId != null) {
kv.set("creator", userId);
}
DbJsonBean<Kv> save = DbJsonService.getInstance().save(TableNames.tio_boot_admin_system_upload_file, kv);
String downloadUrl = getUrl(AwsS3Utils.bucketName, targetName);
Kv kvResult = Kv.create().set("id", save.getData().get("id").toString()).set("url", downloadUrl);
return kvResult;
}
public String getUrl(String bucketName, String targetName) {
return String.format(AwsS3Utils.urlFormat, AwsS3Utils.bucketName, targetName);
}
public Kv getUrlById(String id) {
String sql = "select md5,bucket_name,target_name from tio_boot_admin_system_upload_file where id=? and deleted=0";
Record record = Db.findFirst(sql, Long.parseLong(id));
if (record == null) {
return null;
}
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);
return kv;
}
public Kv getUrlByMd5(String md5) {
String sql = "select id,bucket_name,target_name from tio_boot_admin_system_upload_file where md5=? and deleted=0";
Record record = Db.findFirst(sql, md5);
if (record == null) {
return null;
}
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);
return kv;
}
}
添加 action 中接收上传文件
package com.litongjava.open.chat.handler;
import java.util.Map;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.litongjava.data.model.DbJsonBean;
import com.litongjava.data.services.DbJsonService;
import com.litongjava.data.utils.DbJsonBeanUtils;
import com.litongjava.data.utils.KvUtils;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.open.chat.constants.TableNames;
import com.litongjava.open.chat.services.AwsS3StorageService;
import com.litongjava.tio.boot.http.TioHttpContext;
import com.litongjava.tio.boot.utils.TioRequestParamUtils;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.tio.http.common.UploadFile;
import com.litongjava.tio.http.server.model.HttpCors;
import com.litongjava.tio.http.server.util.HttpServerResponseUtils;
import com.litongjava.tio.http.server.util.Resps;
import com.litongjava.tio.utils.resp.RespVo;
public class SystemFileS3Handler {
public HttpResponse upload(HttpRequest request) throws Exception {
HttpResponse httpResponse = TioHttpContext.getResponse();
HttpServerResponseUtils.enableCORS(httpResponse, new HttpCors());
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return httpResponse;
}
UploadFile uploadFile = request.getUploadFile("file");
String category = request.getParam("category");
AwsS3StorageService storageService = Aop.get(AwsS3StorageService.class);
if (uploadFile != null) {
RespVo respVo = storageService.upload(category, uploadFile);
return Resps.json(httpResponse, respVo);
}
return Resps.json(httpResponse, RespVo.ok("Fail"));
}
public HttpResponse getUploadRecordByMd5(HttpRequest request) throws Exception {
HttpResponse httpResponse = TioHttpContext.getResponse();
HttpServerResponseUtils.enableCORS(httpResponse, new HttpCors());
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return httpResponse;
}
// 调用DbJsonService查询数据
Map<String, Object> map = TioRequestParamUtils.getRequestMap(request);
Kv kv = KvUtils.camelToUnderscore(map);
DbJsonBean<Record> jsonBean = DbJsonService.getInstance().get(TableNames.tio_boot_admin_system_upload_file, kv);
DbJsonBean<Kv> dbJsonBean = DbJsonBeanUtils.recordToKv(jsonBean);
return Resps.json(httpResponse,
RespVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg()));
}
public HttpResponse getUrl(HttpRequest request) throws Exception {
HttpResponse httpResponse = TioHttpContext.getResponse();
HttpServerResponseUtils.enableCORS(httpResponse, new HttpCors());
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return httpResponse;
}
AwsS3StorageService storageService = Aop.get(AwsS3StorageService.class);
RespVo respVo = null;
String id = request.getParam("id");
String md5 = request.getParam("md5");
if (StrKit.notBlank(id)) {
// id,md5,name,url,
Kv kv = storageService.getUrlById(id);
if (kv == null) {
respVo = RespVo.fail();
} else {
respVo = RespVo.ok(kv);
}
} else if (StrKit.notBlank(md5)) {
Kv kv = storageService.getUrlByMd5(md5);
if (kv == null) {
respVo = RespVo.fail();
} else {
respVo = RespVo.ok(kv);
}
} else {
respVo = RespVo.fail("id or md5 can not be empty");
}
return Resps.json(httpResponse, respVo);
}
}
配置路由
SystemFileS3Handler systemFileS3Handler = Aop.get(SystemFileS3Handler.class);
r.add("/api/system/file/s3/upload", systemFileS3Handler::upload);
r.add("/api/system/file/s3/md5", systemFileS3Handler::getUploadRecordByMd5);
r.add("/api/system/file/s3/url", systemFileS3Handler::getUrl);
测试
测试上传
curl --location --request POST 'http://localhost:8100/tio-boot-admin/api/system/file/upload/s3' \
--header 'authorization: 123456' \
--header 'Content-Type: multipart/form-data; boundary=--------------------------946279255222128586808179' \
--header 'Cookie: PHPSESSID=f1aa9dbe6c8e4d06aa5bc59d3b7b43b2' \
--form 'file=@"F:\\my_file\\my_photo\\aliyun\\配置.png"' \
--form 'category="sjsu/professor"'
返回数据
{
"code": 1,
"data": {
"id": "394502029835268096",
"url": "https://rumiapp.s3.us-west-1.amazonaws.com/sjsu/professor/394502024734994432.png"
},
"ok": true
}