# GridFs 操作文件
# GridFs 介绍
GridFs 是 MongoDB 提供的用于持久化存储文件的模块,CMS 使用 MongoDB 存储数据,使用 GridFs 可以快速集成开发
它的工作原理是:
在 GridFs 存储文件时将文件分块存储,文件会按照 256KB 的大小分割成多个块进行存储,GridFs 使用两个集合 (collection) 存储文件如下图
一个集合是 chunks (分块),用于存储文件的二进制数据;另一个集合是 files (完整文件),用于存储文件的元数据信息 (文件名称,块大小,上传时间等信息)
从 GridFs 中读取文件要对文件的各个块进行组装,合并。
# 引入 pom 依赖
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>3.3.3</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> | |
<groupId>com.poi-learn</groupId> | |
<artifactId>maven-mybatis-test</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<name>maven-mybatis-test</name> | |
<description>maven-mybatis-test</description> | |
<url/> | |
<licenses> | |
<license/> | |
</licenses> | |
<developers> | |
<developer/> | |
</developers> | |
<scm> | |
<connection/> | |
<developerConnection/> | |
<tag/> | |
<url/> | |
</scm> | |
<properties> | |
<java.version>17</java.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-jdbc</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-web</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>com.mysql</groupId> | |
<artifactId>mysql-connector-j</artifactId> | |
<scope>runtime</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
<optional>true</optional> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.baomidou</groupId> | |
<artifactId>mybatis-plus-generator</artifactId> | |
<version>3.5.3.1</version> | |
</dependency> | |
<dependency> | |
<groupId>com.baomidou</groupId> | |
<artifactId>mybatis-plus-spring-boot3-starter</artifactId> | |
<version>3.5.5</version> | |
</dependency> | |
<dependency> | |
<groupId>p6spy</groupId> | |
<artifactId>p6spy</artifactId> | |
<version>3.9.1</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.commons</groupId> | |
<artifactId>commons-lang3</artifactId> | |
<version>3.12.0</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.velocity</groupId> | |
<artifactId>velocity-engine-core</artifactId> | |
<version>2.3</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-data-mongodb</artifactId> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-maven-plugin</artifactId> | |
<configuration> | |
<excludes> | |
<exclude> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
</exclude> | |
</excludes> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
实际引入 mongodb 的即可,这个项目是我 玩 mybatis 导入的其他依赖
配置 mongodb 数据库配置到 yml
server: | |
port: 80 | |
servlet: | |
context-path: /dkx | |
spring: | |
datasource: | |
driver-class-name: com.p6spy.engine.spy.P6SpyDriver | |
url: jdbc:p6spy:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC&useUnicode=true | |
username: root | |
password: dkx.. | |
main: | |
banner-mode: off | |
data: | |
mongodb: | |
uri: mongodb://localhost:27017/test | |
database: test | |
mybatis-plus: | |
configuration: | |
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl | |
map-underscore-to-camel-case: true | |
global-config: | |
banner: off |
实际配置 mongodb 的配置即可
如果要对一个集合进行操作那么需要对实体类进行配置相关的注解如下:
- @Document (collection = "shop") 对当前实体类声明集合名称
- @Id 让 mongodb 在插入一条数据的时候自动生成_id 的值
package com.poilearn.entity; | |
import com.baomidou.mybatisplus.annotation.IdType; | |
import com.baomidou.mybatisplus.annotation.TableField; | |
import com.baomidou.mybatisplus.annotation.TableId; | |
import com.baomidou.mybatisplus.annotation.TableName; | |
import java.io.Serializable; | |
import java.math.BigDecimal; | |
import lombok.AllArgsConstructor; | |
import lombok.Getter; | |
import lombok.NoArgsConstructor; | |
import lombok.Setter; | |
import org.springframework.data.annotation.Id; | |
import org.springframework.data.mongodb.core.mapping.Document; | |
/** | |
* <p> | |
* 商品表 | |
* </p> | |
* | |
* @author dkx | |
* @since 2024-09-08 | |
*/ | |
@Getter | |
@Setter | |
@AllArgsConstructor | |
@NoArgsConstructor | |
@TableName("tab_shop") | |
@Document(collection = "shop") | |
public class Shop implements Serializable { | |
private static final long serialVersionUID = 1L; | |
/** | |
* 主键 | |
*/ | |
@TableId(value = "id", type = IdType.ASSIGN_UUID) | |
@Id | |
private String id; | |
/** | |
* 商品名称 | |
*/ | |
@TableField("name") | |
private String name; | |
/** | |
* 商品描述 | |
*/ | |
@TableField("description") | |
private String description; | |
/** | |
* 商品类型 | |
*/ | |
@TableField("type") | |
private String type; | |
/** | |
* 商品价格 | |
*/ | |
@TableField("price") | |
private BigDecimal price; | |
} |
# 存储文件
controller
@RestController | |
@RequestMapping("/poilearn/shop") | |
public class ShopController { | |
@Autowired | |
private IShopService iShopService; | |
@PostMapping("/addFile") | |
public String addFile(@RequestBody MultipartFile file) { | |
return iShopService.addPNG(file); | |
} | |
} |
serviceImpl
@Service | |
@Slf4j | |
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService { | |
@Autowired | |
private ShopMapper shopMapper; | |
@Autowired | |
private CsdnUserInfoMapper csdnUserInfoMapper; | |
@Autowired | |
private GridFsTemplate gridFsTemplate; | |
@Autowired | |
private MongoTemplate mongoTemplate; | |
@Autowired | |
private GridFSBucket gridFSBucket; | |
public String addPNG(MultipartFile file) { | |
try { | |
InputStream inputStream = file.getInputStream(); | |
return gridFsTemplate.store(inputStream, file.getOriginalFilename(), file.getContentType()) + ""; | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |
测试结果:
# 下载文件
# 在 config 包中定义 Mongodb 的配置类
如下:
GridFsBucket 用于打开下载流对象
config
package com.example.demomonogo.config; | |
/** | |
* @author john | |
* @date 2019/12/21 - 10:39 | |
*/ | |
import com.mongodb.MongoClient; | |
import com.mongodb.client.MongoDatabase; | |
import com.mongodb.client.gridfs.GridFSBucket; | |
import com.mongodb.client.gridfs.GridFSBuckets; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
@Configuration | |
public class MongoConfig { | |
@Value("${spring.data.mongodb.database}") | |
String db; | |
@Bean | |
public GridFSBucket getGridFSBucket(MongoClient mongoClient) { | |
MongoDatabase database = mongoClient.getDatabase(db); | |
GridFSBucket bucket = GridFSBuckets.create(database); | |
return bucket; | |
} | |
} |
controller
@RestController | |
@RequestMapping("/poilearn/shop") | |
public class ShopController { | |
@Autowired | |
private IShopService iShopService; | |
@GetMapping("/downFile") | |
public void downFile(@RequestParam("id") String id) { | |
iShopService.downloadPng(id); | |
} | |
} |
serviceImpl
@Service | |
@Slf4j | |
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService { | |
@Autowired | |
private ShopMapper shopMapper; | |
@Autowired | |
private CsdnUserInfoMapper csdnUserInfoMapper; | |
@Autowired | |
private GridFsTemplate gridFsTemplate; | |
@Autowired | |
private MongoTemplate mongoTemplate; | |
@Autowired | |
private GridFSBucket gridFSBucket; | |
public void downloadPng(String id) { | |
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(id))); | |
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId()); | |
GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream); | |
File file = new File("D:\\png\\", "test.png"); | |
if (!file.exists()) { | |
file.getParentFile().mkdirs(); | |
} | |
try ( | |
InputStream inputStream = gridFsResource.getInputStream(); | |
FileOutputStream fileOutputStream = new FileOutputStream(file) | |
) { | |
byte[] bytes = new byte[1024]; | |
int i = 0; | |
while ((i = inputStream.read(bytes)) != -1) { | |
fileOutputStream.write(bytes, 0, i); | |
} | |
fileOutputStream.flush(); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |
测试结果:
拿着刚才存储文件的_id 请求下载下这个文件
# 删除文件
通过_id 来删除某个文件或者直接全部删除文件的时候 将会连带该文件的分块也一并被删除掉
controller
@RestController | |
@RequestMapping("/poilearn/shop") | |
public class ShopController { | |
@Autowired | |
private IShopService iShopService; | |
@GetMapping("/delFile") | |
public void delFile(@RequestParam("id") String id) { | |
iShopService.delPng(id); | |
} | |
} |
serviceImpl
@Service | |
@Slf4j | |
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService { | |
@Autowired | |
private ShopMapper shopMapper; | |
@Autowired | |
private CsdnUserInfoMapper csdnUserInfoMapper; | |
@Autowired | |
private GridFsTemplate gridFsTemplate; | |
@Autowired | |
private MongoTemplate mongoTemplate; | |
@Autowired | |
private GridFSBucket gridFSBucket; | |
public void delPng(String id) { | |
// 会同时删除分块数据 | |
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(id))); | |
} | |
} |
测试结果