[파일 업로드 개선] FileUploadResponseDto 및 MultipleFileUploadResponseDto에 groupOid 필드 추가, FileServiceImpl에서 응답 DTO 생성 로직 수정 및 createUploadResponse 메서드 제거. FileUtils 클래스에 파일 업로드 메서드 추가 및 불필요한 메서드 제거로 코드 정리.
This commit is contained in:
		@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.domain.base.file.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import lombok.Builder;
 | 
				
			||||||
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Data
 | 
				
			||||||
 | 
					@Builder
 | 
				
			||||||
 | 
					public class FileUploadDto {
 | 
				
			||||||
 | 
					    private Long groupOid;
 | 
				
			||||||
 | 
					    private List<FileUploadResponseDto> files;  // 파일 정보들
 | 
				
			||||||
 | 
					    private int totalCount;
 | 
				
			||||||
 | 
					    private int successCount;
 | 
				
			||||||
 | 
					    private int failureCount;
 | 
				
			||||||
 | 
					    private List<String> errorMessages;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,15 @@
 | 
				
			|||||||
package com.bio.bio_backend.domain.base.file.dto;
 | 
					package com.bio.bio_backend.domain.base.file.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.fasterxml.jackson.annotation.JsonInclude;
 | 
				
			||||||
import lombok.Builder;
 | 
					import lombok.Builder;
 | 
				
			||||||
import lombok.Data;
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Data
 | 
					@Data
 | 
				
			||||||
@Builder
 | 
					@Builder
 | 
				
			||||||
 | 
					@JsonInclude(JsonInclude.Include.NON_NULL)
 | 
				
			||||||
public class FileUploadResponseDto {
 | 
					public class FileUploadResponseDto {
 | 
				
			||||||
    private Long oid;
 | 
					    private Long oid;
 | 
				
			||||||
 | 
					    private Long groupOid;
 | 
				
			||||||
    private String originalFileName;
 | 
					    private String originalFileName;
 | 
				
			||||||
    private String downloadUrl;
 | 
					    private String downloadUrl;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,12 @@
 | 
				
			|||||||
package com.bio.bio_backend.domain.base.file.dto;
 | 
					package com.bio.bio_backend.domain.base.file.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import lombok.Builder;
 | 
				
			||||||
import lombok.Data;
 | 
					import lombok.Data;
 | 
				
			||||||
import org.springframework.web.multipart.MultipartFile;
 | 
					import org.springframework.web.multipart.MultipartFile;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Data
 | 
					@Data
 | 
				
			||||||
 | 
					@Builder
 | 
				
			||||||
public class MultipleFileUploadRequestDto {
 | 
					public class MultipleFileUploadRequestDto {
 | 
				
			||||||
    private List<MultipartFile> files;
 | 
					    private List<MultipartFile> files;
 | 
				
			||||||
    private String description;
 | 
					    private String description;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import java.util.List;
 | 
				
			|||||||
@Builder
 | 
					@Builder
 | 
				
			||||||
public class MultipleFileUploadResponseDto {
 | 
					public class MultipleFileUploadResponseDto {
 | 
				
			||||||
    private List<FileUploadResponseDto> files;
 | 
					    private List<FileUploadResponseDto> files;
 | 
				
			||||||
 | 
					    private Long groupOid;
 | 
				
			||||||
    private int totalCount;
 | 
					    private int totalCount;
 | 
				
			||||||
    private int successCount;
 | 
					    private int successCount;
 | 
				
			||||||
    private int failureCount;
 | 
					    private int failureCount;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,12 @@ public class FileServiceImpl implements FileService {
 | 
				
			|||||||
        File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), generateOid());
 | 
					        File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), generateOid());
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // 응답 DTO 생성 및 반환
 | 
					        // 응답 DTO 생성 및 반환
 | 
				
			||||||
        return createUploadResponse(savedFile);
 | 
					        return FileUploadResponseDto.builder()
 | 
				
			||||||
 | 
					            .oid(savedFile.getOid())
 | 
				
			||||||
 | 
					            .groupOid(savedFile.getGroupOid())
 | 
				
			||||||
 | 
					            .originalFileName(savedFile.getOriginalFileName())
 | 
				
			||||||
 | 
					            .downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
 | 
				
			||||||
 | 
					            .build();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -90,7 +95,11 @@ public class FileServiceImpl implements FileService {
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                // 단일 파일 업로드 처리
 | 
					                // 단일 파일 업로드 처리
 | 
				
			||||||
                File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), groupOid);
 | 
					                File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), groupOid);
 | 
				
			||||||
                FileUploadResponseDto uploadedFile = createUploadResponse(savedFile);
 | 
					                FileUploadResponseDto uploadedFile = FileUploadResponseDto.builder()
 | 
				
			||||||
 | 
					                                .oid(savedFile.getOid())
 | 
				
			||||||
 | 
					                                .originalFileName(savedFile.getOriginalFileName())
 | 
				
			||||||
 | 
					                                .downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
 | 
				
			||||||
 | 
					                                .build();
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                uploadedFiles.add(uploadedFile);
 | 
					                uploadedFiles.add(uploadedFile);
 | 
				
			||||||
                successCount++;
 | 
					                successCount++;
 | 
				
			||||||
@@ -105,8 +114,8 @@ public class FileServiceImpl implements FileService {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // 다중 파일 업로드 결과 반환
 | 
					 | 
				
			||||||
        return MultipleFileUploadResponseDto.builder()
 | 
					        return MultipleFileUploadResponseDto.builder()
 | 
				
			||||||
 | 
					                .groupOid(groupOid)
 | 
				
			||||||
                .files(uploadedFiles)
 | 
					                .files(uploadedFiles)
 | 
				
			||||||
                .totalCount(files.size())
 | 
					                .totalCount(files.size())
 | 
				
			||||||
                .successCount(successCount)
 | 
					                .successCount(successCount)
 | 
				
			||||||
@@ -158,14 +167,6 @@ public class FileServiceImpl implements FileService {
 | 
				
			|||||||
                .build();
 | 
					                .build();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private FileUploadResponseDto createUploadResponse(File savedFile) {
 | 
					 | 
				
			||||||
        return FileUploadResponseDto.builder()
 | 
					 | 
				
			||||||
                .oid(savedFile.getOid())
 | 
					 | 
				
			||||||
                .originalFileName(savedFile.getOriginalFileName())
 | 
					 | 
				
			||||||
                .downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
 | 
					 | 
				
			||||||
                .build();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public File getFileByOid(Long oid) {
 | 
					    public File getFileByOid(Long oid) {
 | 
				
			||||||
        return fileRepository.findByOidAndUseFlagTrue(oid)
 | 
					        return fileRepository.findByOidAndUseFlagTrue(oid)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,21 +2,32 @@ package com.bio.bio_backend.global.utils;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.springframework.util.StringUtils;
 | 
					import org.springframework.util.StringUtils;
 | 
				
			||||||
import org.springframework.web.multipart.MultipartFile;
 | 
					import org.springframework.web.multipart.MultipartFile;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					import java.nio.file.Path;
 | 
				
			||||||
import java.nio.file.Paths;
 | 
					import java.nio.file.Paths;
 | 
				
			||||||
import java.nio.file.StandardCopyOption;
 | 
					 | 
				
			||||||
import java.time.LocalDate;
 | 
					import java.time.LocalDate;
 | 
				
			||||||
import java.time.format.DateTimeFormatter;
 | 
					import java.time.format.DateTimeFormatter;
 | 
				
			||||||
import java.util.UUID;
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Component;
 | 
				
			||||||
 | 
					import lombok.RequiredArgsConstructor;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.dto.FileUploadDto;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.dto.FileUploadResponseDto;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadRequestDto;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadResponseDto;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.service.FileService;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.base.file.dto.FileUploadRequestDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 파일 관련 유틸리티 클래스
 | 
					 * 파일 관련 유틸리티 클래스
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Component
 | 
				
			||||||
 | 
					@RequiredArgsConstructor
 | 
				
			||||||
public class FileUtils {
 | 
					public class FileUtils {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    private final FileService fileService;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 파일 유효성 검사
 | 
					     * 파일 유효성 검사
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -35,32 +46,6 @@ public class FileUtils {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 업로드 디렉토리 생성
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static Path createUploadDirectory(String uploadPath) throws IOException {
 | 
					 | 
				
			||||||
        Path uploadDir = Paths.get(uploadPath);
 | 
					 | 
				
			||||||
        if (!Files.exists(uploadDir)) {
 | 
					 | 
				
			||||||
            Files.createDirectories(uploadDir);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return uploadDir;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 년월일 기반 업로드 디렉토리 생성
 | 
					 | 
				
			||||||
     * 예: uploads/2024/01/15/
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static Path createDateBasedUploadDirectory(String baseUploadPath) throws IOException {
 | 
					 | 
				
			||||||
        LocalDate today = LocalDate.now();
 | 
					 | 
				
			||||||
        String yearMonthDay = today.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        Path dateBasedPath = Paths.get(baseUploadPath, yearMonthDay);
 | 
					 | 
				
			||||||
        if (!Files.exists(dateBasedPath)) {
 | 
					 | 
				
			||||||
            Files.createDirectories(dateBasedPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return dateBasedPath;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 년월 기반 업로드 디렉토리 생성
 | 
					     * 년월 기반 업로드 디렉토리 생성
 | 
				
			||||||
     * 예: uploads/2024/01/
 | 
					     * 예: uploads/2024/01/
 | 
				
			||||||
@@ -76,35 +61,6 @@ public class FileUtils {
 | 
				
			|||||||
        return yearMonthPath;
 | 
					        return yearMonthPath;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 년 기반 업로드 디렉토리 생성
 | 
					 | 
				
			||||||
     * 예: uploads/2024/
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static Path createYearUploadDirectory(String baseUploadPath) throws IOException {
 | 
					 | 
				
			||||||
        LocalDate today = LocalDate.now();
 | 
					 | 
				
			||||||
        String year = today.format(DateTimeFormatter.ofPattern("yyyy"));
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        Path yearPath = Paths.get(baseUploadPath, year);
 | 
					 | 
				
			||||||
        if (!Files.exists(yearPath)) {
 | 
					 | 
				
			||||||
            Files.createDirectories(yearPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return yearPath;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 지정된 날짜로 업로드 디렉토리 생성
 | 
					 | 
				
			||||||
     * 예: uploads/2024/01/15/
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static Path createDateBasedUploadDirectory(String baseUploadPath, LocalDate date) throws IOException {
 | 
					 | 
				
			||||||
        String yearMonthDay = date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        Path dateBasedPath = Paths.get(baseUploadPath, yearMonthDay);
 | 
					 | 
				
			||||||
        if (!Files.exists(dateBasedPath)) {
 | 
					 | 
				
			||||||
            Files.createDirectories(dateBasedPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return dateBasedPath;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 파일 확장자 추출
 | 
					     * 파일 확장자 추출
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -127,7 +83,7 @@ public class FileUtils {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public static Path saveFileToDisk(MultipartFile multipartFile, Path uploadDir, String storedFileName) throws IOException {
 | 
					    public static Path saveFileToDisk(MultipartFile multipartFile, Path uploadDir, String storedFileName) throws IOException {
 | 
				
			||||||
        Path targetLocation = uploadDir.resolve(storedFileName);
 | 
					        Path targetLocation = uploadDir.resolve(storedFileName);
 | 
				
			||||||
        Files.copy(multipartFile.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
 | 
					        Files.copy(multipartFile.getInputStream(), targetLocation, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
 | 
				
			||||||
        return targetLocation;
 | 
					        return targetLocation;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -138,173 +94,44 @@ public class FileUtils {
 | 
				
			|||||||
        return StringUtils.cleanPath(originalFileName);
 | 
					        return StringUtils.cleanPath(originalFileName);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 파일 크기를 사람이 읽기 쉬운 형태로 변환
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static String formatFileSize(long bytes) {
 | 
					 | 
				
			||||||
        if (bytes < 1024) return bytes + " B";
 | 
					 | 
				
			||||||
        if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
 | 
					 | 
				
			||||||
        if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
 | 
					 | 
				
			||||||
        return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 파일 확장자로부터 MIME 타입 추정
 | 
					     * 파일 업로드 (단일/다중 파일 모두 지원)
 | 
				
			||||||
 | 
					     * 사용 예시:
 | 
				
			||||||
 | 
					     * // 단일 파일 업로드
 | 
				
			||||||
 | 
					     * FileUploadDto fileResult = fileUtils.uploadFile(
 | 
				
			||||||
 | 
					     *     requestDto.getFile(),
 | 
				
			||||||
 | 
					     *     "프로필 이미지"
 | 
				
			||||||
 | 
					     * );
 | 
				
			||||||
 | 
					     * member.setFileGroupId(fileResult.getGroupOid());
 | 
				
			||||||
 | 
					     * // 다중 파일 업로드
 | 
				
			||||||
 | 
					     * FileUploadDto filesResult = fileUtils.uploadFiles(
 | 
				
			||||||
 | 
					     *     requestDto.getFiles(), 
 | 
				
			||||||
 | 
					     *     "게시판 첨부파일: " + board.getTitle()
 | 
				
			||||||
 | 
					     * );
 | 
				
			||||||
 | 
					     * board.setFileGroupId(filesResult.getGroupOid());
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static String getMimeTypeFromExtension(String fileName) {
 | 
					    public FileUploadDto uploadFile(MultipartFile file, String description) {
 | 
				
			||||||
        if (fileName == null) return "application/octet-stream";
 | 
					        // 단일 파일도 List로 감싸서 다중 파일 업로드 방식 사용
 | 
				
			||||||
        
 | 
					        List<MultipartFile> files = List.of(file);
 | 
				
			||||||
        String extension = extractFileExtension(fileName).toLowerCase();
 | 
					        return uploadFiles(files, description);
 | 
				
			||||||
        switch (extension) {
 | 
					 | 
				
			||||||
            case ".txt": return "text/plain";
 | 
					 | 
				
			||||||
            case ".html": case ".htm": return "text/html";
 | 
					 | 
				
			||||||
            case ".css": return "text/css";
 | 
					 | 
				
			||||||
            case ".js": return "application/javascript";
 | 
					 | 
				
			||||||
            case ".json": return "application/json";
 | 
					 | 
				
			||||||
            case ".xml": return "application/xml";
 | 
					 | 
				
			||||||
            case ".pdf": return "application/pdf";
 | 
					 | 
				
			||||||
            case ".zip": return "application/zip";
 | 
					 | 
				
			||||||
            case ".jpg": case ".jpeg": return "image/jpeg";
 | 
					 | 
				
			||||||
            case ".png": return "image/png";
 | 
					 | 
				
			||||||
            case ".gif": return "image/gif";
 | 
					 | 
				
			||||||
            case ".bmp": return "image/bmp";
 | 
					 | 
				
			||||||
            case ".svg": return "image/svg+xml";
 | 
					 | 
				
			||||||
            case ".mp4": return "video/mp4";
 | 
					 | 
				
			||||||
            case ".avi": return "video/x-msvideo";
 | 
					 | 
				
			||||||
            case ".mp3": return "audio/mpeg";
 | 
					 | 
				
			||||||
            case ".wav": return "audio/wav";
 | 
					 | 
				
			||||||
            default: return "application/octet-stream";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /**
 | 
					    public FileUploadDto uploadFiles(List<MultipartFile> files, String description) {
 | 
				
			||||||
     * 안전한 파일명 생성 (특수문자 제거)
 | 
					        MultipleFileUploadRequestDto requestDto = MultipleFileUploadRequestDto.builder()
 | 
				
			||||||
     */
 | 
					            .files(files)
 | 
				
			||||||
    public static String createSafeFileName(String originalFileName) {
 | 
					            .description(description)
 | 
				
			||||||
        if (originalFileName == null) return "";
 | 
					            .build();
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // 특수문자 제거 및 공백을 언더스코어로 변경
 | 
					        MultipleFileUploadResponseDto response = fileService.uploadMultipleFiles(requestDto);
 | 
				
			||||||
        String safeName = originalFileName
 | 
					 | 
				
			||||||
                .replaceAll("[^a-zA-Z0-9가-힣._-]", "_")
 | 
					 | 
				
			||||||
                .replaceAll("_+", "_")
 | 
					 | 
				
			||||||
                .trim();
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // 파일명이 너무 길면 자르기
 | 
					        return FileUploadDto.builder()
 | 
				
			||||||
        if (safeName.length() > 100) {
 | 
					            .groupOid(response.getGroupOid())
 | 
				
			||||||
            String extension = extractFileExtension(safeName);
 | 
					            .files(response.getFiles())
 | 
				
			||||||
            safeName = safeName.substring(0, 100 - extension.length()) + extension;
 | 
					            .totalCount(response.getTotalCount())
 | 
				
			||||||
        }
 | 
					            .successCount(response.getSuccessCount())
 | 
				
			||||||
        
 | 
					            .failureCount(response.getFailureCount())
 | 
				
			||||||
        return safeName;
 | 
					            .errorMessages(response.getErrorMessages())
 | 
				
			||||||
    }
 | 
					            .build();
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 파일이 이미지인지 확인
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean isImageFile(String fileName) {
 | 
					 | 
				
			||||||
        if (fileName == null) return false;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        String extension = extractFileExtension(fileName).toLowerCase();
 | 
					 | 
				
			||||||
        return extension.matches("\\.(jpg|jpeg|png|gif|bmp|svg|webp)$");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 파일이 문서인지 확인
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean isDocumentFile(String fileName) {
 | 
					 | 
				
			||||||
        if (fileName == null) return false;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        String extension = extractFileExtension(fileName).toLowerCase();
 | 
					 | 
				
			||||||
        return extension.matches("\\.(pdf|doc|docx|xls|xlsx|ppt|pptx|txt|rtf)$");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 파일이 압축파일인지 확인
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean isArchiveFile(String fileName) {
 | 
					 | 
				
			||||||
        if (fileName == null) return false;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        String extension = extractFileExtension(fileName).toLowerCase();
 | 
					 | 
				
			||||||
        return extension.matches("\\.(zip|rar|7z|tar|gz|bz2)$");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 현재 날짜의 년월일 문자열 반환
 | 
					 | 
				
			||||||
     * 예: "2024/01/15"
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static String getCurrentDatePath() {
 | 
					 | 
				
			||||||
        LocalDate today = LocalDate.now();
 | 
					 | 
				
			||||||
        return today.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 지정된 날짜의 년월일 문자열 반환
 | 
					 | 
				
			||||||
     * 예: "2024/01/15"
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static String getDatePath(LocalDate date) {
 | 
					 | 
				
			||||||
        return date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 파일 경로에서 년월일 정보 추출
 | 
					 | 
				
			||||||
     * 예: "uploads/2024/01/15/file.txt" -> "2024/01/15"
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static String extractDateFromPath(String filePath) {
 | 
					 | 
				
			||||||
        if (filePath == null || filePath.isEmpty()) {
 | 
					 | 
				
			||||||
            return "";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        // 정규식으로 년/월/일 패턴 찾기
 | 
					 | 
				
			||||||
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\d{4}/\\d{2}/\\d{2})");
 | 
					 | 
				
			||||||
        java.util.regex.Matcher matcher = pattern.matcher(filePath);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if (matcher.find()) {
 | 
					 | 
				
			||||||
            return matcher.group(1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return "";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 년월일 폴더 구조가 유효한지 확인
 | 
					 | 
				
			||||||
     * 예: "2024/01/15" -> true, "2024/13/45" -> false
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean isValidDatePath(String datePath) {
 | 
					 | 
				
			||||||
        if (datePath == null || datePath.isEmpty()) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            String[] parts = datePath.split("/");
 | 
					 | 
				
			||||||
            if (parts.length != 3) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            int year = Integer.parseInt(parts[0]);
 | 
					 | 
				
			||||||
            int month = Integer.parseInt(parts[1]);
 | 
					 | 
				
			||||||
            int day = Integer.parseInt(parts[2]);
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // 년도 범위 체크 (1900 ~ 2100)
 | 
					 | 
				
			||||||
            if (year < 1900 || year > 2100) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // 월 범위 체크 (1 ~ 12)
 | 
					 | 
				
			||||||
            if (month < 1 || month > 12) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // 일 범위 체크 (1 ~ 31)
 | 
					 | 
				
			||||||
            if (day < 1 || day > 31) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // 실제 존재하는 날짜인지 확인
 | 
					 | 
				
			||||||
            LocalDate.of(year, month, day);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user