Firebase Storage
添加一个 Bucket
创建 bucket
Firebase Storage 使用存储桶(Bucket)来组织和存储您的文件。如果您刚创建了 Firebase 项目,Firebase 会为您自动创建一个默认的存储桶。
- 您可以在 Firebase 控制台的 Storage 部分查看和管理您的存储桶。
- 要添加或管理存储桶,请访问Firebase 控制台中的 Storage 部分,并按需创建或配置存储桶。
简单的上传文件示例
配置 bucket
String bucketName = EnvUtils.getStr("BUCKET_NAME");
@SuppressWarnings("deprecation")
FirebaseOptions.Builder builder = new FirebaseOptions.Builder();
String bucketName = EnvUtils.getStr("BUCKET_NAME");
builder.setStorageBucket(bucketName + ".appspot.com");
以下是一个简单的 Java 示例,展示了如何上传文件到 Firebase Storage:
package com.litongjava.open.chat.config;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Before;
import org.junit.Test;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.Storage;
import com.google.firebase.cloud.StorageClient;
import com.litongjava.tio.utils.environment.EnvUtils;
public class FirebaseUploadFileTest {
@Before
public void before() {
EnvUtils.load();
try {
new FirebaseAppConfiguration().config();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testUploadFile() {
Bucket bucket = StorageClient.getInstance().bucket();
String localFileName = "F:\\my_file\\my_photo\\kitty\\kitty-cat.jpg";
Path path = Paths.get(localFileName);
byte[] fileContent = null;
try {
fileContent = Files.readAllBytes(path);
} catch (IOException e) {
e.printStackTrace();
}
String targetName = "public/images/test.png";
BlobId blobId = BlobId.of(bucket.getName(), targetName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("image/png").build();
Storage storage = bucket.getStorage();
Blob blob = storage.create(blobInfo, fileContent);
System.out.println("File uploaded to Firebase Storage: " + blob.getMediaLink());
}
}
输出的地址访问失败
https://storage.googleapis.com/download/storage/v1/b/rumi-bdb43.appspot.com/o/public%2Fimages%2Ftest.png?generation=1719389554988278&alt=media
使用下面的地址访问成功
https://firebasestorage.googleapis.com/v0/b/rumi-bdb43.appspot.com/o/public%2Fimages%2Ftest.png?alt=media
请确保将your-bucket-name.appspot.com
替换为您的实际存储桶名称,path/to/your/local/file.png
替换为您希望上传的文件的本地路径,以及public/images/yourImageName.png
替换为您希望在 Firebase Storage 中存储文件的路径。
将上传信息保存到数据库
将上传信息保存到数据库是上传文件流程的一个重要环节,它不仅能帮助我们跟踪文件的上传记录,还能为文件的管理、检索提供便利。在本节中,我们将通过一个示例,详细介绍如何在 Java 应用中实现这一功能,并将文件上传信息保存到数据库。
数据库表设计
参考 24.1
文件上传处理逻辑
- 在文件上传处理的逻辑中,我们首先将文件上传到 Firebase Storage,然后将上传的文件信息保存到数据库中。下面是处理文件上传和保存信息到数据库的 Java 代码示例.
- 对于需要获取上传文件的 URL 以供前端下载或展示的情况,我们可以通过查询数据库获取到文件的
bucket_name
和target_name
,进而构造出文件的访问 URL:
package com.litongjava.tio.boot.admin.services;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.Storage;
import com.google.firebase.cloud.StorageClient;
import com.jfinal.kit.Kv;
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.tio.boot.admin.costants.TableNames;
import com.litongjava.tio.http.common.UploadFile;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.http.ContentTypeUtils;
import com.litongjava.tio.utils.resp.RespBodyVo;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.crypto.digest.MD5;
import lombok.extern.slf4j.Slf4j;
/**
* Created by Tong Li <https://github.com/litongjava>
*/
@Slf4j
public class GoogleStorageService {
String bucketName = EnvUtils.getStr("BUCKET_NAME");
public RespBodyVo uploadImageToGoogle(UploadFile uploadFile) {
String filename = uploadFile.getName();
String suffix = FileNameUtil.getSuffix(filename);
String contentType = ContentTypeUtils.getContentType(suffix);
byte[] fileContent = uploadFile.getData();
//int size = uploadFile.getSize();
return uploadImageBytes(fileContent, filename, suffix, contentType);
}
public RespBodyVo uploadImageBytes(byte[] fileContent, String filename, String suffix, String contentType) {
return uploadBytes(fileContent, filename, suffix, "public/images", contentType);
}
public RespBodyVo uploadBytes(byte[] fileContent, String filename, String suffix, String folderName,
String contentType) {
// 上传文件
long threadId = Thread.currentThread().getId();
if (threadId > 31L) {
threadId %= 31L;
}
if (threadId < 0L) {
threadId = 0L;
}
long id = (new SnowflakeIdGenerator(threadId, 0L)).generateId();
String newFilename = id + "." + suffix;
String targetName = folderName + "/" + newFilename;
uploadBytesToGoogle(fileContent, targetName, contentType);
// 存入到数据库
String md5 = MD5.create().digestHex(fileContent);
Kv kv = Kv.create();
kv.set("md5", md5);
kv.set("filename", filename);
kv.set("file_size", fileContent.length);
kv.set("platform", "google");
kv.set("bucket_name", bucketName);
String replaceTargetName = replaceTargetName(targetName);
kv.set("target_name", replaceTargetName);
kv.set("file_id", id);
DbJsonBean<Kv> save = DbJsonService.getInstance().save(TableNames.tio_boot_admin_system_upload_file, kv);
// 下载地址
String downloadUrl = getUrl(bucketName, replaceTargetName);
Kv kv1 = Kv.create();
kv1.set("id", save.getData().get("id") + "");
kv1.set("url", downloadUrl);
// 返回RespVo
return RespBodyVo.ok(kv1);
}
public Blob uploadBytesToGoogle(byte[] fileContent, String targetName, String contentType) {
Bucket bucket = StorageClient.getInstance().bucket();
BlobId blobId = BlobId.of(bucket.getName(), targetName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType(contentType).build();
Storage storage = bucket.getStorage();
Blob blob = storage.create(blobInfo, fileContent);
log.info("blob:{}", blob);
return blob;
}
private String replaceTargetName(String targetName) {
return targetName.replace("/", "%2F");
}
public String getUrlByFileId(long fileId) {
String sql = "select bucket_name,target_name from " + TableNames.tio_boot_admin_system_upload_file + " where id=?";
Record record = Db.findFirst(sql, fileId);
return getUrl(record.getStr("bucket_name"), record.getStr("target_name"));
}
public String getUrl(String name, String targetName) {
String template = "https://firebasestorage.googleapis.com/v0/b/%s.appspot.com/o/%s?alt=media";
return String.format(template, name, targetName);
}
}
handler
server 编写完成后对外提供一个 handler,为前端提供 2 个 endpont 用于上传文件和获取文件地址
package com.litongjava.tio.boot.admin.handler;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.tio.boot.admin.services.GoogleStorageService;
import com.litongjava.tio.boot.http.TioControllerContext;
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.RespBodyVo;
public class SystemFileFirebaseHandler {
public HttpResponse upload(HttpRequest request) throws Exception {
HttpResponse httpResponse = TioControllerContext.getResponse();
HttpServerResponseUtils.enableCORS(httpResponse, new HttpCors());
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return httpResponse;
}
UploadFile uploadFile = request.getUploadFile("file");
GoogleStorageService googleStorageService = Aop.get(GoogleStorageService.class);
if (uploadFile != null) {
RespBodyVo respVo = googleStorageService.uploadImageToGoogle(uploadFile);
return Resps.json(httpResponse, respVo);
}
return Resps.json(httpResponse, RespBodyVo.ok("Fail"));
}
public HttpResponse getUrl(HttpRequest request) {
HttpResponse httpResponse = TioControllerContext.getResponse();
HttpServerResponseUtils.enableCORS(httpResponse, new HttpCors());
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return httpResponse;
}
long fileId = Long.parseLong(request.getParam("id"));
GoogleStorageService googleStorageService = Aop.get(GoogleStorageService.class);
String url = googleStorageService.getUrlByFileId(fileId);
return Resps.json(httpResponse, RespBodyVo.ok(url));
}
}
注册 handler
HttpReqeustSimpleHandlerRoute r = TioBootServer.me().getHttpReqeustSimpleHandlerRoute();
SystemFileFirebaseHandler systemFileFirebaseHandler = Aop.get(SystemFileFirebaseHandler.class);
r.add("/api/system/file/uploadToGoogle", systemFileFirebaseHandler::upload);
r.add("/api/system/file/firebase/getUrl", systemFileFirebaseHandler::getUrl);
http api
接下来,我们将详细介绍如何通过 API 接口上传图片到 Google Firebase Storage,并如何获取上传图片的 URL。我们会使用两个 RESTful API 接口:一个用于上传图片,另一个用于获取图片的访问 URL。
1. 上传图片到 Google Firebase Storage
API 端点
POST /api/system/file/uploadToGoogle
请求
要上传图片,您需要使用multipart/form-data
类型的 POST 请求,并将图片文件作为请求的一部分。以下是使用curl
命令上传图片的示例:
curl --location --request POST 'https://ip/tio-boot-admin/api/system/file/uploadToGoogle' \
--header 'Content-Type: multipart/form-data; boundary=--------------------------416606819414649391318961' \
--form 'file=@"C:\\Users\\Administrator\\Pictures\\gpt-translate.png"'
请确保将ip
替换为您的服务器地址,以及调整文件路径至您的图片位置。
响应
上传成功后,服务器会返回一个包含图片 ID 和访问 URL 的 JSON 响应:
{
"code": 1,
"data": {
"id": "368264036325801984",
"url": "https://firebasestorage.googleapis.com/v0/b/{bucketName}/o/public%2Fimages%2F368264030806097920.png?alt=media"
},
"ok": true
}
id
是数据库中记录的唯一标识符,url
是图片在 Google Firebase Storage 的访问 URL。
2. 获取图片的 URL
一旦图片上传到 Firebase Storage,您可能需要根据图片的 ID 获取其访问 URL。
API 端点
GET /api/system/file/firebase/getUrl
请求
通过将图片 ID 作为查询参数传递,您可以请求图片的 URL。以下是使用curl
获取图片 URL 的示例:
curl --location --request GET 'https://ip/tio-boot-admin/api/system/file/getGoogleFileUrl?id=368264036325801984'
同样,请确保将ip
替换为您的服务器地址,并使用正确的图片 ID 作为请求参数。
响应
服务器将返回一个包含图片 URL 的 JSON 响应:
{
"code": 1,
"url": "https://firebasestorage.googleapis.com/v0/b/{bucketName}/o/public%2Fimages%2F368264030806097920.png?alt=media",
"ok": true
}
这个 URL 可以直接用于 Web 页面或移动应用中,以展示或下载图片。
总结
通过上述两个 API 端点,我们能够实现一个完整的图片上传与检索流程。上传接口允许用户将图片上传到 Google Firebase Storage,并将上传信息保存到数据库中。而获取 URL 接口则提供了一种方式,通过数据库中保存的 ID 来检索并获取图片的访问 URL。这样的设计不仅简化了前端的工作流程,也提高了后端数据管理的效率和安全性。希望这篇文档能够帮助您更好地理解和实现基于 Google Firebase Storage 的图片上传与管理功能。