diff --git a/mens-core/pom.xml b/mens-core/pom.xml index 17d3402..2f21089 100644 --- a/mens-core/pom.xml +++ b/mens-core/pom.xml @@ -305,6 +305,15 @@ + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + + + commons-configuration commons-configuration diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsRequestDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsRequestDTO.java index c96e9a7..b797e82 100644 --- a/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsRequestDTO.java +++ b/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsRequestDTO.java @@ -1,5 +1,7 @@ package kr.xit.biz.ens.model.cmm; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; @@ -9,7 +11,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.hibernate.validator.constraints.NotEmpty; /** *
@@ -30,14 +31,14 @@ import org.hibernate.validator.constraints.NotEmpty;
 @NoArgsConstructor
 @AllArgsConstructor
 @SuperBuilder
+@JsonInclude(Include.NON_ABSENT)
 public class CmmEnsRequestDTO implements Serializable {
 
     /**
      * 시군구 코드
      */
     @Schema(requiredMode = RequiredMode.REQUIRED, title = "시군구코드", example = "88328")
-    @NotEmpty(message = "시군구 코드는 필수 입니다")
-    @Size(max = 10)
+    @Size(min = 1, max = 10, message = "시군구 코드는 필수 입니다")
     @JsonProperty("signguCode")
     private String signguCode;
 
@@ -45,8 +46,7 @@ public class CmmEnsRequestDTO implements Serializable {
      * 과태료 코드
      */
     @Schema(requiredMode = RequiredMode.REQUIRED, title = "과태료코드", example = "11")
-    @NotEmpty(message = "과태료 코드는 필수 입니다")
-    @Size(max = 2)
+    @Size(min = 1, max = 2, message = "과태료 코드는 필수 입니다")
     @JsonProperty("ffnlgCode")
-    private final String ffnlgCode = "11";
+    private String ffnlgCode = "11";
 }
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/pplus/PplusDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/pplus/PplusDTO.java
index 2f04a7e..5d37b2a 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/pplus/PplusDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/pplus/PplusDTO.java
@@ -1,9 +1,9 @@
 package kr.xit.biz.ens.model.pplus;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
-import java.util.List;
 import javax.validation.Valid;
 import javax.validation.constraints.Size;
 import kr.xit.biz.ens.model.cmm.CmmEnsRequestDTO;
