前置背景
现在我们做的网站,一般都是需要处理图片,视频等多媒体资源的,那你知道一般的系统是怎么处理图片的吗?下面是我目前了解到的,如果各位看官还知道别的方法,欢迎补充哦!
-
服务器文件系统存储:最常见的方式是将图片存储在服务器的文件系统中,通常是在特定的文件夹中。每个图片文件都有一个唯一的文件路径,以便服务器和网站应用程序能够访问和提供这些图片。这就是常见的静态资源访问啦。
-
云存储:许多网站使用云存储服务,这种方式具有伸缩性和可靠性,同时减轻了服务器的负担。这种就是转成外链的形式了。
-
内容分发网络(CDN):有些网站使用CDN来存储和分发图片。CDN是一种分布式网络,它将内容存储在多个地理位置的服务器上,以提供更快的访问速度和更好的性能。图片通常存储在CDN上,而不是网站的原始服务器上。这种也是转成外链的形式了
-
数据库存储:虽然不太常见,但有些网站可能会将图片存储在数据库中,以便更好地管理和检索图片。这通常发生在小型网站或需要强大图片管理功能的应用程序中。
上面四个方法处理后的图片最后在数据库储存的形式无非就是两种---外链(url的形式)还有blob类型存储。
今天重点来介绍一下blob类型在数据库读写图片~
写图片
提前准备好实体类和数据库的映射,这里关键的是图片对应的字段在数据库中的数据类型是BLOB/LONGBLOB。在实体类的类型可以是byte[] / String。(方便前端直接显示)
BLOB 是用于存储二进制数据的通用类型,但它有一定的大小限制。
存储的二进制数据的大小在数据库管理系统中可能会有一些限制,通常在 64KB 到 4GB 之间,具体取决于数据库的实现和配置。
LONGBLOB 是 BLOB 的一个变种,它用于存储更大的二进制数据。通常,LONGBLOB 可以存储比 BLOB 更大的数据,范围通常在 4GB 到 2^32-1 之间,具体取决于数据库管理系统。
下面是关键代码。
Image image = new Image();
byte[] imageData = file.getBytes();
// 获取文件扩展名
String originalFileName = file.getOriginalFilename();
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
// 添加前缀和类型
String prefixedBase64Data = "data:image/" + fileExtension + ";base64," + Base64.getEncoder().encodeToString(imageData);
//转换成字节流
byte[] prefixedImageData = prefixedBase64Data.getBytes(StandardCharsets.UTF_8);
image.setUrl(prefixedImageData);
这里提前添加前缀是因为后续读的时候返回给前端,前端可以直接赋值给image的src属性。
完整代码
下面附上完整的代码。有需要的朋友可以直接拿去用
实体类Image
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
/*
* 上传图片备份到数据库的实体类对象
* */
@Data
@NoArgsConstructor
@Table(name = "t_images")
@Entity
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "image_id")
private Long imageId;
private String name;
private String type;
private byte[] url;
private Boolean status;
}
service层
import com.sky.image.entitys.Image;
import com.sky.image.vos.ImageSuccessVO;
import com.sky.mapper.ImageMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Service
public class FileUploadServiceImpl {
@Autowired
private ImageMapper imageMapper;
//TODO 写一篇博客总结一下如何上传图片到数据库(或者说如何在系统中处理文件上传)
public ImageSuccessVO handleFileUpload(MultipartFile file) throws IOException {
try {
ImageSuccessVO imageSuccessVO= new ImageSuccessVO(0,null );
if (!file.isEmpty()) {
Image image = new Image();
byte[] imageData = file.getBytes();
// 获取文件扩展名
String originalFileName = file.getOriginalFilename();
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
// 添加前缀和类型
String prefixedBase64Data = "data:image/" + fileExtension + ";base64," + Base64.getEncoder().encodeToString(imageData);
//转换成字节流
byte[] prefixedImageData = prefixedBase64Data.getBytes(StandardCharsets.UTF_8);
image.setUrl(prefixedImageData);
image.setStatus(true);
image.setType(fileExtension); // 设置类型为文件扩展名
// 设置图片名称,可以根据需求自定义
image.setName(originalFileName);
imageMapper.insertImage(image);
//设置返回的图片数据,包括设置好的图片url还有id
imageSuccessVO.setData(new ImageSuccessVO.Data(prefixedBase64Data,originalFileName,image.getImageId()+""));
}
return imageSuccessVO;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
mapper.xml
<!-- 插入图像数据并返回自动生成的 imageId -->
<insert id="insertImage" parameterType="com.sky.image.entitys.Image" useGeneratedKeys="true" keyProperty="imageId">
<!-- 插入通用图像记录,关联到特定图像 (url) -->
INSERT INTO t_images (name, type, url, status)
VALUES (#{name}, #{type}, #{url}, #{status})
</insert>
至于读图片,在前面写图片的基础上,可以直接按照储存外链的形式来读就行啦!
总结
总结一下,将图片直接储存在数据库的做法大体上和将图片以外链的形式没什么区别,最大的不同就是处理需要能储存更大数据的数据库类型blob,这种做法比较适合小型的系统或者是用来做毕设的系统。对图片的读写速度有要求的朋友们建议还是用外链+cdn加速的方法来储存外链啦!