1. Overview
In this tutorial, we’ll discuss how to upload and retrieve files using MongoDB and Spring Boot.
We’ll use MongoDB BSON for small files and GridFS for the larger ones.
2. Maven Configuration
First, we’ll add the spring-boot-starter-data-mongodb dependency to our pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
In addition, we’ll need the spring-boot-starter-web and spring-boot-starter-thymeleaf dependencies to display the user interface of our application. These dependencies are also shown in our Guide to Spring Boot with Thymeleaf.
In this tutorial, we’re using Spring Boot version 2.x.
3. Spring Boot Properties
Next, we’ll configure the necessary Spring Boot properties.
Let’s start with the MongoDB properties:
spring.data.mongodb.host=localhost spring.data.mongodb.port=27017 spring.data.mongodb.database=springboot-mongo
We’ll also set the Servlet Multipart properties to allow uploading large files:
spring.servlet.multipart.max-file-size=256MB spring.servlet.multipart.max-request-size=256MB spring.servlet.multipart.enabled=true
4. Uploading Small Files
Now, we’ll discuss how to upload and retrieve small files (size < 16MB) using MongoDB BSON.
Here, we have a simple Document class — Photo. We’ll store our image file in a BSON Binary:
@Document(collection = "photos") public class Photo { @Id private String id; private String title; private Binary image; }
And we’ll have a simple PhotoRepository:
public interface PhotoRepository extends MongoRepository<Photo, String> { }
Now, for the PhotoService, we’ll have only two methods:
- addPhoto() — to upload a Photo to MongoDB
- getPhoto() — to retrieve a Photo with a given id
@Service public class PhotoService { @Autowired private PhotoRepository photoRepo; public String addPhoto(String title, MultipartFile file) throws IOException { Photo photo = new Photo(title); photo.setImage( new Binary(BsonBinarySubType.BINARY, file.getBytes())); photo = photoRepo.insert(photo); return photo.getId(); } public Photo getPhoto(String id) { return photoRepo.findById(id).get(); } }
5. Uploading Large Files
Now, we’ll use GridFS to upload and retrieve large files.
First, we’ll define a simple DTO – Video – to represent a large file:
public class Video { private String title; private InputStream stream; }
Similar to the PhotoService, we’ll have a VideoService with two methods — addVideo() and getVideo():
@Service public class VideoService { @Autowired private GridFsTemplate gridFsTemplate; @Autowired private GridFsOperations operations; public String addVideo(String title, MultipartFile file) throws IOException { DBObject metaData = new BasicDBObject(); metaData.put("type", "video"); metaData.put("title", title); ObjectId id = gridFsTemplate.store( file.getInputStream(), file.getName(), file.getContentType(), metaData); return id.toString(); } public Video getVideo(String id) throws IllegalStateException, IOException { GridFSFile file = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id))); Video video = new Video(); video.setTitle(file.getMetadata().get("title").toString()); video.setStream(operations.getResource(file).getInputStream()); return video; } }
For more details on using GridFS with Spring, check our GridFS in Spring Data MongoDB article.
6. Controllers
Now, let’s take a look at the controllers — PhotoController and VideoController.
6.1. PhotoController
First, we have the PhotoController, which will use our PhotoService to add/get photos.
We’ll define the addPhoto() method to upload and create a new Photo:
@PostMapping("/photos/add") public String addPhoto(@RequestParam("title") String title, @RequestParam("image") MultipartFile image, Model model) throws IOException { String id = photoService.addPhoto(title, image); return "redirect:/photos/" + id; }
We also have getPhoto() to retrieve a Photo with a given id:
@GetMapping("/photos/{id}") public String getPhoto(@PathVariable String id, Model model) { Photo photo = photoService.getPhoto(id); model.addAttribute("title", photo.getTitle()); model.addAttribute("image", Base64.getEncoder().encodeToString(photo.getImage().getData())); return "photos"; }
Note that as we have the image data returned as a byte[], we’ll convert it to a Base64 String to display it on the front-end.
6.2 VideoController
Next, let’s have a look at our VideoController.
This will have a similar method, addVideo(), to upload a Video to our MongoDB:
@PostMapping("/videos/add") public String addVideo(@RequestParam("title") String title, @RequestParam("file") MultipartFile file, Model model) throws IOException { String id = videoService.addVideo(title, file); return "redirect:/videos/" + id; }
And here we have getVideo() to retrieve a Video with a given id:
@GetMapping("/videos/{id}") public String getVideo(@PathVariable String id, Model model) throws Exception { Video video = videoService.getVideo(id); model.addAttribute("title", video.getTitle()); model.addAttribute("url", "/videos/stream/" + id); return "videos"; }
We can also add a streamVideo() method that will create a streaming URL from the Video InputStream:
@GetMapping("/videos/stream/{id}") public void streamVideo(@PathVariable String id, HttpServletResponse response) throws Exception { Video video = videoService.getVideo(id); FileCopyUtils.copy(video.getStream(), response.getOutputStream()); }
7. Front-End
Finally, let’s see our front-end.
Let’s start with uploadPhoto.html, which provides a simple form to upload an image:
<html> <body> <h1>Upload new Photo</h1> <form method="POST" action="/photos/add" enctype="multipart/form-data"> Title:<input type="text" name="title" /> Image:<input type="file" name="image" accept="image/*" /> <input type="submit" value="Upload" /> </form> </body> </html>
Next, we’ll add the photos.html view to display our photos:
<html> <body> <h1>View Photo</h1> Title: <span th:text="${title}">name</span> <img alt="sample" th:src="*{'data:image/png;base64,'+image}" /> </body> </html>
Similarly, we have the uploadVideo.html to upload a Video:
<html> <body> <h1>Upload new Video</h1> <form method="POST" action="/videos/add" enctype="multipart/form-data"> Title:<input type="text" name="title" /> Video:<input type="file" name="file" accept="video/*" /> <input type="submit" value="Upload" /> </form> </body> </html>
And videos.html to display videos:
<html> <body> <h1>View Video</h1> Title: <span th:text="${title}">title</span> <video width="400" controls> <source th:src="${url}" /> </video> </body> </html>
8. Conclusion
In this article, we learned how to upload and retrieve files using MongoDB and Spring Boot. We used both BSON and GridFS to upload and retrieve files.
As always, the full source code is available in the GitHub project.