您好,登錄后才能下訂單哦!
本篇內容介紹了“SpringBoot怎么使用Mongo的GridFs實現分布式文件存儲操作”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
前言
GridFs介紹
什么時候使用GridFs
GridFs的原理
環境
引入依賴和項目配置
使用GridFsTemplate操作GridFs
這段時間在公司實習,安排給我一個任務,讓在系統里實現一個知識庫的模塊,產品說,就像百度網盤那樣。。。我tm…,這不就是應了那句話,“這個需求很簡單,怎么實現我不管”。
可是我google小能手怎么會認輸呢,本來還說研究一下FastDFS啥的,但是因為我們項目用的Mongo作為數據庫,了解到Mongo自帶分布式文件系統GridFs,這簡直天助我也。
我們平時使用Mongo也可以直接把文件的二進制保存在Document中,就相當于mysql的blob格式,但是mongo限制Document最大為16MB,那我們超過16MB的文件可咋辦吶,就可以利用GridFs來存儲。
在某些情況下,在MongoDB數據庫中存儲大文件可能比在系統級文件系統上更高效。
如果文件系統限制目錄中的文件數,則可以使用GridFS根據需要存儲任意數量的文件。如果要從大型文件的各個部分訪問信息而無需將整個文件加載到內存中,可以使用GridFS調用文件的各個部分,而無需將整個文件讀入內存。
如果要保持文件和元數據在多個系統和設施中自動同步和部署,可以使用GridFS。使用地理位置分散的副本集時,MongoDB可以自動將文件及其元數據分發到多個 mongod實例和工具中。
GridFS不是將文件存儲在單個文檔中,而是將文件分成多個部分或塊,并將每個塊存儲為單獨的文檔。
GridFS使用兩個集合來存儲文件。一個集合存儲文件塊,另一個存儲文件元數據。
默認情況下,每一個塊的大小為255kB; 但最后一個塊除外。最后一個塊只有必要的大小。類似地,不大于塊大小的文件只有最終塊,只使用所需的空間和一些額外的元數據。
當查詢GridFS文件時,驅動程序將根據需要重新組裝塊。可以對通過GridFS存儲的文件執行范圍查詢。還可以從文件的任意部分訪問信息,例如“跳過”到視頻或音頻文件的中間。
Spring Boot 2.0.4
Maven 3.5
Java 1.8
MongoDB 4.0
Robo 1.3.1
首先添加Mongo客戶端的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
然后編寫配置文件
spring: application: name: demo data: mongodb: uri: mongodb://root:你的密碼@localhost:27019 authentication-database: admin database: 你的數據庫
GridFsTemplate是Spring提供的專門操作GridFs的客戶端,提供了一系列開箱即用的方法
只要把它注入到我們的Conteoller中,就可以愉快的CRUD了,需要注意的是獲取文件時要注入MongoDbFactory ,我們使用默認配置的話,直接注入就好。
import com.mongodb.Block; import com.mongodb.MongoClient; import com.mongodb.client.MongoDatabase; import com.mongodb.client.gridfs.GridFSBucket; import com.mongodb.client.gridfs.GridFSBuckets; import com.mongodb.client.gridfs.model.GridFSFile; import com.mongodb.client.gridfs.model.GridFSUploadOptions; import com.mongodb.gridfs.GridFS; import com.mongodb.gridfs.GridFSDBFile; import org.bson.BsonValue; import org.bson.Document; import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.*; @RestController @RequestMapping("/files") public class FileController { private Logger logger = LoggerFactory.getLogger(GridFsServiceImpl.class); //匹配文件ID的正則 private static Pattern NUMBER_PATTERN = Pattern.compile("(?<==).*(?=})"); @Autowired GridFsTemplate gridFsTemplate; @Autowired MongoDbFactory mongoDbFactory; /** * 上傳文件 * * @param file 文件 * @return 文件名和文件存儲的fileId鍵值對的Map */ @RequestMapping(value = "/upload", method = RequestMethod.POST) public Map<String, ObjectId> upload(@RequestParam(value = "file") MultipartFile file) { if(pathId == null || fileType == null || pathId.equals("") || fileType.equals("")){ logger.debug("上傳文件出錯"); throw new RuntimeException("上傳文件出錯:pathId and fileType can not be null"); } Map<String, String> map = new HashMap<>(1); String fileName = file.getOriginalFilename(); //設置元數據 DBObject metaData = new BasicDBObject(); metaData.put("userId","1"); metaData.put("fileExtension",FilenameUtils.getExtension(file.getOriginalFilename())); //存儲文件的擴展名 try { InputStream inputStream = file.getInputStream(); ObjectId fileId = gridFsTemplate.store(inputStream, fileName,metaData); //這個getFileId是我自己封裝的獲取文件ID的方法 map.put(file.getOriginalFilename(),getFileId(fileId.toString())); } catch (IOException e) { logger.debug("上傳文件失敗: "+file); throw new RuntimeException("上傳文件失敗:"+e.getMessage()); } return map; } /** * 通過文件fileId下載文件 * * @param fileId 文件fileId * @param response 文件輸出流 */ @RequestMapping(value = "/downLoadByFileId") public void downLoadByFileId(@RequestParam(value = "fileId") ObjectId fileId, HttpServletResponse response) { GridFSFile gridFsFile = gridFsTemplate.findOne(new Query().addCriteria(Criteria.where("_id").is(fileId))); if (gridFsFile != null) { // mongo-java-driver3.x以上的版本就變成了這種方式獲取 GridFSBucket bucket = GridFSBuckets.create(mongoDbFactory.getDb()); GridFSDownloadStream gridFsDownloadStream = bucket.openDownloadStream(gridFsFile.getObjectId()); GridFsResource gridFsResource = new GridFsResource(gridFsFile,gridFsDownloadStream); String fileName = gridFsFile.getFilename().replace(",", ""); //處理中文文件名亂碼 if (request.getHeader("User-Agent").toUpperCase().contains("MSIE") || request.getHeader("User-Agent").toUpperCase().contains("TRIDENT") || request.getHeader("User-Agent").toUpperCase().contains("EDGE")) { fileName = java.net.URLEncoder.encode(fileName, "UTF-8"); } else { //非IE瀏覽器的處理: fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); } response.setHeader("Content-Disposition", "inline;filename=\"" + fileName + "\""); response.setContentType(application/octet-stream); IOUtils.copy(gridFsResource.getInputStream(), response.getOutputStream()); }else { logger.info("文件不存在"); } } /** * 根據文件名查詢文件列表 * @param fileName 文件名 * @return */ @RequestMapping("/search") public List<Map<String,Object>> search(String filePath, String fileName) { //這里返回的是一個List<Map<String,Object>> //因為GridFSFindIterable 迭代出來的GridFSFile不能直接返回 GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query().addCriteria (Criteria.where("filename").regex("^.*"+fileName+".*$"))); return getGridFSFiles(gridFSFiles); } /** * 通過fileId刪除文件 * @param fileId 文件ID * @return 成功為true, 失敗為false */ @RequestMapping("/deleteFilesByObjectId") public boolean deleteFilesByObjectId(@RequestParam(value = "fileId") String fileId) { try { gridFsTemplate.delete(new Query().addCriteria(Criteria.where("_id").is(fileId))); }catch (Exception e){ logger.debug("刪除文件失敗: fileId= "+fileId); throw new RuntimeException("刪除文件失敗:"+e.getMessage()); } } /** * 根據GridFSFiles迭代器返回文件列表,因為不能直接返回,所以寫了這個工具方法 * @param gridFSFiles 從數據庫取出的文件集合 * @return List<Map<String,Object>> */ private List<Map<String,Object>> getGridFSFiles(GridFSFindIterable gridFSFiles){ List<Map<String,Object>> result = new ArrayList<>(); for (GridFSFile file : gridFSFiles) { HashMap<String,Object> map = new HashMap<>(6); map.put("fileId",getFileId(file.getId().toString())); map.put("fileName",file.getFilename()); map.put("fileExtension",file.getMetadata().get("fileExtension")); map.put("fileSize",file.getLength()/1024); map.put("uploadTime",file.getUploadDate()); map.put("user",file.getMetadata().get("userId")); result.add(map); } return result; } /** * 因為從mongo中獲取的文件Id是BsonObjectId {value=5d7068bbcfaf962be4c7273f}的樣子 * 需要字符串截取 * @param bsonObjectId 數據庫文件的BsonObjectId */ private String getFileId(String bsonObjectId) { Matcher m = NUMBER_PATTERN.matcher(bsonObjectId); if(!m.find()){ return bsonObjectId; } return m.group(); } }
“SpringBoot怎么使用Mongo的GridFs實現分布式文件存儲操作”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。