This commit is contained in:
Jonathan Cook
2019-10-23 15:01:44 +02:00
parent db85c8f275
commit 684ec0d2e3
20486 changed files with 1642483 additions and 0 deletions
@@ -0,0 +1,4 @@
/.idea/
/target/
/spring-boot-persistence.iml
@@ -0,0 +1,5 @@
# Relevant Articles
- [Auto-Generated Field for MongoDB using Spring Boot](https://www.baeldung.com/spring-boot-mongodb-auto-generated-field)
- [Spring Boot Integration Testing with Embedded MongoDB](http://www.baeldung.com/spring-boot-embedded-mongodb)
- [Upload and Retrieve Files Using MongoDB and Spring Boot](https://www.baeldung.com/spring-boot-mongodb-upload-file)
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-persistence-mongodb</artifactId>
<name>spring-boot-persistence-mongodb</name>
<packaging>war</packaging>
<description>This is simple boot application for Spring boot persistence mongodb test</description>
<parent>
<artifactId>parent-boot-2</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit Jupiter dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit platform launcher -->
<!-- To be able to run tests from IDE directly -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>${junit-platform.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-persistence</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autoconfiguration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*LiveTest.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntTest.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
@@ -0,0 +1,13 @@
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootPersistenceApplication {
public static void main(String ... args) {
SpringApplication.run(SpringBootPersistenceApplication.class, args);
}
}
@@ -0,0 +1,10 @@
package com.baeldung.mongodb.daos;
import com.baeldung.mongodb.models.User;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserRepository extends MongoRepository<User, Long> {
}
@@ -0,0 +1,30 @@
package com.baeldung.mongodb.events;
import com.baeldung.mongodb.models.User;
import com.baeldung.mongodb.services.SequenceGeneratorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.stereotype.Component;
@Component
public class UserModelListener extends AbstractMongoEventListener<User> {
private SequenceGeneratorService sequenceGenerator;
@Autowired
public UserModelListener(SequenceGeneratorService sequenceGenerator) {
this.sequenceGenerator = sequenceGenerator;
}
@Override
public void onBeforeConvert(BeforeConvertEvent<User> event) {
if (event.getSource().getId() < 1) {
event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME));
}
}
}
@@ -0,0 +1,9 @@
package com.baeldung.mongodb.file.daos;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.baeldung.mongodb.file.models.Photo;
public interface PhotoRepository extends MongoRepository<Photo, String> {
}
@@ -0,0 +1,51 @@
package com.baeldung.mongodb.file.models;
import org.bson.types.Binary;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "photos")
public class Photo {
@Id
private String id;
private String title;
private Binary image;
public Photo(String title) {
super();
this.title = title;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Binary getImage() {
return image;
}
public void setImage(Binary image) {
this.image = image;
}
@Override
public String toString() {
return "Photo [id=" + id + ", title=" + title + ", image=" + image + "]";
}
}
@@ -0,0 +1,39 @@
package com.baeldung.mongodb.file.models;
import java.io.InputStream;
public class Video {
private String title;
private InputStream stream;
public Video() {
super();
}
public Video(String title) {
super();
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public InputStream getStream() {
return stream;
}
public void setStream(InputStream stream) {
this.stream = stream;
}
@Override
public String toString() {
return "Video [title=" + title + "]";
}
}
@@ -0,0 +1,30 @@
package com.baeldung.mongodb.file.services;
import java.io.IOException;
import org.bson.BsonBinarySubType;
import org.bson.types.Binary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.baeldung.mongodb.file.daos.PhotoRepository;
import com.baeldung.mongodb.file.models.Photo;
@Service
public class PhotoService {
@Autowired
private PhotoRepository photoRepo;
public Photo getPhoto(String id) {
return photoRepo.findById(id).get();
}
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();
}
}
@@ -0,0 +1,44 @@
package com.baeldung.mongodb.file.services;
import java.io.IOException;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.baeldung.mongodb.file.models.Video;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.client.gridfs.model.GridFSFile;
@Service
public class VideoService {
@Autowired
private GridFsTemplate gridFsTemplate;
@Autowired
private GridFsOperations operations;
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;
}
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();
}
}
@@ -0,0 +1,43 @@
package com.baeldung.mongodb.file.web;
import java.io.IOException;
import java.util.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.baeldung.mongodb.file.models.Photo;
import com.baeldung.mongodb.file.services.PhotoService;
@Controller
public class PhotoController {
@Autowired
private PhotoService photoService;
@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";
}
@GetMapping("/photos/upload")
public String uploadPhoto(Model model) {
model.addAttribute("message", "hello");
return "uploadPhoto";
}
@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;
}
}
@@ -0,0 +1,51 @@
package com.baeldung.mongodb.file.web;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.baeldung.mongodb.file.models.Video;
import com.baeldung.mongodb.file.services.VideoService;
@Controller
public class VideoController {
@Autowired
private VideoService videoService;
@GetMapping("/videos/{id}")
public String getVideo(@PathVariable String id, Model model) throws IllegalStateException, IOException {
Video video = videoService.getVideo(id);
model.addAttribute("title", video.getTitle());
model.addAttribute("url", "/videos/stream/" + id);
return "videos";
}
@GetMapping("/videos/stream/{id}")
public void streamVideo(@PathVariable String id, HttpServletResponse response) throws IllegalStateException, IOException {
Video video = videoService.getVideo(id);
FileCopyUtils.copy(video.getStream(), response.getOutputStream());
}
@GetMapping("/videos/upload")
public String uploadVideo(Model model) {
model.addAttribute("message", "hello");
return "uploadVideo";
}
@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;
}
}
@@ -0,0 +1,32 @@
package com.baeldung.mongodb.models;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "database_sequences")
public class DatabaseSequence {
@Id
private String id;
private long seq;
public DatabaseSequence() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getSeq() {
return seq;
}
public void setSeq(long seq) {
this.seq = seq;
}
}
@@ -0,0 +1,73 @@
package com.baeldung.mongodb.models;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "users")
public class User {
@Transient
public static final String SEQUENCE_NAME = "users_sequence";
@Id
private long id;
private String firstName;
private String lastName;
private String email;
public User() { }
public User(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
}
@@ -0,0 +1,35 @@
package com.baeldung.mongodb.services;
import com.baeldung.mongodb.models.DatabaseSequence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import java.util.Objects;
import static org.springframework.data.mongodb.core.FindAndModifyOptions.options;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
@Service
public class SequenceGeneratorService {
private MongoOperations mongoOperations;
@Autowired
public SequenceGeneratorService(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
public long generateSequence(String seqName) {
DatabaseSequence counter = mongoOperations.findAndModify(query(where("_id").is(seqName)),
new Update().inc("seq",1), options().returnNew(true).upsert(true),
DatabaseSequence.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
}
@@ -0,0 +1,13 @@
spring.application.name=spring-boot-persistence
server.port=8082
#spring boot mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=springboot-mongo
spring.thymeleaf.cache=false
spring.servlet.multipart.max-file-size=256MB
spring.servlet.multipart.max-request-size=256MB
spring.servlet.multipart.enabled=true
@@ -0,0 +1,14 @@
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Upload Files MongoDB</title>
</head>
<body>
<h1>Home Page</h1>
<div th:if="${message != null}" th:text="${message}">Message</div>
<br/>
<a href="/photos/upload">Upload new Photo</a>
<br/><br/>
<a href="/videos/upload">Upload new Video</a>
</body>
</html>
@@ -0,0 +1,10 @@
<html xmlns:th="https://www.thymeleaf.org">
<body>
<h1>View Photo</h1>
Title: <span th:text="${title}">name</span>
<br/>
<img alt="sample" th:src="*{'data:image/png;base64,'+image}" width="200"/>
<br/> <br/>
<a href="/">Back to home page</a>
</body>
</html>
@@ -0,0 +1,15 @@
<html xmlns:th="https://www.thymeleaf.org">
<body>
<h1>Upload new Photo</h1>
<form method="POST" action="/photos/add" enctype="multipart/form-data">
Title:<input type="text" name="title" />
<br/>
Image:<input type="file" name="image" accept="image/*" />
<br/>
<br/>
<input type="submit" value="Upload" />
</form>
</body>
</html>
@@ -0,0 +1,15 @@
<html xmlns:th="https://www.thymeleaf.org">
<body>
<h1>Upload new Video</h1>
<form method="POST" action="/videos/add" enctype="multipart/form-data">
Title:<input type="text" name="title" />
<br/>
Video:<input type="file" name="file" accept="video/*" />
<br/>
<br/>
<input type="submit" value="Upload" />
</form>
</body>
</html>
@@ -0,0 +1,15 @@
<html xmlns:th="https://www.thymeleaf.org">
<body>
<h1>View Video</h1>
Title: <span th:text="${title}">title</span>
<br/>
<br/>
<video width="400" controls>
<source th:src="${url}" />
</video>
<br/> <br/>
<a href="/">Back to home page</a>
</body>
</html>
@@ -0,0 +1,63 @@
package com.baeldung.mongodb;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.util.SocketUtils;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
class ManualEmbeddedMongoDbIntegrationTest {
private MongodExecutable mongodExecutable;
private MongoTemplate mongoTemplate;
@AfterEach
void clean() {
mongodExecutable.stop();
}
@BeforeEach
void setup() throws Exception {
String ip = "localhost";
int randomPort = SocketUtils.findAvailableTcpPort();
IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main.PRODUCTION)
.net(new Net(ip, randomPort, Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
mongoTemplate = new MongoTemplate(new MongoClient(ip, randomPort), "test");
}
@DisplayName("Given object When save object using MongoDB template Then object can be found")
@Test
void test() throws Exception {
// given
DBObject objectToSave = BasicDBObjectBuilder.start()
.add("key", "value")
.get();
// when
mongoTemplate.save(objectToSave, "collection");
// then
assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
.containsOnly("value");
}
}
@@ -0,0 +1,40 @@
package com.baeldung.mongodb;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.mongodb.daos.UserRepository;
import com.baeldung.mongodb.models.User;
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class MongoDbAutoGeneratedFieldIntegrationTest {
@Autowired
UserRepository userRepository;
@Test
public void contextLoads() {}
@Test
public void givenUserObject_whenSave_thenCreateNewUser() {
User user = new User();
user.setFirstName("John");
user.setLastName("Doe");
user.setEmail("john.doe@example.com");
userRepository.save(user);
assertThat(userRepository.findAll().size()).isGreaterThan(0);
}
}
@@ -0,0 +1,39 @@
package com.baeldung.mongodb;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.baeldung.SpringBootPersistenceApplication;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
@ContextConfiguration(classes = SpringBootPersistenceApplication.class)
@DataMongoTest
@ExtendWith(SpringExtension.class)
@DirtiesContext
public class MongoDbSpringIntegrationTest {
@DisplayName("Given object When save object using MongoDB template Then object can be found")
@Test
public void test(@Autowired MongoTemplate mongoTemplate) {
// given
DBObject objectToSave = BasicDBObjectBuilder.start()
.add("key", "value")
.get();
// when
mongoTemplate.save(objectToSave, "collection");
// then
assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
.containsOnly("value");
}
}