diff --git a/src/main/java/cokr/xit/adds/inf/nims/model/NimsApiResult2.java b/src/main/java/cokr/xit/adds/inf/nims/model/NimsApiResult2.java new file mode 100644 index 0000000..f9956a6 --- /dev/null +++ b/src/main/java/cokr/xit/adds/inf/nims/model/NimsApiResult2.java @@ -0,0 +1,153 @@ +package cokr.xit.adds.inf.nims.model; + +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.ObjectUtils; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import cokr.xit.adds.core.model.ResultCode; +import cokr.xit.adds.core.spring.exception.ApiCustomException; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + *
+ * description :
+ *
+ * packageName : cokr.xit.adds.inf.nims.model
+ * fileName    : NimsApiDto
+ * author      : limju
+ * date        : 2024-03-21
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2024-03-21    limju       최초 생성
+ *
+ * 
+ */ +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NimsApiResult2 { + /** + * Nims API call 결과(ROOT) + */ + private Response response; + + @JsonInclude(JsonInclude.Include.NON_NULL) + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Response { + /** + * API call 결과 헤더 + */ + private Header header; + + /** + * API call 결과 바디 + */ + private Body body; + + /** + * API call 성공시 결과 목록 return + * 실패시 ApiCustomException throw + * 결과 코드: 0-성공, 1-실패, 8-인증완료, 9-인증실패 + * @return List or throw ApiCustomException + */ + @JsonIgnore + public List getResultOrThrow() { + if(header.resultCd == 0 || header.resultCd == 8){ + if(ObjectUtils.isEmpty(body.list)) { + throw ApiCustomException.create(ResultCode.NO_CONTENT); + } + return body.list; + } + throw Objects.requireNonNull(ApiCustomException.of("header")); + } + + /** + * API call 성공시 결과 목록 return + * 실패시 null return + * 결과 코드: 0-성공, 1-실패, 8-인증완료, 9-인증실패 + * @return List or null + */ + @JsonIgnore + public List getResult() { + //return getResult(); + if(header.resultCd == 0 || header.resultCd == 8) { + return body.list; + } + throw Objects.requireNonNull(ApiCustomException.of("header")); + } + + @JsonIgnore + public boolean isEndYn() { + return "Y".equals(body.isEndYn); + } + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Header { + /** + * 결과코드 + * 0 : 성공, 1:실패, 8:인증완료, 9:인증실패 + */ + @JsonAlias({"RESULT_CODE", "resultCd"}) + private Integer resultCd; + + /** + * 결과메세지 + */ + @JsonAlias({"RESULT_MSG", "resultMsg"}) + private String resultMsg; + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Body{ + /** + * 실행 결과 건수 + */ + @JsonAlias("TOTAL_COUNT") + private Integer totalCount; + + /** + * 마지막 데이타 여부 + * Y: 마지막 데이타, N : 마지막 데이타 아님 + */ + @JsonAlias(value = {"IS_END_YN", "isEndYn"}) + private String isEndYn; + + /** + * 전체 데이타 건수 + */ + @JsonProperty(value = "nRecord", required = true) + private Integer nRecord; + + /** + * 요청 결과 목록 + */ + private List list; + } +} diff --git a/src/main/java/cokr/xit/adds/inf/nims/service/bean/InfNimsServiceBean.java b/src/main/java/cokr/xit/adds/inf/nims/service/bean/InfNimsServiceBean.java index d34fd40..adac4a6 100644 --- a/src/main/java/cokr/xit/adds/inf/nims/service/bean/InfNimsServiceBean.java +++ b/src/main/java/cokr/xit/adds/inf/nims/service/bean/InfNimsServiceBean.java @@ -2,6 +2,7 @@ package cokr.xit.adds.inf.nims.service.bean; import java.util.ArrayList; import java.util.List; +import java.util.Map; import javax.validation.Validation; import javax.validation.Validator; @@ -17,6 +18,7 @@ import cokr.xit.adds.core.util.ApiUtil; import cokr.xit.adds.inf.nims.model.NimsApiDto; import cokr.xit.adds.inf.nims.model.NimsApiRequest; import cokr.xit.adds.inf.nims.model.NimsApiResult; +import cokr.xit.adds.inf.nims.model.NimsApiResult2; import cokr.xit.adds.inf.nims.service.InfNimsService; import cokr.xit.foundation.component.AbstractServiceBean; import cokr.xit.foundation.data.JSON; @@ -154,10 +156,48 @@ public class InfNimsServiceBean extends AbstractServiceBean implements InfNimsSe // FIXME: API 호출 시 주석 해제 String rslt = ApiUtil.callNimsApi(nimsUrl + dsuseresult, dto); - NimsApiResult result = json.parse(rslt, new TypeReference<>() {}); - return result.getResponse(); -// return getDsuseRptResponse(); + + ///////////////////////////////////////////////////////////////////////////////// + // FIXME: API 오류 보정을 위해 임시로 사용 + // listDtl의 값이 [] String 형태로 들어오는데, 이를 객체로 변환하기 위해 처리 + // "listDtl": "[{PCE_UNIT=정 PRDUCT_CD=8806519017940 DSUSE_QY=28 MNF_NO=20005 MNF_SEQ=2010136201005327 MIN_DISTB_UNIT=병 PRD_VALID_DE=20230722 PCE_QY=0 PRDUCT_NM=졸피신정10mg (10mg) USR_RPT_ID_NO=AAR_R240108122001673_H0000 MIN_DISTB_QY=1}]", + NimsApiResult2 tempResult = json.parse(rslt, new TypeReference<>() {}); + + List list = tempResult.getResponse().getResult(); + + for (Object o : list) { + Map map = (Map)o; + String input = map.get("listDtl").toString(); + + // Remove the brackets at the beginning and end of the string + input = input.substring(1, input.length() - 1); + + // Split the string into individual objects + String[] objects = input.split("\\}\\s*\\{"); + + // Process each object + for (int i = 0; i < objects.length; i++) { + // Add back the curly braces + objects[i] = objects[i].startsWith("{") ? objects[i] : "{" + objects[i]; + objects[i] = objects[i].endsWith("}") ? objects[i] : objects[i] + "}"; + + objects[i] = objects[i].replaceAll("(\\w+_QY)=([^=]+)\\s{2}", "\"$1\":$2,"); + objects[i] = objects[i].replaceAll("(\\w+)=([^=]+)\\s{2}", "\"$1\":\"$2\","); + objects[i] = objects[i].replaceAll("(\\w+)=([^=]+)\\}", "\"$1\":$2}"); + } + + // Join the objects back into a single string + String output = "[" + String.join(", ", objects) + "]"; + //json.parse(output, new TypeReference<>() {}); + map.put("listDtl", json.parse(output, new TypeReference<>() {})); + } + String tmp = json.stringify(tempResult); + // FIXME: API 오류 보정을 위해 임시로 사용 + ///////////////////////////////////////////////////////////////////////////////// + + NimsApiResult result = json.parse(tmp, new TypeReference<>() {}); + return result.getResponse(); } private NimsApiResult.Response getDsuseRptResponse() { diff --git a/src/test/java/cokr/xit/adds/inf/nims/NimsDtoTest.java b/src/test/java/cokr/xit/adds/inf/nims/NimsDtoTest.java new file mode 100644 index 0000000..2d22141 --- /dev/null +++ b/src/test/java/cokr/xit/adds/inf/nims/NimsDtoTest.java @@ -0,0 +1,176 @@ +package cokr.xit.adds.inf.nims; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.fasterxml.jackson.core.type.TypeReference; + +import cokr.xit.adds.inf.nims.model.NimsApiResult2; +import cokr.xit.foundation.data.JSON; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@ExtendWith(SpringExtension.class) +public class NimsDtoTest { + + @Test + @DisplayName("Nims DTO Test: NIMS에서 받아온 listDtl JSON형태로 변환") + public void test() { + JSON json = new JSON(); + String str = """ + { + "response": { + "header": { + "RESULT_CODE": 0, + "RESULT_MSG": "정상적으로 출력 되었습니다." + }, + "body": { + "TOTAL_COUNT": 0, + "IS_END_YN": "Y", + "nRecord": 5, + "list": [ + { + "DSUSE_PROCESS_DE": "20240108", + "DSUSE_DE": "20240105", + "HDR_DE": "20240105", + "RPT_TY_CD": "신규", + "DSUSE_SE_NM": "보건소폐기", + "DSUSE_PRV_NM": "유효기한 또는 사용기한 경과", + "RND_DTL_RPT_CNT": 1, + "STATUS": "확인", + "RPT_DE": "20240108", + "DSUSE_MTH_NM": "가수분해", + "BSSH_NM": "셀메드한사랑약국", + "ROW_NUM": 1, + "REF_USR_RPT_ID_NO": null, + "INDUTY_NM": "마약류소매업", + "listDtl": "[{PCE_UNIT=정 PRDUCT_CD=8806519017940 DSUSE_QY=28 MNF_NO=20005 MNF_SEQ=2010136201005327 MIN_DISTB_UNIT=병 PRD_VALID_DE=20230722 PCE_QY=0 PRDUCT_NM=졸피신정10mg (10mg) USR_RPT_ID_NO=AAR_R240108122001673_H0000 MIN_DISTB_QY=1}]", + "BSSH_CD": "D00004248", + "USR_RPT_ID_NO": "AAR_R240108122001673_H0000", + "DSUSE_LOC": "수지구보건소" + }, + { + "DSUSE_PROCESS_DE": "20240108", + "DSUSE_DE": "20240105", + "HDR_DE": "20240105", + "RPT_TY_CD": "신규", + "DSUSE_SE_NM": "보건소폐기", + "DSUSE_PRV_NM": "유효기한 또는 사용기한 경과", + "RND_DTL_RPT_CNT": 7, + "STATUS": "확인", + "RPT_DE": "20240108", + "DSUSE_MTH_NM": "가수분해", + "BSSH_NM": "필리아약국", + "ROW_NUM": 2, + "REF_USR_RPT_ID_NO": null, + "INDUTY_NM": "마약류소매업", + "listDtl": "[{PCE_UNIT=정 PRDUCT_CD=8806718002723 DSUSE_QY=120.5086 MNF_NO=20023 MNF_SEQ=2002311466736 MIN_DISTB_UNIT=병 PRD_VALID_DE=20231119 PCE_QY=120.5086 PRDUCT_NM=대원디아제팜정2밀리그램(수출명:디아잠정2밀리그램)(수출명2:트레즈콘정2밀리그램) (2㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806433003210 DSUSE_QY=6 MNF_NO=EE003H76 MNF_SEQ=190710L5F2394 MIN_DISTB_UNIT=병 PRD_VALID_DE=20220617 PCE_QY=6 PRDUCT_NM=데파스정1mg (1㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806429011625 DSUSE_QY=22 MNF_NO=M02002 MNF_SEQ=0000507161 MIN_DISTB_UNIT=병 PRD_VALID_DE=20230224 PCE_QY=22 PRDUCT_NM=아티반정1밀리그람(로라제팜) (1㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806435071637 DSUSE_QY=19 MNF_NO=089619021 MNF_SEQ=204847799109 MIN_DISTB_UNIT=병 PRD_VALID_DE=20221015 PCE_QY=19 PRDUCT_NM=졸피드정5밀리그램(졸피뎀타르타르산염) (5㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806494026722 DSUSE_QY=80 MNF_NO=20001A MNF_SEQ=20001A000606 MIN_DISTB_UNIT=병 PRD_VALID_DE=20230419 PCE_QY=80 PRDUCT_NM=펜민정(염산펜터민) (37.5㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806718033215 DSUSE_QY=2 MNF_NO=20003 MNF_SEQ=2000311213942 MIN_DISTB_UNIT=병 PRD_VALID_DE=20230510 PCE_QY=2 PRDUCT_NM=펜키니정(염산펜터민) (37.5㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0} {PCE_UNIT=정 PRDUCT_CD=8806489012426 DSUSE_QY=2 MNF_NO=CY5151 MNF_SEQ=481706276945 MIN_DISTB_UNIT=박스 PRD_VALID_DE=20220930 PCE_QY=2 PRDUCT_NM=할시온정0.25밀리그람(트리아졸람) (0.25㎎) USR_RPT_ID_NO=AAR_R240108123706946_H0000 MIN_DISTB_QY=0}]", + "BSSH_CD": "D00005271", + "USR_RPT_ID_NO": "AAR_R240108123706946_H0000", + "DSUSE_LOC": "수지구보건소 검사실" + }, + { + "DSUSE_PROCESS_DE": "20240111", + "DSUSE_DE": "20240105", + "HDR_DE": "20240105", + "RPT_TY_CD": "신규", + "DSUSE_SE_NM": "보건소폐기", + "DSUSE_PRV_NM": "사고마약류(파손)", + "RND_DTL_RPT_CNT": 1, + "STATUS": "확인", + "RPT_DE": "20240109", + "DSUSE_MTH_NM": "가수분해", + "BSSH_NM": "수지미래산부인과의원", + "ROW_NUM": 3, + "REF_USR_RPT_ID_NO": null, + "INDUTY_NM": "마약류취급의료업", + "listDtl": "[{PCE_UNIT=앰플 PRDUCT_CD=8806498017429 DSUSE_QY=1 MNF_NO=23040 MNF_SEQ=2304000010140 MIN_DISTB_UNIT=박스 PRD_VALID_DE=20260823 PCE_QY=1 PRDUCT_NM=미다컴주5밀리그람(미다졸람) (5㎎) USR_RPT_ID_NO=H202401000000960742841 MIN_DISTB_QY=0}]", + "BSSH_CD": "H00008333", + "USR_RPT_ID_NO": "H202401000000960742841", + "DSUSE_LOC": "수지구보건소검사실" + }, + { + "DSUSE_PROCESS_DE": "20240111", + "DSUSE_DE": "20240105", + "HDR_DE": "20240105", + "RPT_TY_CD": "신규", + "DSUSE_SE_NM": "보건소폐기", + "DSUSE_PRV_NM": "사고마약류(파손)", + "RND_DTL_RPT_CNT": 1, + "STATUS": "확인", + "RPT_DE": "20240109", + "DSUSE_MTH_NM": "가수분해", + "BSSH_NM": "수지미래산부인과의원", + "ROW_NUM": 4, + "REF_USR_RPT_ID_NO": null, + "INDUTY_NM": "마약류취급의료업", + "listDtl": "[{PCE_UNIT=앰플 PRDUCT_CD=8806498008038 DSUSE_QY=1 MNF_NO=23002 MNF_SEQ=2300200032130 MIN_DISTB_UNIT=박스 PRD_VALID_DE=20260619 PCE_QY=1 PRDUCT_NM=명문구연산펜타닐주사2ml(앰플) (2㎖) USR_RPT_ID_NO=H202401000000960738283 MIN_DISTB_QY=0}]", + "BSSH_CD": "H00008333", + "USR_RPT_ID_NO": "H202401000000960738283", + "DSUSE_LOC": "수지구보건소검사실" + }, + { + "DSUSE_PROCESS_DE": "20240111", + "DSUSE_DE": "20240105", + "HDR_DE": "20240105", + "RPT_TY_CD": "신규", + "DSUSE_SE_NM": "보건소폐기", + "DSUSE_PRV_NM": "재고관리 또는 보관을 하기에 곤란한 사유(사용중단)", + "RND_DTL_RPT_CNT": 1, + "STATUS": "확인", + "RPT_DE": "20240109", + "DSUSE_MTH_NM": "가수분해", + "BSSH_NM": "수지미래산부인과의원", + "ROW_NUM": 5, + "REF_USR_RPT_ID_NO": null, + "INDUTY_NM": "마약류취급의료업", + "listDtl": "[{PCE_UNIT=앰플 PRDUCT_CD=8806578045922 DSUSE_QY=1 MNF_NO=123071 MNF_SEQ=F000536033 MIN_DISTB_UNIT=박스 PRD_VALID_DE=20260913 PCE_QY=1 PRDUCT_NM=아네폴주사(프로포폴) (12㎖) USR_RPT_ID_NO=H202401000000960735283 MIN_DISTB_QY=0}]", + "BSSH_CD": "H00008333", + "USR_RPT_ID_NO": "H202401000000960735283", + "DSUSE_LOC": "수지구보건소검사실" + } + ] + } + } + } + """; + + + NimsApiResult2 result = json.parse(str, new TypeReference<>() {}); + + List list = result.getResponse().getResult(); + + for (Object o : list) { + Map map = (Map)o; + String input = map.get("listDtl").toString(); + + // Remove the brackets at the beginning and end of the string + input = input.substring(1, input.length() - 1); + + // Split the string into individual objects + String[] objects = input.split("\\}\\s*\\{"); + + // Process each object + for (int i = 0; i < objects.length; i++) { + // Add back the curly braces + objects[i] = objects[i].startsWith("{") ? objects[i] : "{" + objects[i]; + objects[i] = objects[i].endsWith("}") ? objects[i] : objects[i] + "}"; + + objects[i] = objects[i].replaceAll("(\\w+_QY)=([^=]+)\\s{2}", "\"$1\":$2,"); + objects[i] = objects[i].replaceAll("(\\w+)=([^=]+)\\s{2}", "\"$1\":\"$2\","); + objects[i] = objects[i].replaceAll("(\\w+)=([^=]+)\\}", "\"$1\":$2}"); + ; + } + + // Join the objects back into a single string + String output = "[" + String.join(", ", objects) + "]"; + map.put("listDtl", output); + } + System.out.println(json.stringify(result)); + } +}