基于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的资料请关注脚本之家其它相关文章!

相关文章

  • java线程中断 interrupt 和 LockSupport解析

    java线程中断 interrupt 和 LockSupport解析

    这篇文章主要为大家介绍了java线程中断 interrupt 和 LockSupport示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Leetcode常见链表问题及代码示例

    Leetcode常见链表问题及代码示例

    这篇文章主要介绍了Leetcode常见链表问题及代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • 浅谈一下Java中的几种JVM级别的锁

    浅谈一下Java中的几种JVM级别的锁

    这篇文章主要介绍了浅谈一下Java中的几种JVM级别的锁,当存在安全漏洞时,也必须有相应的防护措施。顺应这种趋势,虚拟"锁"被发明出来,以解决线程的安全问题。在这篇文章中,我们将研究多年来出现的 Java 中几种典型的 JVM 级锁,需要的朋友可以参考下
    2023-08-08
  • Intellij IDEA的一些调试技巧(小结)

    Intellij IDEA的一些调试技巧(小结)

    本篇文章主要介绍了Intellij IDEA的一些调试技巧(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 一文带你探索Java中的通配符与泛型

    一文带你探索Java中的通配符与泛型

    Java 语言中的泛型是一种强大的特性,它可以将类型参数化,使得代码更具通用性和安全性,本文将深入讲解 Java 通配符和泛型,有需要的小伙伴可以了解下
    2023-12-12
  • 详解在Java程序中运用Redis缓存对象的方法

    详解在Java程序中运用Redis缓存对象的方法

    这篇文章主要介绍了在Java程序中运用Redis缓存对象的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 关于rocketmq中日志文件路径的配置指南

    关于rocketmq中日志文件路径的配置指南

    rocketmq是java编写的,也就是可以指定启动参数,下面这篇文章主要给大家介绍了关于rocketmq中日志文件路径的配置指南,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-04-04
  • mybatis的增删改查运用方式

    mybatis的增删改查运用方式

    这篇文章主要介绍了mybatis的增删改查运用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • java书店系统毕业设计 用户模块(2)

    java书店系统毕业设计 用户模块(2)

    这篇文章主要介绍了java书店系统毕业设计,第二步系统总体设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Spring运行环境Environment的解析

    Spring运行环境Environment的解析

    本文主要介绍了Spring运行环境Environment的解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08

最新评论