Initial commit.
This commit is contained in:
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**
|
||||||
|
!**/src/test/**
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
61
pom.xml
Normal file
61
pom.xml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.2.5.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>rest-file-api</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>demo</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-fileupload</groupId>
|
||||||
|
<artifactId>commons-fileupload</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
13
src/main/java/com/example/demo/DemoApplication.java
Normal file
13
src/main/java/com/example/demo/DemoApplication.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.demo;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class DemoApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(DemoApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.demo.configuration;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.multipart.MultipartResolver;
|
||||||
|
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MultipartResolverConfiguration {
|
||||||
|
@Bean
|
||||||
|
public MultipartResolver multipartResolver(@Value("${app.files.uploads.max-size}") int maxSize) {
|
||||||
|
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
|
||||||
|
multipartResolver.setMaxUploadSize(maxSize * 1000 * 1000);
|
||||||
|
return multipartResolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.example.demo.controller;
|
||||||
|
|
||||||
|
import com.example.demo.payload.UploadFileResponse;
|
||||||
|
import com.example.demo.service.FileService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
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.support.ServletUriComponentsBuilder;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class FileController {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FileController.class);
|
||||||
|
private FileService service;
|
||||||
|
|
||||||
|
public FileController(FileService service) {
|
||||||
|
this.service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/upload")
|
||||||
|
public UploadFileResponse upload(@RequestParam("file") MultipartFile file) {
|
||||||
|
String fileName = service.store(file);
|
||||||
|
|
||||||
|
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
|
||||||
|
.path("/downloadFile/")
|
||||||
|
.path(fileName)
|
||||||
|
.toUriString();
|
||||||
|
|
||||||
|
return new UploadFileResponse(fileName, fileDownloadUri, file.getContentType(), file.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/uploadMultipleFiles")
|
||||||
|
public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
|
||||||
|
return Arrays.asList(files)
|
||||||
|
.stream()
|
||||||
|
.map(file -> upload(file))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/downloadFile/{fileName:.+}")
|
||||||
|
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
|
||||||
|
// Load file as Resource
|
||||||
|
Resource resource = service.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.example.demo.exception;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class FileStorageException extends RuntimeException {
|
||||||
|
public FileStorageException(String s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileStorageException(String s, IOException ex) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.example.demo.exception;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
|
public class MyFileNotFoundException extends RuntimeException {
|
||||||
|
public MyFileNotFoundException(String s, MalformedURLException ex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyFileNotFoundException(String s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.example.demo.payload;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/main/java/com/example/demo/service/FileService.java
Normal file
61
src/main/java/com/example/demo/service/FileService.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package com.example.demo.service;
|
||||||
|
|
||||||
|
import com.example.demo.exception.FileStorageException;
|
||||||
|
import com.example.demo.exception.MyFileNotFoundException;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FileService {
|
||||||
|
|
||||||
|
|
||||||
|
private Path fileStorageLocation;
|
||||||
|
|
||||||
|
public FileService(@Value("${app.files.uploads.dir}") Path fileStorageLocation) {
|
||||||
|
this.fileStorageLocation = fileStorageLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String store(MultipartFile file) {
|
||||||
|
// Normalize file name
|
||||||
|
String fileName = StringUtils.cleanPath(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 = 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 MyFileNotFoundException("File not found " + fileName);
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
throw new MyFileNotFoundException("File not found " + fileName, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main/resources/application.yml
Normal file
14
src/main/resources/application.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
spring:
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
enabled: true
|
||||||
|
file-size-threshold: 2KB
|
||||||
|
max-file-size: 2000MB
|
||||||
|
max-request-size: 2150MB
|
||||||
|
|
||||||
|
app:
|
||||||
|
files:
|
||||||
|
uploads:
|
||||||
|
dir: /home/takiguchi/Developpement/Java/back-ups/demo2/files/uploads
|
||||||
|
# Max size in MB
|
||||||
|
max-size: 2000
|
||||||
Reference in New Issue
Block a user