基于SpringBoot和MySQL實(shí)現(xiàn)圖片CRUD的三種解決方案
引言
在基于 Spring Boot 和 MySQL 開發(fā)的后端程序中,處理圖片的增刪改查(CRUD)通常涉及到兩個(gè)核心部分:存儲(chǔ)圖片路徑信息到數(shù)據(jù)庫(kù)和實(shí)際文件操作(上傳、刪除等)。以下是幾種常見的解決方案,分別詳細(xì)說(shuō)明其使用方法,并對(duì)比優(yōu)缺點(diǎn)
解決方案一:將圖片保存為 BLOB 類型直接存入數(shù)據(jù)庫(kù)
使用方法:
建表語(yǔ)句示例:
CREATE TABLE book_details (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
image BLOB -- 存儲(chǔ)圖片二進(jìn)制數(shù)據(jù)
);
Spring Boot 實(shí)體類定義:
@Entity
public class BookDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Lob
private byte[] image; // 存儲(chǔ)圖片的字節(jié)數(shù)組
// 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());
}
}
優(yōu)點(diǎn):
- 數(shù)據(jù)集中管理,方便備份與遷移。
- 圖片與業(yè)務(wù)數(shù)據(jù)強(qiáng)關(guān)聯(lián),適合小規(guī)模應(yīng)用。
缺點(diǎn):
- 大量圖片存儲(chǔ)會(huì)顯著增加數(shù)據(jù)庫(kù)體積,影響性能。
- 不利于擴(kuò)展,不適合高并發(fā)場(chǎng)景。
解決方案二:將圖片存儲(chǔ)在服務(wù)器文件系統(tǒng),僅保存路徑到數(shù)據(jù)庫(kù)
使用方法:
建表語(yǔ)句示例:
CREATE TABLE book_details (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
image_path VARCHAR(255) -- 存儲(chǔ)圖片路徑
);
Spring Boot 實(shí)體類定義:
@Entity
public class BookDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String imagePath; // 存儲(chǔ)圖片的路徑
// Getters and Setters
}
Controller 示例代碼:
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookRepository bookRepository;
// 文件存儲(chǔ)目錄
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("無(wú)法讀取圖片");
}
}
@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("圖片已更新");
}
}
優(yōu)點(diǎn):
- 減輕數(shù)據(jù)庫(kù)壓力,提升性能。
- 易于擴(kuò)展,支持大量文件存儲(chǔ)。
缺點(diǎn):
- 需要額外管理文件系統(tǒng)或云存儲(chǔ)。
- 文件路徑變更時(shí)需要同步更新數(shù)據(jù)庫(kù)記錄。
解決方案三:使用云存儲(chǔ)服務(wù)(如阿里云 OSS、AWS S3)
使用方法:
建表語(yǔ)句示例:
CREATE TABLE book_details (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
image_url VARCHAR(255) -- 存儲(chǔ)云上的圖片鏈接
);
Spring Boot 實(shí)體類定義:
@Entity
public class BookDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String imageUrl; // 存儲(chǔ)云上的圖片鏈接
// 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()));
// 更新數(shù)據(jù)庫(kù)
book.setTitle(title);
book.setImageUrl("https://bucketName.oss-cn-region.aliyuncs.com/images/" + newFileName);
bookRepository.save(book);
return ResponseEntity.ok("圖片已更新");
}
}
優(yōu)點(diǎn):
- 支持高并發(fā)訪問(wèn),適合大規(guī)模應(yīng)用場(chǎng)景。
- 提供豐富的 API 和工具,便于集成和管理。
缺點(diǎn):
- 增加開發(fā)復(fù)雜度和成本。
- 對(duì)第三方服務(wù)依賴較高,存在潛在風(fēng)險(xiǎn)。
總結(jié)對(duì)比表格
| 方案 | 存儲(chǔ)方式 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|---|
| 方案一:BLOB 存儲(chǔ) | 直接將圖片存入數(shù)據(jù)庫(kù) | 數(shù)據(jù)集中管理,易于備份和遷移 | 影響數(shù)據(jù)庫(kù)性能,不適用于高并發(fā) | 小規(guī)模項(xiàng)目,簡(jiǎn)單功能 |
| 方案二:本地文件系統(tǒng) | 圖片存服務(wù)器,路徑存數(shù)據(jù)庫(kù) | 減輕數(shù)據(jù)庫(kù)壓力,易擴(kuò)展 | 文件管理復(fù)雜,需同步更新路徑 | 中小型項(xiàng)目,單機(jī)部署 |
| 方案三:云存儲(chǔ)服務(wù) | 圖片存云端,URL 存數(shù)據(jù)庫(kù) | 高并發(fā)支持,功能豐富 | 開發(fā)復(fù)雜度高,依賴第三方服務(wù) | 大型項(xiàng)目,分布式架構(gòu) |
根據(jù)你的項(xiàng)目規(guī)模和技術(shù)需求選擇合適的方案,可以平衡開發(fā)效率、性能和可維護(hù)性。
以上就是基于SpringBoot和MySQL實(shí)現(xiàn)圖片CRUD的三種解決方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot MySQL圖片CRUD的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
面試必問(wèn)項(xiàng)之Set實(shí)現(xiàn)類:TreeSet
這篇文章主要介紹了Java TreeSet類的簡(jiǎn)單理解和使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-07-07
JPA在不寫sql的情況下如何實(shí)現(xiàn)模糊查詢
文章介紹了在項(xiàng)目中實(shí)現(xiàn)模糊查詢的幾種方法,包括使用JPA的API、JPQL、QueryByExample和@Query注解,通過(guò)實(shí)現(xiàn)Specification接口和定義接口繼承JpaRepository,可以方便地進(jìn)行單字段和多字段的模糊查詢,文章還提到了BINARY函數(shù)的使用以及查詢結(jié)果的返回2024-11-11
java 方法泛型入?yún)和String的重載關(guān)系詳解
這篇文章主要介紹了java 方法泛型入?yún)和String的重載關(guān)系詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
Java實(shí)例項(xiàng)目零錢通的實(shí)現(xiàn)流程
本篇文章為你帶來(lái)Java的一個(gè)新手實(shí)戰(zhàn)項(xiàng)目,是一個(gè)零錢通系統(tǒng),項(xiàng)目來(lái)自于B站韓順平老師,非常適合新手入門練習(xí),感興趣的朋友快來(lái)看看吧2022-03-03
Java類中this關(guān)鍵字與static關(guān)鍵字的用法解析
這篇文章主要介紹了Java類中this關(guān)鍵字與static關(guān)鍵字的用法解析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Java springboot探究配置文件優(yōu)先級(jí)
在springboot項(xiàng)目中,我們可以通過(guò)在yml文件中設(shè)置變量,再通過(guò)@Value注解來(lái)獲得這個(gè)變量并使用,但如果這個(gè)項(xiàng)目已經(jīng)部署到服務(wù)器上,我們想更改這個(gè)數(shù)據(jù)了需要怎么做呢,其實(shí)在springboot項(xiàng)目中,配置文件是有優(yōu)先級(jí)的2023-04-04

