From 8c34b5da6e07fe15d979207c4b544335e49e979d Mon Sep 17 00:00:00 2001 From: shinmj Date: Thu, 18 Nov 2021 15:57:47 +0900 Subject: [PATCH] =?UTF-8?q?=20=EB=B3=B4=EC=95=88=EC=A0=90=EA=B2=80=20?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=88=98=EC=A0=95(portal-service)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attachment/AttachmentRepositoryImpl.java | 4 + .../service/attachment/AttachmentService.java | 5 +- .../portalservice/utils/FileStorageUtils.java | 28 ++---- .../portalservice/utils/FtpClientDto.java | 3 +- .../portalservice/utils/FtpStorageUtils.java | 18 ++-- .../portalservice/utils/PortalUtils.java | 98 ++++++++++++------- .../AttachmentApiControllerTest.java | 75 +++++++------- 7 files changed, 131 insertions(+), 100 deletions(-) diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/domain/attachment/AttachmentRepositoryImpl.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/domain/attachment/AttachmentRepositoryImpl.java index 4c1c2b8..fcf86bc 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/domain/attachment/AttachmentRepositoryImpl.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/domain/attachment/AttachmentRepositoryImpl.java @@ -72,6 +72,10 @@ public class AttachmentRepositoryImpl implements AttachmentRepositoryCustom{ .where(attachment.attachmentId.code.eq(attachmentCode)) .fetchOne(); + if (seq == null) { + seq = 0L; + } + return AttachmentId.builder() .code(attachmentCode) .seq(seq+1L) diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/service/attachment/AttachmentService.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/service/attachment/AttachmentService.java index cea8d87..662d2c5 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/service/attachment/AttachmentService.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/service/attachment/AttachmentService.java @@ -11,6 +11,7 @@ import org.egovframe.cloud.portalservice.api.attachment.dto.*; import org.egovframe.cloud.portalservice.domain.attachment.Attachment; import org.egovframe.cloud.portalservice.domain.attachment.AttachmentId; import org.egovframe.cloud.portalservice.domain.attachment.AttachmentRepository; +import org.egovframe.cloud.portalservice.utils.PortalUtils; import org.egovframe.cloud.portalservice.utils.StorageUtils; import org.springframework.core.io.Resource; import org.springframework.data.domain.Page; @@ -235,7 +236,7 @@ public class AttachmentService extends AbstractService { * @return 생성된 첨부파일 코드 */ public String save(List saveRequestDtoList) { - String attachmentCode = RandomStringUtils.randomAlphanumeric(20); + String attachmentCode = PortalUtils.randomAlphanumeric(20); for (int i = 0; i < saveRequestDtoList.size(); i++) { AttachmentTempSaveRequestDto requestDto = saveRequestDtoList.get(i); AttachmentId attachmentId = AttachmentId.builder() @@ -357,7 +358,7 @@ public class AttachmentService extends AbstractService { */ public String uploadAndSave(List files, AttachmentUploadRequestDto uploadRequestDto) { String basePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMM")); - String attachmentCode = RandomStringUtils.randomAlphanumeric(20); + String attachmentCode = PortalUtils.randomAlphanumeric(20); for (int i = 0; i < files.size(); i++) { AttachmentId attachmentId = AttachmentId.builder() diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FileStorageUtils.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FileStorageUtils.java index bcdcded..56c018c 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FileStorageUtils.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FileStorageUtils.java @@ -2,6 +2,7 @@ package org.egovframe.cloud.portalservice.utils; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; import org.egovframe.cloud.common.exception.BusinessException; import org.egovframe.cloud.common.exception.BusinessMessageException; import org.egovframe.cloud.common.exception.dto.ErrorCode; @@ -78,16 +79,8 @@ public class FileStorageUtils implements StorageUtils { */ public Path getStorePath(String basePath) { - StringBuffer sb = new StringBuffer(); - sb.append(fileStorageLocation.toString()); - if (!basePath.equals("")) { - sb.append("/"); - sb.append(StringUtils.cleanPath(basePath)); - } - try { - Path path = Paths.get(StringUtils.cleanPath(sb.toString())) - .toAbsolutePath().normalize(); + Path path = fileStorageLocation.resolve(basePath); Files.createDirectories(path); return path; } catch (IOException ex) { @@ -118,10 +111,11 @@ public class FileStorageUtils implements StorageUtils { */ public String renameTemp(String physicalFileName) { String rename = physicalFileName.replace(".temp", ""); + //물리적 파일 처리 Path path = getStorePath(""); - File file = new File(path + "/" + physicalFileName); - File renameFile = new File(path + "/" + rename); + File file = path.resolve(physicalFileName).toFile(); + File renameFile = path.resolve(rename).toFile(); try { file.renameTo(renameFile); } catch (NullPointerException ex) { @@ -143,8 +137,7 @@ public class FileStorageUtils implements StorageUtils { try { Path path = getStorePath(basePath); - - File file = new File(path + "/" + filename); + File file = path.resolve(filename).toFile(); Base64.Decoder decoder = Base64.getDecoder(); byte[] decodeBytes = decoder.decode(requestDto.getFileBase64().getBytes()); @@ -257,9 +250,7 @@ public class FileStorageUtils implements StorageUtils { public Resource downloadFile(String filename) { Path path = getStorePath(""); try { - Path filePath = Paths.get(StringUtils.cleanPath(path.toString() + StringUtils.cleanPath("/" + filename))) - .toAbsolutePath().normalize(); - Resource resource = new UrlResource(filePath.toUri()); + Resource resource = new UrlResource(path.resolve(filename).toUri()); if (resource.exists()) { return resource; @@ -319,9 +310,8 @@ public class FileStorageUtils implements StorageUtils { public boolean deleteFile(String filename) { Path path = getStorePath(""); try { - Path filePath = Paths.get(StringUtils.cleanPath(path.toString() + StringUtils.cleanPath("/" + filename))) - .toAbsolutePath().normalize(); - return Files.deleteIfExists(filePath); + System.out.println("==== paths :" + path.resolve(filename)); + return Files.deleteIfExists(path.resolve(filename)); } catch (IOException e) { log.error("Could not deleted file.", e); return false; diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpClientDto.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpClientDto.java index cbc2206..e02f48a 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpClientDto.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpClientDto.java @@ -1,5 +1,6 @@ package org.egovframe.cloud.portalservice.utils; +import java.util.ArrayList; import lombok.Getter; import lombok.NoArgsConstructor; import org.apache.commons.net.ftp.FTPClient; @@ -58,7 +59,7 @@ public class FtpClientDto { } public FtpClientDto addFiles(List files, String path) { - this.files = files; + this.files = new ArrayList<>(files); this.path = path; return this; } diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpStorageUtils.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpStorageUtils.java index df48623..6cd2497 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpStorageUtils.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/FtpStorageUtils.java @@ -1,7 +1,9 @@ package org.egovframe.cloud.portalservice.utils; +import java.nio.file.Files; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; @@ -366,15 +368,15 @@ public class FtpStorageUtils implements StorageUtils { */ public AttachmentImageResponseDto loadImage(String imagename) { try { - Resource resource = new UrlResource(environment.getProperty("file.url") + StringUtils.cleanPath("/" + imagename)); - InputStream inputStream = new URL(resource.getURL().toString()).openStream(); + String paths = environment.getProperty("file.url") + imagename; + Resource resource = new UrlResource(paths); + InputStream inputStream = resource.getInputStream(); byte[] data = IOUtils.toByteArray(inputStream); inputStream.close(); // get mime type - URLConnection connection = new URL(resource.getURL().toString()).openConnection(); - String contentType = connection.getContentType(); + String contentType = Files.probeContentType(resource.getFile().toPath()); return AttachmentImageResponseDto.builder() .mimeType(contentType) @@ -434,14 +436,14 @@ public class FtpStorageUtils implements StorageUtils { FtpClientDto ftpClientDto = new FtpClientDto(environment); this.connect(ftpClientDto); FTPClient ftpClient = ftpClientDto.getFtpClient(); - // 디렉토리 생성 및 권한 부여 - String directory = StringUtils.cleanPath(ftpClientDto.getDirectory() + "/" + basePath); - makePermissionDirectory(ftpClient, directory); + Path directory = Paths.get(ftpClientDto.getDirectory()).toAbsolutePath().normalize(); + directory.resolve(basePath); + makePermissionDirectory(ftpClient, directory.toString()); this.disconnect(ftpClient); - return Paths.get(directory).toAbsolutePath().normalize(); + return directory; } catch (IOException ex) { log.error("Could not create file store directory.", ex); // 파일을 저장할 수 없습니다. 다시 시도해 주세요. diff --git a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/PortalUtils.java b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/PortalUtils.java index b4952d2..6314da8 100644 --- a/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/PortalUtils.java +++ b/backend/portal-service/src/main/java/org/egovframe/cloud/portalservice/utils/PortalUtils.java @@ -1,12 +1,11 @@ package org.egovframe.cloud.portalservice.utils; -import org.egovframe.cloud.common.config.GlobalConstant; -import org.springframework.util.StringUtils; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.servlet.http.HttpServletRequest; +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.UUID; +import org.apache.commons.io.FilenameUtils; +import org.springframework.util.StringUtils; /** @@ -28,42 +27,69 @@ import java.util.UUID; */ public class PortalUtils { - /** - * '-'을 제거한 uuid 생성 - * - * @return - */ - public static String getUUID() { - return UUID.randomUUID().toString().replaceAll("-", ""); - } + /** + * '-'을 제거한 uuid 생성 + * + * @return + */ + public static String getUUID() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + /** + * 물리적 파일 이름 생성 + * + * @param originalFileName + * @param isTemp + * @return + */ + public static String getPhysicalFileName(String originalFileName, boolean isTemp) { + String ext = StringUtils.getFilenameExtension(originalFileName); + StringBuffer sb = new StringBuffer(); + sb.append(getUUID()); + sb.append("."); + sb.append(ext); + if (isTemp) { + sb.append(".temp"); + } + return StringUtils.cleanPath(sb.toString()); + } + + /** + * 물리적 파일 이름 생성 (.temp) + * + * @param originalFileName + * @return + */ + public static String getPhysicalFileName(String originalFileName) { + return getPhysicalFileName(originalFileName, true); + } /** - * 물리적 파일 이름 생성 + * SecureRandom을 활용한 랜덤 생성 * - * @param originalFileName - * @param isTemp + * @param count * @return */ - public static String getPhysicalFileName(String originalFileName, boolean isTemp) { - String ext = StringUtils.getFilenameExtension(originalFileName); - StringBuffer sb = new StringBuffer(); - sb.append(getUUID()); - sb.append("."); - sb.append(ext); - if(isTemp){ - sb.append(".temp"); + public static String randomAlphanumeric(int count) { + char[] charSet = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '@', + '#', '$', '%', '^', '&'}; + + StringBuffer sb = new StringBuffer(); + SecureRandom sr = new SecureRandom(); + sr.setSeed(LocalDateTime.now().getNano()); + + int idx = 0; + int len = charSet.length; + for (int i = 0; i < count; i++) { + idx = sr.nextInt(len); + sb.append(charSet[idx]); } - return StringUtils.cleanPath(sb.toString()); - } - /** - * 물리적 파일 이름 생성 (.temp) - * - * @param originalFileName - * @return - */ - public static String getPhysicalFileName(String originalFileName) { - return getPhysicalFileName(originalFileName, true); - } + return sb.toString(); + } } diff --git a/backend/portal-service/src/test/java/org/egovframe/cloud/portalservice/api/attachment/AttachmentApiControllerTest.java b/backend/portal-service/src/test/java/org/egovframe/cloud/portalservice/api/attachment/AttachmentApiControllerTest.java index 768dda3..0d34321 100644 --- a/backend/portal-service/src/test/java/org/egovframe/cloud/portalservice/api/attachment/AttachmentApiControllerTest.java +++ b/backend/portal-service/src/test/java/org/egovframe/cloud/portalservice/api/attachment/AttachmentApiControllerTest.java @@ -1,33 +1,8 @@ package org.egovframe.cloud.portalservice.api.attachment; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Base64; -import org.egovframe.cloud.portalservice.api.attachment.dto.*; -import org.egovframe.cloud.portalservice.domain.attachment.Attachment; -import org.egovframe.cloud.portalservice.domain.attachment.AttachmentRepository; -import org.egovframe.cloud.portalservice.service.attachment.AttachmentService; -import org.egovframe.cloud.portalservice.util.RestResponsePage; -import org.egovframe.cloud.portalservice.utils.FileStorageUtils; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.http.*; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartFile; +import static org.assertj.core.api.Assertions.assertThat; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -38,8 +13,43 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.util.encoders.Base64; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentBase64RequestDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentEditorResponseDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentFileResponseDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentResponseDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentTempSaveRequestDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentUpdateRequestDto; +import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentUploadRequestDto; +import org.egovframe.cloud.portalservice.domain.attachment.Attachment; +import org.egovframe.cloud.portalservice.domain.attachment.AttachmentRepository; +import org.egovframe.cloud.portalservice.service.attachment.AttachmentService; +import org.egovframe.cloud.portalservice.util.RestResponsePage; +import org.egovframe.cloud.portalservice.utils.FileStorageUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; @Slf4j @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -47,9 +57,6 @@ import static org.assertj.core.api.Assertions.assertThat; @TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"}) @ActiveProfiles(profiles = "test") class AttachmentApiControllerTest { - @LocalServerPort - private int port; - @Autowired TestRestTemplate restTemplate; @@ -282,6 +289,7 @@ class AttachmentApiControllerTest { List saveRequestDtoList = getTempSaveDto(2); String attachmentCode = attachmentService.save(saveRequestDtoList); + System.out.println("attachmentCode : " + attachmentCode); String url = "/api/v1/attachments/"+attachmentCode; //when @@ -363,6 +371,7 @@ class AttachmentApiControllerTest { } @Test + @Order(1) public void 관리자_첨부파일_목록_검색조회_정상() throws Exception { //given List saveRequestDtoList1 = getTempSaveDto(2); @@ -535,8 +544,6 @@ class AttachmentApiControllerTest { ); } - saveRequestDtoList.stream().forEach(System.out::println); - HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); MultiValueMap body = new LinkedMultiValueMap<>();