Merge pull request #7159 from Doha2012/master
upload files using mongodb and spring boot
This commit is contained in:
commit
176c16eff6
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.java.collections;
|
||||
package com.baeldung.java.collections;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
|
@ -20,6 +20,10 @@
|
|||
<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>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.mongodb.daos;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.mongodb.models.Photo;
|
||||
|
||||
public interface PhotoRepository extends MongoRepository<Photo, String> {
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.mongodb.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.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,38 @@
|
|||
package com.baeldung.mongodb.services;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
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.daos.PhotoRepository;
|
||||
import com.baeldung.mongodb.models.Photo;
|
||||
|
||||
@Service
|
||||
public class PhotoService {
|
||||
|
||||
@Autowired
|
||||
private PhotoRepository photoRepo;
|
||||
|
||||
public Photo getPhoto(String id) {
|
||||
Optional<Photo> result = photoRepo.findById(id);
|
||||
return result.isPresent() ? result.get() : null;
|
||||
}
|
||||
|
||||
public String addPhoto(String title, MultipartFile file) {
|
||||
String id = null;
|
||||
try {
|
||||
Photo photo = new Photo(title);
|
||||
photo.setImage(new Binary(BsonBinarySubType.BINARY, file.getBytes()));
|
||||
photo = photoRepo.insert(photo);
|
||||
id = photo.getId();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.mongodb.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.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) {
|
||||
Video video = null;
|
||||
GridFSFile file = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
|
||||
if (file != null) {
|
||||
video = new Video();
|
||||
video.setTitle(file.getMetadata().get("title").toString());
|
||||
try {
|
||||
video.setStream(operations.getResource(file).getInputStream());
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return video;
|
||||
}
|
||||
|
||||
public String addVideo(String title, MultipartFile file) {
|
||||
DBObject metaData = new BasicDBObject();
|
||||
metaData.put("type", "video");
|
||||
metaData.put("title", title);
|
||||
ObjectId id;
|
||||
try {
|
||||
id = gridFsTemplate.store(file.getInputStream(), file.getName(), file.getContentType(), metaData);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.baeldung.mongodb.web;
|
||||
|
||||
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.models.Photo;
|
||||
import com.baeldung.mongodb.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);
|
||||
if (photo != null) {
|
||||
model.addAttribute("title", photo.getTitle());
|
||||
model.addAttribute("image", Base64.getEncoder().encodeToString(photo.getImage().getData()));
|
||||
return "photos";
|
||||
}
|
||||
model.addAttribute("message", "Photo not found");
|
||||
return "index";
|
||||
}
|
||||
|
||||
@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) {
|
||||
String id = photoService.addPhoto(title, image);
|
||||
if (id == null) {
|
||||
model.addAttribute("message", "Error Occurred");
|
||||
return "index";
|
||||
}
|
||||
return "redirect:/photos/" + id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.baeldung.mongodb.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.models.Video;
|
||||
import com.baeldung.mongodb.services.VideoService;
|
||||
|
||||
@Controller
|
||||
public class VideoController {
|
||||
|
||||
@Autowired
|
||||
private VideoService videoService;
|
||||
|
||||
@GetMapping("/videos/{id}")
|
||||
public String getVideo(@PathVariable String id, Model model) {
|
||||
Video video = videoService.getVideo(id);
|
||||
if (video != null) {
|
||||
model.addAttribute("title", video.getTitle());
|
||||
model.addAttribute("url", "/videos/stream/" + id);
|
||||
return "videos";
|
||||
}
|
||||
model.addAttribute("message", "Video not found");
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/videos/stream/{id}")
|
||||
public void streamVideo(@PathVariable String id, HttpServletResponse response) {
|
||||
Video video = videoService.getVideo(id);
|
||||
if (video != null) {
|
||||
try {
|
||||
FileCopyUtils.copy(video.getStream(), response.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
response.setStatus(500);
|
||||
}
|
||||
} else {
|
||||
response.setStatus(404);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
String id = videoService.addVideo(title, file);
|
||||
if (id == null) {
|
||||
model.addAttribute("message", "Error Occurred");
|
||||
return "index";
|
||||
}
|
||||
return "redirect:/videos/" + id;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,13 @@
|
|||
spring.application.name=spring-boot-persistence
|
||||
server.port=${PORT:0}
|
||||
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,30 @@
|
|||
package com.baeldung.properties.conversion;
|
||||
|
||||
public class Employee {
|
||||
|
||||
private String name;
|
||||
private double salary;
|
||||
|
||||
public Employee(String name, double salary) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.salary = salary;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public double getSalary() {
|
||||
return salary;
|
||||
}
|
||||
|
||||
public void setSalary(double salary) {
|
||||
this.salary = salary;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.properties.conversion;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationPropertiesBinding
|
||||
public class EmployeeConverter implements Converter<String, Employee> {
|
||||
|
||||
@Override
|
||||
public Employee convert(String from) {
|
||||
String[] data = from.split(",");
|
||||
return new Employee(data[0], Double.parseDouble(data[1]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.properties.conversion;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackageClasses = { PropertyConversion.class, EmployeeConverter.class })
|
||||
public class PropertiesConversionApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PropertiesConversionApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.baeldung.properties.conversion;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.convert.DataSizeUnit;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
import org.springframework.util.unit.DataUnit;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:conversion.properties")
|
||||
@ConfigurationProperties(prefix = "conversion")
|
||||
public class PropertyConversion {
|
||||
private Duration timeInDefaultUnit;
|
||||
|
||||
private Duration timeInNano;
|
||||
|
||||
@DurationUnit(ChronoUnit.DAYS)
|
||||
private Duration timeInDays;
|
||||
|
||||
private DataSize sizeInDefaultUnit;
|
||||
|
||||
private DataSize sizeInGB;
|
||||
|
||||
@DataSizeUnit(DataUnit.TERABYTES)
|
||||
private DataSize sizeInTB;
|
||||
|
||||
private Employee employee;
|
||||
|
||||
// Getters and setters
|
||||
|
||||
public Duration getTimeInDefaultUnit() {
|
||||
return timeInDefaultUnit;
|
||||
}
|
||||
|
||||
public void setTimeInDefaultUnit(Duration timeInDefaultUnit) {
|
||||
this.timeInDefaultUnit = timeInDefaultUnit;
|
||||
}
|
||||
|
||||
public Duration getTimeInNano() {
|
||||
return timeInNano;
|
||||
}
|
||||
|
||||
public void setTimeInNano(Duration timeInNano) {
|
||||
this.timeInNano = timeInNano;
|
||||
}
|
||||
|
||||
public Duration getTimeInDays() {
|
||||
return timeInDays;
|
||||
}
|
||||
|
||||
public void setTimeInDays(Duration timeInDays) {
|
||||
this.timeInDays = timeInDays;
|
||||
}
|
||||
|
||||
public DataSize getSizeInDefaultUnit() {
|
||||
return sizeInDefaultUnit;
|
||||
}
|
||||
|
||||
public void setSizeInDefaultUnit(DataSize sizeInDefaultUnit) {
|
||||
this.sizeInDefaultUnit = sizeInDefaultUnit;
|
||||
}
|
||||
|
||||
public DataSize getSizeInGB() {
|
||||
return sizeInGB;
|
||||
}
|
||||
|
||||
public void setSizeInGB(DataSize sizeInGB) {
|
||||
this.sizeInGB = sizeInGB;
|
||||
}
|
||||
|
||||
public DataSize getSizeInTB() {
|
||||
return sizeInTB;
|
||||
}
|
||||
|
||||
public void setSizeInTB(DataSize sizeInTB) {
|
||||
this.sizeInTB = sizeInTB;
|
||||
}
|
||||
|
||||
public Employee getEmployee() {
|
||||
return employee;
|
||||
}
|
||||
|
||||
public void setEmployee(Employee employee) {
|
||||
this.employee = employee;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.properties.conversion;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
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.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
import com.baeldung.properties.conversion.PropertiesConversionApplication;
|
||||
import com.baeldung.properties.conversion.PropertyConversion;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = PropertiesConversionApplication.class)
|
||||
@TestPropertySource("classpath:conversion.properties")
|
||||
public class PropertiesConversionIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private PropertyConversion properties;
|
||||
|
||||
@Test
|
||||
public void whenUseTimeUnitPropertyConversion_thenSuccess() throws Exception {
|
||||
assertEquals(Duration.ofMillis(10), properties.getTimeInDefaultUnit());
|
||||
assertEquals(Duration.ofNanos(9), properties.getTimeInNano());
|
||||
assertEquals(Duration.ofDays(2), properties.getTimeInDays());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUseDataSizePropertyConversion_thenSuccess() throws Exception {
|
||||
assertEquals(DataSize.ofBytes(300), properties.getSizeInDefaultUnit());
|
||||
assertEquals(DataSize.ofGigabytes(2), properties.getSizeInGB());
|
||||
assertEquals(DataSize.ofTerabytes(4), properties.getSizeInTB());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUseCustomPropertyConverter_thenSuccess() throws Exception {
|
||||
assertEquals("john", properties.getEmployee().getName());
|
||||
assertEquals(2000.0, properties.getEmployee().getSalary());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
###### time unit
|
||||
conversion.timeInDefaultUnit=10
|
||||
conversion.timeInNano=9ns
|
||||
conversion.timeInDays=2
|
||||
|
||||
###### data size
|
||||
conversion.sizeInDefaultUnit=300
|
||||
conversion.sizeInGB=2GB
|
||||
conversion.sizeInTB=4
|
||||
|
||||
conversion.employee=john,2000
|
Loading…
Reference in New Issue