最近公司实习,需要使用Mongodb实现文件上传下载功能。我之前也没接触过相应的项目,只好从Mongodb概念开始看...看了好多文章感觉都不是我想要的功能代码。我的需求是能从浏览器中选择文件上传,或者输入文件ID号就能下载。以下的两篇文章是我找到比较好的(也就是Ctrl+V就能运行的代码QAQ)。第一篇是官方文档讲得比较好,第二篇是github一个项目。结合这两篇文章我写了该需求的代码。先看效果:
fs.files
fs.chunks
请求传入刚才的文件Id就能下载
这样一个使用Mongodb文件上传下载流程就基本实现了TAT。如果有相同的需求就接着看吧。
org.springframework.boot
spring-boot-starter-data-mongodb
spring:
data:
mongodb:
#host: 127.0.0.1
#port: 27017
#database: admin
uri: mongodb://localhost:27017/db
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.*;
@Controller
@RequestMapping("/files")
public class FileController {
@Autowired
private GridFS gridFS;
private MongoClient mongoClient = new MongoClient("localhost", 27017);
private MongoDatabase myDatabase = mongoClient.getDatabase("db");
private GridFSBucket gridFSBucket = GridFSBuckets.create(myDatabase);
/**
* 上传文件
*
* @param file 文件
* @return 文件名和文件存储的fileId键值对的Map
*/
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public Map upload(@RequestParam(value = "file") MultipartFile file) {
Map map = new HashMap<>();
try {
InputStream streamToUploadFrom = file.getInputStream();
Document document = new Document();
//自定义数据,放入文件真正名和文件类型
document.append("fileTrueName", file.getOriginalFilename());
document.append("contentType", file.getContentType());
//设置chunks长度为358400字节,如果文件过大则创建新的分块
// 自定义的数据放在metadata里
GridFSUploadOptions options = new GridFSUploadOptions()
.chunkSizeBytes(358400)
.metadata(document);
ObjectId fileId = gridFSBucket.uploadFromStream(UUID.randomUUID().toString(), streamToUploadFrom, options);
System.out.println("上传成功," + "文件名:" + file.getOriginalFilename() + "文件ID:" + fileId);
map.put(file.getOriginalFilename(), fileId);
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
/**
* 通过文件fileId下载文件
*
* @param fileId 文件fileId
* @param response 文件输出流
*/
@RequestMapping(value = "/downLoadByFileId")
public void downLoadByFileId(@RequestParam(value = "fileId") ObjectId fileId, HttpServletResponse response) {
GridFSDBFile gridFSDBFile = gridFS.findOne(fileId);
try {
//获取回复的输出流
OutputStream sos = response.getOutputStream();
//设置编码格式
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
//设置文件返回类型,为上传文件时获取的文件类型
response.setContentType(gridFSDBFile.getMetaData().get("contentType").toString());
response.addHeader("Content-Disposition", "attachment; filename=\"" + gridFSDBFile.getMetaData().get("fileTrueName") + "\"");
//将查询到的数据放入到输出流sos中
gridFSDBFile.writeTo(sos);
sos.flush();
sos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取所有文件fileId
*/
@ResponseBody
@RequestMapping(value = "/getAllFileId")
public List getAllFileId() {
List list = new ArrayList<>();
try {
gridFSBucket.find().forEach(
(Block) gridFSFile -> System.out.println(gridFSFile.getId().toString()));
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 获取fileId文件信息
*/
@ResponseBody
@RequestMapping(value = "/getSpecifyInfoFileByFileId")
public GridFSDBFile getSpecifyInfoFileByFileId(@RequestParam(value = "fileId") String fileId) {
try {
return gridFS.findOne(fileId);
}catch (Exception e){
return null;
}
}
/**
* 通过fileId删除文件
* @param fileId 文件ID
* @return 成功为true, 失败为false
*/
@ResponseBody
@RequestMapping("/deleteFilesByObjectId")
public boolean deleteFilesByObjectId(@RequestParam(value = "fileId") String fileId) {
try {
gridFSBucket.delete(new ObjectId(fileId));
return true;
} catch (Exception e) {
return false;
}
}
}
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.gridfs.GridFS;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MongoDBConfig {
@Bean
public GridFS gridFS() {
return new GridFS(mongo().getDB("db"));
}
@Bean
public Mongo mongo() {
return new MongoClient("localhost", 27017);
}
}
这里遇到个小Bug(对我是)MongoClient mongoClient不能使用@Bean注解去实现IOC,只能通过在代码中
MongoClient mongoClient = new MongoClient("localhost", 27017);这样去生成...如果你知道请留言...到此就基本实现了需求。
顺便说一下,文件下载核心的就是通过文件Id获得输出流,也就是官网文档这句,然后把输出流放入response中就可以下载了。
gridFSBucket.downloadToStream(fileId, streamToDownloadTo);
我使用的方法是版本2.2以前的方法,因为我要获取文件对象中的metadata中的文件名和类型,新版是使用gridFSBucket ,可以参照下面这篇博客了解。也就是下面这段代码
String fileId = "5602de6e5d8bba0d6f2e45e4";
// 从Mongod中查找出一个文件,注意这里返回为com.mongodb.client.gridfs.model.GridFSFile类
GridFSFile gridFsdbFile = operations.findOne(new Query(Criteria.where("_id").is(fileId)));
if (gridFsdbFile != null) {
// mongo-java-driver3.x以上的版本就变成了这种方式获取
GridFSBucket bucket = GridFSBuckets.create(mongoDbFactory.getDb());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 获取Mongodb中文件的缓存输出流
bucket.downloadToStream(gridFsdbFile.getId(), baos);
...
}
//spring-data-mongodb从2.0版本开始,其中GridFsOperations#findOne方法,返回类型为
//com.mongodb.client.gridfs.model.GridFSFile,不是再为com.mongodb.gridfs.GridFSDBFile类型。所
//以,这里就不得不用GridFSBucket来获取文件
不能直接用url测试,也不能用IDEA的REST Client工具上传文件(至少我是不能),最好写一个网页前端文件上传界面,我还是附上吧QAQ(如果不能用就百度个)
测试文件上传
Ctrl +C吧