SpringBoot与MongoDB上传文件的关键是 GridFsTemplate 、GridFSBucket
org.springframework.boot
spring-boot-starter-data-mongodb
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-thymeleaf
cn.hutool
hutool-all
4.5.1
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("files")
public class FileController {
@Autowired private IFileService fileService;
/**
* 上传文件列表
* @param pageIndex
* @param pageSize
* @return
*/
@RequestMapping("/list")
public List list(int pageIndex, int pageSize){
return fileService.listFilesByPage(pageIndex,pageSize);
}
/**
* 在线显示文件
* @param id 文件id
* @return
*/
@GetMapping("/view/{id}")
public ResponseEntity
private static String collectionName = "fileDatas";
@Autowired private MongoTemplate mongoTemplate;
@Autowired private GridFsTemplate gridFsTemplate;
@Autowired private GridFSBucket gridFSBucket;
/**
* 表单上传附件
* @param md5
* @param file
* @return
*/
@Override
public FileDocument saveFile(String md5, MultipartFile file) {
//已存在该文件,则实现秒传
FileDocument fileDocument = getByMd5(md5);
if(fileDocument != null){
return fileDocument;
}
fileDocument = new FileDocument();
fileDocument.setName(file.getOriginalFilename());
fileDocument.setSize(file.getSize());
fileDocument.setContentType(file.getContentType());
fileDocument.setUploadDate(new Date());
fileDocument.setMd5(md5);
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
fileDocument.setSuffix(suffix);
try {
//文件存入gridfs
String gridfsId = uploadFileToGridFS(file.getInputStream() , file.getContentType());
fileDocument.setGridfsId(gridfsId);
//上传的信息保存在mongodb
fileDocument = mongoTemplate.save(fileDocument , collectionName);
}catch (IOException ex){
ex.printStackTrace();
}
return fileDocument;
}
/**
* 上传文件到Mongodb的GridFs中
* @param in
* @param contentType
* @return
*/
private String uploadFileToGridFS(InputStream in , String contentType){
String gridfsId = IdUtil.simpleUUID();
//文件,存储在GridFS中
gridFsTemplate.store(in, gridfsId , contentType);
return gridfsId;
}
/**
* 删除附件
* @param id 文件id
* @param isDeleteFile 是否删除文件
*/
@Override
public void removeFile(String id, boolean isDeleteFile) {
FileDocument fileDocument = mongoTemplate.findById(id , FileDocument.class , collectionName);
if(fileDocument != null){
Query query = new Query().addCriteria(Criteria.where("_id").is(id));
DeleteResult result = mongoTemplate.remove(query , collectionName);
System.out.println("result:" + result.getDeletedCount());
if(isDeleteFile){
Query deleteQuery = new Query().addCriteria(Criteria.where("filename").is(fileDocument.getGridfsId()));
gridFsTemplate.delete(deleteQuery);
}
}
}
/**
* 查询附件
* @param id 文件id
* @return
* @throws IOException
*/
@Override
public Optional getById(String id){
FileDocument fileDocument = mongoTemplate.findById(id , FileDocument.class , collectionName);
if(fileDocument != null){
Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(fileDocument.getGridfsId()));
try {
GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId());
if(in.getGridFSFile().getLength() > 0){
GridFsResource resource = new GridFsResource(fsFile, in);
fileDocument.setContent(IoUtil.readBytes(resource.getInputStream()));
return Optional.of(fileDocument);
}else {
fileDocument = null;
return Optional.empty();
}
}catch (IOException ex){
ex.printStackTrace();
}
}
return Optional.empty();
}
/**
* 根据md5获取文件对象
* @param md5
* @return
*/
@Override
public FileDocument getByMd5(String md5) {
Query query = new Query().addCriteria(Criteria.where("md5").is(md5));
FileDocument fileDocument = mongoTemplate.findOne(query , FileDocument.class , collectionName);
return fileDocument;
}
//文件上传列表
@Override
public List listFilesByPage(int pageIndex, int pageSize) {
Query query = new Query().with(new Sort(Sort.Direction.DESC, "uploadDate"));
long skip = (pageIndex -1) * pageSize;
query.skip(skip);
query.limit(pageSize);
Field field = query.fields();
field.exclude("content");
List files = mongoTemplate.find(query , FileDocument.class , collectionName);
return files;
}
@Controller
public class IndexController {
@Autowired
private IFileService fileService;
//打开index页面
@RequestMapping("/")
public String index(ModelMap map , @RequestParam(value = "pageIndex" , defaultValue = "1") int pageIndex,@RequestParam(value = "pageSize" , defaultValue = "10") int pageSize){
map.addAttribute("list" , fileService.listFilesByPage(pageIndex,pageSize));
return "index";
}
//打开表单上传页面
@RequestMapping("/upload")
public String upload(){
return "upload";
}
//打开js上传页面
@RequestMapping("/jsupload")
public String jsupload(){
return "jsupload";
}
}
spring.application.name=mongodb-upload
server.port=8081
# thymeleaf配置,开发环境不启用缓存,正式环境下请启用缓存,提高性能
spring.thymeleaf.cache=false
# thymeleaf对html元素格式要求严格,设置它的mode为HTML,忘记结束标签后不会报错
spring.thymeleaf.mode=HTML
# 编码
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
# MongoDB 配置
spring.data.mongodb.uri=mongodb://zhuyu:[email protected]:27017,192.168.68.137:27017,192.168.68.139:27017/ai?slaveOk=true&replicaSet=zypcy&write=1&readPreference=secondaryPreferred&connectTimeoutMS=300000
#每个主机的连接数
spring.data.mongodb.connections-per-host=20
#线程队列数,它以上面connectionsPerHost值相乘的结果就是线程队列最大值
spring.data.mongodb.threads-allowed-to-block-for-connection-multiplier=20
spring.data.mongodb.connect-timeout=10000
spring.data.mongodb.socket-timeout=10000
spring.data.mongodb.max-wait-time=5000
#控制是否在一个连接时,系统会自动重试
spring.data.mongodb.auto-connect-retry=true
spring.data.mongodb.socket-keep-alive=true
# limit upload file size
spring.servlet.multipart.max-file-size=30MB
spring.servlet.multipart.max-request-size=50MB
上面的代码还可以更加完善,欢迎朋友们自行添加,如:鉴权—只有授权的用户才能上传文件到文件服务器
MongoDB数据超多之后请使用索引,真实案例,有张表数据超过300万,分页查询超时,设置合理的索引后秒查
如,按时间倒序索引:db.Global_Exception_Info.createIndex({“createDate”:-1}),正序是 1,倒序是 -1