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()); } } }
