MongoDB GridFS支持大文件存储:
GridFS用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等);
GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中;
GridFS 可以更好的存储大于16M的文件;
GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中;
每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
spring-boot-starter-data-mongodb 基于GridFS实现文件的上传下载
application配置文件
server:
port: 9001
spring:
data:
mongodb:
uri: mongodb://root:123456@127.0.0.1:27017/fileInfo?readPreference=secondary&authSource=admin
jackson:
default-property-inclusion: non_null
servlet:
multipart:
max-file-size: 10MB #单个文件上传大小
max-request-size: 100MB #单次请求文件上传大小
http:
encoding:
charset: UTF-8
自定义实体类记录上传文件的相关信息
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "tbl_data_record")
public class FileMetaDomain implements Serializable {
private static final long serialVersionUID = 7733095063283270367L;
@Id
private String id;
/* 文件信息存储在数据库中的uuid */ private List<Object> fileIds;
/* 源文件名 */ private String fileName;
/* 文件类型 */ private String contentType;
/* 文件大小 */ private long size;
/* 更新日期 */ private LocalDate updateTime = LocalDate.now();
/* 创建日期 */ private LocalDate createTime = LocalDate.now();
public FileMetaDomain(String id, String fileName, String contentType, long size){
this.id = id; this.fileName = fileName;
this.contentType = contentType;this.size = size;
}
}
Dao层接口
@Repository
public interface GridFSRepository extends MongoRepository<FileMetaDomain,String> {
@Query("{'fileName': ?0}")
FileMetaDomain findByFileName(String fileName);
}
Service逻辑处理
public interface GridFsService {
String saveFile(MultipartFile file) throws IOException;
void downLoad(HttpServletResponse response, String fileName);
}
实现类
@Slf4j
@Service
public class GridFSServiceImpl implements GridFsService {
private final MongoTemplate mongoTemplate;
private final GridFSRepository repository;
private final GridFsTemplate gridFsTemplate;
@Autowired
public GridFSServiceImpl(GridFSRepository repository, MongoTemplate mongoTemplate, GridFsTemplate gridFsTemplate) {
this.repository = repository;
this.mongoTemplate = mongoTemplate;
this.gridFsTemplate = gridFsTemplate;
}
@Override
public String saveFile(MultipartFile file) throws IOException {
//源文件名
String originalFilename = file.getOriginalFilename();
//文件类型
String contentType = file.getContentType();
//文件大小
long size = file.getSize();
MongoDatabase db = mongoTemplate.getDb();
GridFSBucket gridFSBucket = GridFSBuckets.create(db);
ObjectId objectId = gridFSBucket.uploadFromStream(originalFilename, file.getInputStream());
FileMetaDomain fileMetaDomain = new FileMetaDomain(objectId.toString(),originalFilename,contentType,size);
FileMetaDomain fileMeta = repository.save(fileMetaDomain);
return fileMeta.getId();
}
@Override
public void downLoad(HttpServletResponse response, String fileName){
FileMetaDomain fileMetaDomain = repository.findByFileName(fileName);
Assert.notNull(fileMetaDomain,"当前下载的文件未上传到服务器");
Query query = new Query();
query.addCriteria(Criteria.where("filename").is(fileName));
GridFSFile file = gridFsTemplate.findOne(query);
MongoDatabase db = mongoTemplate.getDb();
try {
//文件名转码,支持中文文件名下载
fileName = URLEncoder.encode(fileName,"UTF-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition","attachment;filename="+fileName);
ServletOutputStream outputStream = response.getOutputStream();
GridFSBuckets.create(db).downloadToStream(file.getObjectId(),outputStream);
outputStream.flush();
outputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
文件上传下载接口
@Slf4j
@RestController
@RequestMapping("/file")
public class GridFSController {
private final GridFsService service;
@Autowired
public GridFSController(GridFsService service) {
this.service = service;
}
@PostMapping("/upload")
@ResponseBody
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file){
try {
if(ObjectUtils.isEmpty(file)){
return ResponseEntity.ok().body("上传文件不能为空");
}else {
return ResponseEntity.ok().body(service.saveFile(file));
}
}catch (Exception e){
log.error("[Upload Failed]",e);
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@GetMapping("/download")
public ResponseEntity<String> download(HttpServletResponse response, @RequestParam("fileName")String fileName){
try {
service.downLoad(response,fileName);
return ResponseEntity.ok().body("SUCCESS");
}catch (Exception e){
log.error("[Download Failed]",e.getMessage());
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}