From 3257739c883a621db4164a034be99d8a57931f03 Mon Sep 17 00:00:00 2001 From: forge-bot Date: Sat, 18 Jul 2026 11:10:31 +0000 Subject: [PATCH] =?UTF-8?q?[=EB=A7=A4=EC=9E=85]=20mg=5Frecv=5Fsvc=20?= =?UTF-8?q?=E2=86=92=20=EC=A0=84=EB=AC=B8=EC=88=98=EC=8B=A0=20@Service=20(?= =?UTF-8?q?ACM-MG-004)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acquiring/codec/MessageCodec.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 boot/modules/acquiring/src/main/java/com/klaro/acquirecore/acquiring/codec/MessageCodec.java diff --git a/boot/modules/acquiring/src/main/java/com/klaro/acquirecore/acquiring/codec/MessageCodec.java b/boot/modules/acquiring/src/main/java/com/klaro/acquirecore/acquiring/codec/MessageCodec.java new file mode 100644 index 0000000..8c94db8 --- /dev/null +++ b/boot/modules/acquiring/src/main/java/com/klaro/acquirecore/acquiring/codec/MessageCodec.java @@ -0,0 +1,91 @@ +package com.klaro.acquirecore.acquiring.codec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * 전문 인코딩/디코딩 컴포넌트 + * Fixed-length 필드 기반 전문 파싱 + */ +@Component +public class MessageCodec { + + private static final Logger log = LoggerFactory.getLogger(MessageCodec.class); + + private static final int LEN_TX_TYPE = 4; + private static final int LEN_TRACE_NO = 12; + private static final int LEN_MERCHANT_ID = 15; + private static final int LEN_AMOUNT = 12; + private static final int LEN_CARD_NO = 20; + private static final int LEN_EXPIRY = 4; + private static final int LEN_INSTALLMENTS = 2; + private static final int LEN_FILLER = 99; + + public UnpackedMessage unpack(byte[] rawMessage) { + if (rawMessage == null || rawMessage.length == 0) { + throw new IllegalArgumentException("Empty message"); + } + + String data = new String(rawMessage); + int offset = 0; + + UnpackedMessage unpacked = new UnpackedMessage(); + unpacked.setRawData(data); + + unpacked.setTxType(extract(data, offset, LEN_TX_TYPE)); + offset += LEN_TX_TYPE; + + unpacked.setTraceNo(extract(data, offset, LEN_TRACE_NO)); + offset += LEN_TRACE_NO; + + unpacked.setMerchantId(extract(data, offset, LEN_MERCHANT_ID)); + offset += LEN_MERCHANT_ID; + + unpacked.setAmount(extract(data, offset, LEN_AMOUNT)); + offset += LEN_AMOUNT; + + unpacked.setCardNo(extract(data, offset, LEN_CARD_NO)); + offset += LEN_CARD_NO; + + unpacked.setExpiryDate(extract(data, offset, LEN_EXPIRY)); + offset += LEN_EXPIRY; + + unpacked.setInstallments(extract(data, offset, LEN_INSTALLMENTS)); + offset += LEN_INSTALLMENTS; + + if (data.length() > offset) { + unpacked.setFiller(extract(data, offset, Math.min(LEN_FILLER, data.length() - offset))); + } + + log.debug("Message unpacked: txType={}, traceNo={}", unpacked.getTxType(), unpacked.getTraceNo()); + return unpacked; + } + + public byte[] pack(UnpackedMessage unpacked) { + StringBuilder sb = new StringBuilder(); + sb.append(padRight(unpacked.getTxType(), LEN_TX_TYPE)); + sb.append(padRight(unpacked.getTraceNo(), LEN_TRACE_NO)); + sb.append(padRight(unpacked.getMerchantId(), LEN_MERCHANT_ID)); + sb.append(padRight(unpacked.getAmount(), LEN_AMOUNT)); + sb.append(padRight(unpacked.getCardNo(), LEN_CARD_NO)); + sb.append(padRight(unpacked.getExpiryDate(), LEN_EXPIRY)); + sb.append(padRight(unpacked.getInstallments(), LEN_INSTALLMENTS)); + sb.append(padRight(unpacked.getFiller(), LEN_FILLER)); + return sb.toString().getBytes(); + } + + private String extract(String data, int offset, int length) { + if (offset >= data.length()) return ""; + int end = Math.min(offset + length, data.length()); + return data.substring(offset, end).trim(); + } + + private String padRight(String value, int length) { + if (value == null) value = ""; + if (value.length() >= length) return value.substring(0, length); + StringBuilder sb = new StringBuilder(value); + while (sb.length() < length) sb.append(' '); + return sb.toString(); + } +}