您的位置:首页 > 数据库 > Mongodb

MongodbGFS结合SpringBoot 实现大文件的简单上传与下载

2018-02-07 21:30 1151 查看

今天主要为大家带来SpringBoot工程中MongodbGFS的简单使用。首先,我们的思路是,用表单提交文件,直接将文件存入Mongodb数据库中,然后将文件直接从数据库下载到客户端。当然我们用的是GFS结构的存储,因此我们的文件最好大于16M以上。这也与mongodb官方的建议相一致。这里还有不清楚的可以看我之前的一篇博客《MongodbGFS存储大文件》,链接


首先我们做一下准备工作,初始化一个SpringBoot工程。这里我继续使用的是gradle。









添加我们需要的依赖,spring-boot-starter-test 用gradle初始化springboot工程时默认添加了,除了这个我们需要添加额外的两个依赖就是,spring-boot-starter-data-mongodb和spring-boot-starter-thymeleaf(模板引擎用来生成网页)。

添加了依赖之后,我们需要进行配置mongodb,thymeleaf。具体的配置说明可以查看官方文档 mongodb使用说明模板引擎在springboot中的配置

这里可以看一下我的配置文件。

[java] view
plain copy

#thymeleaf start

spring.thymeleaf.mode=HTML5

spring.thymeleaf.encoding=UTF-8

spring.thymeleaf.content-type=text/html

spring.thymeleaf.cache=false

#thymeleaf end

#mongodb start

spring.data.mongodb.uri=mongodb://39.106.177.24:27017/zhaotong

#mongodb end

#uploadfile start

spring.http.multipart.max-file-size=1024000KB

spring.http.multipart.max-request-size=2048000KB

#uploadfile end

关于mongodb uri的具体格式,我建议是直接去看源码:



下面的同时也配置了让springmvc放开文件大小的限制,因为我们主要做的是大文件上传。

接下来我们学习一下Springboot提供给我们关于 mongodb的操作工具类。主要我们看3个类:MongoTemplate.class MongodbFactory.class GridFsTemplate.class

首先mongoFacory 其实就和hibernateFactory一样为我们提供基于Mongodb的会话工厂。这里我们看源码:



它主要给我们返回DB对象,这里要说明这个类是线程安全的,为什么是线程安全的呢?我们接着来看DB这个类



很明显DB是线程安全的,那么工厂如何让提供给我们的的db是线程安全的呢?所以就有了接下来这段代码:



大家可以看到了ConcurrentHashMap出现了,所以这里希望大家多看看源代码,是有好处的。

至于MongoTemplate.class 这个类其实和jdbcTemplate扮演的角色一样,这里就不多说了,我们今天主要用到的是GridFsTemplate.class。我们看这个类的源码,我们今天所使用的方法都是来源于这个类。

[java] view
plain copy

/*

* Copyright 2011-2017 the original author or authors.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0
*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package org.springframework.data.mongodb.gridfs;

import static org.springframework.data.mongodb.core.query.Query.*;

import static org.springframework.data.mongodb.gridfs.GridFsCriteria.*;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.List;

import org.springframework.core.io.support.ResourcePatternResolver;

import org.springframework.data.mongodb.MongoDbFactory;

import org.springframework.data.mongodb.core.convert.MongoConverter;

import org.springframework.data.mongodb.core.convert.QueryMapper;

import org.springframework.data.mongodb.core.query.Query;

import org.springframework.util.Assert;

import org.springframework.util.StringUtils;

import com.mongodb.BasicDBObject;

import com.mongodb.DB;

import com.mongodb.DBObject;

import com.mongodb.gridfs.GridFS;

import com.mongodb.gridfs.GridFSDBFile;

import com.mongodb.gridfs.GridFSFile;

import com.mongodb.gridfs.GridFSInputFile;

/**

* {@link GridFsOperations} implementation to store content into MongoDB GridFS.

*

* @author Oliver Gierke

* @author Philipp Schneider

* @author Thomas Darimont

* @author Martin Baumgartner

* @author Christoph Strobl

* @author Mark Paluch

*/

