1. Oversigt
I denne øvelse vil vi diskutere, hvordan man uploader og henter filer ved hjælp af MongoDB og Spring Boot.
Vi bruger MongoDB BSON til små filer og GridFS til de større.
2. Maven-konfiguration
Først tilføjer vi spring-boot-starter-data-mongodb afhængighed af vores pom.xml :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
Derudover har vi brug for spring-boot-starter-web og spring-boot-starter-thymeleaf afhængigheder for at vise vores applikations brugergrænseflade. Disse afhængigheder er også vist i vores guide til fjederstøvle med Thymeleaf.
I denne øvelse bruger vi Spring Boot version 2.x.
3. Spring Boot Egenskaber
Dernæst konfigurerer vi de nødvendige Spring Boot-egenskaber.
Lad os starte med MongoDB-egenskaberne :
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=springboot-mongo
Vi indstiller også Servlet Multipart-egenskaberne til at tillade upload af store filer:
spring.servlet.multipart.max-file-size=256MB
spring.servlet.multipart.max-request-size=256MB
spring.servlet.multipart.enabled=true
4. Upload af små filer
Nu vil vi diskutere, hvordan man uploader og henter små filer (størrelse <16MB) ved hjælp af MongoDB BSON .
Her har vi et simpelt Dokument klasse — Foto. Vi gemmer vores billedfil i en BSON Binær :
@Document(collection = "photos")
public class Photo {
@Id
private String id;
private String title;
private Binary image;
}
Og vi får et simpelt PhotoRepository :
public interface PhotoRepository extends MongoRepository<Photo, String> { }
Nu til Fototjenesten , har vi kun to metoder:
- addPhoto() — for at uploade et Foto til MongoDB
- getPhoto() — for at hente et Foto med et givet 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. Upload af store filer
Nu bruger vi GridFS at uploade og hente store filer.
Først vil vi definere en simpel DTO – Video – for at repræsentere en stor fil:
public class Video {
private String title;
private InputStream stream;
}
Svarende til Fototjenesten , har vi en Videotjeneste med to metoder - addVideo() og 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 flere detaljer om brug af GridFS med Spring, tjek vores GridFS in Spring Data MongoDB-artikel.
6. Controllere
Lad os nu tage et kig på controllerne - PhotoController og VideoController .
6.1. PhotoController
Først har vi PhotoController, som vil bruge vores Fotoservice for at tilføje/hente billeder .
Vi definerer addPhoto() metode til at uploade og oprette et nyt Foto :
@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;
}
Vi har også getPhoto() for at hente et billede med et givet 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";
}
Bemærk, at da vi har billeddataene returneret som en byte[] , konverterer vi den til en Base64 String for at vise det på front-end.
6.2. VideoController
Lad os derefter tage et kig på vores VideoController .
Dette vil have en lignende metode, addVideo() , for at uploade en video til vores 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;
}
Og her har vi getVideo() for at hente en video med et givet 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";
}
Vi kan også tilføje en streamVideo() metode, der vil oprette en streaming-URL fra Videoen 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
Lad os endelig se vores front-end.
Lad os starte med uploadPhoto.html , som giver en simpel formular til at uploade et billede:
<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>
Dernæst tilføjer vi photos.html se for at vise vores billeder:
<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>
På samme måde har vi uploadVideo.html for at uploade en 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>
Og videos.html for at vise videoer:
<html>
<body>
<h1>View Video</h1>
Title: <span th:text="${title}">title</span>
<video width="400" controls>
<source th:src="${url}" />
</video>
</body>
</html>