Spring Boot embarque Tomcat, aucune installation supplémentaire n’est requise. Il suffit de déposer les fichiers dans un dossier local puis d’exposer ce dossier via une URL pour que les navigateurs y accèdent.
Dépendanecs Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
Contrôleur REST
package com.demo.media.controller;
import com.demo.media.payload.UploadResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class MediaUploadController {
private static final DateTimeFormatter PATH_FORMAT = DateTimeFormatter.ofPattern("yyyy/MM/dd");
@Value("${storage.root}")
private String rootFolder;
@PostMapping("/photos")
public ResponseEntity<UploadResponse> handleUpload(@RequestParam("file") MultipartFile file) {
LocalDate today = LocalDate.now();
String subFolder = today.format(PATH_FORMAT);
Path targetDir = Paths.get(rootFolder, subFolder);
if (!Files.exists(targetDir)) {
try {
Files.createDirectories(targetDir);
} catch (IOException e) {
return ResponseEntity.internalServerError()
.body(new UploadResponse("500", "Impossible de créer le dossier", null));
}
}
String extension = com.google.common.io.Files.getFileExtension(file.getOriginalFilename());
String randomName = UUID.randomUUID().toString().replace("-", "") + "." + extension;
Path destination = targetDir.resolve(randomName);
try {
Files.copy(file.getInputStream(), destination, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
return ResponseEntity.internalServerError()
.body(new UploadResponse("500", "Erreur d’écriture", null));
}
String publicUrl = "/photos/" + subFolder + "/" + randomName;
return ResponseEntity.ok(new UploadResponse("200", "Envoi réussi", publicUrl));
}
}
Classe de réponse JSON
package com.demo.media.payload;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UploadResponse {
private String status;
private String message;
private String url;
}
Configuration du mapping statique
package com.demo.media.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
@Value("${storage.root}")
private String diskLocation;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/photos/**")
.addResourceLocations("file:" + diskLocation);
}
}
Paramètres appilcatifs (application.yml)
storage:
root: C:/media/
server:
port: 8080
spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
Après démarrage, un fichier déposé via POST /api/photos sera accessible à l’adresse :
http://localhost:8080/photos/2024/05/12/7f3a9c2b.jpg