로컬 테스트 완료
This commit is contained in:
@@ -3,13 +3,21 @@ package com.eactive.ext.kjb.common;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@Data
|
||||
public class KjbProperty {
|
||||
@Pattern(regexp = "^(https?://[^\\s/$.?#][^\\s]*)|\\s*$", message = "kjb.ums.eai_batch.url 는 유효한 URL 형식이거나 공백이어야 합니다. 예: http://example.com/api")
|
||||
@Pattern(regexp = "^(https?://[^\\s/$.?#][^\\s]*)|\\s*$", message = "kjb.eai_batch.url 는 유효한 URL 형식이거나 공백이어야 합니다. 예: http://example.com/api")
|
||||
private String eaiBatchUrl;
|
||||
|
||||
@Min(1) @Max(10)
|
||||
private int eaiBatchConnectionTimeout = 5;
|
||||
|
||||
@Min(1) @Max(30)
|
||||
private int eaiBatchResponseTimeout = 10;
|
||||
|
||||
@NotEmpty(message = "kjb.ums.eai_batch.send_dir 는 필수값입니다.")
|
||||
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$",
|
||||
message = "kjb.ums.eai_batch.send_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/snd 또는 C:\\Data\\eapim\\portal\\sendmail\\snd")
|
||||
@@ -20,7 +28,19 @@ public class KjbProperty {
|
||||
message = "kjb.ums.eai_batch.backup_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/bak 또는 C:\\Data\\eapim\\portal\\sendmail\\bak")
|
||||
private String eaiBatchBackupDir;
|
||||
|
||||
|
||||
@Pattern(regexp = "^[a-zA-Z0-9]{13}$", message = "kjb.ums.eai_batch.interface_id 는 12자리 영문대소문자 및 숫자 조합이어야 합니다.")
|
||||
private String eaiBatchInterfaceId;
|
||||
|
||||
|
||||
@Pattern(regexp = "^(https?://[^\\s/$.?#][^\\s]*)|\\s*$", message = "kjb.ums.url 는 유효한 URL 형식이거나 공백이어야 합니다. 예: http://example.com/api")
|
||||
private String umsUrl;
|
||||
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_-]{36}$", message = "kjb.ums.api_key 입력 형식이 맞지 않습니다.")
|
||||
private String umsApiKey;
|
||||
|
||||
@Min(1) @Max(10)
|
||||
private int umsConnectionTimeout = 5;
|
||||
|
||||
@Min(1) @Max(30)
|
||||
private int umsResponseTimeout = 10;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,23 @@ 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.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.net.URIBuilder;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@Slf4j
|
||||
public class KjbEaiBatchModule {
|
||||
private final KjbProperty property;
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final RequestConfig requestConfig;
|
||||
|
||||
|
||||
public KjbEaiBatchModule(@NotNull KjbProperty property) {
|
||||
@@ -23,6 +29,10 @@ public class KjbEaiBatchModule {
|
||||
}
|
||||
|
||||
this.property = property;
|
||||
requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(Timeout.ofSeconds(property.getEaiBatchConnectionTimeout()))
|
||||
.setResponseTimeout(Timeout.ofSeconds(property.getEaiBatchResponseTimeout()))
|
||||
.build();
|
||||
|
||||
if (StringUtils.isNotEmpty(property.getEaiBatchUrl())) {
|
||||
this.httpClient = HttpClients.createDefault();
|
||||
@@ -37,8 +47,18 @@ public class KjbEaiBatchModule {
|
||||
log.debug("EAI 배치 호출: {}", reqMessage);
|
||||
|
||||
if (this.httpClient != null) {
|
||||
String url = property.getEaiBatchUrl() + "?eaibatMsg=" + reqMessage.toString();
|
||||
final HttpGet httpGet = new HttpGet(url);
|
||||
URI uri = null;
|
||||
try {
|
||||
uri = new URIBuilder(property.getEaiBatchUrl())
|
||||
.addParameter("eaibatMsg", reqMessage.toString())
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
log.debug("EAI Batch call - {}", uri.toASCIIString());
|
||||
|
||||
final HttpGet httpGet = new HttpGet(uri);
|
||||
httpGet.setConfig(requestConfig);
|
||||
|
||||
String message = httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity(), "EUC-KR"));
|
||||
|
||||
|
||||
@@ -83,17 +83,15 @@ public class EmailJob {
|
||||
errors.put("id", "ID is required");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(messageRequest.getEmail())) {
|
||||
errors.put("email", "Email is required");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(messageRequest.getUsername())) {
|
||||
errors.put("username", "Username is required");
|
||||
}
|
||||
|
||||
|
||||
if (forSend) {
|
||||
// TODO: 발송용 체크
|
||||
if (StringUtils.isEmpty(messageRequest.getEmail())) {
|
||||
errors.put("email", "Email is required");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(messageRequest.getUsername())) {
|
||||
errors.put("username", "Username is required");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(messageRequest.getServiceId())) {
|
||||
errors.put("serviceId", "Service ID is required");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.eactive.ext.kjb.ums;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
@@ -113,6 +114,11 @@ public class EmailSendModule {
|
||||
throw new IllegalArgumentException("MessageRequest MessageCode serviceId is required");
|
||||
}
|
||||
|
||||
if (MessageCode.Channels.EMAIL.getValue() != (messageRequest.getMessageCode().getChannels() & MessageCode.Channels.EMAIL.getValue())) {
|
||||
log.error("지원하지 않는 발송 채널 - {}", messageRequest.getMessageCode());
|
||||
throw new IllegalArgumentException("지원하지 않는 발송 채널 - " + messageRequest.getMessageCode());
|
||||
}
|
||||
|
||||
if (repo != null) {
|
||||
repo.save(messageRequest);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.eactive.ext.kjb.ums;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import com.eactive.ext.kjb.ums.gson.IUmsGsonObject;
|
||||
import com.eactive.ext.kjb.ums.gson.UmsRequestPayload;
|
||||
import com.eactive.ext.kjb.ums.gson.VerifyPhoneUmsTemplate;
|
||||
import com.eactive.ext.kjb.utils.ValidationUtil;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
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.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@Slf4j
|
||||
public class KjbUmsService {
|
||||
private final static String SEND_URL = "/ums/openapi/send";
|
||||
private final static String CONTENT_TYPE = "application/json; charset=utf-8";
|
||||
private final static String AUTHORIZATION_FMT = "Bearer %s";
|
||||
|
||||
private final KjbProperty property;
|
||||
private final boolean isRealMode;
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final RequestConfig requestConfig;
|
||||
|
||||
|
||||
public KjbUmsService(KjbProperty property) {
|
||||
if (property == null) {
|
||||
log.error("[KJB-UMS] 파라미터 설정 되지 않음");
|
||||
throw new IllegalArgumentException("property is null");
|
||||
}
|
||||
|
||||
isRealMode = property.getUmsUrl() != null && StringUtils.isNotEmpty(property.getUmsUrl().trim());
|
||||
|
||||
if (isRealMode) {
|
||||
ValidationUtil.validateOrThrow(property);
|
||||
|
||||
httpClient = HttpClients.createDefault();
|
||||
requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(Timeout.ofSeconds(property.getEaiBatchConnectionTimeout()))
|
||||
.setResponseTimeout(Timeout.ofSeconds(property.getEaiBatchResponseTimeout()))
|
||||
.build();
|
||||
} else {
|
||||
httpClient = HttpClients.createDefault();
|
||||
requestConfig = null;
|
||||
}
|
||||
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public boolean send(MessageRequest messageRequest) {
|
||||
if (messageRequest == null) {
|
||||
throw new IllegalArgumentException("messageRequest is null");
|
||||
}
|
||||
|
||||
if (MessageCode.Channels.KAKAO_ALIMTALK.getValue() != (messageRequest.getMessageCode().getChannels() & MessageCode.Channels.KAKAO_ALIMTALK.getValue())) {
|
||||
log.error("지원하지 않는 발송 채널 - {}", messageRequest.getMessageCode().toString());
|
||||
throw new IllegalArgumentException("지원하지 않는 발송 채널 - " + messageRequest.getMessageCode().toString());
|
||||
}
|
||||
|
||||
IUmsGsonObject content = null;
|
||||
content = VerifyPhoneUmsTemplate.builder().authNumber(messageRequest.getMessage()).build();
|
||||
|
||||
String umsMessageId = this.sendKakaoAlimTalk(messageRequest.getId(),
|
||||
UmzBizWorkCode.VERIFY_PHONE,
|
||||
messageRequest.getPhone(),
|
||||
content
|
||||
);
|
||||
|
||||
log.info("MessageRequest sent - {}", umsMessageId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String sendKakaoAlimTalk(String guid, UmzBizWorkCode bizWorkCode, String cpno, IUmsGsonObject content) {
|
||||
if (content == null) {
|
||||
throw new IllegalArgumentException("content is null");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(guid)) {
|
||||
guid = String.format("OBP-%s", DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()));
|
||||
}
|
||||
|
||||
UmsRequestPayload payload = UmsRequestPayload.builder()
|
||||
.messageIdentityNo(guid)
|
||||
.msgBizWorkCode(bizWorkCode.getCode())
|
||||
.content(content)
|
||||
.cellphone(cpno)
|
||||
.msgSndChnlCd(UmsRequestPayload.ChannelCode.KM)
|
||||
.build();
|
||||
|
||||
return callUms(SEND_URL, payload, (messageId, ex) -> {
|
||||
if (ex != null) {
|
||||
log.error("UMS Call error", ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
log.info("UMS Call success. ({})", messageId);
|
||||
}).join().getUmsMessageId();
|
||||
}
|
||||
|
||||
private CompletableFuture<UmsCallResult> callUms(@SuppressWarnings("SameParameterValue") String url, UmsRequestPayload requestPayload,
|
||||
BiConsumer<UmsCallResult, Throwable> callback) {
|
||||
return CompletableFuture
|
||||
.supplyAsync(() -> {
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(requestPayload);
|
||||
|
||||
HttpPost httpPost = new HttpPost(property.getUmsUrl() + url);
|
||||
httpPost.setHeader("Content-Type", CONTENT_TYPE);
|
||||
httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, property.getUmsApiKey()));
|
||||
httpPost.setEntity(EntityBuilder.create().setText(json).setContentType(ContentType.APPLICATION_JSON).build());
|
||||
|
||||
httpPost.setConfig(requestConfig);
|
||||
|
||||
AtomicReference<UmsCallResult> result = new AtomicReference<>();
|
||||
if (isRealMode) {
|
||||
try {
|
||||
httpClient.execute(httpPost, res -> {
|
||||
String body = EntityUtils.toString(res.getEntity());
|
||||
result.set(gson.fromJson(body, UmsCallResult.class));
|
||||
result.get().setUmsMessageId(requestPayload.getMessageIdentityNo());
|
||||
result.get().setSuccess(true);
|
||||
return result;
|
||||
});
|
||||
} catch (IOException e) {
|
||||
log.error("UMS Call error", e);
|
||||
result.set(
|
||||
UmsCallResult.builder()
|
||||
.umsMessageId(requestPayload.getMessageIdentityNo())
|
||||
.isSuccess(false)
|
||||
.throwable(e)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log.warn("UMS URL 미지정으로 실제 호출을 진행하지 않음.");
|
||||
result.set(UmsCallResult.builder().isSuccess(true).build());
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("UMS Call URI : {}", httpPost.getUri().toASCIIString());
|
||||
log.debug("UMS Call Request payload : {}", json);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return result.get();
|
||||
})
|
||||
.whenComplete(callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.eactive.ext.kjb.ums;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class UmsCallResult {
|
||||
private String umsMessageId;
|
||||
private boolean isSuccess;
|
||||
|
||||
private String returnCode;
|
||||
private String returnMessage;
|
||||
private String returnPayload;
|
||||
|
||||
private Throwable throwable;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.eactive.ext.kjb.ums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public enum UmzBizWorkCode {
|
||||
MONITORING("B_ELFN_09510", "OBP 모니터링"),
|
||||
VERIFY_PHONE("S55_ICT_0006", "API Portal 인증번호"),
|
||||
;
|
||||
|
||||
@Getter
|
||||
private String code;
|
||||
@Getter
|
||||
private String displayName;
|
||||
|
||||
UmzBizWorkCode(String code, String displayName) {
|
||||
this.code = code;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.eactive.ext.kjb.ums.gson;
|
||||
|
||||
/**
|
||||
* GSON Serialize 용 Object
|
||||
*/
|
||||
public interface IUmsGsonObject {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.eactive.ext.kjb.ums.gson;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class ObpMonitoringUmsTemplate implements IUmsGsonObject {
|
||||
@SerializedName("AUTH_NO")
|
||||
private String authNumber;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.eactive.ext.kjb.ums.gson;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@Getter
|
||||
public class UmsRequestPayload {
|
||||
// MSG_IDNT_NO string 메시지식별번호 50 O "발송 구분을 위한 거래 번호 (GUID 권고)
|
||||
//GUID로 입력이 어려울시
|
||||
//어플리케이션코드(3자리)+난수 로 유니크한 ID로 채번 권고"
|
||||
@Length(min = 1, max = 50)
|
||||
@NotEmpty
|
||||
@SerializedName("MSG_IDNT_NO")
|
||||
private String messageIdentityNo;
|
||||
|
||||
// MSG_BZWK_CD string 메시지업무코드 30 O UMS에 등록된 메시지업무코드(AS-IS 템플릿ID)
|
||||
@NotEmpty
|
||||
@Length(min = 1, max = 30)
|
||||
@SerializedName("MSG_BZWK_CD")
|
||||
private String msgBizWorkCode;
|
||||
|
||||
// 메시지업무파라미터내용 / 4000 / JSONObject
|
||||
// MSG_BZWK_PARAM_CTNT object 메시지업무파라미터내용 4000 메시지업무코드의 템플릿에서 사용하는 변수와 변수값
|
||||
@NotNull
|
||||
@SerializedName("MSG_BZWK_PARAM_CTNT")
|
||||
private IUmsGsonObject content;
|
||||
|
||||
// 발송예약일시 / 14 / 실 발송 일자(yyyyMMddHHmmss)
|
||||
// SND_RESR_DTTM string 발송예약일시 14 20240418111500 O 실 발송 일자(현재시간)
|
||||
@Pattern(regexp = "^[0-9]{14}$")
|
||||
@NotEmpty
|
||||
@SerializedName("SND_RESR_DTTM")
|
||||
private String sendReservationDatetime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
|
||||
|
||||
// 휴대전화번호 / 44 / 휴대폰번호(평문, 암호화 둘다가능)
|
||||
// CPNO string 휴대전화번호 44 "암호화 또는 평문 (safedb not rrno)
|
||||
//문자일 시 암호문
|
||||
//숫자일 시 전화번호
|
||||
//고객번호 또는 휴대전화번호 필수"
|
||||
@NotEmpty
|
||||
@Pattern(regexp = "^[0-9]{10,11}$")
|
||||
@SerializedName("CPNO")
|
||||
private String cellphone;
|
||||
|
||||
// 발송부점코드 / 4 /
|
||||
// SND_BRCD string 발송부점코드 4 O 0333
|
||||
@NotEmpty
|
||||
@SerializedName("SND_BRCD")
|
||||
private String sendBranchCode = "0990";
|
||||
|
||||
// 발송직원번호 / 7 / ECEB057(텔러번호?)
|
||||
// SND_EMPNO string 발송직원번호 7 O ? 넣긴해야함
|
||||
@NotEmpty
|
||||
@SerializedName("SND_EMPNO")
|
||||
private String sendEmployeeNo = "ECEB057";
|
||||
|
||||
// SRVC_ID string 서비스ID 11 요청단 측 서비스ID
|
||||
@NotEmpty
|
||||
@SerializedName("SRVC_ID")
|
||||
private String serviceId = "eAPIM";
|
||||
|
||||
// MSG_SND_CHNL_CD string 메시지발송채널코드 2
|
||||
@SerializedName("MSG_SND_CHNL_CD")
|
||||
@NotEmpty
|
||||
private ChannelCode msgSndChnlCd = ChannelCode.KM;
|
||||
|
||||
// VALDTN_RSLT_CD string 검증결과코드 2 00으로 고정
|
||||
@SerializedName("VALDTN_RSLT_CD")
|
||||
@NotEmpty
|
||||
private String validationResultCode = "00";
|
||||
|
||||
public enum ChannelCode {
|
||||
SM, // SMS
|
||||
LM, // LMS
|
||||
MM, // MMS
|
||||
KM, // 카카오-알림톡
|
||||
FM, // 카카오-친구톡
|
||||
SR, // RCS-SMS
|
||||
LR, // RCS-LMS
|
||||
MR, // RCS-MMS
|
||||
TR, // RCS-TEMPLATE
|
||||
IR, // RCS-IMAGE Template
|
||||
PM // Push
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.eactive.ext.kjb.ums.gson;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class VerifyPhoneUmsTemplate implements IUmsGsonObject {
|
||||
@SerializedName("ATHN_NO")
|
||||
private String authNumber;
|
||||
}
|
||||
Reference in New Issue
Block a user