Files
lionsdev-client-impl-quarkus/src/main/java/dev/lions/components/FileUploadComponent.java

227 lines
6.7 KiB
Java

package dev.lions.components;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.validation.constraints.NotNull;
import java.io.Serial;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.file.UploadedFile;
import dev.lions.config.ApplicationConfig;
import dev.lions.exceptions.FileUploadException;
import dev.lions.services.FileStorageService;
import dev.lions.utils.FileValidator;
import dev.lions.utils.SecurityUtils;
import java.io.Serializable;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Composant de gestion des téléchargements de fichiers.
* Fournit une interface sécurisée et performante pour le téléchargement,
* la validation et la gestion des fichiers dans l'application.
*
* @author Lions Dev Team
* @version 2.1
*/
@Named
@ViewScoped
@Slf4j
public class FileUploadComponent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private static final int MAX_FILES = 10; // Limite de fichiers autorisés
private static final String TEMP_DIR_PREFIX = "upload_"; // Préfixe pour répertoire temporaire
@Inject
ApplicationConfig appConfig;
@Inject
FileStorageService storageService;
@Inject
FileValidator fileValidator;
@Inject
SecurityUtils securityUtils;
@Getter
private final List<UploadedFileInfo> uploadedFiles = new ArrayList<>();
@Getter
@Setter
private String uploadDirectory;
@Getter
@Setter
private boolean multiple = false;
@Getter
@Setter
private String acceptedTypes;
@Getter
@Setter
private long maxFileSize;
/**
* Initialisation du composant.
*/
@PostConstruct
public void init() {
this.maxFileSize = appConfig.getMaxFileSize();
this.acceptedTypes = appConfig.getAllowedFileTypes();
this.uploadDirectory = createTempUploadDirectory();
log.info("Composant de téléchargement initialisé. Taille max: {}, Types acceptés: {}",
maxFileSize, acceptedTypes);
}
/**
* Gère l'événement de téléchargement de fichier.
*
* @param event L'événement PrimeFaces contenant le fichier téléchargé.
*/
public void handleFileUpload(@NotNull FileUploadEvent event) {
UploadedFile file = event.getFile();
log.info("Téléchargement de fichier : {}", file.getFileName());
try {
validateUploadRequest(file);
UploadedFileInfo fileInfo = processUploadedFile(file);
uploadedFiles.add(fileInfo);
addSuccessMessage("Fichier téléchargé avec succès : " + fileInfo.getFileName());
} catch (FileUploadException e) {
log.error("Erreur de validation du fichier : {}", file.getFileName(), e);
addErrorMessage(e.getMessage());
} catch (IOException e) {
log.error("Erreur lors du traitement du fichier : {}", file.getFileName(), e);
addErrorMessage("Une erreur est survenue lors du traitement du fichier.");
}
}
/**
* Valide la requête de téléchargement.
*
* @param file Le fichier téléchargé.
*/
private void validateUploadRequest(UploadedFile file) {
if (uploadedFiles.size() >= MAX_FILES) {
throw new FileUploadException("Vous avez atteint le nombre maximum de fichiers autorisés.");
}
fileValidator.validateFile(file, acceptedTypes, maxFileSize);
}
/**
* Traite et stocke le fichier téléchargé.
*
* @param file Le fichier téléchargé.
* @return Les informations du fichier.
* @throws IOException En cas d'erreur de stockage.
*/
private UploadedFileInfo processUploadedFile(UploadedFile file) throws IOException {
String secureFileName = generateSecureFileName(file.getFileName());
Path destinationPath = storageService.storeFile(file.getInputStream(), uploadDirectory, secureFileName);
return UploadedFileInfo.builder()
.id(UUID.randomUUID().toString())
.fileName(file.getFileName())
.contentType(file.getContentType())
.size(file.getSize())
.path(destinationPath)
.build();
}
/**
* Génère un nom de fichier sécurisé.
*
* @param originalFileName Nom original.
* @return Nom sécurisé.
*/
private String generateSecureFileName(String originalFileName) {
String extension = getFileExtension(originalFileName);
return securityUtils.sanitizeFileName(UUID.randomUUID().toString() + "." + extension);
}
/**
* Récupère l'extension d'un fichier.
*
* @param fileName Nom du fichier.
* @return Extension.
*/
private String getFileExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf('.') + 1);
}
/**
* Crée un répertoire temporaire pour les téléchargements.
*
* @return Le chemin du répertoire temporaire.
*/
private String createTempUploadDirectory() {
return storageService.createTempDirectory(TEMP_DIR_PREFIX + UUID.randomUUID());
}
/**
* Nettoie les ressources lors de la destruction du composant.
*/
@PreDestroy
public void cleanup() {
try {
storageService.deleteDirectory(uploadDirectory);
log.info("Répertoire temporaire supprimé : {}", uploadDirectory);
} catch (Exception e) {
log.error("Erreur lors du nettoyage des ressources : {}", uploadDirectory, e);
}
}
/**
* Ajoute un message de succès dans l'interface utilisateur.
*
* @param message Message à afficher.
*/
private void addSuccessMessage(String message) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message));
}
/**
* Ajoute un message d'erreur dans l'interface utilisateur.
*
* @param message Message à afficher.
*/
private void addErrorMessage(String message) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message));
}
/**
* Classe interne représentant un fichier téléchargé.
*/
@Getter
@Builder
public static class UploadedFileInfo {
private final String id;
private final String fileName;
private final String contentType;
private final long size;
private final Path path;
}
}