Gestion de fichiers images dans Springboot

La gestion de l’upload de fichiers images dans Springboot s’appuie sur plusieurs classes et fichiers.

FileUploadController agit comme un contrôleur qui va recevoir la demande d’upload de fichier (via l’url /upload) et la demande d’afficher l’image ( via l’url /files/{filename:.+} ). nCette classe contient une référence sur une classe FileSystemStorageService implementant l’interface StorageService.

StorageService est une simple interface qui permet de définir les actions classiques d’un service Spring de stockage.

FileSystemStorageService implémente de façon réelle l’interface StorageService pour la gestion du lieu de stockage des fichiers. Par ailleurs, pour une raison de sécurité, on peut stocker les fichiers uploadés dans un dossier dont l’accès est protégé pour éviter l’upload de fichiers critiques sur le serveur en devinant l’URL.

upload.html est un fichier gérant le formulaire HTML permettant d’envoyer un fichier simplement sans javascript encore une fois pour simplifier cet exemple.

Après les liaisons entre les fichiers, voici le contenu très simplifié de ces derniers:

<!DOCTYPE html><html lang="en"><head>
  <title>upload</title>
<body>
<form method="post" enctype="multipart/form-data" action="/upload">
 <div>
   <label for="file">Sélectionner le fichier à envoyer</label>
   <input type="file" id="file" name="file" >
 </div> <div>
   <button>Envoyer</button>
 </div>
</form>
</body></html>

L’upload d’un fichier image se fait vers le contrôleur FileUploadController via l’action /upload, cette classe permet aussi l’affichage d’une ressource image dans le navigateur (il manque la gestion des exceptions à coder en plus) :

@Controller
public class FileUploadController {
  // Service spring de stockage des fichiers
  private final StorageService storageService;
  // Constructeur de la classe avec l'activation du service
  @Autowired
  public FileUploadController(StorageService storageService) {
    this.storageService = storageService;
  }

  @GetMapping("/files/{filename:.+}")
  @ResponseBody
   public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
  Resource file = storageService.loadAsResource(filename);
  String mimeType = URLConnection.guessContentTypeFromName(file.getFilename());
   long contentLength = 0;
   try {
	contentLength = file.contentLength();
   } catch (IOException e) { }
		
   InputStream fileInputStream = null;
   try {   fileInputStream = file.getInputStream();
    } catch (IOException e) {}
		
   return ResponseEntity.ok().contentLength( contentLength )
	.contentType(MediaType.parseMediaType( mimeType ))
	.body(new InputStreamResource( fileInputStream ));
  }

//Upload d'un fichier 
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
   storageService.store(file);
   return "redirect:/";
}

}

L’interface StorageService permet de définir les méthodes à implémenter par FileSystemStorageService.

public interface StorageService {
    void init();
    String store(MultipartFile file);
    Stream<Path> loadAll();
    Path load(String filename);
    Resource loadAsResource(String filename);
    void deleteAll();
}

Enfin la classe FileSystemStorageService permet de créer un service qui va stocker les fichiers dans un dossier ./Stockage dans le projet Spring (la gestion des exceptions est à coder en plus):

@Service
public class FileSystemStorageService implements StorageService {
  private final Path rootLocation;
  @Autowired
  public FileSystemStorageService() {
    this.rootLocation = Paths.get("./Stockage/");
   }
  @Override
  @PostConstruct
  public void init() {
     try {
	Files.createDirectories(rootLocation);
    } catch (IOException e) {}
   }

  @Override
   public String store(MultipartFile file) {
String filename = StringUtils.cleanPath(file.getOriginalFilename());
  try {
  if (file.isEmpty()) {}  
  if (filename.contains("..")) { }
   try (InputStream inputStream = file.getInputStream()) {
    Files.copy(inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
    }
   } catch (IOException e) {	}
   return filename;
}

@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) {	return null; }

}

@Override
public Path load(String filename) {
  return rootLocation.resolve(filename);
}

@Override
public Resource loadAsResource(String filename) {
  Path file = load(filename);
  Resource resource = null;
  try {
     resource = new UrlResource(file.toUri());
   if (resource.exists() || resource.isReadable()) {
      return resource;
   } else {
     System.out.println("File not found " + filename); 
   }
  } catch (MalformedURLException e) { }
		return resource;
}

@Override
public void deleteAll() {
  FileSystemUtils.deleteRecursively(rootLocation.toFile());
}

}

Le code du contrôleur FileUploadController permet d’afficher le fichier image dans le navigateur, si on souhaite proposer en téléchargement un fichier, la méthode serveFile doit être modifiée:

    Resource file = storageService.loadAsResource(filename);
   return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFilename() + "\"").body(file);

Merci à cet article (https://spring.io/guides/gs/uploading-files/) qui a permit la rédaction de ce contenu.

A propos Pierre Jean

Ingénieur de Recherche CERIS Centre d'Enseignement et de Recherche en Informatique et Systèmes IMT Mines Alès UMR Euromov DHM Plus de détails sur Pierre JEAN
Ce contenu a été publié dans Développement, IMT Mines Alès. Vous pouvez le mettre en favoris avec ce permalien.