1. Przegląd
W tym samouczku omówimy, jak przesyłać i pobierać pliki za pomocą MongoDB i Spring Boot.
Będziemy używać MongoDB BSON dla małych plików i GridFS dla większych.
2. Konfiguracja Maven
Najpierw dodamy spring-boot-starter-data-mongodb zależność od naszego pom.xml :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
Ponadto będziemy potrzebować strony startowej spring-boot-starter i spring-boot-starter-thymeleaf zależności do wyświetlenia interfejsu użytkownika naszej aplikacji. Te zależności są również pokazane w naszym Przewodniku po Spring Boot with Thymeleaf.
W tym samouczku używamy Spring Boot w wersji 2.x.
3. Właściwości wiosennego rozruchu
Następnie skonfigurujemy niezbędne właściwości Spring Boot.
Zacznijmy od właściwości MongoDB :
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=springboot-mongo
Ustawimy również właściwości Servlet Multipart, aby umożliwić przesyłanie dużych plików:
spring.servlet.multipart.max-file-size=256MB
spring.servlet.multipart.max-request-size=256MB
spring.servlet.multipart.enabled=true
4. Przesyłanie małych plików
Teraz omówimy, jak przesyłać i pobierać małe pliki (rozmiar <16 MB) za pomocą MongoDB BSON .
Tutaj mamy prosty Dokument klasa — Zdjęcie. Będziemy przechowywać nasz plik obrazu w BSON binarny :
@Document(collection = "photos")
public class Photo {
@Id
private String id;
private String title;
private Binary image;
}
I będziemy mieć proste PhotoRepository :
public interface PhotoRepository extends MongoRepository<Photo, String> { }
Teraz dla PhotoService , będziemy mieć tylko dwie metody:
- dodajZdjęcie() — aby przesłać zdjęcie do MongoDB
- getPhoto() — aby pobrać zdjęcie o podanym identyfikatorze
@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. Przesyłanie dużych plików
Teraz użyjemy GridFS do przesyłania i pobierania dużych plików.
Najpierw zdefiniujemy prosty DTO – Wideo – do reprezentowania dużego pliku:
public class Video {
private String title;
private InputStream stream;
}
Podobny do PhotoService , będziemy mieć usługę wideo dwiema metodami — addVideo() i 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;
}
}
Więcej informacji na temat korzystania z GridFS ze Springiem zapoznaj się z naszym artykułem GridFS w Spring Data MongoDB.
6. Kontrolery
Przyjrzyjmy się teraz kontrolerom — PhotoController i Kontroler wideo .
6.1. Kontroler zdjęć
Po pierwsze, mamy PhotoController, który będzie korzystał z naszej PhotoService dodawać/pobierać zdjęcia .
Zdefiniujemy addPhoto() metoda przesyłania i tworzenia nowego zdjęcia :
@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;
}
Mamy też getPhoto() aby pobrać zdjęcie o podanym identyfikatorze:
@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";
}
Pamiętaj, że ponieważ dane obrazu są zwracane jako byte[] , przekonwertujemy go na Base64 Ciąg aby wyświetlić go na interfejsie użytkownika.
6.2. Kontroler wideo
Następnie spójrzmy na nasz VideoController .
Będzie to miało podobną metodę, addVideo() , aby przesłać film do naszej bazy danych 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;
}
A oto mamy getVideo() aby pobrać wideo z podanym 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";
}
Możemy również dodać streamVideo() metoda, która utworzy strumieniowy adres URL z Wideo strumień wejściowy :
@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. Interfejs
Na koniec zobaczmy nasz interfejs.
Zacznijmy od uploadPhoto.html , który zapewnia prosty formularz do przesłania obrazu:
<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>
Następnie dodamy photos.html widok, aby wyświetlić nasze zdjęcia:
<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>
Podobnie mamy uploadVideo.html przesłać film :
<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>
I videos.html aby wyświetlić filmy:
<html>
<body>
<h1>View Video</h1>
Title: <span th:text="${title}">title</span>
<video width="400" controls>
<source th:src="${url}" />
</video>
</body>
</html>