-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Setup loading images to the temp directory
- Loading branch information
1 parent
3a9c8e4
commit e9da52f
Showing
18 changed files
with
612 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,4 @@ out/ | |
|
||
### VS Code ### | ||
.vscode/ | ||
/upload-image-dir/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.example.mypixel; | ||
|
||
public class ErrorInfo { | ||
public final String url; | ||
public final String ex; | ||
|
||
public ErrorInfo(String url, Exception ex) { | ||
this.url = url; | ||
this.ex = ex.getLocalizedMessage(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,26 @@ | ||
package com.example.mypixel; | ||
|
||
import com.example.mypixel.storage.StorageProperties; | ||
import com.example.mypixel.storage.StorageService; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
|
||
@SpringBootApplication | ||
@EnableConfigurationProperties(StorageProperties.class) | ||
public class MyPixelApplication { | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(MyPixelApplication.class, args); | ||
} | ||
|
||
@Bean | ||
CommandLineRunner init(StorageService storageService) { | ||
return (args) -> { | ||
storageService.deleteAll(); | ||
storageService.init(); | ||
}; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/main/java/com/example/mypixel/controller/ErrorController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.example.mypixel.controller; | ||
|
||
import com.example.mypixel.ErrorInfo; | ||
import com.example.mypixel.exception.InvalidImageFormat; | ||
import com.example.mypixel.exception.StorageException; | ||
import com.example.mypixel.exception.StorageFileNotFoundException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
|
||
@ControllerAdvice | ||
public class ErrorController { | ||
|
||
@ResponseStatus(HttpStatus.NOT_FOUND) | ||
@ExceptionHandler(StorageFileNotFoundException.class) | ||
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException ex, HttpServletRequest request) { | ||
String requestUrl = request.getRequestURL().toString(); | ||
ErrorInfo errorInfo = new ErrorInfo(requestUrl, ex); | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorInfo); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(InvalidImageFormat.class) | ||
public ResponseEntity<?> handleInvalidImageFormat(InvalidImageFormat ex, HttpServletRequest request) { | ||
String requestUrl = request.getRequestURL().toString(); | ||
ErrorInfo errorInfo = new ErrorInfo(requestUrl, ex); | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorInfo); | ||
} | ||
|
||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | ||
@ExceptionHandler(StorageException.class) | ||
public ResponseEntity<?> handleStorageException(StorageException ex, HttpServletRequest request) { | ||
String requestUrl = request.getRequestURL().toString(); | ||
ErrorInfo errorInfo = new ErrorInfo(requestUrl, ex); | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorInfo); | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
src/main/java/com/example/mypixel/controller/ImageUploadController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.example.mypixel.controller; | ||
|
||
|
||
import java.io.IOException; | ||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
import com.example.mypixel.exception.InvalidImageFormat; | ||
import com.example.mypixel.storage.StorageService; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.multipart.MultipartFile; | ||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; | ||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; | ||
|
||
@RestController | ||
public class ImageUploadController { | ||
|
||
private final StorageService storageService; | ||
|
||
@Autowired | ||
public ImageUploadController(StorageService storageService) { | ||
this.storageService = storageService; | ||
} | ||
|
||
@GetMapping("/") | ||
public List<String> listUploadedFiles() { | ||
|
||
return storageService.loadAll().map( | ||
path -> MvcUriComponentsBuilder.fromMethodName(ImageUploadController.class, | ||
"serveFile", path.getFileName().toString()).build().toUri().toString()) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
@GetMapping("/images/{filename:.+}") | ||
@ResponseBody | ||
public ResponseEntity<Resource> serveFile(@PathVariable String filename) throws IOException { | ||
|
||
Resource file = storageService.loadAsResource(filename); | ||
|
||
if (file == null) | ||
return ResponseEntity.notFound().build(); | ||
|
||
String location = ServletUriComponentsBuilder | ||
.fromCurrentRequest() | ||
.toUriString(); | ||
|
||
return ResponseEntity.ok() | ||
.contentType(MediaType.IMAGE_JPEG) | ||
.header(HttpHeaders.LOCATION, location) | ||
.header(HttpHeaders.CONTENT_DISPOSITION, | ||
"attachment; filename=\"" + file.getFilename() + "\"").body(file); | ||
} | ||
|
||
@PostMapping("/") | ||
public ResponseEntity<Void> handleFileUpload(@RequestParam("file") MultipartFile file) { | ||
|
||
String contentType = file.getContentType(); | ||
if (!contentType.equals("image/jpeg") && !contentType.equals("image/png")) { | ||
throw new InvalidImageFormat("Only JPEG or PNG images are allowed"); | ||
} | ||
|
||
storageService.store(file); | ||
|
||
String filename = file.getOriginalFilename(); | ||
|
||
URI location = ServletUriComponentsBuilder | ||
.fromCurrentRequest() | ||
.path("/images/{filename}") | ||
.buildAndExpand(filename) | ||
.toUri(); | ||
|
||
return ResponseEntity.created(location).build(); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/mypixel/exception/InvalidImageFormat.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.mypixel.exception; | ||
|
||
public class InvalidImageFormat extends IllegalArgumentException { | ||
|
||
public InvalidImageFormat(String message) { | ||
super(message); | ||
} | ||
|
||
public InvalidImageFormat(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/mypixel/exception/StorageException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.mypixel.exception; | ||
|
||
public class StorageException extends RuntimeException { | ||
|
||
public StorageException(String message) { | ||
super(message); | ||
} | ||
|
||
public StorageException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/mypixel/exception/StorageFileNotFoundException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.mypixel.exception; | ||
|
||
public class StorageFileNotFoundException extends StorageException { | ||
|
||
public StorageFileNotFoundException(String message) { | ||
super(message); | ||
} | ||
|
||
public StorageFileNotFoundException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/example/mypixel/storage/StorageProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.example.mypixel.storage; | ||
|
||
import jakarta.annotation.Resource; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
||
@ConfigurationProperties("storage") | ||
public class StorageProperties { | ||
|
||
/** | ||
* Folder location for storing images | ||
*/ | ||
@Value("${storage.temp-images}") | ||
private String location; | ||
|
||
public String getLocation() { | ||
return location; | ||
} | ||
|
||
public void setLocation(String location) { | ||
this.location = location; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/example/mypixel/storage/StorageService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.example.mypixel.storage; | ||
|
||
import org.springframework.core.io.Resource; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.nio.file.Path; | ||
import java.util.stream.Stream; | ||
|
||
public interface StorageService { | ||
|
||
void init(); | ||
|
||
void store(MultipartFile file); | ||
|
||
Stream<Path> loadAll(); | ||
|
||
Path load(String filename); | ||
|
||
Resource loadAsResource(String filename); | ||
|
||
void deleteAll(); | ||
} |
102 changes: 102 additions & 0 deletions
102
src/main/java/com/example/mypixel/storage/TempStorageService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package com.example.mypixel.storage; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.MalformedURLException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardCopyOption; | ||
import java.util.stream.Stream; | ||
|
||
import com.example.mypixel.exception.StorageException; | ||
import com.example.mypixel.exception.StorageFileNotFoundException; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.core.io.UrlResource; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.util.FileSystemUtils; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Service | ||
public class TempStorageService implements StorageService { | ||
|
||
private final Path rootLocation; | ||
|
||
@Autowired | ||
public TempStorageService(StorageProperties properties) { | ||
|
||
if (properties.getLocation().trim().length() == 0) { | ||
throw new StorageException("File upload location can not be Empty."); | ||
} | ||
|
||
this.rootLocation = Paths.get(properties.getLocation()); | ||
} | ||
|
||
@Override | ||
public void store(MultipartFile file) { | ||
try { | ||
if (file.isEmpty()) { | ||
throw new StorageException("Failed to store empty file."); | ||
} | ||
Path destinationFile = this.rootLocation.resolve( | ||
Paths.get(file.getOriginalFilename())) | ||
.normalize().toAbsolutePath(); | ||
if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) { | ||
// This is a security check | ||
throw new StorageException("Cannot store file outside current directory."); | ||
} | ||
try (InputStream inputStream = file.getInputStream()) { | ||
Files.copy(inputStream, destinationFile, | ||
StandardCopyOption.REPLACE_EXISTING); | ||
} | ||
} catch (IOException e) { | ||
throw new StorageException("Failed to store file.", e); | ||
} | ||
} | ||
|
||
@Override | ||
public Stream<Path> loadAll() { | ||
try { | ||
return Files.walk(this.rootLocation, 1) | ||
.filter(path -> !path.equals(this.rootLocation)) | ||
.map(this.rootLocation::relativize); | ||
} catch (IOException e) { | ||
throw new StorageException("Failed to read stored files", e); | ||
} | ||
} | ||
|
||
@Override | ||
public Path load(String filename) { | ||
return rootLocation.resolve(filename); | ||
} | ||
|
||
@Override | ||
public Resource loadAsResource(String filename) { | ||
try { | ||
Path file = load(filename); | ||
Resource resource = new UrlResource(file.toUri()); | ||
if (resource.exists() || resource.isReadable()) { | ||
return resource; | ||
} else { | ||
throw new StorageFileNotFoundException("Could not read file: " + filename); | ||
} | ||
} catch (MalformedURLException e) { | ||
throw new StorageFileNotFoundException("Could not read file: " + filename, e); | ||
} | ||
} | ||
|
||
@Override | ||
public void deleteAll() { | ||
FileSystemUtils.deleteRecursively(rootLocation.toFile()); | ||
} | ||
|
||
@Override | ||
public void init() { | ||
try { | ||
Files.createDirectories(rootLocation); | ||
} catch (IOException e) { | ||
throw new StorageException("Could not initialize storage", e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
spring: | ||
servlet: | ||
multipart: | ||
max-file-size: 8MB | ||
max-request-size: 8MB | ||
|
||
storage: | ||
temp-images: upload-image-dir |
Oops, something went wrong.