파트너코드 조회
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package com.eactive.ext.kjb.common;
|
||||
|
||||
public class KjbObpException extends Exception {
|
||||
private int statusCode;
|
||||
|
||||
public KjbObpException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public KjbObpException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public KjbObpException(int statusCode, String message) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,18 @@ public class KjbProperty {
|
||||
@NotEmpty
|
||||
private String obpPartnerCodeValue = "100001-01";
|
||||
|
||||
@KjbPropertyValue(key = "kjb.obp.connection_timeout", defaultValue = "5")
|
||||
@Min(1) @Max(10)
|
||||
private int obpConnectionTimeout = 5;
|
||||
|
||||
@KjbPropertyValue(key = "kjb.obp.response_timeout", defaultValue = "5")
|
||||
@Min(1) @Max(30)
|
||||
private int obpResponseTimeout = 5;
|
||||
|
||||
@KjbPropertyValue(key = "kjb.obp.timeout", defaultValue = "10")
|
||||
@Min(1) @Max(30)
|
||||
private int obpTimeout = 10;
|
||||
|
||||
|
||||
@KjbPropertyValue(key = "kjb.obp.url.commission", defaultValue = "/api/billing/billing/findBillingForCondition")
|
||||
@NotEmpty
|
||||
|
||||
@@ -1,36 +1,84 @@
|
||||
package com.eactive.ext.kjb.obp;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.eactive.ext.kjb.common.KjbObpException;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class KjbObpModule {
|
||||
private static final String FAKE_PARTNER_CODE = "999999-99";
|
||||
|
||||
private static KjbObpModule _instance;
|
||||
|
||||
private final KjbProperty property;
|
||||
private final ObpClient client;
|
||||
|
||||
public static synchronized KjbObpModule getInstance(KjbProperty kjbProperty) {
|
||||
if (_instance == null) {
|
||||
_instance = new KjbObpModule(kjbProperty);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private KjbObpModule(KjbProperty kjbProperty) {
|
||||
if (kjbProperty == null) {
|
||||
throw new IllegalArgumentException("KjbProperty cannot be null");
|
||||
}
|
||||
this.property = kjbProperty;
|
||||
this.client = ObpClient.getInstance(kjbProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim, 숫자이외 자동 치환
|
||||
* @param bizNo
|
||||
* @return
|
||||
* 사업자등록번호로 partnerCode 조회
|
||||
* @param bizNo 사업자등록번호 (숫자 외 문자 자동 제거)
|
||||
* @return partnerCode
|
||||
* @throws KjbObpException 조회 실패 시
|
||||
*/
|
||||
public static JsonObject queryOrganization(String bizNo) {
|
||||
public String queryPartnerCode(String bizNo) throws KjbObpException {
|
||||
bizNo = ObpUtil.onlyDigit(bizNo);
|
||||
|
||||
if (StringUtils.isEmpty(bizNo)) {
|
||||
throw new IllegalArgumentException("BizNo is not empty.");
|
||||
throw new IllegalArgumentException("BizNo is empty.");
|
||||
}
|
||||
|
||||
if (bizNo.length() != 10) {
|
||||
throw new IllegalArgumentException("BizNo is not valid.");
|
||||
throw new IllegalArgumentException("BizNo must be 10 digits. (input: " + bizNo + ")");
|
||||
}
|
||||
|
||||
return null;
|
||||
// 가상모드: URL 미설정 시 가상 파트너코드 반환
|
||||
if (!client.isRealMode()) {
|
||||
log.info("[OBP] 가상모드 - 가상 partnerCode 반환: {}", FAKE_PARTNER_CODE);
|
||||
return FAKE_PARTNER_CODE;
|
||||
}
|
||||
|
||||
String path = String.format(property.getObpUrlOrganizationFmt(), bizNo);
|
||||
log.debug("[OBP] queryPartnerCode - bizNo: {}, path: {}", bizNo, path);
|
||||
|
||||
ObpResponse response = client.get(path);
|
||||
|
||||
if (response.getStatus() != 200) {
|
||||
log.warn("[OBP] queryPartnerCode failed - status: {}, body: {}", response.getStatus(), response.getBody());
|
||||
throw new KjbObpException(response.getStatus(), "OBP 조회 실패: " + response.getBody());
|
||||
}
|
||||
|
||||
ObpOrganization org = ObpOrganization.fromResponse(response);
|
||||
|
||||
if (org == null) {
|
||||
throw new KjbObpException("OBP 응답 파싱 실패");
|
||||
}
|
||||
|
||||
if (!org.hasPartnerCode()) {
|
||||
throw new KjbObpException("partnerCode가 없습니다. bizNo: " + bizNo);
|
||||
}
|
||||
|
||||
return org.getPartnerCode();
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
log.info("queryOrganization Test");
|
||||
queryOrganization("123asd123asd123");
|
||||
/**
|
||||
* ObpClient 반환 (직접 API 호출용)
|
||||
*/
|
||||
public ObpClient getClient() {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.eactive.ext.kjb.obp;
|
||||
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class ObpClient {
|
||||
private static ObpClient _instance;
|
||||
|
||||
private final KjbProperty property;
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final RequestConfig requestConfig;
|
||||
private final boolean isRealMode;
|
||||
|
||||
public synchronized static ObpClient getInstance(KjbProperty kjbProperty) {
|
||||
if (_instance == null) {
|
||||
_instance = new ObpClient(kjbProperty);
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private ObpClient(KjbProperty kjbProperty) {
|
||||
if (kjbProperty == null) {
|
||||
throw new IllegalArgumentException("KjbProperty cannot be null");
|
||||
}
|
||||
|
||||
this.property = kjbProperty;
|
||||
this.isRealMode = StringUtils.isNotEmpty(kjbProperty.getObpUrl());
|
||||
|
||||
this.requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(Timeout.ofSeconds(kjbProperty.getObpConnectionTimeout()))
|
||||
.setResponseTimeout(Timeout.ofSeconds(kjbProperty.getObpResponseTimeout()))
|
||||
.build();
|
||||
|
||||
if (isRealMode) {
|
||||
this.httpClient = HttpClients.createDefault();
|
||||
} else {
|
||||
this.httpClient = null;
|
||||
log.warn("[OBP] URL이 설정되지 않음. 실제 OBP 연동 없이 동작함");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 요청
|
||||
* @param path API 경로 (예: /api/customer/...)
|
||||
* @return ObpResponse
|
||||
*/
|
||||
public ObpResponse get(String path) {
|
||||
return get(path, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 요청 (추가 헤더 포함)
|
||||
* @param path API 경로
|
||||
* @param additionalHeaders 추가 헤더
|
||||
* @return ObpResponse
|
||||
*/
|
||||
public ObpResponse get(String path, Map<String, String> additionalHeaders) {
|
||||
String url = property.getObpUrl() + path;
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
applyDefaultHeaders(httpGet);
|
||||
applyAdditionalHeaders(httpGet, additionalHeaders);
|
||||
httpGet.setConfig(requestConfig);
|
||||
|
||||
return execute(httpGet);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 요청 (JSON body)
|
||||
* @param path API 경로
|
||||
* @param jsonBody JSON 문자열
|
||||
* @return ObpResponse
|
||||
*/
|
||||
public ObpResponse post(String path, String jsonBody) {
|
||||
return post(path, jsonBody, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 요청 (JSON body, 추가 헤더 포함)
|
||||
* @param path API 경로
|
||||
* @param jsonBody JSON 문자열
|
||||
* @param additionalHeaders 추가 헤더
|
||||
* @return ObpResponse
|
||||
*/
|
||||
public ObpResponse post(String path, String jsonBody, Map<String, String> additionalHeaders) {
|
||||
String url = property.getObpUrl() + path;
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
applyDefaultHeaders(httpPost);
|
||||
applyAdditionalHeaders(httpPost, additionalHeaders);
|
||||
httpPost.setConfig(requestConfig);
|
||||
|
||||
if (StringUtils.isNotEmpty(jsonBody)) {
|
||||
httpPost.setEntity(EntityBuilder.create()
|
||||
.setText(jsonBody)
|
||||
.setContentType(ContentType.APPLICATION_JSON)
|
||||
.build());
|
||||
}
|
||||
|
||||
return execute(httpPost);
|
||||
}
|
||||
|
||||
private void applyDefaultHeaders(HttpUriRequestBase request) {
|
||||
request.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||
request.setHeader(property.getObpTrustSystemKey(), property.getObpTrustSystemValue());
|
||||
request.setHeader(property.getObpPartnerCodeKey(), property.getObpPartnerCodeValue());
|
||||
}
|
||||
|
||||
private void applyAdditionalHeaders(HttpUriRequestBase request, Map<String, String> additionalHeaders) {
|
||||
if (additionalHeaders != null) {
|
||||
additionalHeaders.forEach(request::setHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private ObpResponse execute(HttpUriRequestBase request) {
|
||||
if (!isRealMode) {
|
||||
log.warn("[OBP] URL 미설정으로 실제 호출하지 않음. 요청: {} {}", request.getMethod(), request.getRequestUri());
|
||||
ObpResponse mockResponse = new ObpResponse();
|
||||
mockResponse.setStatus(200);
|
||||
mockResponse.setBody("{}");
|
||||
return mockResponse;
|
||||
}
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
try {
|
||||
log.debug("[OBP] 요청: {} {}", request.getMethod(), request.getRequestUri());
|
||||
|
||||
Future<ObpResponse> future = executor.submit(() ->
|
||||
httpClient.execute(request, response -> {
|
||||
ObpResponse obpResponse = new ObpResponse();
|
||||
obpResponse.setStatus(response.getCode());
|
||||
obpResponse.setBody(EntityUtils.toString(response.getEntity(), "UTF-8"));
|
||||
|
||||
Arrays.asList(response.getHeaders()).forEach(header ->
|
||||
obpResponse.getHeaders().put(header.getName(), header.getValue()));
|
||||
|
||||
return obpResponse;
|
||||
})
|
||||
);
|
||||
|
||||
ObpResponse response = future.get(property.getObpTimeout(), TimeUnit.SECONDS);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("[OBP] 응답: status={}, body={}", response.getStatus(), response.getBody());
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
log.error("[OBP] 호출 실패: {} {}", request.getMethod(), request.getRequestUri(), e);
|
||||
ObpResponse errorResponse = new ObpResponse();
|
||||
errorResponse.setStatus(-1);
|
||||
errorResponse.setBody(e.getMessage());
|
||||
return errorResponse;
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 실제 모드 여부
|
||||
*/
|
||||
public boolean isRealMode() {
|
||||
return isRealMode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.eactive.ext.kjb.obp;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* OBP Organization 조회 응답
|
||||
* - 필수 필드만 명시적으로 선언하고, 나머지는 rawJson으로 보관하여 유연성 확보
|
||||
*/
|
||||
@Data
|
||||
public class ObpOrganization {
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
// 핵심 필드
|
||||
@SerializedName("partnerCode")
|
||||
private String partnerCode;
|
||||
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("state")
|
||||
private String state;
|
||||
|
||||
@SerializedName("status")
|
||||
private String status;
|
||||
|
||||
@SerializedName("businessManRegistrationNo")
|
||||
private String businessManRegistrationNo;
|
||||
|
||||
@SerializedName("corporateRegistrationNo")
|
||||
private String corporateRegistrationNo;
|
||||
|
||||
@SerializedName("representativeName")
|
||||
private String representativeName;
|
||||
|
||||
// 원본 JSON (추가 필드 접근용
|
||||
private transient JsonObject rawJson;
|
||||
|
||||
/**
|
||||
* JSON 문자열에서 파싱
|
||||
*/
|
||||
public static ObpOrganization fromJson(String json) {
|
||||
if (json == null || json.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ObpOrganization org = gson.fromJson(json, ObpOrganization.class);
|
||||
org.rawJson = new JsonParser().parse(json).getAsJsonObject();
|
||||
return org;
|
||||
}
|
||||
|
||||
/**
|
||||
* ObpResponse에서 파싱
|
||||
*/
|
||||
public static ObpOrganization fromResponse(ObpResponse response) {
|
||||
if (response == null || response.getStatus() != 200) {
|
||||
return null;
|
||||
}
|
||||
return fromJson(response.getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 JSON에서 추가 필드 조회
|
||||
* @param fieldName 필드명 (예: "englishName", "description")
|
||||
* @return 필드 값 (없으면 null)
|
||||
*/
|
||||
public String getField(String fieldName) {
|
||||
if (rawJson == null || !rawJson.has(fieldName) || rawJson.get(fieldName).isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return rawJson.get(fieldName).getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 JSON에서 중첩 필드 조회
|
||||
* @param path 경로 (예: "type.name", "type.parent.name")
|
||||
* @return 필드 값 (없으면 null)
|
||||
*/
|
||||
public String getNestedField(String path) {
|
||||
if (rawJson == null || path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] parts = path.split("\\.");
|
||||
JsonObject current = rawJson;
|
||||
|
||||
for (int i = 0; i < parts.length - 1; i++) {
|
||||
if (!current.has(parts[i]) || current.get(parts[i]).isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
current = current.getAsJsonObject(parts[i]);
|
||||
}
|
||||
|
||||
String lastField = parts[parts.length - 1];
|
||||
if (!current.has(lastField) || current.get(lastField).isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return current.get(lastField).getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 JSON 객체 반환
|
||||
*/
|
||||
public JsonObject getRawJson() {
|
||||
return rawJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* partnerCode 유효성 확인
|
||||
*/
|
||||
public boolean hasPartnerCode() {
|
||||
return partnerCode != null && !partnerCode.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.eactive.ext.kjb.obp;
|
||||
|
||||
public class ObpRequest {
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.ext.kjb.obp.common;
|
||||
package com.eactive.ext.kjb.obp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.eactive.ext.kjb.obp.common;
|
||||
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class ObpClient {
|
||||
private static ObpClient _instance;
|
||||
|
||||
public synchronized static ObpClient getInstance(KjbProperty kjbProperty) {
|
||||
if (_instance == null) {
|
||||
_instance = new ObpClient(kjbProperty);
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private ObpClient(KjbProperty kjbProperty) {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user