Last active
January 15, 2020 17:10
-
-
Save tinmegali/9f6634be3d1b8429d249c837982ad9d3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
@SpringBootApplication | |
@EnableConfigurationProperties({ApplicationProperties.class}) | |
public class Application { | |
// ... | |
} |
This file contains hidden or 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
spring: | |
servlet: | |
multipart: | |
# Enable multipart uploads | |
enabled: true | |
# Threshold after which files are written to disk. | |
file-size-threshold: 2KB | |
# Max file size | |
max-file-size: 15MB | |
# Max request size | |
max-request-size: 20MB | |
application: | |
file: | |
## File Storage Properties | |
# All files uploaded will be stored in this directory | |
upload-dir: /home/[user]/files |
This file contains hidden or 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
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) | |
public class ApplicationProperties { | |
public File file; | |
public File getFile() { | |
return file; | |
} | |
public void setFile(File file) { | |
this.file = file; | |
} | |
public static class File { | |
public String uploadDir; | |
public String getUploadDir() { | |
return uploadDir; | |
} | |
public void setUploadDir(String uploadDir) { | |
this.uploadDir = uploadDir; | |
} | |
} | |
} |
This file contains hidden or 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
@ResponseStatus(HttpStatus.NOT_FOUND) | |
public class FileNotFoundException extends RuntimeException { | |
public FileNotFoundException(String message) { | |
super(message); | |
} | |
public FileNotFoundException(String message, Throwable cause) { | |
super(message, cause); | |
} | |
} |
This file contains hidden or 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
@RestController | |
@RequestMapping("/api/files") | |
public class FileResource { | |
private static final Logger logger = LoggerFactory.getLogger(FileResource.class); | |
private final FileStorageService fileStorageService; | |
public FileResource(FileStorageService fileStorageService) { | |
this.fileStorageService = fileStorageService; | |
} | |
@PostMapping("/uploadFile") | |
public ResponseEntity<UploadFileResponse> uploadFile(@RequestParam("file") MultipartFile file) { | |
UploadFileResponse resp = saveFile(file); | |
return ResponseEntity.created(URI.create( resp.getFileDownloadUri() )) | |
.body(resp); | |
} | |
private UploadFileResponse saveFile(@RequestParam("file") MultipartFile file) { | |
String fileName = fileStorageService.storeFile(file); | |
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath() | |
.path("/downloadFile/") | |
.path(fileName) | |
.toUriString(); | |
return new UploadFileResponse(fileName, fileDownloadUri, | |
file.getContentType(), file.getSize()); | |
} | |
@PostMapping("/uploadMultipleFiles") | |
public ResponseEntity<List<UploadFileResponse>> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) { | |
List<UploadFileResponse> resp = Arrays.stream(files) | |
.map(this::saveFile) | |
.collect(Collectors.toList()); | |
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath() | |
.path("/downloadFile/") | |
.toUriString(); | |
return ResponseEntity.created(URI.create( fileDownloadUri )) | |
.body(resp); | |
} | |
@GetMapping("/downloadFile/{fileName:.+}") | |
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) { | |
// Load file as Resource | |
Resource resource = fileStorageService.loadFileAsResource(fileName); | |
// Try to determine file's content type | |
String contentType = null; | |
try { | |
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath()); | |
} catch (IOException ex) { | |
logger.info("Could not determine file type."); | |
} | |
// Fallback to the default content type if type could not be determined | |
if(contentType == null) { | |
contentType = "application/octet-stream"; | |
} | |
return ResponseEntity.ok() | |
.contentType(MediaType.parseMediaType(contentType)) | |
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") | |
.body(resource); | |
} | |
@DeleteMapping("/{fileName:.+}") | |
public ResponseEntity<Boolean> deleteFile(@PathVariable String fileName, HttpServletRequest request) { | |
try { | |
boolean resp = fileStorageService.deleteFile(fileName); | |
return ResponseEntity.ok() | |
.body(resp); | |
} catch (IOException e) { | |
throw new InternalServerErrorException(""); | |
} | |
} | |
} |
This file contains hidden or 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
public class FileStorageException extends RuntimeException { | |
public FileStorageException(String message) { | |
super(message); | |
} | |
public FileStorageException(String message, Throwable cause) { | |
super(message, cause); | |
} | |
} |
This file contains hidden or 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
@Service | |
public class FileStorageService implements FileStorageService { | |
private final Path fileStorageLocation; | |
@Autowired | |
public FileStorageServiceImpl(ApplicationProperties applicationProperties) { | |
this.fileStorageLocation = Paths.get(applicationProperties.getFile().getUploadDir()) | |
.toAbsolutePath().normalize(); | |
try { | |
Files.createDirectories(this.fileStorageLocation); | |
} catch (Exception ex) { | |
throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex); | |
} | |
} | |
public String storeFile(MultipartFile file) { | |
// Normalize file name | |
String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); | |
try { | |
// Check if the file's name contains invalid characters | |
if(fileName.contains("..")) { | |
throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName); | |
} | |
// Copy file to the target location (Replacing existing file with the same name) | |
Path targetLocation = this.fileStorageLocation.resolve(fileName); | |
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); | |
return fileName; | |
} catch (IOException ex) { | |
throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex); | |
} | |
} | |
public Resource loadFileAsResource(String fileName) { | |
try { | |
Path filePath = this.fileStorageLocation.resolve(fileName).normalize(); | |
Resource resource = new UrlResource(filePath.toUri()); | |
if(resource.exists()) { | |
return resource; | |
} else { | |
throw new FileNotFoundException("File not found " + fileName); | |
} | |
} catch (MalformedURLException ex) { | |
throw new FileNotFoundException("File not found " + fileName, ex); | |
} | |
} | |
@Override | |
public boolean deleteFile(String fileName) throws IOException { | |
Resource resource = loadFileAsResource(fileName); | |
return resource.getFile().delete(); | |
} | |
} |
This file contains hidden or 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
public class UploadFileResponse { | |
private String fileName; | |
private String fileDownloadUri; | |
private String fileType; | |
private long size; | |
public UploadFileResponse(String fileName, String fileDownloadUri, String fileType, long size) { | |
this.fileName = fileName; | |
this.fileDownloadUri = fileDownloadUri; | |
this.fileType = fileType; | |
this.size = size; | |
} | |
public String getFileName() { | |
return fileName; | |
} | |
public void setFileName(String fileName) { | |
this.fileName = fileName; | |
} | |
public String getFileDownloadUri() { | |
return fileDownloadUri; | |
} | |
public void setFileDownloadUri(String fileDownloadUri) { | |
this.fileDownloadUri = fileDownloadUri; | |
} | |
public String getFileType() { | |
return fileType; | |
} | |
public void setFileType(String fileType) { | |
this.fileType = fileType; | |
} | |
public long getSize() { | |
return size; | |
} | |
public void setSize(long size) { | |
this.size = size; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment