Refactor: 한글 압축 파일 업로드 구현

This commit is contained in:
김용수 2024-09-26 22:22:13 +09:00
parent cc37d3048f
commit 5a3b17b59a
5 changed files with 26 additions and 20 deletions

View File

@ -72,6 +72,9 @@ dependencies {
// FCM // FCM
implementation 'com.google.firebase:firebase-admin:7.1.1' implementation 'com.google.firebase:firebase-admin:7.1.1'
// Apache Commons Compress
implementation 'org.apache.commons:commons-compress:1.21'
} }
tasks.named('test') { tasks.named('test') {

View File

@ -15,22 +15,24 @@ import com.worlabel.global.exception.ErrorCode;
import com.worlabel.global.service.S3UploadService; import com.worlabel.global.service.S3UploadService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
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.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@Slf4j @Slf4j
@Service @Service
@ -38,10 +40,10 @@ import java.util.zip.ZipInputStream;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ImageService { public class ImageService {
private final ProjectRepository projectRepository;
private final FolderRepository folderRepository;
private final S3UploadService s3UploadService; private final S3UploadService s3UploadService;
private final ImageRepository imageRepository; private final ImageRepository imageRepository;
private final FolderRepository folderRepository;
private final ProjectRepository projectRepository;
/** /**
* 이미지 리스트 업로드 * 이미지 리스트 업로드
@ -183,26 +185,28 @@ public class ImageService {
return folder; return folder;
} }
// Apache Commons Compress 라이브러리를 사용하여 ZIP 파일을 처리
// 압축 파일을 임시 폴더에 압축 해제하는 메서드
private void unzip(MultipartFile zipFile, String destDir) throws IOException { private void unzip(MultipartFile zipFile, String destDir) throws IOException {
try (ZipInputStream zis = new ZipInputStream(zipFile.getInputStream())) { try (ZipArchiveInputStream zis = new ZipArchiveInputStream(zipFile.getInputStream(), "MS949")) {
ZipEntry zipEntry; ArchiveEntry entry;
while ((zipEntry = zis.getNextEntry()) != null) { while ((entry = zis.getNextEntry()) != null) {
ZipArchiveEntry zipEntry = (ZipArchiveEntry) entry;
Path newPath = zipSlipProtect(zipEntry, Paths.get(destDir)); Path newPath = zipSlipProtect(zipEntry, Paths.get(destDir));
if (zipEntry.isDirectory()) { if (zipEntry.isDirectory()) {
Files.createDirectories(newPath); Files.createDirectories(newPath);
} else { } else {
Files.createDirectories(newPath.getParent()); Files.createDirectories(newPath.getParent());
Files.copy(zis, newPath); try(OutputStream os = Files.newOutputStream(newPath)){
IOUtils.copy(zis, os);
}
} }
zis.closeEntry();
} }
} }
} }
// 보안을 위해 압축 파일 경로를 보호하는 메서드 // 보안을 위해 압축 파일 경로를 보호하는 메서드
private Path zipSlipProtect(ZipEntry zipEntry, Path targetDir) throws IOException { private Path zipSlipProtect(ZipArchiveEntry zipEntry, Path targetDir) throws IOException {
Path targetDirResolved = targetDir.resolve(zipEntry.getName()); Path targetDirResolved = targetDir.resolve(zipEntry.getName());
Path normalizePath = targetDirResolved.normalize(); Path normalizePath = targetDirResolved.normalize();
if (!normalizePath.startsWith(targetDir)) { if (!normalizePath.startsWith(targetDir)) {

View File

@ -78,11 +78,7 @@ public class ProjectController {
@PostMapping("/projects/{project_id}/auto") @PostMapping("/projects/{project_id}/auto")
public void autoLabeling( public void autoLabeling(
@PathVariable("project_id") final Integer projectId, @PathVariable("project_id") final Integer projectId,
@RequestBody final AutoModelRequest request, @RequestBody final AutoModelRequest request) {
HttpServletRequest httpServletRequest) {
String clientIp = httpServletRequest.getRemoteAddr();
int clientPort = httpServletRequest.getRemotePort();
log.debug("클라이언트 IP: {}, 포트 번호: {}", clientIp, clientPort);
projectService.autoLabeling(projectId, request); projectService.autoLabeling(projectId, request);
} }

View File

@ -167,6 +167,9 @@ public class ProjectService {
String endPoint = project.getProjectType().getValue() + "/predict"; String endPoint = project.getProjectType().getValue() + "/predict";
List<Image> imageList = imageRepository.findImagesByProjectIdAndPending(projectId); List<Image> imageList = imageRepository.findImagesByProjectIdAndPending(projectId);
if(imageList.isEmpty()){
throw new CustomException(ErrorCode.DATA_NOT_FOUND);
}
List<AutoLabelingImageRequest> imageRequestList = imageList.stream() List<AutoLabelingImageRequest> imageRequestList = imageList.stream()
.map(AutoLabelingImageRequest::of) .map(AutoLabelingImageRequest::of)
.toList(); .toList();

View File

@ -8,7 +8,7 @@ import java.util.Objects;
@Getter @Getter
public class CustomException extends RuntimeException{ public class CustomException extends RuntimeException{
private final ErrorCode errorCode; private final ErrorCode errorCode;
private Errors errors; private final Errors errors;
public CustomException(ErrorCode errorCode) { public CustomException(ErrorCode errorCode) {
this(errorCode, errorCode.getMessage(), null); this(errorCode, errorCode.getMessage(), null);