diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileLocationService.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileLocationService.java new file mode 100644 index 0000000000..6b2f33e885 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileLocationService.java @@ -0,0 +1,31 @@ +package com.baeldung.db.indexing; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +@Service +class FileLocationService { + + @Autowired + FileSystemRepository fileSystemRepository; + @Autowired + ImageDbRepository imageDbRepository; + + Long save(byte[] bytes, String imageName) throws Exception { + String location = fileSystemRepository.save(bytes, imageName); + + return imageDbRepository.save(new Image(imageName, location)) + .getId(); + } + + FileSystemResource find(Long imageId) { + Image image = imageDbRepository.findById(imageId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + + return fileSystemRepository.findInFileSystem(image.getLocation()); + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemImageController.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemImageController.java new file mode 100644 index 0000000000..09e33bb943 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemImageController.java @@ -0,0 +1,30 @@ +package com.baeldung.db.indexing; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.MediaType; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("file-system") +class FileSystemImageController { + + @Autowired + FileLocationService fileLocationService; + + @PostMapping("/image") + Long uploadImage(@RequestParam MultipartFile image) throws Exception { + return fileLocationService.save(image.getBytes(), image.getOriginalFilename()); + } + + @GetMapping(value = "/image/{imageId}", produces = MediaType.IMAGE_JPEG_VALUE) + FileSystemResource downloadImage(@PathVariable Long imageId) throws Exception { + return fileLocationService.find(imageId); + } +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemRepository.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemRepository.java new file mode 100644 index 0000000000..bc6bdecfed --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/FileSystemRepository.java @@ -0,0 +1,36 @@ +package com.baeldung.db.indexing; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.stereotype.Repository; + +@Repository +class FileSystemRepository { + + String RESOURCES_DIR = FileSystemRepository.class.getResource("/") + .getPath(); + + String save(byte[] content, String imageName) throws Exception { + Path newFile = Paths.get(RESOURCES_DIR + new Date().getTime() + "-" + imageName); + Files.createDirectories(newFile.getParent()); + + Files.write(newFile, content); + + return newFile.toAbsolutePath() + .toString(); + } + + FileSystemResource findInFileSystem(String location) { + try { + return new FileSystemResource(Paths.get(location)); + } catch (Exception e) { + // Handle access or file not found problems. + throw new RuntimeException(); + } + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/Image.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/Image.java new file mode 100644 index 0000000000..5348788c12 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/Image.java @@ -0,0 +1,62 @@ +package com.baeldung.db.indexing; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Lob; + +@Entity +class Image { + + @Id + @GeneratedValue + Long id; + + String name; + + String location; + + @Lob + byte[] content; + + public Image() { + } + + public Image(String name, String location) { + this.name = name; + this.location = location; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageArchiveApplication.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageArchiveApplication.java new file mode 100644 index 0000000000..02d2db32b3 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageArchiveApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.db.indexing; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ImageArchiveApplication { + + public static void main(String[] args) { + SpringApplication.run(ImageArchiveApplication.class, args); + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageController.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageController.java new file mode 100644 index 0000000000..1b2378a51f --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageController.java @@ -0,0 +1,46 @@ +package com.baeldung.db.indexing; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +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.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ResponseStatusException; + +import lombok.extern.slf4j.Slf4j; + +@RestController +@Slf4j +class ImageController { + + @Autowired + ImageDbRepository imageDbRepository; + + @PostMapping("/image") + long uploadImage(@RequestParam MultipartFile multipartImage) throws IOException { + Image dbImage = new Image(); + dbImage.setName(multipartImage.getOriginalFilename()); + dbImage.setContent(multipartImage.getBytes()); + + return imageDbRepository.save(dbImage) + .getId(); + } + + @GetMapping(value = "/image/{imageId}", produces = MediaType.IMAGE_JPEG_VALUE) + Resource downloadImage(@PathVariable Long imageId) { + byte[] image = imageDbRepository.findById(imageId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)) + .getContent(); + + return new ByteArrayResource(image); + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageDbRepository.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageDbRepository.java new file mode 100644 index 0000000000..eb33f14dae --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/db/indexing/ImageDbRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.db.indexing; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +interface ImageDbRepository extends JpaRepository { + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/FileSystemImageIntegrationTest.java b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/FileSystemImageIntegrationTest.java new file mode 100644 index 0000000000..3082f16a78 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/FileSystemImageIntegrationTest.java @@ -0,0 +1,69 @@ +package com.baeldung.db.indexing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@SpringBootTest(classes = ImageArchiveApplication.class) +@AutoConfigureMockMvc +class FileSystemImageIntegrationTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + FileLocationService fileLocationService; + + @Test + void givenJpegImage_whenUploadIt_thenReturnItsId() throws Exception { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + InputStream image = classLoader.getResourceAsStream("baeldung.jpeg"); + + MockMultipartHttpServletRequestBuilder multipartRequest = MockMvcRequestBuilders.multipart("/file-system/image") + .file(new MockMultipartFile("image", "baeldung", MediaType.TEXT_PLAIN_VALUE, image)); + + MvcResult result = mockMvc.perform(multipartRequest) + .andExpect(status().isOk()) + .andReturn(); + + assertThat(result.getResponse() + .getContentAsString()) + .isEqualTo("1"); + } + + @Test + void givenBaeldungImage_whenDownloadIt_thenReturnTheImage() throws Exception { + given(fileLocationService.find(1L)) + .willReturn(baeldungJpegResource()); + + mockMvc.perform(MockMvcRequestBuilders + .get("/file-system/image/1") + .contentType(MediaType.IMAGE_JPEG_VALUE)) + .andExpect(status().isOk()); + } + + private FileSystemResource baeldungJpegResource() { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + String imagePath = classLoader.getResource("baeldung.jpeg") + .getFile(); + + return new FileSystemResource(Paths.get(imagePath)); + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/ImageIntegrationTest.java b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/ImageIntegrationTest.java new file mode 100644 index 0000000000..f7d4ecf129 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/db/indexing/ImageIntegrationTest.java @@ -0,0 +1,72 @@ +package com.baeldung.db.indexing; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@SpringBootTest(classes = ImageArchiveApplication.class) +@AutoConfigureMockMvc +class ImageIntegrationTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + ImageDbRepository imageRepository; + + @Test + void givenBaeldungJpegImage_whenUploadIt_thenReturnItsId() throws Exception { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + InputStream image = classLoader.getResourceAsStream("baeldung.jpeg"); + + MockMultipartHttpServletRequestBuilder multipartRequest = MockMvcRequestBuilders.multipart("/image") + .file(new MockMultipartFile("image", "baeldung", MediaType.TEXT_PLAIN_VALUE, image)); + + MvcResult result = mockMvc.perform(multipartRequest) + .andExpect(status().isOk()) + .andReturn(); + + assertThat(result.getResponse() + .getContentAsString()) + .isEqualTo("1"); + } + + @Test + void givenExistingImage_whenDownloadIt_thenReturnHttpStatusOk() throws Exception { + given(imageRepository.findById(1L)) + .willReturn(Optional.of(baeldungImage())); + + mockMvc.perform(MockMvcRequestBuilders + .get("/image/1") + .contentType(MediaType.IMAGE_JPEG_VALUE)) + .andExpect(status().isOk()); + } + + private Image baeldungImage() throws IOException { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + + Image mockImage = new Image(); + mockImage.setContent(Files.readAllBytes(Paths.get(classLoader.getResource("baeldung.jpeg") + .getFile()))); + return mockImage; + } + +} diff --git a/persistence-modules/spring-boot-persistence-2/src/test/resources/baeldung.jpeg b/persistence-modules/spring-boot-persistence-2/src/test/resources/baeldung.jpeg new file mode 100644 index 0000000000..2654748a27 Binary files /dev/null and b/persistence-modules/spring-boot-persistence-2/src/test/resources/baeldung.jpeg differ