基于SpringBoot和MySQL实现图片CRUD的三种解决方案

 更新时间:2025年08月07日 09:30:53   作者:爱的叹息  
在基于 Spring Boot 和 MySQL 开发的后端程序中,处理图片的增删改查(CRUD)通常涉及到两个核心部分:存储图片路径信息到数据库和实际文件操作(上传、删除等),以下是几种常见的解决方案,分别详细说明其使用方法,并对比优缺点,需要的朋友可以参考下

引言

在基于 Spring Boot 和 MySQL 开发的后端程序中,处理图片的增删改查(CRUD)通常涉及到两个核心部分:存储图片路径信息到数据库实际文件操作(上传、删除等)。以下是几种常见的解决方案,分别详细说明其使用方法,并对比优缺点

解决方案一:将图片保存为 BLOB 类型直接存入数据库

使用方法:

建表语句示例:

CREATE TABLE book_details (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    image BLOB  -- 存储图片二进制数据
);

Spring Boot 实体类定义:

@Entity
public class BookDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    @Lob
    private byte[] image; // 存储图片的字节数组

    // Getters and Setters
}

Controller 示例代码:

@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookRepository bookRepository;

    @PostMapping("/upload")
    public ResponseEntity<String> uploadBookImage(@RequestParam("title") String title, 
                                                 @RequestParam("file") MultipartFile file) throws IOException {
        BookDetail book = new BookDetail();
        book.setTitle(title);
        book.setImage(file.getBytes());
        bookRepository.save(book);
        return ResponseEntity.ok("图片已上传");
    }

    @GetMapping("/image/{id}")
    public ResponseEntity<byte[]> getBookImage(@PathVariable Long id) {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(book.getImage());
    }
}

优点:

  • 数据集中管理,方便备份与迁移。
  • 图片与业务数据强关联,适合小规模应用。

缺点:

  • 大量图片存储会显著增加数据库体积,影响性能。
  • 不利于扩展,不适合高并发场景。

解决方案二:将图片存储在服务器文件系统,仅保存路径到数据库

使用方法:

建表语句示例:

CREATE TABLE book_details (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    image_path VARCHAR(255)  -- 存储图片路径
);

Spring Boot 实体类定义:

@Entity
public class BookDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String imagePath; // 存储图片的路径

    // Getters and Setters
}

Controller 示例代码:

@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookRepository bookRepository;

    // 文件存储目录
    private static final String FILE_DIR = "D:/images/";

    @PostMapping("/upload")
    public ResponseEntity<String> uploadBookImage(@RequestParam("title") String title, 
                                                 @RequestParam("file") MultipartFile file) throws IOException {
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        Path filePath = Paths.get(FILE_DIR, fileName);
        Files.write(filePath, file.getBytes());

        BookDetail book = new BookDetail();
        book.setTitle(title);
        book.setImagePath(filePath.toString());
        bookRepository.save(book);

        return ResponseEntity.ok("图片已上传");
    }

    @GetMapping("/image/{id}")
    public ResponseEntity<Resource> getBookImage(@PathVariable Long id) throws IOException {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        Path path = Paths.get(book.getImagePath());
        Resource resource = new UrlResource(path.toUri());

        if (resource.exists() || resource.isReadable()) {
            return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(resource);
        } else {
            throw new RuntimeException("无法读取图片");
        }
    }

    @DeleteMapping("/delete/{id}")
    public ResponseEntity<String> deleteBookImage(@PathVariable Long id) throws IOException {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        Path path = Paths.get(book.getImagePath());
        if (Files.exists(path)) {
            Files.delete(path);
        }
        bookRepository.delete(book);
        return ResponseEntity.ok("图片已删除");
    }

    @PutMapping("/update/{id}")
    public ResponseEntity<String> updateBookImage(@PathVariable Long id, 
                                              @RequestParam("title") String title, 
                                              @RequestParam("file") MultipartFile file) throws IOException {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        Path oldPath = Paths.get(book.getImagePath());
        if (Files.exists(oldPath)) {
            Files.delete(oldPath);
        }

        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        Path newPath = Paths.get(FILE_DIR, fileName);
        Files.write(newPath, file.getBytes());

        book.setTitle(title);
        book.setImagePath(newPath.toString());
        bookRepository.save(book);

        return ResponseEntity.ok("图片已更新");
    }
}

优点:

  • 减轻数据库压力,提升性能。
  • 易于扩展,支持大量文件存储。

缺点:

  • 需要额外管理文件系统或云存储。
  • 文件路径变更时需要同步更新数据库记录。

解决方案三:使用云存储服务(如阿里云 OSS、AWS S3)

使用方法:

建表语句示例:

CREATE TABLE book_details (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    image_url VARCHAR(255)  -- 存储云上的图片链接
);

Spring Boot 实体类定义:

@Entity
public class BookDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String imageUrl; // 存储云上的图片链接

    // Getters and Setters
}

Controller 示例代码(以阿里云 OSS 为例):

