diff --git a/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java index 2cb4c0d..3c428b5 100644 --- a/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java +++ b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java @@ -1,19 +1,14 @@ package cokr.xit.ens.core.config; -import java.util.Arrays; -import java.util.List; +import java.util.*; -import org.springdoc.core.GroupedOpenApi; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; +import org.springdoc.core.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.context.annotation.*; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.*; +import io.swagger.v3.oas.models.info.*; +import io.swagger.v3.oas.models.servers.*; @Configuration public class SpringDocConfig { @@ -188,6 +183,14 @@ public class SpringDocConfig { .build(); } + @Profile({"local", "prod", "dev"}) + @Bean + public GroupedOpenApi niceApiDoc() { + return GroupedOpenApi.builder() + .group("전자고지-NICE 인증톡") + .pathsToMatch("/nice/talk/**") + .build(); + } // @Bean // public GroupedOpenApi adminApiDoc() { diff --git a/src/main/java/cokr/xit/ens/core/utils/DateUtil.java b/src/main/java/cokr/xit/ens/core/utils/DateUtil.java index aa1e614..37ad0ef 100644 --- a/src/main/java/cokr/xit/ens/core/utils/DateUtil.java +++ b/src/main/java/cokr/xit/ens/core/utils/DateUtil.java @@ -15,6 +15,7 @@ import lombok.extern.slf4j.*; @Slf4j public class DateUtil { + private static final String DEFAULT_YMD_DT_FMT ="yyyy-MM-dd HH:mm:ss"; /** *
메소드 설명: 절대시간(단위: milliesecond)을 현재 시간으로 반환 한다.
diff --git a/src/main/java/cokr/xit/ens/modules/nice/cmm/NiceCiUtils.java b/src/main/java/cokr/xit/ens/modules/nice/cmm/NiceCiUtils.java index c9e73f1..fe50b5f 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/cmm/NiceCiUtils.java +++ b/src/main/java/cokr/xit/ens/modules/nice/cmm/NiceCiUtils.java @@ -2,7 +2,6 @@ package cokr.xit.ens.modules.nice.cmm; import java.io.*; import java.nio.charset.*; -import java.util.concurrent.atomic.*; import org.apache.commons.lang3.*; @@ -138,8 +137,8 @@ public class NiceCiUtils { strRtnText.append(strText.charAt(i)); continue; } - - if (strText.charAt(i) > 127) + char c = strText.charAt(i); + if (c > 127 || c == '\n' || c == '\t') skipIdx += 2; else skipIdx++; @@ -163,20 +162,30 @@ public class NiceCiUtils { */ public static String getStringKr(String strText, int iBytes) { StringBuilder strRtnText = new StringBuilder(); - AtomicInteger iByte = new AtomicInteger(); - - strText.chars().limit(iBytes).forEach(c -> { - strRtnText.append((char) c); - iByte.addAndGet((c > 127) ? 2 : 1); - if (iByte.get() >= iBytes) return; - }); + int iByte = 0; + + // 문자열을 문자 배열로 변환하여 반복문을 통해 처리 + for (int i = 0; i < strText.length(); i++) { + char c = strText.charAt(i); + strRtnText.append(c); + // 한글 등의 2바이트 문자 처리 + if(c > 127 || c == '\n' || c == '\t') { + iByte += 2; + }else{ + iByte++; + } + // 지정된 바이트 수를 넘으면 반복 종료 + if (iByte >= iBytes) { + break; // for 루프 종료 + } + } return strRtnText.toString(); } public static int lengthKr(String strText) { return strText.chars() - .map(ch -> ch > 127 ? 2 : 1) // 한글(또는 다른 비 ASCII 문자)인 경우 2바이트, 아니면 1바이트 + .map(ch -> (ch > 127 || ch == '\n' || ch == '\t') ? 2 : 1) // 한글(또는 다른 비 ASCII 문자)인 경우 2바이트, 아니면 1바이트 .sum(); } @@ -203,6 +212,13 @@ public class NiceCiUtils { .readLine(); } + // 특수 문자를 2바이트로 간주하는 메서드 + private static boolean isToByte(char c) { + // 추가적으로 2바이트로 계산할 특수 문자 정의 + // 필요에 따라 추가 가능 + return "\t\n".indexOf(c) >= 0; + } + public static void main(String[] args) throws IOException { final String tgt = new String("123ab한글이ㅂa들어있다열자ㅁ".getBytes(), StandardCharsets.UTF_8); final String tgt2 = new String("123ab한글이ㅂa들어있다열자ㅁ".getBytes(), StandardCharsets.ISO_8859_1); @@ -224,8 +240,6 @@ public class NiceCiUtils { System.out.println(substringKr("gks한글이시작되는데", 8)); System.out.println(substringKr("한글로abcdefgh계속", 12)); System.out.println(substringKr("1한글2ㅇ ab", 10)); - //System.out.println(substringKor(tgt, 11)); -; System.out.println(leftKr(tgt, 18)); System.out.println(leftKr(tgt2, 18)); diff --git a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiCommon.java b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiCommon.java index 78e9bc1..5b5aa89 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiCommon.java +++ b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiCommon.java @@ -89,7 +89,7 @@ public class NiceCiCommon { * */ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "단말기구분(3자리)", example = "503") - @Size(min = 1, max = 1, message = "단말기 구분은 3자리 입니다.") + @Size(min = 3, max = 3, message = "단말기 구분은 3자리 입니다.") private String deviceClassification = "503"; public void setDeviceClassification(String deviceClassification) { this.deviceClassification = StringUtils.rightPad(nvl(deviceClassification), 3, StringUtils.SPACE); @@ -111,7 +111,7 @@ public class NiceCiCommon { * */ @Schema(title = "응답코드(4자리)", example = " ") - @Pattern(regexp = "^$|^[P|E|S][\\d]{3}$", message = "응답코드(4자리)는 4자리 입니다") + @Pattern(regexp = "^\\s{4}$|$|^[P|E|S][\\d]{3}$", message = "응답코드(4자리)는 4자리 입니다") private String rsltCode = StringUtils.rightPad(StringUtils.EMPTY, 4, StringUtils.SPACE); public void setRsltCode(String rsltCode) { this.rsltCode = StringUtils.rightPad(nvl(rsltCode), 4, StringUtils.SPACE); diff --git a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiDTO.java b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiDTO.java index 7896660..92524b4 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiDTO.java +++ b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiDTO.java @@ -48,8 +48,8 @@ public class NiceCiDTO { * 전문길이 set * */ - @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "TR Code", example = " ") - @Size(min = 10, max = 10, message = "트랜잭션 코드는 10자리 입니다.") + //@Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "TR Code", example = " ") + //@Size(min = 10, max = 10, message = "트랜잭션 코드는 10자리 입니다.") private String trCode = StringUtils.EMPTY; public void setTrCode(String trCode) { this.trCode = StringUtils.leftPad(nvl(trCode), 10, StringUtils.SPACE); @@ -94,6 +94,7 @@ public class NiceCiDTO { */ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "조회사유", example = " ") @Size(min = 2, max = 2, message = "조회사유는 2자리 입니다") + //@Pattern(regexp = "^\\s{2}$|s{1,2}", message = "조회사유는 2자리 입니다") private String queryReason = StringUtils.rightPad(StringUtils.EMPTY, 2, StringUtils.SPACE); public void setQueryReason(String queryReason) { this.queryReason = StringUtils.rightPad(nvl(queryReason), 2, StringUtils.SPACE); @@ -106,7 +107,7 @@ public class NiceCiDTO { * */ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "조회요청건수", example = " ") - @Max(value = 48, message = "조회요청 최대건수는 48입니다") + @Pattern(regexp = "^\\s{2}$|\\d{1,2}", message = "조회요청 최대건수는 48입니다(2자리)") private String queryReqCnt = StringUtils.rightPad(StringUtils.EMPTY, 2, StringUtils.SPACE); public void setQueryReqCnt(Integer queryReqCnt) { this.queryReqCnt = StringUtils.rightPad(nvl(queryReqCnt == null? "": queryReqCnt.toString()), 2, StringUtils.SPACE); @@ -124,7 +125,7 @@ public class NiceCiDTO { */ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "SMS발송요청구분코드", example = " ", allowableValues = {"0", "1", "2", "3"}) @Pattern(regexp = "[0-3]", message = "SMS발송요청구분코드 0 ~ 3 입니다(1자리)") - private String smsSndReqCode = StringUtils.SPACE;; + private String smsSndReqCode = "1"; /** *
@@ -133,7 +134,7 @@ public class NiceCiDTO {
          * 
*/ @Schema(title = "SMS 발송메세지", example = " ") - @Pattern(regexp = "^$|[\\s]{10,2000}", message = "SMS발송메세지는 10 ~ 2000자리 입니다") + @Pattern(regexp = "^[\\s\\S]{10,2000}$", message = "SMS발송메세지는 10 ~ 2000자리 입니다") private String sndMessage = StringUtils.rightPad(StringUtils.EMPTY, 2000, StringUtils.SPACE); public void setSndMessage(String sndMessage) { this.sndMessage = NiceCiUtils.rightPadKr(nvl(sndMessage), 2000, StringUtils.SPACE); @@ -146,7 +147,7 @@ public class NiceCiDTO { * */ @Schema(title = "SMS 발신번호", example = " ") - @Pattern(regexp = "^$|[\\d]{3,12}", message = "SMS 발신번호는 3 ~ 12자리 입니다") + @Pattern(regexp = "^\\s{12}$|[\\d]{3,12}", message = "SMS 발신번호는 3 ~ 12자리 입니다") private String sndPhoneNo = StringUtils.rightPad(StringUtils.EMPTY, 12, StringUtils.SPACE); public void setSndPhoneNo(String sndPhoneNo) { this.sndPhoneNo = StringUtils.rightPad(nvl(sndPhoneNo), 12, StringUtils.SPACE); @@ -196,10 +197,10 @@ public class NiceCiDTO { * */ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, title = "버튼요청건수", example = " ") - @Max(value = 5, message = "버튼요청건수는 1자리 입니다") + @Pattern(regexp = "^ |[0-5]$", message = "버튼요청건수는 1자리로 최대 5 입니다.") private String btnReqCnt = StringUtils.SPACE; public void setBtnReqCnt(Integer btnReqCnt) { - this.btnReqCnt = StringUtils.rightPad(nvl(btnReqCnt == null ? "" : btnReqCnt.toString()), 2, StringUtils.SPACE); + this.btnReqCnt = StringUtils.rightPad(nvl(btnReqCnt == null ? "" : btnReqCnt.toString()), 1, StringUtils.SPACE); } /** @@ -464,11 +465,12 @@ public class NiceCiDTO { // return sb.toString(); // } - public static Response parse(String tgtStr) { + public static Response parse(String tgtString) { final int repeatLength = 110; final int[] parseLength = { 10, // tr-code 83, // 공통부 + // FIXME: spec과 상이 - 확인 필요 : "1"이 들어오고 있다 17, // 공란 2, // 응답건수 1, // SMS발송요청구분코드 @@ -478,9 +480,10 @@ public class NiceCiDTO { 84, // 공란 }; // FIXME: 인코딩확인후 적용 - String tgtString = NiceCiUtils.covertCharset(tgtStr, "EUC-KR"); + //String tgtString = NiceCiUtils.covertCharset(tgtStr, "EUC-KR"); - if (StringUtils.isNotBlank(tgtString) && tgtString.length() >= 2319) { + //if (StringUtils.isNotBlank(tgtString) && NiceCiUtils.lengthKr(tgtString) >= 2210) { + if (StringUtils.isNotBlank(tgtString)) { Response response = new Response(); int idx = 0; response.setTrCode(StringUtils.left(tgtString, parseLength[idx])); @@ -510,12 +513,13 @@ public class NiceCiDTO { response.setPrivateEmptyField(StringUtils.left(tgtString, parseLength[idx])); tgtString = tgtString.substring(parseLength[idx]); - if(tgtString.length() % repeatLength == 0){ - int repeat = tgtString.length() / repeatLength; + if(NiceCiUtils.lengthKr(tgtString) % repeatLength == 0){ + int repeat = NiceCiUtils.lengthKr(tgtString) / repeatLength; String finalTgtString = tgtString; List resResults = IntStream.range(0, repeat) .mapToObj(i -> { - String currentString = finalTgtString.substring(i * repeatLength, (i + 1) * repeatLength); + String currentString = NiceCiUtils.substringKr(finalTgtString, i * repeatLength); + //String currentString = finalTgtString.substring(i * repeatLength, (i + 1) * repeatLength); return NiceCiResult.parse(currentString); }) .collect(Collectors.toList()); diff --git a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiResult.java b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiResult.java index a6424e8..e0e368b 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiResult.java +++ b/src/main/java/cokr/xit/ens/modules/nice/model/NiceCiResult.java @@ -268,7 +268,7 @@ public class NiceCiResult { 15, // 공란 }; - if (StringUtils.isNotBlank(tgtString) && tgtString.length()%110 == 0) { + if (StringUtils.isNotBlank(tgtString) && NiceCiUtils.lengthKr(tgtString)%110 == 0) { NiceCiResult result = new NiceCiResult(); int idx = 0; diff --git a/src/main/java/cokr/xit/ens/modules/nice/model/Client.java b/src/main/java/cokr/xit/ens/modules/nice/model/TestSocketClient.java similarity index 62% rename from src/main/java/cokr/xit/ens/modules/nice/model/Client.java rename to src/main/java/cokr/xit/ens/modules/nice/model/TestSocketClient.java index e64e70f..38c9bba 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/model/Client.java +++ b/src/main/java/cokr/xit/ens/modules/nice/model/TestSocketClient.java @@ -4,7 +4,7 @@ import java.io.*; import java.net.*; import java.nio.charset.*; -public class Client { +public class TestSocketClient { public static void main(String[] args) { final String msg = "0000006438NICEIF 020031895B503 Z755400 000000010320240919 4 誘쇱����濡� 愿�由ъ����쇳�곗���� 源��댁갔��猿� 諛��≫�� 誘몃�⑺�듯��猷� 怨�吏���媛� ��李⑺���듬����.\n" @@ -26,7 +26,8 @@ public class Client { + "\n" + "�� ��由쇳�� ���� �� 醫��닿�吏����� 諛��〓��吏� ���듬����.\n" + "\n" - + "臾몄��泥� : 044-211-3377 31 1 WL "; + + "臾몄��泥� : 044-211-3377 31 1 WL " + + "\n "; final String msg2 = "0000006150NICEIF 020031895B503 Z755400 000000010320240919 4 민자도로 관리지원센터에서 김해찬님께 발송한 미납통행료 고지서가 도착했습니다.\n" + "\n" @@ -47,17 +48,20 @@ public class Client { + "\n" + "※ 알림톡 수신 시 종이고지서는 발송되지 않습니다.\n" + "\n" - + "문의처 : 044-211-3377 31 1 WL " - + "\n "; + + "문의처 : 044-211-3377"; + //+ "\nEXIT"; - try (Socket socket = new Socket("localhost", 12345); // 서버에 연결 + try (Socket socket = new Socket("127.0.0.1", 10002); // 서버에 연결 BufferedWriter out = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), Charset.forName("EUC-KR"))); //new OutputStreamWriter(socket.getOutputStream())); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream(), Charset.forName("EUC-KR")))) { + socket.setSoTimeout(2000); + out.write(msg2); + out.write("\nEXIT"); out.newLine(); out.flush(); diff --git a/src/main/java/cokr/xit/ens/modules/nice/model/Server.java b/src/main/java/cokr/xit/ens/modules/nice/model/TestSocketServer.java similarity index 64% rename from src/main/java/cokr/xit/ens/modules/nice/model/Server.java rename to src/main/java/cokr/xit/ens/modules/nice/model/TestSocketServer.java index 026a454..356df88 100644 --- a/src/main/java/cokr/xit/ens/modules/nice/model/Server.java +++ b/src/main/java/cokr/xit/ens/modules/nice/model/TestSocketServer.java @@ -4,13 +4,11 @@ import java.io.*; import java.net.*; import java.nio.charset.*; -import org.apache.commons.lang.*; - -public class Server { +public class TestSocketServer { public static void main(String[] args) { - try (ServerSocket serverSocket = new ServerSocket(12345)) { // 포트 12345에서 서버 소켓 열기 + try (ServerSocket serverSocket = new ServerSocket(10002)) { // 포트 12345에서 서버 소켓 열기 System.out.println("서버가 시작되었습니다."); while (true) { @@ -23,33 +21,46 @@ public class Server { } private static void handleClient(Socket clientSocket) { - final String res = "trCode " + - // NiceCommon - "NICEIF 020031895B503rsltorgId orgMngNo orgSndDt niceMngNo niceSndDt" + - " "+ - // 개별응답부 - "241~~~~~~~~~~~~~~~~~~~~~~~ 010 1 "+ - // 응답반복부 - "18401011449211name2 001 "+ - "19412341234567이름2 1 "; + final String niceCiRes = "0000002310NICEIF 021031896N503P000Z755400 000000010320240919 466241822620240919160011 1013민자도로 관리지원센터에서 김해찬님께 발송한 미납통행료 고지서가 도착했습니다.\n" + + "\n" + + "민자도로 미납통행료 고지서\n" + + "\n" + + "□ 차량번호 : 19너0914\n" + + "□ 미납발생 노선 : 서울-문산\n" + + "□ 미납발생 기간 : 2021년 04월 12일~2023년 08월 30일\n" + + "□ 납부금액 : 819,500원(42건)\n" + + "□ 납부기한 : 2024년10월01일\n" + + "□ 납부방법 : \n" + + "① 하단의 (납부하기) 클릭\n" + + "② 가상계좌 납부\n" + + "-(가상계좌) : 농협은행 792000-36-986609\n" + + "국민은행 731190-72-253083\n" + + "우리은행 283752-73-918780\n" + + "신한은행 562146-27-470101\n" + + "\n" + + "※ 알림톡 수신 시 종이고지서는 발송되지 않습니다.\n" + + "\n" + + "문의처 : 044-211-3377 0442113377 3 18912111020220김해찬 01084289916 0010108428991620240919160011 "; try (BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream(), Charset.forName("EUC-KR"))); + // new InputStreamReader(clientSocket.getInputStream(), Charset.forName("UTF-8"))); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), Charset.forName("EUC-KR")))) { // 클라이언트로부터 메시지 읽기 String message; StringBuffer sb = new StringBuffer(); - while((message = in.readLine()) != null && !(message.length() >= 10 && StringUtils.isEmpty(message.trim()))) { // 빈 줄이 들어올 때까지 읽기 - sb.append(message); + while((message = in.readLine()) != null) { + if("EXIT".equals(message)) break; + sb.append(message).append("\n"); }; System.out.println("=============>>>클라이언트로부터 받은 메시지<<<===================================="); System.out.println(sb.toString()); System.out.println("=============>>>클라이언트로부터 받은 메시지<<<===================================="); // 응답 메시지 작성 및 전송 - out.write(res); + out.write(niceCiRes); out.newLine(); out.flush(); } catch (IOException e) { diff --git a/src/main/java/cokr/xit/ens/modules/nice/presentation/NiceCiController.java b/src/main/java/cokr/xit/ens/modules/nice/presentation/NiceCiController.java new file mode 100644 index 0000000..2159f1e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/nice/presentation/NiceCiController.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.modules.nice.presentation; + +import org.springframework.http.*; +import org.springframework.web.bind.annotation.*; + +import cokr.xit.ens.modules.nice.service.*; +import io.swagger.v3.oas.annotations.*; +import io.swagger.v3.oas.annotations.tags.*; +import lombok.*; + +/** + *
+ * description :
+ * packageName : cokr.xit.ens.modules.nice.presentation
+ * fileName    : NiceCiController
+ * author      : limju
+ * date        : 2024 9월 27
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2024 9월 27   limju       최초 생성
+ *
+ * 
+ */ +@Tag(name = "NiceCiController", description = "NICE CI 인증톡") +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/nice/talk") +public class NiceCiController { + private final NiceCiService niceCiService; + + @Operation(summary = "(대량)전송요청") + @PostMapping(value = "/send/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendBulk() { + return new ResponseEntity<>(niceCiService.requestSendBulk(), HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/nice/service/NiceCiService.java b/src/main/java/cokr/xit/ens/modules/nice/service/NiceCiService.java new file mode 100644 index 0000000..46a14fe --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/nice/service/NiceCiService.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.modules.nice.service; + +import org.apache.commons.lang3.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.*; + +import cokr.xit.ens.core.aop.*; +import cokr.xit.ens.modules.nice.cmm.*; +import cokr.xit.ens.modules.nice.model.*; +import cokr.xit.ens.modules.nice.service.support.*; +import lombok.*; +import lombok.extern.slf4j.*; + +/** + *
+ * description :
+ * packageName : cokr.xit.ens.modules.nice.service
+ * fileName    : NiceCiService
+ * author      : limju
+ * date        : 2024 9월 27
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2024 9월 27   limju       최초 생성
+ *
+ * 
+ */ +@Slf4j +@Service +@RequiredArgsConstructor +public class NiceCiService { + @Value("${contract.niceCi.orgId}") + private String ORG_ID; + + @Value("${contract.niceCi.clientId}") + private String CLIENT_ID; + + private final NiceCiApiService niceCiApiService; + + final String msg = "민자도로 관리지원센터에서 김해찬님께 발송한 미납통행료 고지서가 도착했습니다.\n" + + "\n" + + "민자도로 미납통행료 고지서\n" + + "\n" + + "□ 차량번호 : 19너0914\n" + + "□ 미납발생 노선 : 서울-문산\n" + + "□ 미납발생 기간 : 2021년 04월 12일~2023년 08월 30일\n" + + "□ 납부금액 : 819,500원(42건)\n" + + "□ 납부기한 : 2024년10월01일\n" + + "□ 납부방법 : \n" + + "① 하단의 (납부하기) 클릭\n" + + "② 가상계좌 납부\n" + + "-(가상계좌) : 농협은행 792000-36-986609\n" + + "국민은행 731190-72-253083\n" + + "우리은행 283752-73-918780\n" + + "신한은행 562146-27-470101\n" + + "\n" + + "※ 알림톡 수신 시 종이고지서는 발송되지 않습니다.\n" + + "\n" + + "문의처 : 044-211-3377"; + + public EnsResponseVO requestSendBulk() { + NiceCiDTO.Request ciRequest = new NiceCiDTO.Request(); + //ciRequest.setTrCode("0000006150"); + // // 공통부 + // + // // 개별요청부 + // nr.setQueryReason(StringUtils.EMPTY); + // nr.setQueryReqCnt(46); + // nr.setSmsSndReqCode("1"); + String tmp = NiceCiUtils.rightPadKr(msg, 2000, StringUtils.SPACE); + System.out.println( + String.format("[%s] kr length - %d, utf-8 length - %d", tmp, NiceCiUtils.lengthKr(tmp), tmp.length())); + ciRequest.setSndMessage(msg); + // nr.setSndPhoneNo("010"); + // nr.setContactSearchCode("1"); + + // 공통부 + NiceCiCommon nc = new NiceCiCommon(); + // nc.setGrpCode("grpCode"); + //nc.setTrType("Type"); + nc.setTrClassification("31895"); // 거래구분 + nc.setOrgId(ORG_ID); // 참가기관Id - property 에서 + nc.setOrgMngNo("0000000103"); // 기관관리번호 + nc.setOrgSndDt("20240919"); + + NiceCiDTO.QueryRequest qr = new NiceCiDTO.QueryRequest(); + NiceCiDTO.ButtonRequest br = new NiceCiDTO.ButtonRequest(); + + ciRequest.setNiceCommon(nc); + ciRequest.getQueryRequests().add(qr); + ciRequest.getButtonRequests().add(br); + // nc.setNiceMngNo(StringUtils.EMPTY); + // nc.setNiceSndDt(StringUtils.EMPTY); + String ciTxt = ciRequest.ofString(); + String ft = String.format("%s%s", StringUtils.leftPad(String.valueOf(NiceCiUtils.lengthKr(ciTxt)), 10, "0"), + ciTxt); + System.out.println( + String.format("[%s] kr length - %d, utf-8 length - %d", ft, NiceCiUtils.lengthKr(ft), ft.length())); + + // String rtnMsg = niceCiApiService.requestSendBulk(ciRequest); + // NiceCiDTO.Response resDTO = NiceCiDTO.Response.parse(rtnMsg); + return niceCiApiService.requestSendBulk(ciRequest); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/nice/service/support/NiceCiApiService.java b/src/main/java/cokr/xit/ens/modules/nice/service/support/NiceCiApiService.java new file mode 100644 index 0000000..3601347 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/nice/service/support/NiceCiApiService.java @@ -0,0 +1,127 @@ +package cokr.xit.ens.modules.nice.service.support; + +import java.io.*; +import java.net.*; +import java.nio.charset.*; +import java.util.*; +import java.util.stream.*; + +import javax.validation.*; + +import org.apache.commons.lang3.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.*; + +import cokr.xit.ens.core.aop.*; +import cokr.xit.ens.core.exception.*; +import cokr.xit.ens.core.exception.code.*; +import cokr.xit.ens.modules.nice.cmm.*; +import cokr.xit.ens.modules.nice.model.*; +import lombok.*; +import lombok.extern.slf4j.*; + +/** + *
+ * description :
+ * packageName : cokr.xit.ens.modules.nice.service.support
+ * fileName    : NiceCiService
+ * author      : limju
+ * date        : 2024 9월 27
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2024 9월 27   limju       최초 생성
+ *
+ * 
+ */ +@Slf4j +@Service +@RequiredArgsConstructor +public class NiceCiApiService { + + @Value("${contract.niceCi.host}") + private String HOST; + + @Value("${contract.niceCi.port}") + private int PORT; + + @Value("${contract.niceCi.timeout}") + private int TIMEOUT; + + private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + public EnsResponseVO requestSendBulk(final NiceCiDTO.Request reqDTO) { + List errors = new ArrayList<>(); + final Set> list = validator.validate(reqDTO); + if (!list.isEmpty()) { + errors.addAll(list.stream() + .map(row -> String.format("%s=%s", row.getPropertyPath(), row.getMessageTemplate())) + .collect(Collectors.toList()) + ); + } + + if(!errors.isEmpty()){ + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.INVALID_DATA) + .errMsg(errors.toString()) + .build(); + } + String ciTxt = reqDTO.ofString(); + String ft = String.format("%s%s", StringUtils.leftPad(String.valueOf(NiceCiUtils.lengthKr(ciTxt)), 10, "0"), + ciTxt); + log.info("[{}] kr length - {}, utf-8 length - {}", ft, NiceCiUtils.lengthKr(ft), ft.length()); + + final String rtnMsg; + try { + rtnMsg = sendNiceCiSocket(ft); + } catch (Exception e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.API_COMM_ERROR) + .errMsg(e.getMessage()) + .build(); + } + NiceCiDTO.Response resDTO = NiceCiDTO.Response.parse(rtnMsg); + return EnsResponseVO.okBuilder() + .resultInfo(resDTO) + .build(); + } + + private String sendNiceCiSocket(final String binTxt) { + String rtnMsg = ""; + + try (Socket socket = new Socket(HOST, PORT); // 서버에 연결 + BufferedWriter out = new BufferedWriter( + new OutputStreamWriter(socket.getOutputStream(), Charset.forName("EUC-KR"))); + //new OutputStreamWriter(socket.getOutputStream())); + BufferedReader in = new BufferedReader( + new InputStreamReader(socket.getInputStream(), Charset.forName("EUC-KR")))) { + + socket.setSoTimeout(TIMEOUT); // 읽기 타임아웃 설정 + + out.write(binTxt); + // FIXME: 테스트 소켓서버 통신을 위해 임시로 추가 : 테스트 완료후 제거 + out.write("\nEXIT"); + + out.newLine(); + out.flush(); + + String message; + StringBuffer sb = new StringBuffer(); + while((message = in.readLine()) != null) { + sb.append(message); + }; + rtnMsg = sb.toString(); + System.out.println("=============>>>서버 응답(EUC-KR로 읽어온 값)<<<===================================="); + System.out.println(rtnMsg); + System.out.println("=============>>>서버 응답(EUC-KR로 읽어온 값)<<<===================================="); + } catch (SocketTimeoutException e) { + // 타임아웃 발생 시 처리 + log.error("NICE CI Socket 서버 응답 시간 초과: " + e.getMessage()); + throw BizRuntimeException.create("NICE CI Socket 서버 응답 시간 초과로 인해 통신이 종료되었습니다."); + + } catch (IOException e) { + throw BizRuntimeException.create(e.getMessage()); + } + return rtnMsg; + } +} diff --git a/src/main/resources/config/conf-app.yml b/src/main/resources/config/conf-app.yml index 33e48d8..f2c1331 100644 --- a/src/main/resources/config/conf-app.yml +++ b/src/main/resources/config/conf-app.yml @@ -2,7 +2,7 @@ app: access: auth: exclude: - uri: ${xit.app.ctx}/example/.*, ${xit.app.ctx}/kko/mydoc/.*, ${xit.app.ctx}/kko/talk/.*, ${xit.app.ctx}/kko/alimtalk/.*, ${xit.app.ctx}/nv/signtalk/.*, ${xit.app.ctx}/kt/signtalk/.*, ${xit.app.ctx}/kt/gibis/.*, ${xit.app.ctx}/api/msg/result, ${xit.app.ctx}/iup/.*, ${xit.app.ctx}/traffic/.*, ${xit.app.ctx}/sys/mng/.*, ${xit.app.ctx}/sys/util/.*, ${xit.app.ctx}/intgrn/noti/.*, ${xit.app.ctx}/cmft/.*, ${xit.app.ctx}/bill/.* + uri: ${xit.app.ctx}/example/.*, ${xit.app.ctx}/kko/mydoc/.*, ${xit.app.ctx}/kko/talk/.*, ${xit.app.ctx}/nice/talk/.*, ${xit.app.ctx}/kko/alimtalk/.*, ${xit.app.ctx}/nv/signtalk/.*, ${xit.app.ctx}/kt/signtalk/.*, ${xit.app.ctx}/kt/gibis/.*, ${xit.app.ctx}/api/msg/result, ${xit.app.ctx}/iup/.*, ${xit.app.ctx}/traffic/.*, ${xit.app.ctx}/sys/mng/.*, ${xit.app.ctx}/sys/util/.*, ${xit.app.ctx}/intgrn/noti/.*, ${xit.app.ctx}/cmft/.*, ${xit.app.ctx}/bill/.* pallel: thread: basic: diff --git a/src/main/resources/config/conf-contract.yml b/src/main/resources/config/conf-contract.yml index 896d9f4..8229821 100644 --- a/src/main/resources/config/conf-contract.yml +++ b/src/main/resources/config/conf-contract.yml @@ -135,8 +135,11 @@ contract: read: /api/msg/read niceCi: - ip: 10.1.1.55 + host: 127.0.0.1 + #host: 10.1.1.5 port: 10002 + # ms + timeout: 3000 orgId: Z755400 # 개발 clientId: 0027370001 diff --git a/src/main/resources/mybatis-mapper/mybatis-config.xml b/src/main/resources/mybatis-mapper/mybatis-config.xml index 54a6663..8655be4 100644 --- a/src/main/resources/mybatis-mapper/mybatis-config.xml +++ b/src/main/resources/mybatis-mapper/mybatis-config.xml @@ -46,11 +46,4 @@ - - - - - - -