@@ -69,10 +69,9 @@ public class PplusDTO {
          * 우편 제작 요청 발신/수신 data file, 첨부파일의 경우 필수 값 아님
          * 
*/ - //@JsonIgnore + @JsonIgnore @Schema(requiredMode = RequiredMode.AUTO, title = "첨부파일", example = " ") - @NotEmpty(message = "첨부파일은 필수 입니다") - private MultipartFile[] pstFile; + private MultipartFile pstFile; } /** @@ -82,20 +81,38 @@ public class PplusDTO { * Response: PpCommonResponse * */ - @Schema(name = "PpAcceptRequest2", description = "Postplus 우편제작 접수 요청 DTO") + @Schema(name = "PpAcceptRequestStruct", description = "Postplus 우편제작 접수 요청 구조 DTO") @Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder @JsonInclude(JsonInclude.Include.NON_NULL) - public static class PpAcceptRequest2 extends CmmEnsRequestDTO { + public static class PpAcceptRequestStruct extends CmmEnsRequestDTO { @Schema(requiredMode = RequiredMode.REQUIRED) @Valid - private ReqMstData master; + private PpAcceptReqDataStruct master; @Schema(requiredMode = RequiredMode.REQUIRED) @Valid - private ReqDtlData detail; + private PpAcceptReqDataStruct detail; + } + + /** + *
+     * Postplus 우편제작 접수 요청 Data 구조 DTO
+     * 
+ */ + @Schema(name = "PpAcceptReqDataStruct", description = "Postplus 우편제작 접수 요청 Data 구조 DTO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @SuperBuilder + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class PpAcceptReqDataStruct { + @NotBlank + private String cols; + @NotBlank + private String rows; } /** @@ -136,51 +153,13 @@ public class PplusDTO { * Postplus 우편제작 접수 요청 Data Master DTO * */ - @Schema(name = "ReqMstData", description = "Postplus 우편제작 접수 요청 Data Master DTO") - @Data - @NoArgsConstructor - @AllArgsConstructor - @SuperBuilder - @JsonInclude(JsonInclude.Include.NON_NULL) - public static class ReqMstData { - - @NotBlank - private List cols; - @NotBlank - private List rows; - } - - /** - *
-     * Postplus 우편제작 접수 요청 Data Detail DTO
-     * 
- */ - @Schema(name = "ReqDtlData", description = "Postplus 우편제작 접수 요청 Data Dtl DTO") - @Data - @NoArgsConstructor - @AllArgsConstructor - @SuperBuilder - @JsonInclude(JsonInclude.Include.NON_NULL) - public static class ReqDtlData { - - @NotBlank - private List cols; - @NotBlank - private List> rows; - } - - /** - *
-     * Postplus 우편제작 접수 요청 Data Master DTO
-     * 
- */ - @Schema(name = "ReqDataMst", description = "Postplus 우편제작 접수 요청 Data master DTO") + @Schema(name = "PpAcceptReqDataMst", description = "Postplus 우편제작 접수 요청 Data master DTO") @Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder @JsonInclude(JsonInclude.Include.NON_NULL) - public static class ReqDataMst { + public static class PpAcceptReqDataMst { //----------------------------------------------------------------------- // 필수 //----------------------------------------------------------------------- @@ -344,7 +323,8 @@ public class PplusDTO { */ @Schema(requiredMode = RequiredMode.REQUIRED, title = "반송여부유무", example = "N") @NotEmpty(message = "반송여부는 필수입니다(Y|N)") - private final String 반송여부 = "N"; + //private final String 반송여부 = "N"; + private final String[] 반송여부 = new String[]{"Y", "N"}; /** *
@@ -445,13 +425,13 @@ public class PplusDTO {
      * Postplus 우편제작 접수 요청 Data Detail DTO
      * 
*/ - @Schema(name = "ReqDataDtl", description = "Postplus 우편제작 접수 요청 Data detail DTO") + @Schema(name = "PpAcceptReqDataDtl", description = "Postplus 우편제작 접수 요청 Data detail DTO") @Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder @JsonInclude(JsonInclude.Include.NON_NULL) - public static class ReqDataDtl { + public static class PpAcceptReqDataDtl { //----------------------------------------------------------------------- // 필수 //----------------------------------------------------------------------- diff --git a/mens-core/src/main/java/kr/xit/core/spring/config/custom/bouncy/BouncyUtils.java b/mens-core/src/main/java/kr/xit/core/spring/config/custom/bouncy/BouncyUtils.java index 1c5dcc7..8813bf3 100644 --- a/mens-core/src/main/java/kr/xit/core/spring/config/custom/bouncy/BouncyUtils.java +++ b/mens-core/src/main/java/kr/xit/core/spring/config/custom/bouncy/BouncyUtils.java @@ -143,14 +143,14 @@ public class BouncyUtils { } } - public static void encryptionFile(String key, String filePath) throws IOException { + public static void encryptionFile(final String key, final String filePath, final String fileName) throws IOException { byte[] plainFileBytes = FileUtil.getFileBytesFrom(filePath); - FileUtil.saveFile(filePath, encrypt(key, plainFileBytes)); + FileUtil.saveFile(filePath, fileName, encrypt(key, plainFileBytes)); } - public static void decryptionFile(String key, String filePath) throws IOException { + public static void decryptionFile(final String key, final String filePath, final String fileName) throws IOException { byte[] encryptedFileBytes = FileUtil.getFileBytesFrom(filePath); - FileUtil.saveFile(filePath, BouncyDecUtils.decrypt(key, encryptedFileBytes)); + FileUtil.saveFile(filePath, fileName, BouncyDecUtils.decrypt(key, encryptedFileBytes)); } /** diff --git a/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java b/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java index c3bb145..6a6aa3a 100644 --- a/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java +++ b/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java @@ -47,6 +47,7 @@ import reactor.core.publisher.Mono; * @see ClientError * @see ServerError * @see ErrorParse + * @see kr.xit.core.spring.config.support.CustomJacksonConfig */ @Slf4j @Component diff --git a/mens-core/src/main/java/kr/xit/core/support/utils/FileUtil.java b/mens-core/src/main/java/kr/xit/core/support/utils/FileUtil.java index 47e259f..11c819f 100644 --- a/mens-core/src/main/java/kr/xit/core/support/utils/FileUtil.java +++ b/mens-core/src/main/java/kr/xit/core/support/utils/FileUtil.java @@ -1,8 +1,27 @@ package kr.xit.core.support.utils; +import static java.nio.file.Files.probeContentType; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import kr.xit.core.exception.BizRuntimeException; import java.io.*; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItem; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; /** *
@@ -19,6 +38,8 @@ import java.io.*;
  *
  * 
*/ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class FileUtil { public static byte[] getFileBytesFrom(String path) { @@ -36,12 +57,158 @@ public class FileUtil { return fileBytes; } - public static void saveFile(String path, byte[] fileData) { + public static void saveFile(String path, String fileName, byte[] fileData) { + Path p = Paths.get(path); - try(FileOutputStream fos = new FileOutputStream(path);){ + if(!Files.isDirectory(p)){ + try { + Files.createDirectory(p); + } catch (IOException e) { + throw BizRuntimeException.create(e.getMessage()); + } + } + try(FileOutputStream fos = new FileOutputStream(path + "/" + fileName);){ fos.write(fileData); } catch (IOException e) { throw BizRuntimeException.create(e.getMessage()); } } + + /** + * 파일명 + 파일경로를 받아 MultipartFile 생성 return + * @param fileNm + * @param filePath + * @return MultipartFile + */ + @SuppressWarnings("DuplicatedCode") + public static MultipartFile createMutipartFile(final String fileNm, final String filePath){ + File file = new File(filePath+"/"+fileNm); + try { + FileItem fileItem = new DiskFileItem(fileNm, probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile()); + + try(InputStream input = Files.newInputStream(file.toPath()); + OutputStream os = fileItem.getOutputStream()) { + IOUtils.copy(input, os); + }catch(IOException e){ + throw BizRuntimeException.create(e.getMessage()); + } + return new CommonsMultipartFile(fileItem); + + } catch (IOException ex) { + throw BizRuntimeException.create(ex.getMessage()); + } + } + + /** + * binary(byte) 파일객체 에서 MultipartFile 객체 GET + * @param fileNm 원본파일 명 + * @param filePath 업로드 경로 - MultipartFile 객체 생성을 위한 임시 경로 + * @param data byte 파일 객체 + * @param isFileDelete 임시 파일 삭제 여부 + * @return MultipartFile 생성된 MultipartFile + */ + @SuppressWarnings("DuplicatedCode") + public static MultipartFile createMutipartFileFromBytes(final String fileNm, final String filePath, final byte[] data, boolean isFileDelete){ + File file = new File(filePath+"/"+fileNm); + try { + FileUtils.writeByteArrayToFile(file, data); + + FileItem fileItem = new DiskFileItem(fileNm, probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile()); + + try(InputStream input = Files.newInputStream(file.toPath()); + OutputStream os = fileItem.getOutputStream()) { + IOUtils.copy(input, os); + }catch(IOException e){ + throw BizRuntimeException.create(e.getMessage()); + } + if(isFileDelete && file.exists()) { + //noinspection ResultOfMethodCallIgnored + file.delete(); + } + return new CommonsMultipartFile(fileItem); + } catch (IOException ex) { + throw BizRuntimeException.create(ex.getMessage()); + } + } + + /** + * zip 파일 생성 + * @param filePath source file path + * @param fileNameList source file name list + * @param zipFilePath zip file folder + * @param zipFileName zip file name + */ + public static String compressZip(final String filePath, final List fileNameList, final String zipFilePath, final String zipFileName) { + List fileList = new ArrayList<>(); + + fileNameList.forEach(s -> fileList.add(new File(filePath, s))); + return compressZip(fileList, zipFilePath, zipFileName); + } + + /** + * Zip 파일 생성 + * @param fileList zip file name list + * @param zipFilePath zip file folder + * @param zipFileName zip file name + */ + public static String compressZip(final List fileList, final String zipFilePath, final String zipFileName) { + File zipFile = new File(zipFilePath, zipFileName); + + byte[] buff = new byte[4096]; + // 압축파일 생성 + try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))){ + + // 파일 압축 + fileList.forEach(f -> { + try(FileInputStream fis = new FileInputStream(f)){ + // 압축파일 지정 + ZipEntry ze = new ZipEntry(f.getName()); + zos.putNextEntry(ze); + + // 압축 파일에 추가 + int len; + while ((len = fis.read(buff)) > 0) zos.write(buff, 0, len); + + zos.closeEntry(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + }); + return zipFilePath + "/" + zipFileName; + + } catch (FileNotFoundException e) { + log.error("zip파일 생성 오류::{}", e.getLocalizedMessage()); + throw BizRuntimeException.create("zip 파일생성 오류[대상파일 미존재]"); + } catch (IOException e) { + log.error("zip파일 생성 오류::{}", e.getLocalizedMessage()); + throw BizRuntimeException.create("zip 파일생성 오류[대상파일 미존재]"); + } + } + + /** + *
+     * path 경로의 모든 파일 삭제(directory 포함)
+     * @param path String 삭제할 경로
+     * 
+ */ + public static void removeDirectyAndFiles(String path){ + try { + // 작업 파일 삭제 + Path dir = Paths.get(path); + Files.walk(dir) // Traverse the file tree in depth-first order + .sorted(Comparator.reverseOrder()) + .forEach(f -> { + try { + Files.delete(f); //delete each file or directory + } catch (IOException e) { + log.error(e.getLocalizedMessage()); + e.printStackTrace(); + } + }); + }catch (IOException ie){ + log.error(ie.getLocalizedMessage()); + ie.printStackTrace(); + } + } } diff --git a/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java b/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java index 3858ed5..3e9f4c9 100644 --- a/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java +++ b/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java @@ -1,15 +1,8 @@ package kr.xit.core.support.utils; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.cfg.CoercionAction; -import com.fasterxml.jackson.databind.cfg.CoercionInputShape; import java.io.IOException; import java.util.List; import java.util.Map; @@ -18,9 +11,25 @@ import kr.xit.core.spring.util.SpringUtils; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + /** - * JSON Util Class + *
+ * description : JSON Utility
+ *
+ * packageName : kr.xit.core.support.utils
+ * fileName    : JsonUtils
+ * author      : limju
+ * date        : 2023-09-04
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2023-09-04    limju       최초 생성
+ *
+ * 
+ * @see kr.xit.core.spring.config.support.CustomJacksonConfig */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class JsonUtils { @@ -75,8 +84,11 @@ public class JsonUtils { * @return T */ public static T toObjByObj(final Object obj, final Class cls) { - final String str = toJson(obj); - return str != null ? toObject(str, cls) : null; + try { + return obj != null ? OM.convertValue(obj, cls) : null; + } catch (IllegalArgumentException e) { + throw BizRuntimeException.create(e.getLocalizedMessage()); + } } /** @@ -111,6 +123,91 @@ public class JsonUtils { } } + /** + * Object의 key와 value를 추출 + * -> key배열, value배열의 JSONObject return + * @param obj key, value를 추출할 Object + * @param keyName key배열의 JSON key name + * @param valueName value배열의 JSON key name + * @return JSONObject key배열, value배열의 JSONObject + */ + public static JSONObject extractObjKeyValue(final Object obj, final String keyName, final String valueName){ + return extractJsonKeyValue(toObjByObj(obj, JSONObject.class), keyName, valueName); + } + + /** + * JSONObject의 key와 value를 추출 + * -> key배열, value배열의 JSONObject return + * @param json + * @param keyName key배열의 JSON key name + * @param valueName value배열의 JSON key name + * @return JSONObject key배열, value배열의 JSONObject + */ + public static JSONObject extractJsonKeyValue(final JSONObject json, final String keyName, final String valueName){ + final JSONObject rtnJson = new JSONObject(); + final JSONArray keys = new JSONArray(); + final JSONArray values = new JSONArray(); + for (Object key : json.keySet()) { + Object value = json.get(key); + + if (value instanceof JSONObject) + extractJsonKeyValue((JSONObject)value, keyName, valueName); + else if (value instanceof JSONArray) + ((JSONArray)value).forEach(obj -> extractJsonKeyValue((JSONObject)obj, keyName, valueName)); + else{ + //System.out.println(key + ", " + value); + keys.add(String.valueOf(key)); + values.add(value); + } + } + rtnJson.put(keyName, keys); + rtnJson.put(valueName, values); + return rtnJson; + } + + /** + * JSONArray의 key와 value를 추출 + * -> key배열, value배열의 JSONObject return + * @param jsons JSONArray + * @param keyName key배열의 JSON key name + * @param valueName value배열의 JSON key name + * @return JSONObject key배열, value배열의 JSONObject + */ + public static JSONObject extractJsonArrayKeyValue(final net.sf.json.JSONArray jsons, final String keyName, final String valueName){ + final JSONObject rtnJson = new JSONObject(); + final JSONArray keys = new JSONArray(); + final JSONArray values = new JSONArray(); + for(int i = 0; i extractJsonKeyValue((JSONObject)obj, keyName, valueName)); + else{ + //System.out.println(key + ", " + value); + keys.add(String.valueOf(key)); + values.add(value); + } + } + rtnJson.put(keyName, keys); + rtnJson.put(valueName, values); + return rtnJson; + } + /** * Json 데이터 보기 좋게 변환. * @param obj Object json @@ -125,25 +222,6 @@ public class JsonUtils { } } - private static ObjectMapper getObjectMapper() { - final ObjectMapper om = new ObjectMapper(); - om.setSerializationInclusion(Include.NON_NULL); - // No serializer found for class 에러 - private 필드 - om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); - om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); - om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - om.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, false); - - om.coercionConfigDefaults() - .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull); -// om.coercionConfigFor(LogicalType.Enum) -// .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull); -// om.coercionConfigFor(LogicalType.POJO) -// .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull); - - return om; - } - /** * Json 데이터 보기 좋게 변환. * @param json String json