我花了3块6,给自己搞了一个在线图床功能
快来薅羊毛:轻量云对象存储
随着社交媒体和图片分享平台的广泛应用,图床(即图片托管服务)成为了开发者和内容创作者不可或缺的一部分。图床允许用户将图片上传到云端存储,并通过 URL 进行访问,减少了用户设备上的存储空间占用,同时提供了高效的图片管理和访问方式。腾讯云的轻量对象存储(COS)为开发者提供了一个简单且高效的图床解决方案,本文将介绍如何使用腾讯云 COS 构建一个完整的在线图床功能。
1. 什么是图床
图床(Image Hosting Service)是指将图片存储在云端服务器上,通过 HTTP 或 HTTPS 协议提供图片访问链接的服务。图床的核心功能包括:通过图床,用户无需再将图片存储在本地服务器上,大大提高了系统的扩展性和图片访问速度。
- 图片上传:用户可以将图片上传到云端。
- 图片存储:图片保存在云存储上,并根据文件名生成唯一的文件路径或 URL。
- 图片访问:用户通过 URL 来访问已上传的图片。
2. 腾讯云轻量对象存储 COS
腾讯云 COS(Cloud Object Storage)是腾讯云提供的一种云存储服务,适合存储海量非结构化数据,如图片、视频、日志等。其具备以下特点:
- 高可靠性:COS 提供多副本存储机制,确保数据的高可用性和持久性。
- 低成本:COS 提供按需计费服务,用户只需为实际存储和流量付费,适合各种规模的应用场景。
- 高性能:COS 提供快速的数据访问能力,特别适合图片和视频等大数据量的存储和访问。
- 易于集成:腾讯云提供丰富的 SDK 和 API,使得 COS 可以方便地与现有应用程序集成。
3. 构建图床的需求
一个完整的在线图床功能需要满足以下需求:在实现这些需求之前,我们需要进行一些基本的准备工作。
- 用户注册与认证:用户需要进行身份验证,以确保图片上传和管理是私密的。
- 图片上传:支持上传单张或多张图片,且上传的图片可以按需生成 URL 地址。
- 图片存储:上传的图片会存储在腾讯云 COS 中,支持大文件存储和快速访问。
- 图片管理:用户可以查看已上传的图片,支持删除或更新图片。
- 图片访问:通过 URL 访问已上传的图片,支持前端展示。
4. 准备工作
4.1 注册腾讯云账号
首先,前往 腾讯云官网 注册一个腾讯云账号。如果已有账号,可以直接登录。
4.2 创建腾讯云 COS 存储桶
- 登录腾讯云管理控制台,找到 COS 服务。
- 创建一个新的存储桶,并设置访问权限(公共读或私有读等)。
- 获取 AppID、SecretID 和 SecretKey,这些信息将用于后续的 SDK 配置和鉴权。
4.3 配置环境
为了在 Java 项目中使用腾讯云 COS,需要导入腾讯云的 SDK。以下是添加依赖的方式。
使用 Maven 管理依赖
在 pom.xml
文件中加入以下依赖:
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.54</version>
</dependency>
配置腾讯云 COS 参数
在 application.properties
或 application.yml
中配置腾讯云 COS 相关参数:
tencent:
cos:
secretId: xxxxxxx
secretKey: xxxxxxxxxxxxxxxxx
region: ap-nanjing
bucketName: number-89757-1259242531
5. 后端实现
5.1 创建实体类
首先,我们需要创建一个实体类 Image
来存储图床中的图片信息,包括图片的 URL、文件名、文件大小等。
package com.example.demo.entity;
// 响应 DTO
public class ResponseDto {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
5.3 创建 COS 服务
接下来,我们创建一个 CosService
类来封装所有与腾讯云 COS 相关的操作,包括上传、删除、获取文件等功能。
package com.example.demo.service;
import com.example.demo.controller.CosImageController;
import com.example.demo.entity.ResponseDto;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.model.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Service
public class CosService {
@Value("${tencent.cos.secretId}")
private String secretId;
@Value("${tencent.cos.secretKey}")
private String secretKey;
@Value("${tencent.cos.region}")
private String region;
@Value("${tencent.cos.bucketName}")
private String bucketName;
/**
* 上传文件到 COS
*
* @param file 上传的文件
* @param key 上传到 COS 的对象键
* @return 文件的 URL 地址
* @throws IOException
*/
public String uploadFile(File file, String key) throws IOException {
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
ClientConfig clientConfig = new ClientConfig(new Region(region));
COSClient cosClient = new COSClient(cred, clientConfig);
// // 创建上传请求
// PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
// // 执行上传
// cosClient.putObject(putObjectRequest);
FileInputStream fileInputStream = new FileInputStream(file);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, fileInputStream, new ObjectMetadata());
cosClient.putObject(putObjectRequest);
// 生成文件的 URL 地址
return "https://" + bucketName + ".cos." + region + ".myqcloud.com/" + key;
}
/**
* 删除 COS 中的文件
*
* @param key 文件的对象键
*/
public void deleteFile(String key) {
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
ClientConfig clientConfig = new ClientConfig(new Region(region));
COSClient cosClient = new COSClient(cred, clientConfig);
cosClient.deleteObject(bucketName, key);
}
/**
* 获取 COS 中所有文件的列表
*
* @return 文件列表
*/
public List<ResponseDto> listFiles() {
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
ClientConfig clientConfig = new ClientConfig(new Region(region));
COSClient cosClient = new COSClient(cred, clientConfig);
ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
.withBucketName(bucketName)
.withPrefix(""); // 可以设置前缀来过滤文件
ObjectListing objectListing = cosClient.listObjects(listObjectsRequest);
List<COSObjectSummary> aa = objectListing.getObjectSummaries();
List<ResponseDto> result = new ArrayList<>();
for (COSObjectSummary vv :aa){
ResponseDto dd = new ResponseDto();
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, vv.getKey());
// req.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); // 设置URL有效期为1小时
URL signedUrl = cosClient.generatePresignedUrl(req);
dd.setUrl(signedUrl.toString());
result.add(dd);
}
return result;
}
/**
* 转换 MultipartFile 为 File 对象
*
* @param file 上传的 MultipartFile 文件
* @return 转换后的 File 对象
* @throws IOException
*/
public File convertMultiPartToFile(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
file.transferTo(convFile);
return convFile;
}
/**
* 关闭 COS 客户端
*/
public void shutdown() {
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
ClientConfig clientConfig = new ClientConfig(new Region(region));
COSClient cosClient = new COSClient(cred, clientConfig);
cosClient.shutdown();
}
}
5.4 创建控制器
控制器 ImageController
处理前端的请求,例如上传图片、列出图片、删除图片等。
package com.example.demo.controller;
import com.example.demo.entity.ResponseDto;
import com.example.demo.service.CosService;
import com.qcloud.cos.model.COSObjectSummary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.http.ResponseEntity;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
@Controller
public class CosImageController {
@Autowired
private CosService cosService; // 调用 COS 服务
// 图片存储路径
private static final String UPLOAD_DIR = "src/main/resources/static/uploads/";
@GetMapping("/")
public String ocrPage() {
return "cos"; // 返回上传页面视图
}
// 上传图片
@PostMapping("/image/upload")
public String uploadImage(@RequestParam("file") MultipartFile file) throws IOException {
// 将上传的文件保存到 COS
// 确保上传目录存在
Path uploadPath = Paths.get(UPLOAD_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 获取文件输入流并存储文件
Path filePath = uploadPath.resolve(file.getOriginalFilename());
try (InputStream inputStream = file.getInputStream()) {
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
}
try {
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
// String fileUrl = cosService.uploadFile(convertMultiPartToFile(file), fileName);
String fileUrl = cosService.uploadFile(filePath.toFile(), fileName);
System.out.printf(fileUrl);
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/";
}
// 获取已上传的图片列表
@GetMapping("/image/list")
@ResponseBody
public List<ResponseDto> getImageList() {
// 这里假设已经存储了图片的 URL 和 ID
List<ResponseDto> sss = cosService.listFiles();
return sss; // 你可以从数据库或 COS 获取图片信息
}
// 删除图片
@DeleteMapping("/image/delete/{id}")
public ResponseEntity<?> deleteImage(@PathVariable String id) {
// 根据 ID 删除文件
cosService.deleteFile(id); // 你可以根据文件 ID 从 COS 删除文件
return ResponseEntity.ok().build();
}
// 辅助方法:转换 MultipartFile 为 File
private File convertMultiPartToFile(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
file.transferTo(convFile);
return convFile;
}
// 图片信息 DTO
public static class ImageDto {
private String id;
private String url;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
6. 前端实现
前端部分实现图床的用户界面,支持图片上传和展示。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图床管理</title>
<!-- 引入 Bootstrap 样式 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.image-preview {
max-width: 100px;
max-height: 100px;
object-fit: cover;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">图床管理</h1>
<!-- 图片上传部分 -->
<div class="mb-4">
<h3>上传图片</h3>
<form action="/image/upload" method="post" enctype="multipart/form-data">
<input type="file" class="form-control" name="file" required>
<button type="submit" class="btn btn-primary">上传</button>
</form>
</div>
<!-- 已上传的图片列表 -->
<h3>已上传图片</h3>
<div id="imageList" class="row"></div>
</div>
<!-- 引入 jQuery 和 Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// 加载已上传的图片列表
function loadImageList() {
$.ajax({
url: '/image/list', // 后端获取图片列表的接口
type: 'GET',
success: function (images) {
$('#imageList').empty(); // 清空当前列表
images.forEach(function (image) {
$('#imageList').append(`
<div class="col-md-3 mb-3">
<div class="card">
<img src="${image.url}" class="card-img-top" alt="Image" style="height: 150px; object-fit: cover;">
<div class="card-body">
<a href="${image.url}" target="_blank" class="btn btn-primary btn-sm">查看</a>
<button class="btn btn-danger btn-sm delete-btn" data-id="${image.id}">删除</button>
</div>
</div>
</div>
`);
});
},
error: function (xhr, status, error) {
alert("加载图片列表失败:" + error);
}
});
}
// 删除图片
$(document).on('click', '.delete-btn', function () {
var imageId = $(this).data('id');
$.ajax({
url: '/image/delete/' + imageId, // 后端删除图片的接口
type: 'DELETE',
success: function () {
loadImageList(); // 更新图片列表
},
error: function (xhr, status, error) {
alert("删除失败:" + error);
}
});
});
// 初始化时加载图片列表
loadImageList();
</script>
</body>
</html>
7. 效果展示
我们使用了 Spring Boot 构建后端,腾讯云 COS 作为存储服务,并实现了图片上传、删除和展示等功能。通过前端 HTML 页面,我们实现了图片上传和查看功能。通过这种方式,我们不仅可以实现一个高效、可靠的图床系统,还能够充分利用腾讯云的云存储优势,提高系统的性能和可扩展性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?