public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver {

private final MongoDbFactory dbFactory;

private final String bucket;

private final MongoConverter converter;

private final QueryMapper queryMapper;

/**

* Creates a new {@link GridFsTemplate} using the given {@link MongoDbFactory} and {@link MongoConverter}.

*

* @param dbFactory must not be {@literal null}.

* @param converter must not be {@literal null}.

*/

public GridFsTemplate(MongoDbFactory dbFactory, MongoConverter converter) {

this(dbFactory, converter, null);

}

/**

* Creates a new {@link GridFsTemplate} using the given {@link MongoDbFactory} and {@link MongoConverter}.

*

* @param dbFactory must not be {@literal null}.

* @param converter must not be {@literal null}.

* @param bucket

*/

public GridFsTemplate(MongoDbFactory dbFactory, MongoConverter converter, String bucket) {

Assert.notNull(dbFactory, "MongoDbFactory must not be null!");

Assert.notNull(converter, "MongoConverter must not be null!");

this.dbFactory = dbFactory;

this.converter = converter;

this.bucket = bucket;

this.queryMapper = new QueryMapper(converter);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String)

*/

public GridFSFile store(InputStream content, String filename) {

return store(content, filename, (Object) null);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.Object)

*/

@Override

public GridFSFile store(InputStream content, Object metadata) {

return store(content, null, metadata);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, com.mongodb.DBObject)

*/

@Override

public GridFSFile store(InputStream content, DBObject metadata) {

return store(content, null, metadata);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.String)

*/

public GridFSFile store(InputStream content, String filename, String contentType) {

return store(content, filename, contentType, (Object) null);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.Object)

*/

public GridFSFile store(InputStream content, String filename, Object metadata) {

return store(content, filename, null, metadata);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.String, java.lang.Object)

*/

public GridFSFile store(InputStream content, String filename, String contentType, Object metadata) {

DBObject dbObject = null;

if (metadata != null) {

dbObject = new BasicDBObject();

converter.write(metadata, dbObject);

}

return store(content, filename, contentType, dbObject);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, com.mongodb.DBObject)

*/

public GridFSFile store(InputStream content, String filename, DBObject metadata) {

return this.store(content, filename, null, metadata);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, com.mongodb.DBObject)

*/

public GridFSFile store(InputStream content, String filename, String contentType, DBObject metadata) {

Assert.notNull(content, "InputStream must not be null!");

GridFSInputFile file = getGridFs().createFile(content);

if (filename != null) {

file.setFilename(filename);

}

if (metadata != null) {

file.setMetaData(metadata);

}

if (contentType != null) {

file.setContentType(contentType);

}

file.save();

return file;

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#find(com.mongodb.DBObject)

*/

public List<GridFSDBFile> find(Query query) {

if (query == null) {

return getGridFs().find(new BasicDBObject());

}

DBObject queryObject = getMappedQuery(query.getQueryObject());

DBObject sortObject = getMappedQuery(query.getSortObject());

return getGridFs().find(queryObject, sortObject);

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#findOne(com.mongodb.DBObject)

*/

public GridFSDBFile findOne(Query query) {

return getGridFs().findOne(getMappedQuery(query));

}

/*

* (non-Javadoc)

* @see org.springframework.data.mongodb.gridfs.GridFsOperations#delete(org.springframework.data.mongodb.core.query.Query)

*/

public void delete(Query query) {

getGridFs().remove(getMappedQuery(query));

}

/*

* (non-Javadoc)

* @see org.springframework.core.io.ResourceLoader#getClassLoader()

*/

public ClassLoader getClassLoader() {

return dbFactory.getClass().getClassLoader();

}

/*

* (non-Javadoc)

* @see org.springframework.core.io.ResourceLoader#getResource(java.lang.String)

*/

public GridFsResource getResource(String location) {

GridFSDBFile file = findOne(query(whereFilename().is(location)));

return file != null ? new GridFsResource(file) : null;

}

/*

* (non-Javadoc)

* @see org.springframework.core.io.support.ResourcePatternResolver#getResources(java.lang.String)

*/

public GridFsResource[] getResources(String locationPattern) {

if (!StringUtils.hasText(locationPattern)) {

return new GridFsResource[0];

}

AntPath path = new AntPath(locationPattern);

if (path.isPattern()) {

List<GridFSDBFile> files = find(query(whereFilename().regex(path.toRegex())));

List<GridFsResource> resources = new ArrayList<GridFsResource>(files.size());

for (GridFSDBFile file : files) {

resources.add(new GridFsResource(file));

}

return resources.toArray(new GridFsResource[resources.size()]);

}

return new GridFsResource[] { getResource(locationPattern) };

}

private DBObject getMappedQuery(Query query) {

return query == null ? new Query().getQueryObject() : getMappedQuery(query.getQueryObject());

}

private DBObject getMappedQuery(DBObject query) {

return query == null ? null : queryMapper.getMappedObject(query, null);

}

private GridFS getGridFs() {

DB db = dbFactory.getDb();

return bucket == null ? new GridFS(db) : new GridFS(db, bucket);

}

}

所以说不需要看文档,看他的源码我们就知道如何使用了。接下来我们实战,首先我们做一个html模板,用来上传文件,和下载文件。代码如下:



源码:

[html] view
plain copy

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:th="http://www.thymeleaf.org">

<head>

<title>uploadForm</title>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

</head>

<body>

<div>

<form method="POST" enctype="multipart/form-data" action="/uploadfile">

<input type="file" name="file" />

<input type="submit" value="上传" />

</form>

<form method="POST" action="/downloadfile">

<p>输入文件名<input type="text" name="fname" /></p>

<input type="submit" value="下载" />

</form>

</div>

</body>

</html>

接着我们编写controller ,这次我们是学习,就不分层写了,如果正式开发,我们最好按照层级来写。controller代码如下:

[java] view
plain copy

package com.example.controller;

import java.io.IOException;

import java.io.InputStream;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.Part;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

import org.springframework.data.mongodb.core.query.Criteria;

import org.springframework.data.mongodb.core.query.Query;

import org.springframework.data.mongodb.gridfs.GridFsTemplate;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import com.mongodb.gridfs.GridFSDBFile;

import com.mongodb.gridfs.GridFSFile;

@Controller

@EnableAutoConfiguration

public class FileUploadController {

// 获得SpringBoot提供的mongodb的GridFS对象

@Autowired

private GridFsTemplate gridFsTemplate;

// 工程主页

@RequestMapping(value = "/", method = RequestMethod.GET)

String home(Model model) {

return "uploadForm";

}

// 上传文件控制器

@RequestMapping(value = "/uploadfile", method = RequestMethod.POST)

@ResponseBody

String uploadfile(HttpServletRequest request) {

String result = "error";

try {

/**

* Servlet3.0新增了request.getParts()/getPart(String filename) api,

* 用于获取使用multipart/form-data格式传递的http请求的请求体, 通常用于获取上传文件。

*/

Part part = request.getPart("file");

// 获得提交的文件名

String filename = part.getSubmittedFileName();

// 获得文件输入流

InputStream ins = part.getInputStream();

// 获得文件类型

String contenttype = part.getContentType();

// 将文件存储到mongodb中,mongodb 将会返回这个文件的具体信息

GridFSFile gfs = gridFsTemplate.store(ins, filename, contenttype);

result = gfs.toString();

} catch (IOException e) {

} catch (ServletException e) {

e.printStackTrace();

}

return result;

}

// 下载文件控制器

@RequestMapping(value = "/downloadfile", method = RequestMethod.POST)

@ResponseBody

String downloadfile(@RequestParam(name = "fname", required = true) String filename, HttpServletResponse response) {

/**

* 关于Query的具体用发下面的链接给的很清楚了,这里就不多说了。

*

* @link{http://www.baeldung.com/queries-in-spring-data-mongodb}

*/

Query query = Query.query(Criteria.where("filename").is(filename));

// 查询单个文件

GridFSDBFile gfsfile = gridFsTemplate.findOne(query);

// 通知浏览器进行文件下载

response.setContentType(gfsfile.getContentType());

response.setHeader("Content-Disposition", "attachment;filename=" + gfsfile.getFilename());

try {

gfsfile.writeTo(response.getOutputStream());

} catch (IOException e) {

e.printStackTrace();

}

return "success";

}

}

然后我们使用gradle启动工程:





然后我们打开主页选择上传的文件:



点击上传之后,我们收到服务器返回的文件信息(我没有做处理,信息就是Mongodb返回的):



接下来我们回到主页,去下载这个文件(输入刚才上传的文件名):



然后点击下载就出现了下面的一幕:



浏览器已经开始下载我们的文件了。

这就是我们这次演示的过程。Mongodb为我们管理文件,特别由于Mongodb本身就是分布式数据库,我们的文件也就是分布式存储了,比自己搭建一个分布式文件服务器方便多了。但Mongodbgfs适合大文件,小文件直接存入文档,更加方便。

给一点我的建议:多看源码,多看官方的文档。

如有问题,可联系我:1427730623.

我的工程结构图(一个入口类,一个html,一个controller,再加一个配置文件,代码基本上博客都贴出来了,我就不放工程了):

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: