我花了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. 构建图床的需求

一个完整的在线图床功能需要满足以下需求:在实现这些需求之前,我们需要进行一些基本的准备工作。

  1. 用户注册与认证:用户需要进行身份验证,以确保图片上传和管理是私密的。
  2. 图片上传:支持上传单张或多张图片,且上传的图片可以按需生成 URL 地址。
  3. 图片存储:上传的图片会存储在腾讯云 COS 中,支持大文件存储和快速访问。
  4. 图片管理:用户可以查看已上传的图片,支持删除或更新图片。
  5. 图片访问:通过 URL 访问已上传的图片,支持前端展示。

4. 准备工作

4.1 注册腾讯云账号

首先,前往 腾讯云官网 注册一个腾讯云账号。如果已有账号,可以直接登录。

4.2 创建腾讯云 COS 存储桶

  1. 登录腾讯云管理控制台,找到 COS 服务。
  2. 创建一个新的存储桶,并设置访问权限(公共读或私有读等)。
  3. 获取 AppIDSecretIDSecretKey,这些信息将用于后续的 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.propertiesapplication.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 页面,我们实现了图片上传和查看功能。通过这种方式,我们不仅可以实现一个高效、可靠的图床系统,还能够充分利用腾讯云的云存储优势,提高系统的性能和可扩展性。

posted @   张不惑  阅读(69)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示