@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookRepository bookRepository;

    // 初始化 OSS 客户端
    private OSS ossClient = new OSSClientBuilder().build("endpoint", "accessKeyId", "accessKeySecret");

    @PostMapping("/upload")
    public ResponseEntity<String> uploadBookImage(@RequestParam("title") String title, 
                                                 @RequestParam("file") MultipartFile file) throws IOException {
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        ossClient.putObject("bucketName", "images/" + fileName, new ByteArrayInputStream(file.getBytes()));

        BookDetail book = new BookDetail();
        book.setTitle(title);
        book.setImageUrl("https://bucketName.oss-cn-region.aliyuncs.com/images/" + fileName);
        bookRepository.save(book);

        return ResponseEntity.ok("图片已上传");
    }

    @DeleteMapping("/delete/{id}")
    public ResponseEntity<String> deleteBookImage(@PathVariable Long id) {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        String url = book.getImageUrl();
        String objectName = url.replace("https://bucketName.oss-cn-region.aliyuncs.com/", "");
        ossClient.deleteObject("bucketName", objectName);
        bookRepository.delete(book);
        return ResponseEntity.ok("图片已删除");
    }

    @PutMapping("/update/{id}")
    public ResponseEntity<String> updateBookImage(@PathVariable Long id, 
                                              @RequestParam("title") String title, 
                                              @RequestParam("file") MultipartFile file) throws IOException {
        BookDetail book = bookRepository.findById(id).orElseThrow();
        String oldUrl = book.getImageUrl();
        String oldObjectName = oldUrl.replace("https://bucketName.oss-cn-region.aliyuncs.com/", "");

        // 删除旧图片
        ossClient.deleteObject("bucketName", oldObjectName);

        // 上传新图片
        String newFileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        ossClient.putObject("bucketName", "images/" + newFileName, new ByteArrayInputStream(file.getBytes()));

        // 更新数据库
        book.setTitle(title);
        book.setImageUrl("https://bucketName.oss-cn-region.aliyuncs.com/images/" + newFileName);
        bookRepository.save(book);

        return ResponseEntity.ok("图片已更新");
    }
}

优点:

  • 支持高并发访问,适合大规模应用场景。
  • 提供丰富的 API 和工具,便于集成和管理。

缺点:

  • 增加开发复杂度和成本。
  • 对第三方服务依赖较高,存在潜在风险。

总结对比表格

方案存储方式优点缺点适用场景
方案一:BLOB 存储直接将图片存入数据库数据集中管理,易于备份和迁移影响数据库性能,不适用于高并发小规模项目,简单功能
方案二:本地文件系统图片存服务器,路径存数据库减轻数据库压力,易扩展文件管理复杂,需同步更新路径中小型项目,单机部署
方案三:云存储服务图片存云端,URL 存数据库高并发支持,功能丰富开发复杂度高,依赖第三方服务大型项目,分布式架构

根据你的项目规模和技术需求选择合适的方案,可以平衡开发效率、性能和可维护性。

以上就是基于SpringBoot和MySQL实现图片CRUD的三种解决方案的详细内容,更多关于SpringBoot MySQL图片CRUD的资料请关注脚本之家其它相关文章!

相关文章

  • spring boot中配置hikari连接池属性方式

    spring boot中配置hikari连接池属性方式

    这篇文章主要介绍了spring boot中配置hikari连接池属性方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 面试必问项之Set实现类:TreeSet

    面试必问项之Set实现类:TreeSet

    这篇文章主要介绍了Java TreeSet类的简单理解和使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-07-07
  • JPA在不写sql的情况下如何实现模糊查询

    JPA在不写sql的情况下如何实现模糊查询

    文章介绍了在项目中实现模糊查询的几种方法,包括使用JPA的API、JPQL、QueryByExample和@Query注解,通过实现Specification接口和定义接口继承JpaRepository,可以方便地进行单字段和多字段的模糊查询,文章还提到了BINARY函数的使用以及查询结果的返回
    2024-11-11
  • Java C++题解eetcode940不同的子序列 II

    Java C++题解eetcode940不同的子序列 II

    这篇文章主要为大家介绍了Java C++题解eetcode940不同的子序列 II实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • java 方法泛型入参T和String的重载关系详解

    java 方法泛型入参T和String的重载关系详解

    这篇文章主要介绍了java 方法泛型入参T和String的重载关系详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Java实例项目零钱通的实现流程

    Java实例项目零钱通的实现流程

    本篇文章为你带来Java的一个新手实战项目,是一个零钱通系统,项目来自于B站韩顺平老师,非常适合新手入门练习,感兴趣的朋友快来看看吧
    2022-03-03
  • 详解Java设计模式之备忘录模式的使用

    详解Java设计模式之备忘录模式的使用

    这篇文章主要介绍了Java设计模式之备忘录模式的使用,备忘录模式中的发起者和管需要的朋友可以参考下
    2016-02-02
  • Java类中this关键字与static关键字的用法解析

    Java类中this关键字与static关键字的用法解析

    这篇文章主要介绍了Java类中this关键字与static关键字的用法解析,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • Java springboot探究配置文件优先级

    Java springboot探究配置文件优先级

    在springboot项目中,我们可以通过在yml文件中设置变量,再通过@Value注解来获得这个变量并使用,但如果这个项目已经部署到服务器上,我们想更改这个数据了需要怎么做呢,其实在springboot项目中,配置文件是有优先级的
    2023-04-04
  • Java 容器类源码详解 Set

    Java 容器类源码详解 Set

    这篇文章主要介绍了Java 容器类源码详解 Set,Set 表示由无重复对象组成的集合,也是集合框架中重要的一种集合类型,直接扩展自 Collection 接口。,需要的朋友可以参考下
    2019-06-06

最新评论