目录
需求分析
- 上传文件:用户应该能够通过前端界面选择要上传的文件,并将其发送到后端服务器。后端服务器应该能够接收文件并将其保存到指定的位置。上传的文件应该包含文件名、文件类型和文件内容等信息。
- 保存文件:后端服务器应该将上传的文件保存到指定的位置,并将文件的元数据保存到数据库中。文件的元数据应该包括文件名、文件大小、上传日期和主键等信息。主键可以使用MongoDB的ObjectId类型生成。
- 返回文件元数据:上传成功后,后端服务器应该返回文件的元数据给前端。这些元数据可以包括文件名、文件大小、上传日期和主键等信息。这些信息可以用于后续的文件访问和操作。
- 访问文件:用户应该能够通过接口访问上传的文件,并能够下载或查看文件内容。后端服务器应该能够根据文件的主键或其他标识符检索文件,并将文件内容返回给前端。文件内容可以通过流的方式返回给前端,以避免内存溢出等问题。
- 安全性考虑:在上传和访问文件时,应该考虑安全性问题,例如身份验证和授权等。只有授权用户才能上传和访问文件,以确保文件的安全性和保密性。
解决方案
GridFsTemplate是Spring Data MongoDB提供的一个工具类,用于在MongoDB中存储和检索大型文件。以下是GridFsTemplate实现文件上传、下载和删除的优点:文件上传:
- GridFsTemplate提供了方便的API,可以轻松地将文件上传到MongoDB中。
- GridFsTemplate可以将文件分割成多个块,并将这些块存储在tempFs.chunks集合中,以支持高度可扩展性和并发性。
- GridFsTemplate可以将文件的元数据保存在tempFs.files集合中,包括文件名、文件大小、上传日期和主键等信息。
文件下载:
- GridFsTemplate提供了方便的API,可以轻松地从MongoDB中检索和下载文件。
- GridFsTemplate可以将文件块重新组合成原始文件,并将文件内容作为流返回给前端,以避免内存溢出等问题。
文件删除:
- GridFsTemplate提供了方便的API,可以轻松地从MongoDB中删除文件。
- GridFsTemplate可以根据文件的主键或其他标识符检索文件,并将其从tempFs.chunks和tempFs.files集合中删除。
实现步骤
- 解决临时文件和正式文件区分处理
- 解决上传问题
- 解决下载问题
- 解决删除问题
具体实现如下
添加mavenspring-boot-starter-data-mongodb
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
配置文件GridFsTemplate
实现临时文件和正式文件存储桶分离
@Configuration
public class GridFsConfig {
@Bean(name = "gridTempFsTemplate")
public GridFsTemplate gridTempFsTemplate(MongoDatabaseFactory dbFactory, MongoConverter converter) {
return new GridFsTemplate(dbFactory, converter, "tempFs");
}
@Bean(name = "gridFormalFsTemplate")
public GridFsTemplate gridFormalFsTemplate(MongoDatabaseFactory dbFactory, MongoConverter converter) {
return new GridFsTemplate(dbFactory, converter, "formalFs");
}
}
创建GridFsTemplateUtil
工具类管理文件的上传、下载和删除
@Slf4j
@Component
public class GridFsTemplateUtil {
@Resource(name = "gridTempFsTemplate")
private GridFsTemplate gridTempFsTemplate;
@Resource(name = "gridFormalFsTemplate")
private GridFsTemplate gridFormalFsTemplate;
/**
* 上传临时文件
*
* @param file 文件
* @return {@link String}
*/
public String saveTempFile(MultipartFile file, String fileName) {
DBObject metaData = new BasicDBObject();
metaData.put("createTime", new Date());
metaData.put("createUser", SecurityContextUtils.getUserId());
InputStream inputStream;
try {
inputStream = file.getInputStream();
//文件流:inputStream
//id:文件的唯一标识id
//file.getContentType():内容类型
//metaData:元数据
return gridTempFsTemplate.store(inputStream, fileName, file.getContentType(), metaData).toString();
} catch (IOException e) {
log.error("上传失败", e);
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 上传临时文件
*
* @param file 文件
* @return {@link String}
*/
public String saveTempFile(MultipartFile file) {
DBObject metaData = new BasicDBObject();
metaData.put("createTime", new Date());
metaData.put("createUser", SecurityContextUtils.getUserId());
String fileName = file.getOriginalFilename();
InputStream inputStream;
try {
inputStream = file.getInputStream();
//文件流:inputStream
//id:文件的唯一标识id
//file.getContentType():内容类型
//metaData:元数据
return gridTempFsTemplate.store(inputStream, fileName, file.getContentType(), metaData).toString();
} catch (IOException e) {
log.error("上传失败", e);
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 上传正式文件
*
* @param file 文件
* @return {@link String}
*/
public String saveFormalFsFile(MultipartFile file) {
DBObject metaData = new BasicDBObject();
metaData.put("createTime", new Date());
metaData.put("createUser", SecurityContextUtils.getUserId());
String fileName = file.getOriginalFilename();
InputStream inputStream;
try {
inputStream = file.getInputStream();
//文件流:inputStream
//id:文件的唯一标识id
//file.getContentType():内容类型
//metaData:元数据
return gridFormalFsTemplate.store(inputStream, fileName, file.getContentType(), metaData).toString();
} catch (IOException e) {
log.error("上传失败", e);
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 上传正式文件
*
* @param file 文件
* @return {@link String}
*/
public String saveFormalFsFile(MultipartFile file, String fileName) {
DBObject metaData = new BasicDBObject();
InputStream inputStream;
try {
inputStream = file.getInputStream();
//文件流:inputStream
//id:文件的唯一标识id
//file.getContentType():内容类型
//metaData:元数据
return gridFormalFsTemplate.store(inputStream, fileName, file.getContentType(), metaData).toString();
} catch (IOException e) {
log.error("上传失败", e);
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 获取临时文件
*
* @param id 文件id
* @return {@link GridFsResource}
*/
public GridFsResource getTempFile(String id) {
log.info("Getting file.." + id);
GridFSFile gridFsFile = gridTempFsTemplate
.findOne(new Query(Criteria.where("_id").is(id)));
if (gridFsFile != null) {
return gridTempFsTemplate.getResource(gridFsFile);
}
throw new MyException(ErrorCode.ERROR);
}
/**
* 获取正式文件
*
* @param id 文件id
* @return {@link GridFsResource}
*/
public GridFsResource getFormalFile(String id) {
log.info("Getting file.." + id);
GridFSFile gridFsFile = gridTempFsTemplate
.findOne(new Query(Criteria.where("_id").is(id)));
if (gridFsFile != null) {
return gridFormalFsTemplate.getResource(gridFsFile);
}
throw new MyException(ErrorCode.ERROR);
}
/**
* 删除临时文件
*
* @param id 文件id
*/
public void deleteTempFile(String id) {
gridTempFsTemplate.delete(new Query().addCriteria(Criteria.where("_id").is(id)));
}
/**
* 删除正式文件
*
* @param id 文件id
*/
public void deleteFormalFile(String id) {
gridFormalFsTemplate.delete(new Query().addCriteria(Criteria.where("_id").is(id)));
}
}
创建GridFsTemplateFileController
控制器暴露上传、下载和删除接口
@Slf4j
@RestController
@RequestMapping("/gridFsFile")
@Api(tags = "上传文件控制器")
public class GridFsTemplateFileController {
@Autowired
private GridFsTemplateUtil gridFsTemplateUtil;
/**
* 上传临时文件
*
* @param file 文件
* @return {@link RespJson}
*/
@ApiOperation(value = "上传临时文件(mongodb)", notes = "上传临时文件(mongodb)")
@PostMapping(value = "uploadTempFile", headers = "content-type=multipart/form-data")
public RespJson<String> uploadTempFile(@RequestPart(value = "file") MultipartFile file) {
return RespJson.success(gridFsTemplateUtil.saveTempFile(file));
}
/**
* 上传正式文件
*
* @param file 文件
* @return {@link RespJson}
*/
@ApiOperation(value = "上传正式文件(mongodb)", notes = "上传正式文件(mongodb)")
@PostMapping(value = "uploadFormalFile", headers = "content-type=multipart/form-data")
public RespJson<String> uploadFormalFile(@RequestPart(value = "file") MultipartFile file) {
return RespJson.success(gridFsTemplateUtil.saveFormalFsFile(file));
}
/**
* 获取临时文件
*
* @param id 文件id
* @return {@link RespJson}
*/
@ApiOperation(value = "获取临时文件(mongodb)", notes = "获取临时文件(mongodb)")
@GetMapping(value = "getTempFile")
public ResponseEntity<InputStreamResource> getTempFile(HttpServletRequest request,
HttpServletResponse response,
@RequestParam String id) {
try {
GridFsResource tempFile = gridFsTemplateUtil.getTempFile(id);
InputStream inputStream = tempFile.getInputStream();
// 设置HTTP响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + tempFile.getFilename());
headers.add(HttpHeaders.CONTENT_TYPE, tempFile.getContentType());
headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(Objects.requireNonNull(tempFile.getGridFSFile()).getLength()));
// 返回文件流
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.parseMediaType(tempFile.getContentType()))
.body(new InputStreamResource(inputStream));
}catch (Exception e){
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 获取正式文件
*
* @param id 文件id
* @return {@link RespJson}
*/
@ApiOperation(value = "获取正式文件(mongodb)", notes = "获取正式文件(mongodb)")
@GetMapping(value = "getFormalFile")
public ResponseEntity<InputStreamResource> getFormalFile(HttpServletRequest request,
HttpServletResponse response,
@RequestParam String id) {
try {
GridFsResource tempFile = gridFsTemplateUtil.getFormalFile(id);
InputStream inputStream = tempFile.getInputStream();
// 设置HTTP响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + tempFile.getFilename());
headers.add(HttpHeaders.CONTENT_TYPE, tempFile.getContentType());
headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(Objects.requireNonNull(tempFile.getGridFSFile()).getLength()));
// 返回文件流
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.parseMediaType(tempFile.getContentType()))
.body(new InputStreamResource(inputStream));
}catch (Exception e){
throw new MyException(ErrorCode.ERROR);
}
}
/**
* 删除临时文件
*
* @param id 文件id
* @return {@link RespJson}
*/
@ApiOperation(value = "删除临时文件(mongodb)", notes = "删除临时文件(mongodb)")
@GetMapping(value = "deleteTempFile")
public RespJson<Boolean> deleteTempFile(@RequestParam String id) {
gridFsTemplateUtil.deleteTempFile(id);
return RespJson.success();
}
/**
* 获取正式文件
*
* @param id 文件id
* @return {@link RespJson}
*/
@ApiOperation(value = "获取正式文件(mongodb)", notes = "获取正式文件(mongodb)")
@GetMapping(value = "deleteFormalFile")
public RespJson<Boolean> deleteFormalFile(@RequestParam String id) {
gridFsTemplateUtil.deleteFormalFile(id);
return RespJson.success();
}
}
总结
总体来说,GridFsTemplate提供了方便的API和高度可扩展的存储方案,使得在MongoDB中存储和检索大型文件变得更加容易和高效。
![](https://resource.liulingfengyu.cn/img/扫码_搜索联合传播样式-标准色版压缩版.png)