史上最简单的mongodbGFS整合教程

今天主要为大家带来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中的配置。



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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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。我们看这个类的源码,我们今天所使用的方法都是来源于这个类。






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
/* 

* 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模板,用来上传文件,和下载文件。代码如下:





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<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代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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,再加一个配置文件,代码基本上博客都贴出来了,我就不放工程了):





更多内容敬请关注:“林老师带你学编程

林老师带你学编程 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!