Merge branch 'jenkins_with_weblogic' of ssh://git@192.168.240.178:18081/eapim/eapim-online.git into jenkins_with_weblogic

This commit is contained in:
pksup
2026-01-20 09:36:30 +09:00
17 changed files with 199 additions and 53 deletions
+32
View File
@@ -0,0 +1,32 @@
# 레이아웃 조건부 처리 (RefValue)
FlatReader에서 GROUP/GRID 항목의 조건부 처리를 위한 RefValue 설정 방법
## 지원 조건
| 표현식 | 의미 | 설명 |
|--------|------|------|
| `NM` | EQUALS | 값이 NM과 일치하는 경우 |
| `NM\|EM` | OR | 값이 NM 또는 EM과 일치하는 경우 |
| `!EM` | NOT | 값이 EM이 아닌 경우 |
| `!NM\|EM` | NOT OR | 값이 NM도 아니고 EM도 아닌 경우 |
## 레이아웃 설정 예시
| 항목명 | 설명 | Depth | Type | Node | OccMin | Length | OccMax | RefPath | RefValue |
|--------|------|-------|------|------|--------|--------|--------|---------|----------|
| Message | 메시지부 | 1 | 3 | 0 | 1 | 0 | 1 | Message.Msg_Header.MSG_HEDR_KNCD | NM\|EM |
| Msg_Header | 메시지헤더 | 2 | 3 | 0 | 1 | 0 | 1 | | |
| MSG_HEDR_KNCD | 메시지헤더종류코드 | 3 | 2 | 1 | 1 | 2 | 1 | | NM |
## 동작 설명
위 예시에서 `Message` 항목은 `MSG_HEDR_KNCD` 값이 `NM` 또는 `EM`일 때만 처리됩니다.
- `MSG_HEDR_KNCD = "NM"` → Message 처리됨
- `MSG_HEDR_KNCD = "EM"` → Message 처리됨
- `MSG_HEDR_KNCD = "XX"` → Message 스킵됨
## 변경 파일
- `elink-online-common/src/main/java/com/eactive/eai/message/parser/FlatReader.java`
@@ -138,11 +138,12 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
// if (RESPONSE_TYPE_ASYNC.equals(responseType)) { // table의 값이 ASYNC 로 들어가 있는데 response_type_async는 ASYN 로 되어 있어 아래처럼 비교함 jwhong 2025
if ("ASYNC".equals(responseType)) {
//responseEntity = ResponseEntity.ok("dummy"); // comment by jwhong
servletResponse.addHeader("traceId", responseData); // uuid를 response header에
//servletResponse.addHeader("traceId", responseData); // uuid를 response header에
servletResponse.addHeader("traceId", transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID)); // uuid를 response header에
int httpStatus = servletResponse.getStatus();
if (httpStatus == 200) {
// 업체별 aync response message 가 다르다.
String asyncMsgStyle = httpProp.getProperty("ASYNC_RTNMSG_TYPE", "").toUpperCase();
String asyncMsgStyle = httpProp.getProperty("ASYNC_RTNMSG_TYPE", "");
String responseBody ="";
if (asyncMsgStyle == null || asyncMsgStyle.trim().isEmpty()) {
responseBody = makeResponseBodyMsg();
@@ -158,6 +159,8 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
// responseEntity = ResponseEntity.ok().contentType(mediaType).body(responseData);
// 버즈빌 포인트 적립 처리하기 위하여 정상응답이더라도 응답코드(apiRsltCd) 값이 200이 아닌 경우 처리를 위하여 수정
// Filter에서 설정한 response status값을 responseEntity 생성시 적용 modify by lwk 2025.03.24
servletResponse.addHeader("traceId", transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID)); // uuid를 response header에
int httpStatus = servletResponse.getStatus();
if (httpStatus != 200) {
responseEntity = ResponseEntity.status(httpStatus).contentType(mediaType).body(responseData);
@@ -1,85 +1,150 @@
package com.eactive.eai.adapter.controller;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterManager;
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterUri;
import com.eactive.eai.common.stdmessage.STDMessageManager;
import com.eactive.eai.common.stdmessage.STDMsgInfoAddOnVO;
public class ApiRequestBodyFilter extends OncePerRequestFilter {
static final String KJB_ROOTLESS_ARRAY = "{ \"KJB_ROOTLESS_ARRAY\" : ";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
// 1. 필터 대상
String encoding = getInboundGroupAdapterEncoding(request);
if (!isTarget(request)) {
filterChain.doFilter(request, response);
return;
}
// 2. 요청 전문 읽기
String body = readBody(request);
if (body == null || body.isEmpty()) {
//원본 바디를 byte[]로 읽기 (개행 포함 그대로) 왜? 뒤에 필터에서 HMAC값 계산할수도 있어서 변조되면 안됨. 개행문자도 그대로 가야함.
byte[] rawBody = readBodyAsBytes(request);
if (rawBody == null || rawBody.length == 0) {
filterChain.doFilter(request, response);
return;
}
String modifiedBody = body;
byte[] finalBody = rawBody;
try {
Object json = JSONValue.parse(body);
// 3. 예제: ROOTLESS ARRAY 보정
String bodyStr = new String(rawBody, encoding);
Object json = JSONValue.parse(bodyStr);
if (json instanceof JSONArray) {
JSONObject wrap = new JSONObject();
wrap.put("KJB_ROOTLESS_ARRAY", json);
modifiedBody = wrap.toJSONString();
bodyStr = KJB_ROOTLESS_ARRAY + bodyStr + "}";
finalBody = bodyStr.getBytes(encoding);
}
} catch (Exception e) {
// 변조 실패 원본 유지
modifiedBody = body;
// JSON 파싱 실패 원본 유지
finalBody = rawBody;
}
byte[] bytes = modifiedBody.getBytes(request.getCharacterEncoding() != null ? request.getCharacterEncoding() : Charset.defaultCharset().name() );
// 5. Wrapper로 재주입
// Wrapper로 재주입
HttpServletRequest wrapped =
new CachedBodyHttpServletRequest(request, bytes);
new CachedBodyHttpServletRequest(request, finalBody);
filterChain.doFilter(wrapped, response);
}
private boolean isTarget(HttpServletRequest request) {
String uri = request.getRequestURI();
return ("POST".equals(request.getMethod()) || "PUT".equals(request.getMethod()))
&& (uri.startsWith("/api") || uri.startsWith("/mapi") ) && !uri.startsWith("/mapi/oauth2/token");
&& (uri.startsWith("/api") || uri.startsWith("/mapi"))
&& !uri.startsWith("/mapi/oauth2/token");
}
private String readBody(HttpServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = request.getReader()) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
private byte[] readBodyAsBytes(HttpServletRequest request) throws IOException {
try (ServletInputStream is = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
}
}
private String getInboundGroupAdapterEncoding(HttpServletRequest request) {
String apiUri = request.getRequestURI();
apiUri = StringUtils.removeStart(apiUri, request.getContextPath());
apiUri = StringUtils.removeEnd(apiUri, "/");
String methodAndUri = request.getMethod() + "|" + apiUri;
String adapterGrpName;
HttpDynamicInAdapterUri adptUri = null;
try {
STDMessageManager manager = STDMessageManager.getInstance();
STDMsgInfoAddOnVO stdMsgInfo = manager.getStdMsgInfoAddOn(methodAndUri);
adapterGrpName = stdMsgInfo.gAdapterGroupName();
adptUri = findAdptUri(apiUri, HttpDynamicInAdapterManager.getInstance(), adapterGrpName);
} catch (Exception e) {
adptUri = null;
}
AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO( adptUri.getAdptGrpName());
if( adapterGroupVO == null ) {
return Charset.defaultCharset().name();
}
return StringUtils.isNotBlank(adapterGroupVO.getMessageEncode()) ? adapterGroupVO.getMessageEncode() : Charset.defaultCharset().name(); //서버 jvm file.encoding 확인, file.encoding=utf-8 주고있음.
}
private HttpDynamicInAdapterUri findAdptUri(String apiUri, HttpDynamicInAdapterManager manager, String adapterGrpName) throws Exception {
if (StringUtils.isBlank(apiUri)) {
return null;
}
for (int i = 0; i < 10; i++) {
HttpDynamicInAdapterUri adptUri = manager.getAdptUri(apiUri);
if (adptUri != null) {
if (adptUri.getAdptGrpName().equals(adapterGrpName)) {
return adptUri;
}
}
apiUri = StringUtils.substringBeforeLast(apiUri, "/");
if (apiUri.length() < 4) { // /api
return null;
}
}
return sb.toString();
}
}
return null;
}
}
@@ -13,6 +13,8 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
static final String KJB_ROOTLESS_ARRAY = "{ \"KJB_ROOTLESS_ARRAY\" : ";
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
@@ -34,6 +36,7 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
}
String removeRootlessArrayKeyFormResponseBody(String body) {
try {
Object root = JSONValue.parse(body);
@@ -239,8 +239,12 @@ public class ApiAdapterService extends HttpAdapterServiceSupport {
if (paramValue == null) { // parameter가 없는 경우때문에 처리
paramValue = "";
}
else { // jwhong decrypt
}
// 순수한 Body값을 저장을 위해 위치 변경.
transactionProp.put(INBOUND_REQUEST_MESSAGE, paramValue);
// paramValue가 null이 아닌 빈문자열(""," ")인 경우에 대비하여 조건 수정.
if (StringUtils.isNotBlank(paramValue)) { // jwhong decrypt
paramValue = doPreDecryption(paramValue, transactionProp, request);
}
@@ -296,7 +300,8 @@ public class ApiAdapterService extends HttpAdapterServiceSupport {
message = "";
}
transactionProp.put(INBOUND_REQUEST_MESSAGE, message);
// 위치변경 : 가공되지 않은 Body값을 저장하기 위하여 위쪽으로 이동.
// transactionProp.put(INBOUND_REQUEST_MESSAGE, message);
// 로컬 서비스 호출 ,encoding 처리 추가
String result = (String) service(adptGrpName, adptName, message, transactionProp, request, response);
@@ -14,6 +14,7 @@ public class AsyncReponseFilter implements HttpClientAdapterFilter, HttpAdapterS
public static final String X_TRACE_ID = "partnerTraceId";
public static final String TRACE_ID = "traceId";
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
@@ -21,6 +22,7 @@ public class AsyncReponseFilter implements HttpClientAdapterFilter, HttpAdapterS
logger.debug("AsyncReponseFilter] PreFilter Processing Start!!");
String traceId = tempProp.getProperty(TransactionContextKeys.TRANSACTION_UUID, "");
String xloanToken = tempProp.getProperty(TransactionContextKeys.X_LOAN_TOKEN, "");
Properties filterHeaders = (Properties) tempProp.get("FILTERHEADER");
if (filterHeaders == null) {
@@ -35,7 +37,13 @@ public class AsyncReponseFilter implements HttpClientAdapterFilter, HttpAdapterS
filterHeaders.put(X_TRACE_ID, inboundHeaderMap.get(X_TRACE_ID));
logger.debug("AsyncReponseFilter] Processing Key ["+X_TRACE_ID+"], value ["+inboundHeaderMap.get(X_TRACE_ID)+"]");
}
if (inboundHeaderMap.containsKey(TransactionContextKeys.X_LOAN_TOKEN)||inboundHeaderMap.containsKey(TransactionContextKeys.X_LOAN_TOKEN.toLowerCase())) {
filterHeaders.put(TransactionContextKeys.X_LOAN_TOKEN, inboundHeaderMap.get(TransactionContextKeys.X_LOAN_TOKEN));
logger.debug("AsyncReponseFilter] Processing Key ["+TransactionContextKeys.X_LOAN_TOKEN+"], value ["+inboundHeaderMap.get(TransactionContextKeys.X_LOAN_TOKEN)+"]");
}
}
filterHeaders.setProperty(TRACE_ID, traceId);
logger.debug("AsyncReponseFilter] Processing Key ["+TRACE_ID+"], value ["+traceId+"]");
@@ -24,6 +24,9 @@ public class HttpClient5AdapterFilterFactory {
case SIMPLEFRAMEWORK:
filter = new SimpleFrameworkFilter();
break;
case SIMPLEFRAMEWORKBODY:
filter = new SimpleframeworkBodyFilter();
break;
case JBOBP:
filter = new JBOBPFilter();
break;
@@ -2,6 +2,7 @@ package com.eactive.eai.custom.kjb.adapter.http.client.filter;
public enum HttpClient5AdapterFilterType {
SIMPLEFRAMEWORK,
SIMPLEFRAMEWORKBODY,
JBOBP,
KFTCFACE,
KFTCP2P,
@@ -0,0 +1,26 @@
package com.eactive.eai.custom.kjb.adapter.http.client.filter;
import java.util.Properties;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import com.eactive.eai.common.TransactionContextKeys;
public class SimpleframeworkBodyFilter extends SimpleFrameworkFilter {
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
throws Exception {
Object returnMessage = super.doPreFilter(adptGrpName, adptName, prop, message, tempProp);
JSONObject bizJsonStr = null;
if ( returnMessage instanceof String ) {
bizJsonStr = (JSONObject) JSONValue.parse( (String)returnMessage);
bizJsonStr.put("GUID", tempProp.get(TransactionContextKeys.GUID));
}
return bizJsonStr != null ? bizJsonStr.toJSONString() : returnMessage;
}
}
Binary file not shown.
@@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzY3zugQeOrTkol2fHIhD
/S8FqvNX6ijrU7v8wEnaIYVG1ay6ehAmlg6dc7J0Bvf1Ed5EvbDEI+4sa8n6egWa
zHSL4GXQXj9QFZGvRRah6nPhYiAvbLqHPwvG4QreIwx1Yt4tx63m8gFid6QjEsZP
DbWeX6bXW1scR+qtztkq2CGvOHlej5JHsdP350hH3Hq2sxdmTHurVwFJdfzBwDkU
MJlLwIEkkbACK1hrQhrEf1uKX8HtxrozSS8sso4wFrOPe8u/ykqYmSPlSfUsPvNr
cK/VroyX63RAE+giH84Y8mSHLr+mfEG3AhdJ1+ZqB9jBunTZDiGKn00mT4jJLwgr
BwIDAQAB
-----END PUBLIC KEY-----
Binary file not shown.
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXoqB4PrgZpJISjBe9ht
Y1R3Ne9ehxugWucwA4cBWAnYwvmrRAK0p8p+HuDikdZPq2hyAG02ucNt9xoru+Va
K4spNGieORbh0hmLRdvVBBM7Ureia3WhKED5abNnnPQw+jCLZNVYtO9rbtRhpUEG
t73sN1+0bOZlVBkbLenvWKJs2+tyE0gHhwgS8Fzrb++LHYN/c0KoTm+G9ITuPWoM
Vu/iME5WHqR95TkLKpx6s5J/le4BvncQDmkvKFIX9/DFN57orXQVB2lzDF8fMeWC
xaaHXtgfo2ercKKEdHQ5GFIgWN8+j2ZgU2JqfucazJpOpOGcizHiQKzh//NE7beD
IwIDAQAB
-----END PUBLIC KEY-----
@@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8M6NO6KfKRTwwOfZ/slx
fT/4vPzr1zXvgTHoVq/dyoCk8OeVS0OOJXln7ZqDPkKSlfd1X1fdDaEOfLJXfvPC
Hz7AOTBdr1/Y+Ro4slflO8d9/HbNkUZQTsbS/JqnpD20isP+sSJXHVOq5zEa4bbC
tGcpDIwoOIWqoCAA++jUSKhMZEiag5hWKUBi3wpLLjHiKtk9NZxvfCJO6GMJpN1c
O37cnudSan+oDGn3Twb579pK+gG3UZejQABhrqkv63MhMLrl74tXbHL9HX9shJjQ
zq8SQn2k/RbwLVE+USuDmN8BZkVmtQZRirr3d8yT+BlpgodeqMX8PYcztV+4VTvl
swIDAQAB
-----END PUBLIC KEY-----
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqCW0auFk5bqt7OZ2AtFw
xa/se93/hgNwDNC1kxKZpnvNM5YVj5gjlf0jOSVGNJlFTVvjIBcyPC7s1zlFDhgm
ebUKplRuw82lkIkS7mPjsqfPvMQlFjjLgrnECQ3AD86EkRcUT/bVliOtwLY6YJUa
5/1eqZCIRfLPVxOApSHuQLJ9JmSPhttwfKwTED3G2dB85D+QN5+Nre5nnWDjMScT
KOcyUZHOLO6m0UupBYU94XGJG4EEMwzSE/Lq1eJ49/wUsvaKY6Kz5G30d/ANwRZI
ex82Wp91ZPOasKKOB6vnQ/LNcMhhyYf6IzCliMUUFl53YeheXmvfWX6VLfWgjlLk
HQIDAQAB
-----END PUBLIC KEY-----