이메일 발송 테스트 코드

This commit is contained in:
Rinjae
2025-11-10 11:00:37 +09:00
parent 4283c8b3fc
commit 5b354cffb1
9 changed files with 284 additions and 95 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ jar {
test { test {
useJUnitPlatform() useJUnitPlatform()
systemProperty "kjb_safedb.mode", project.findProperty("kjb_safedb.mode") ?: "" systemProperty "kjb_safedb.mode", System.getProperty("kjb_safedb.mode")
if (project.hasProperty("safedb")) { if (project.hasProperty("safedb")) {
systemProperty "kjb_safedb.mode", "real" systemProperty "kjb_safedb.mode", "real"
@@ -0,0 +1,11 @@
package com.eactive.ext.kjb.common;
public class KjbEaiBatchException extends Exception {
public KjbEaiBatchException(String message) {
super(message);
}
public KjbEaiBatchException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -16,21 +16,35 @@ public class KjbProperty {
private int eaiBatchConnectionTimeout = 5; private int eaiBatchConnectionTimeout = 5;
@Min(1) @Max(30) @Min(1) @Max(30)
private int eaiBatchResponseTimeout = 10; private int eaiBatchResponseTimeout = 5;
@Min(1) @Max(30)
private int eaiBatchTimeout = 10;
@NotEmpty
private String eaiBatchCharset = "euc-kr";
@NotEmpty(message = "kjb.ums.eai_batch.send_dir 는 필수값입니다.") @NotEmpty(message = "kjb.ums.eai_batch.send_dir 는 필수값입니다.")
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$", @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") message = "kjb.ums.eai_batch.send_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/snd 또는 c:\\kjb-logs\\sendmail\\snd")
private String umsEaiBatchSendDir; private String umsEaiBatchSendDir;
@NotEmpty(message = "kjb.ums.eai_batch.backup_dir 는 필수값입니다.") @NotEmpty(message = "kjb.ums.eai_batch.backup_dir 는 필수값입니다.")
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$", @Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$",
message = "kjb.ums.eai_batch.backup_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/bak 또는 C:\\Data\\eapim\\portal\\sendmail\\bak") message = "kjb.ums.eai_batch.backup_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/bak 또는 c:\\kjb-logs\\sendmail\\bak")
private String umsEaiBatchBackupDir; private String umsEaiBatchBackupDir;
@NotEmpty(message = "kjb.ums.eai_batch.error_dir 는 필수값입니다.")
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$",
message = "kjb.ums.eai_batch.error_dir 은 절대 경로여야 합니다. 예: /Data/eapim/portal/sendmail/errpr 또는 c:\\kjb-logs\\sendmail\\error")
private String umsEaiBatchErrorDir;
@Pattern(regexp = "^[a-zA-Z0-9]{13}$", message = "kjb.ums.eai_batch.interface_id 는 12자리 영문대소문자 및 숫자 조합이어야 합니다.") @Pattern(regexp = "^[a-zA-Z0-9]{13}$", message = "kjb.ums.eai_batch.interface_id 는 12자리 영문대소문자 및 숫자 조합이어야 합니다.")
private String umsEaiBatchInterfaceId; private String umsEaiBatchInterfaceId;
@Min(1) @Max(365)
private int umsEaiBatchRetentionDate = 60;
@Pattern(regexp = "^(https?://[^\\s/$.?#][^\\s]*)|\\s*$", message = "kjb.ums.host_url 는 유효한 URL 형식이거나 공백이어야 합니다. 예: http://example.com/api") @Pattern(regexp = "^(https?://[^\\s/$.?#][^\\s]*)|\\s*$", message = "kjb.ums.host_url 는 유효한 URL 형식이거나 공백이어야 합니다. 예: http://example.com/api")
private String umsHostUrl; private String umsHostUrl;
@@ -42,5 +56,8 @@ public class KjbProperty {
private int umsConnectionTimeout = 5; private int umsConnectionTimeout = 5;
@Min(1) @Max(30) @Min(1) @Max(30)
private int umsResponseTimeout = 10; private int umsResponseTimeout = 5;
@Min(1) @Max(30)
private int umsTimeout = 10;
} }
@@ -0,0 +1,64 @@
package com.eactive.ext.kjb.eai;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.io.File;
import java.nio.file.Paths;
@Data
@Builder
@Slf4j
public class EaiBatchInterface {
@Pattern(regexp = "^[a-zA-Z0-9]{13}$", message = "id는 12자리 영문대소문자 및 숫자 조합이어야 합니다.")
private String id;
@NotEmpty
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$", message = "sendDir은 절대경로로 지정되어야 합니다.")
private String sendDir;
@NotEmpty
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$", message = "backupDir은 절대경로로 지정되어야 합니다.")
private String backupDir;
@NotEmpty
@Pattern(regexp = "^(?:[a-zA-Z]:\\\\|\\\\|\\/)(?:[\\w\\-\\.]+[\\\\\\/])*[\\w\\-\\.]+$", message = "errorDir은 절대경로로 지정되어야 합니다.")
private String errorDir;
public void moveError(String filename) {
move(filename, errorDir);
}
public void moveBackup(String filename) {
move(filename, backupDir);
}
private void move(String filename, String targetDir) {
File file = Paths.get(sendDir, filename).toFile();
File targetDirFile = new File(targetDir);
File targetFile = new File(targetDir, file.getName());
log.debug("송신파일 이동 시작 - {} -> {}", filename, targetDir);
if (!file.exists()) {
log.warn("송신 파일이 존재 하지 않습니다. ({})", file.getAbsolutePath());
return;
}
if (!targetDirFile.exists()) {
if (!targetDirFile.mkdirs()) {
log.warn("대상 디렉토리 생성 실패 ({})", file.getAbsolutePath());
return;
}
}
if (!file.renameTo(targetFile)) {
log.warn("송신 파일 이동 실패 - {}", targetFile.getAbsolutePath());
return;
}
}
}
@@ -4,6 +4,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@Slf4j @Slf4j
@@ -17,6 +18,9 @@ public class EaiBatchMessage {
@Getter @Getter
private String count = ""; private String count = "";
/**
* 요청시 사용 안함, 응답시 1: 성공, 2: 실패
*/
@Getter @Getter
private String resultCode = ""; private String resultCode = "";
@@ -28,14 +32,17 @@ public class EaiBatchMessage {
private boolean isReadOnly = false; private boolean isReadOnly = false;
private String charset;
private EaiBatchMessage() {} private EaiBatchMessage() {}
public static EaiBatchMessage createRequest(String interfaceId, String filename) { public static EaiBatchMessage createRequest(String interfaceId, String filename, String charset) {
EaiBatchMessage message = new EaiBatchMessage(); EaiBatchMessage message = new EaiBatchMessage();
message.interfaceId = interfaceId; message.interfaceId = interfaceId;
message.filename = filename; message.filename = filename;
message.charset = charset;
return message; return message;
} }
@@ -46,16 +53,16 @@ public class EaiBatchMessage {
message.isReadOnly = true; message.isReadOnly = true;
if (rawMessage.length() >= 40) { if (rawMessage.length() >= 40) {
message.interfaceId = rawMessage.substring(0, 20).trim(); message.interfaceId = rawMessage.substring(0, 19).trim();
message.baseDate = rawMessage.substring(20, 28).trim(); message.baseDate = rawMessage.substring(19, 27).trim();
message.count = rawMessage.substring(28, 38).trim(); message.count = rawMessage.substring(27, 37).trim();
message.resultCode = rawMessage.substring(38, 39).trim(); message.resultCode = rawMessage.substring(37, 38).trim();
// filename 은 @@가 발견되면 이전 까지 trim / 발견되지 않으면 나머지 전체 그리고 trim // filename 은 @@가 발견되면 이전 까지 trim / 발견되지 않으면 나머지 전체 그리고 trim
int endIdx = rawMessage.indexOf("@@", 39); int endIdx = rawMessage.indexOf("@@", 38);
if (endIdx == -1) { if (endIdx == -1) {
message.filename = rawMessage.substring(39).trim(); message.filename = rawMessage.substring(38).trim();
} else { } else {
message.filename = rawMessage.substring(39, endIdx).trim(); message.filename = rawMessage.substring(38, endIdx).trim();
} }
} }
@@ -74,16 +81,20 @@ public class EaiBatchMessage {
return rawMessage; return rawMessage;
} else { } else {
ByteBuffer buffer = ByteBuffer.allocate(1024); ByteBuffer buffer = ByteBuffer.allocate(1024);
// 0~19 : 인터페이스ID (20) try {
buffer.put(fixedString(interfaceId, 20)); // 인터페이스ID (19)
// 19-8: 기준일자 (8) buffer.put(fixedString(interfaceId, 19));
buffer.put(fixedString(baseDate, 8)); // 기준일자 (8)
// 27-10 : 건수 (10) buffer.put(fixedString(baseDate, 8));
buffer.put(fixedString(count, 10)); // 건수 (10)
// 37-1 : 결과코드 (1) buffer.put(fixedString(count, 10));
buffer.put(fixedString(resultCode, 1)); // 결과코드 (1)
// 38-100 : 파일명 (100) buffer.put(fixedString(resultCode, 1));
buffer.put(fixedString(filename, 100)); // 파일명 (100)
buffer.put(fixedString(filename, 100));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
// 종료 구분자 (2) // 종료 구분자 (2)
buffer.put("@@".getBytes()); buffer.put("@@".getBytes());
@@ -93,11 +104,11 @@ public class EaiBatchMessage {
} }
} }
private byte[] fixedString(String str, int length) { private byte[] fixedString(String str, int length) throws UnsupportedEncodingException {
if (str == null) { if (str == null) {
str = ""; str = "";
} }
byte[] strBytes = str.getBytes(); byte[] strBytes = str.getBytes(this.charset);
byte[] result = new byte[length]; byte[] result = new byte[length];
int copyLength = Math.min(strBytes.length, length); int copyLength = Math.min(strBytes.length, length);
@@ -1,5 +1,6 @@
package com.eactive.ext.kjb.eai; package com.eactive.ext.kjb.eai;
import com.eactive.ext.kjb.common.KjbEaiBatchException;
import com.eactive.ext.kjb.common.KjbProperty; import com.eactive.ext.kjb.common.KjbProperty;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -11,10 +12,13 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.net.URIBuilder;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException; import java.io.File;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.concurrent.*;
@Slf4j @Slf4j
public class KjbEaiBatchModule { public class KjbEaiBatchModule {
@@ -42,10 +46,16 @@ public class KjbEaiBatchModule {
} }
} }
public EaiBatchMessage call(String interfaceId, String filename) throws IOException { public EaiBatchMessage call(@Valid EaiBatchInterface intf, String filename) throws KjbEaiBatchException {
EaiBatchMessage reqMessage = EaiBatchMessage.createRequest(interfaceId, filename); EaiBatchMessage reqMessage = EaiBatchMessage.createRequest(intf.getId(), filename, property.getEaiBatchCharset());
log.debug("EAI 배치 호출: {}", reqMessage); log.debug("EAI 배치 호출: {}", reqMessage);
// 송신 파일 체크
File sendFile = Paths.get(intf.getSendDir(), filename).toFile();
if (!sendFile.exists() || !sendFile.isFile()) {
throw new KjbEaiBatchException("Not found send file - " + sendFile.toPath());
}
if (this.httpClient != null) { if (this.httpClient != null) {
URI uri = null; URI uri = null;
try { try {
@@ -60,17 +70,37 @@ public class KjbEaiBatchModule {
final HttpGet httpGet = new HttpGet(uri); final HttpGet httpGet = new HttpGet(uri);
httpGet.setConfig(requestConfig); httpGet.setConfig(requestConfig);
String message = httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity(), "EUC-KR")); ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() ->
httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity(), "EUC-KR")));
EaiBatchMessage resMessage = EaiBatchMessage.fromResponse(message); EaiBatchMessage resMessage = null;
log.debug("EAI 배치 응답: {}", resMessage); try {
return resMessage; String message = future.get(property.getEaiBatchTimeout(), TimeUnit.SECONDS);
resMessage = EaiBatchMessage.fromResponse(message);
log.debug("EAI 배치 응답: {}", resMessage);
return resMessage;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("EAI Batch call exception", e);
throw new KjbEaiBatchException("EAI Batch call failed", e);
} finally {
executor.shutdown();
// EAI 송신 실패일 경우 에러 경로로 이동
if (resMessage != null && "1".equals(resMessage.getResultCode())) {
intf.moveBackup(filename);
} else {
intf.moveError(filename);
}
}
} else { } else {
log.info("EAI_BATCH_URL 이 설정되지 않아 실제 호출하지 않음. 요청 메시지: {}", reqMessage); log.info("EAI_BATCH_URL 이 설정되지 않아 실제 호출하지 않음. 요청 메시지: {}", reqMessage);
// 정상응답 리턴 // 정상응답 리턴
EaiBatchMessage resMessage = EaiBatchMessage.fromResponse(String.format("%-20s%-8s%-10s%-1s%s@@", interfaceId, "", "0000000000", "1", "S:" + filename)); EaiBatchMessage resMessage = EaiBatchMessage.fromResponse(String.format("%-19s%-8s%-10s%-1s%s@@", intf.getId(), "", "0000000000", "1", "S:" + filename));
log.debug("EAI 배치 응답(모의): {}", resMessage); log.debug("EAI 배치 응답(모의): {}", resMessage);
intf.moveBackup(filename);
return resMessage; return resMessage;
} }
} }
@@ -3,9 +3,13 @@ package com.eactive.ext.kjb.ums;
import com.eactive.apim.portal.portaluser.entity.PortalUser; import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.template.entity.MessageRequest; import com.eactive.apim.portal.template.entity.MessageRequest;
import com.eactive.apim.portal.template.repository.MessageRequestRepository; import com.eactive.apim.portal.template.repository.MessageRequestRepository;
import com.eactive.ext.kjb.common.KjbEaiBatchException;
import com.eactive.ext.kjb.common.KjbProperty; import com.eactive.ext.kjb.common.KjbProperty;
import com.eactive.ext.kjb.eai.EaiBatchMessage; import com.eactive.ext.kjb.eai.EaiBatchMessage;
import com.eactive.ext.kjb.eai.EaiBatchInterface;
import com.eactive.ext.kjb.eai.KjbEaiBatchModule; import com.eactive.ext.kjb.eai.KjbEaiBatchModule;
import com.eactive.ext.kjb.safedb.KjbSafedbWrapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -28,6 +32,10 @@ public class EmailJob {
private final KjbProperty prop; private final KjbProperty prop;
private final MessageRequest messageRequest; private final MessageRequest messageRequest;
private static final int READY = 1; // Temp 파일 생성 단계
private static final int BEFORE_SEND = 2;
private static final int SEND = 3;
private final Path tempFilePath; private final Path tempFilePath;
private final Path eaiFilePath; private final Path eaiFilePath;
private final Path backupFilePath; private final Path backupFilePath;
@@ -35,13 +43,15 @@ public class EmailJob {
private final MessageRequestRepository messageRequestRepository; private final MessageRequestRepository messageRequestRepository;
private final LocalDateTime now = LocalDateTime.now(); private final LocalDateTime now = LocalDateTime.now();
private int eaiPhase = 0;
private EmailJob(KjbProperty prop, MessageRequest messageRequest, MessageRequestRepository messageRequestRepository) { private EmailJob(KjbProperty prop, MessageRequest messageRequest, MessageRequestRepository messageRequestRepository) {
this.messageRequest = messageRequest; this.messageRequest = messageRequest;
this.prop = prop; this.prop = prop;
String filename = messageRequest.getServiceId() + "_" + DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(now); String filename = messageRequest.getServiceId() + "_" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(now);
this.tempFilePath = Paths.get(prop.getUmsEaiBatchSendDir(), filename + ".tmp"); this.tempFilePath = Paths.get(prop.getUmsEaiBatchSendDir(), filename + ".tmp");
this.eaiFilePath = Paths.get(prop.getUmsEaiBatchSendDir(), filename); this.eaiFilePath = Paths.get(prop.getUmsEaiBatchSendDir(), filename);
this.backupFilePath = Paths.get(prop.getUmsEaiBatchBackupDir(), filename); this.backupFilePath = Paths.get(prop.getUmsEaiBatchBackupDir(), filename);
@@ -112,7 +122,7 @@ public class EmailJob {
@Transactional @Transactional
public void sendEmail() { public void sendEmail() throws KjbEaiBatchException {
if (messageRequestRepository != null) { if (messageRequestRepository != null) {
PortalUser user = messageRequest.getUser(); PortalUser user = messageRequest.getUser();
if (user != null) { if (user != null) {
@@ -130,9 +140,11 @@ public class EmailJob {
log.debug("발송 성공 처리"); log.debug("발송 성공 처리");
doSuccess(); doSuccess();
} catch (KjbEaiBatchException e) {
doFail(e);
} catch (Exception e) { } catch (Exception e) {
log.error("이메일 발송 실패", e); log.error(e.getMessage(), e);
doFail(); doFail(e);
} finally { } finally {
doDeleteEaiFile(); doDeleteEaiFile();
} }
@@ -142,13 +154,24 @@ public class EmailJob {
// TODO: EAI 발송용 파일 삭제 // TODO: EAI 발송용 파일 삭제
} }
private void doFail() { private void doFail(Exception e) throws KjbEaiBatchException {
// TODO: EAI 발송 실패 처리 // TODO: EAI 발송 실패 처리
if (e instanceof KjbEaiBatchException) {
throw (KjbEaiBatchException) e;
} else {
throw new KjbEaiBatchException("이메일 발송 실패", e);
}
} }
private void eaiBatchCall() throws IOException { private void eaiBatchCall() throws KjbEaiBatchException {
KjbEaiBatchModule eaiBatchModule = new KjbEaiBatchModule(prop); KjbEaiBatchModule eaiBatchModule = new KjbEaiBatchModule(prop);
EaiBatchMessage result = eaiBatchModule.call(prop.getUmsEaiBatchInterfaceId(), eaiFilePath.getFileName().toString()); EaiBatchInterface eaiBatchInterface = EaiBatchInterface.builder()
.id(prop.getUmsEaiBatchInterfaceId())
.sendDir(prop.getUmsEaiBatchSendDir())
.backupDir(prop.getUmsEaiBatchBackupDir())
.errorDir(prop.getUmsEaiBatchErrorDir())
.build();
EaiBatchMessage result = eaiBatchModule.call(eaiBatchInterface, eaiFilePath.getFileName().toString());
if (!"1".equals(result.getResultCode())) { if (!"1".equals(result.getResultCode())) {
log.error("EAI Batch call failed: {}", result); log.error("EAI Batch call failed: {}", result);
@@ -159,19 +182,11 @@ public class EmailJob {
} }
private void doSuccess() { private void doSuccess() {
// 백업 디렉토리로 복사 // 딱히 뭐 할 거 없음.
try {
Files.copy(eaiFilePath, backupFilePath);
log.debug("Copied EAI file to backup: {} -> {}", eaiFilePath.toString(), backupFilePath.toString());
} catch (IOException e) {
log.error("Cannot copy EAI file to backup: {} -> {}", eaiFilePath.toString(), backupFilePath.toString(), e);
}
} }
public void doCreateNewFile() { public void doCreateNewFile() {
final String filename = "EMAIL_" + messageRequest.getId() + ".json";
if (eaiFilePath.toFile().exists()) { if (eaiFilePath.toFile().exists()) {
log.error("Mail File exists for ID: {}", messageRequest.getId()); log.error("Mail File exists for ID: {}", messageRequest.getId());
throw new IllegalStateException("Mail File exists for ID: " + messageRequest.getId()); throw new IllegalStateException("Mail File exists for ID: " + messageRequest.getId());
@@ -210,29 +225,48 @@ public class EmailJob {
} catch (IOException e) { } catch (IOException e) {
log.error("Cannot write JSON to file: {}", eaiFilePath.toString(), e); log.error("Cannot write JSON to file: {}", eaiFilePath.toString(), e);
throw new RuntimeException(e); throw new RuntimeException(e);
} finally {
// 임시 파일이 남아 있다면 오류 상황이므로 에러 경로로 이동
if (Files.exists(tempFilePath)) {
try {
Files.move(tempFilePath, Paths.get(prop.getUmsEaiBatchErrorDir(), tempFilePath.getFileName().toString()));
} catch (IOException e) {
log.warn("임시 파일 저장시 실패 하여 에러 경로로 옮기는 도중 에러 발생", e);
}
}
} }
} }
public String generateJSON(boolean isPretty) { public String generateJSON(boolean isPretty) {
validateMessageRequest(messageRequest, true, true); validateMessageRequest(messageRequest, true, true);
KjbSafedbWrapper safedb = KjbSafedbWrapper.getInstance();
JsonObject jsonObject = new JsonObject(); JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("MAKE_DATE", DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDateTime.now())); jsonObject.addProperty("MAKE_DATE", DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDateTime.now()));
jsonObject.addProperty("MAKE_SEQNO", "0001"); jsonObject.addProperty("MAKE_SEQNO", "0001");
jsonObject.addProperty("CAMP_ID", messageRequest.getServiceId()); // 전자금융 고객이메일 발송 업무ID (SERVICE_ID) jsonObject.addProperty("CAMP_ID", messageRequest.getServiceId()); // 전자금융 고객이메일 발송 업무ID (SERVICE_ID)
jsonObject.addProperty("ID", messageRequest.getUmsUid()); // 고객 ID jsonObject.addProperty("ID", messageRequest.getUmsUid()); // 고객 ID
jsonObject.addProperty("EMAIL", messageRequest.getEmail()); jsonObject.addProperty("EMAIL", safedb.encryptNotRnnoString(messageRequest.getEmail()));
jsonObject.addProperty("NAME", messageRequest.getUsername()); jsonObject.addProperty("NAME", messageRequest.getUsername());
jsonObject.addProperty("ENCKEY", ""); // 보안메일용으로 기입 불필요 jsonObject.addProperty("ENCKEY", ""); // 보안메일용으로 기입 불필요
Gson gson = new Gson();
log.debug("Template string to json: {}", messageRequest.getMessage());
JsonObject contentJSon = gson.fromJson(messageRequest.getMessage(), JsonObject.class);
contentJSon.entrySet().forEach(entry -> {
jsonObject.add(entry.getKey(), entry.getValue());
});
jsonObject.addProperty("SUBJECT", messageRequest.getSubject()); // jsonObject.addProperty("SUBJECT", messageRequest.getSubject());
jsonObject.addProperty("MESSAGE", messageRequest.getMessage()); // jsonObject.addProperty("MESSAGE", messageRequest.getMessage());
String jsonString;
if (isPretty) { if (isPretty) {
return new GsonBuilder().setPrettyPrinting().create().toJson(jsonObject); jsonString = new GsonBuilder().setPrettyPrinting().create().toJson(jsonObject);
} else { } else {
return jsonObject.toString(); jsonString = jsonObject.toString();
} }
return jsonString;
} }
} }
@@ -3,6 +3,7 @@ package com.eactive.ext.kjb.ums;
import com.eactive.apim.portal.template.entity.MessageCode; import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.entity.MessageRequest; import com.eactive.apim.portal.template.entity.MessageRequest;
import com.eactive.apim.portal.template.repository.MessageRequestRepository; import com.eactive.apim.portal.template.repository.MessageRequestRepository;
import com.eactive.ext.kjb.common.KjbEaiBatchException;
import com.eactive.ext.kjb.common.KjbProperty; import com.eactive.ext.kjb.common.KjbProperty;
import com.eactive.ext.kjb.utils.ValidationUtil; import com.eactive.ext.kjb.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -14,25 +15,36 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@Slf4j @Slf4j
public class EmailSendModule { public class KjbEmailSendModule {
private static EmailSendModule instance = null; public final static int[] ALLOW_CHANNELS = { MessageCode.Channels.EMAIL.getValue() };
private static KjbEmailSendModule instance = null;
private static KjbProperty prop; private static KjbProperty prop;
private final MessageRequestRepository repo; private final MessageRequestRepository repo;
public static synchronized EmailSendModule getInstance(KjbProperty property, public static synchronized KjbEmailSendModule getInstance(KjbProperty property,
MessageRequestRepository messageRequestRepository) { MessageRequestRepository messageRequestRepository) {
ValidationUtil.validateOrThrow(property); ValidationUtil.validateOrThrow(property);
if (instance == null) { if (instance == null) {
instance = new EmailSendModule(property, messageRequestRepository); instance = new KjbEmailSendModule(property, messageRequestRepository);
} }
return instance; return instance;
} }
public static boolean isAllowChannel(MessageRequest message) {
for (int channel : ALLOW_CHANNELS) {
if ((message.getMessageCode().getChannels() & channel) == channel) {
return true;
}
}
return false;
}
public static void environmentCheck() { public static void environmentCheck() {
if (StringUtils.isEmpty(prop.getEaiBatchUrl())) { if (StringUtils.isEmpty(prop.getEaiBatchUrl())) {
@@ -91,8 +103,8 @@ public class EmailSendModule {
private EmailSendModule(KjbProperty property, private KjbEmailSendModule(KjbProperty property,
MessageRequestRepository repo) { MessageRequestRepository repo) {
this.repo = repo; this.repo = repo;
if (property != null && prop == null) { if (property != null && prop == null) {
@@ -102,33 +114,28 @@ public class EmailSendModule {
environmentCheck(); environmentCheck();
} }
public CompletableFuture<Boolean> sendEmail(MessageRequest messageRequest, BiConsumer<Boolean, Throwable> callback) { public void sendEmail(MessageRequest messageRequest) throws KjbEaiBatchException {
return CompletableFuture String serviceId = "UNKNOWN";
.supplyAsync(() -> {
String serviceId = "UNKNOWN";
serviceId = messageRequest.getMessageCode().getServiceId(); serviceId = messageRequest.getMessageCode().getServiceId();
messageRequest.setServiceId(serviceId); messageRequest.setServiceId(serviceId);
if (StringUtils.isEmpty(serviceId)) { if (StringUtils.isEmpty(serviceId)) {
throw new IllegalArgumentException("MessageRequest MessageCode serviceId is required"); throw new IllegalArgumentException("MessageRequest MessageCode serviceId is required");
} }
if (MessageCode.Channels.EMAIL.getValue() != (messageRequest.getMessageCode().getChannels() & MessageCode.Channels.EMAIL.getValue())) { if (MessageCode.Channels.EMAIL.getValue() != (messageRequest.getMessageCode().getChannels() & MessageCode.Channels.EMAIL.getValue())) {
log.error("지원하지 않는 발송 채널 - {}", messageRequest.getMessageCode()); log.error("지원하지 않는 발송 채널 - {}", messageRequest.getMessageCode());
throw new IllegalArgumentException("지원하지 않는 발송 채널 - " + messageRequest.getMessageCode()); throw new IllegalArgumentException("지원하지 않는 발송 채널 - " + messageRequest.getMessageCode());
} }
if (repo != null) { if (repo != null) {
repo.save(messageRequest); repo.save(messageRequest);
} }
EmailJob job = EmailJob.create(prop, messageRequest, repo); EmailJob job = EmailJob.create(prop, messageRequest, repo);
job.sendEmail(); job.sendEmail();
log.debug("JSON : {}", job.generateJSON(true)); log.debug("JSON : {}", job.generateJSON(true));
return true;
})
.whenComplete(callback);
} }
} }
@@ -2,8 +2,9 @@ package com.eactive.ext.kjb.ums.test;
import com.eactive.apim.portal.template.entity.MessageCode; import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.entity.MessageRequest; import com.eactive.apim.portal.template.entity.MessageRequest;
import com.eactive.ext.kjb.common.KjbEaiBatchException;
import com.eactive.ext.kjb.common.KjbProperty; import com.eactive.ext.kjb.common.KjbProperty;
import com.eactive.ext.kjb.ums.EmailSendModule; import com.eactive.ext.kjb.ums.KjbEmailSendModule;
import com.eactive.ext.kjb.ums.KjbUmsService; import com.eactive.ext.kjb.ums.KjbUmsService;
import com.eactive.ext.kjb.utils.OsUtil; import com.eactive.ext.kjb.utils.OsUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -65,31 +66,45 @@ public class UmsTest {
"true".equalsIgnoreCase(System.getenv("KJB_EAPIM_TEST_ENABLED")), "true".equalsIgnoreCase(System.getenv("KJB_EAPIM_TEST_ENABLED")),
"OS 환경변수 내 KJB_EAPIM_TEST_ENABLED=TRUE 설정되어 있어야 동작함"); "OS 환경변수 내 KJB_EAPIM_TEST_ENABLED=TRUE 설정되어 있어야 동작함");
// prop.setEaiBatchUrl("http://172.31.32.111:10230/BATAppWeb/EaiBatCall"); prop.setEaiBatchUrl("http://172.31.32.111:10230/BATAppWeb/EaiBatCall");
prop.setEaiBatchUrl(""); prop.setEaiBatchUrl("");
prop.setUmsEaiBatchSendDir("c:\\kjb-logs\\sendmail\\snd"); prop.setUmsEaiBatchSendDir("c:\\kjb-logs\\sendmail\\snd");
prop.setUmsEaiBatchBackupDir("c:\\kjb-logs\\sendmail\\bak"); prop.setUmsEaiBatchBackupDir("c:\\kjb-logs\\sendmail\\bak");
prop.setUmsEaiBatchErrorDir("c:\\kjb-logs\\sendmail\\error");
prop.setUmsEaiBatchInterfaceId("UAGFF00001UIE"); prop.setUmsEaiBatchInterfaceId("UAGFF00001UIE");
EmailSendModule service = EmailSendModule.getInstance(prop, null);
System.getProperties().keySet().forEach(key -> {
log.info("{}: {}", key, System.getProperty((String) key));
});
KjbEmailSendModule service = KjbEmailSendModule.getInstance(prop, null);
MessageRequest messageRequest = new MessageRequest(); MessageRequest messageRequest = new MessageRequest();
messageRequest.setId(UUID.randomUUID().toString()); messageRequest.setId(UUID.randomUUID().toString());
messageRequest.setMessageCode(MessageCode.USER_VERIFICATION_EMAIL); messageRequest.setMessageCode(MessageCode.USER_VERIFICATION_EMAIL);
messageRequest.setEmail("dearmai@dearmai.net"); messageRequest.setEmail("dearmai@dearmai.net");
messageRequest.setUsername("김광은"); messageRequest.setUsername("김광은");
messageRequest.setSubject("제목 - test"); messageRequest.setSubject("제목 - test");
messageRequest.setMessage("내용 - test"); messageRequest.setMessage("{\"ATHN_NO\": \"543216\"}");
messageRequest.setServiceId("FM_APIM001");
log.info("MessageRequest - {}", messageRequest);
CompletableFuture<Boolean> future = service.sendEmail(messageRequest, (result, ex) -> { try {
if (ex != null) { service.sendEmail(messageRequest);
log.error("failed", ex); } catch (KjbEaiBatchException e) {
} else { throw new RuntimeException(e);
log.info("result: {}", result); }
}
});
future.join(); // CompletableFuture<Boolean> future = service.sendEmail(messageRequest, (result, ex) -> {
// if (ex != null) {
// log.error("failed", ex);
// } else {
// log.info("result: {}", result);
// }
// });
//
// future.join();
log.info("done"); log.info("done");
} }