From 81a027740b663cfc7402ca0c5ebfdce3be9f3852 Mon Sep 17 00:00:00 2001 From: "hehihoho3@gmail.com" Date: Mon, 21 Apr 2025 17:59:36 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B9=9C=EA=B5=AC=ED=86=A1=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/itn/com/cmm/util/MsgSendUtils.java | 2 +- .../let/kakao/kakaoComm/KakaoSendUtil.java | 256 +++++++++--------- 2 files changed, 126 insertions(+), 132 deletions(-) diff --git a/src/main/java/itn/com/cmm/util/MsgSendUtils.java b/src/main/java/itn/com/cmm/util/MsgSendUtils.java index 339137e9..74ba0866 100644 --- a/src/main/java/itn/com/cmm/util/MsgSendUtils.java +++ b/src/main/java/itn/com/cmm/util/MsgSendUtils.java @@ -463,7 +463,7 @@ public final class MsgSendUtils { } } - private static Boolean getReplaceYN(String smsTxtTemplate) {// 여러 치환 구문이 포함된 정규식 패턴 + public static Boolean getReplaceYN(String smsTxtTemplate) {// 여러 치환 구문이 포함된 정규식 패턴 if (smsTxtTemplate == null) { return false; // null일 경우 false 반환 diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java index 31e0dcbd..b3e10af4 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java @@ -1,12 +1,15 @@ package itn.let.kakao.kakaoComm; +import java.io.UnsupportedEncodingException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,6 +22,9 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import egovframework.rte.fdl.idgnr.EgovIdGnrService; +import itn.com.cmm.MjonFTSendVO; +import itn.com.cmm.MjonMsgSendVO; +import itn.com.cmm.util.MsgSendUtils; import itn.com.cmm.util.StringUtil; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate; @@ -294,25 +300,23 @@ public class KakaoSendUtil { - KakaoReturnVO templateDetail = kakaoApiTemplate.selectKakaoApiTemplateDetail(kakaoVO); - String templateContent = templateDetail.getTemplateContent(); // 알림톡 템플릿 - kakaoVO.setTemplateContent(templateContent); - String templateTitle = templateDetail.getTemplateTitle(); + String templateContent = kakaoVO.getTemplateContent(); // 친구톡 내용 +// kakaoVO.setTemplateContent(templateContent); +// String templateTitle = templateDetail.getTemplateTitle(); // log.info(" + templateDetail :: [{}]", templateDetail); // templateDetail.getButtonList().forEach(t->log.info(" + ButtonList :: [{}]", t.toString())); Boolean hasContentReplacement = this.replBooleanStrChecker(templateContent); - Boolean hasTitleReplacement = this.replBooleanStrChecker(templateTitle); - Boolean hasButtonReplacement = this.needsButtonReplacement(templateDetail.getButtonList()); +// Boolean hasTitleReplacement = this.replBooleanStrChecker(templateTitle); +// Boolean hasButtonReplacement = this.needsButtonReplacement(templateDetail.getButtonList()); /** @jsonStr 필요유무 */ - boolean hasTitleOrButtons = StringUtils.isNotEmpty(templateTitle) - || CollectionUtils.isNotEmpty(templateDetail.getButtonList()); + boolean hasTitleOrButtons = CollectionUtils.isNotEmpty(kakaoVO.getButtonVOList()); /** @jsonStr 반복유무 */ - boolean needsJsonReplacement = hasTitleReplacement || hasButtonReplacement; +// boolean needsJsonReplacement = hasTitleReplacement || hasButtonReplacement; String sharedJsonStr = null; String subMsgTxt = kakaoVO.getSubMsgTxt(); // 실패 대체 문자 @@ -322,125 +326,105 @@ public class KakaoSendUtil { // 사용자 개인 단가 정보 불러오기 MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(kakaoVO.getUserId()); - + + String smsTxtTemp = templateContent; + Boolean replaceYN = MsgSendUtils.getReplaceYN(templateContent); + + boolean hasPerformedMsgType = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 /** @MSGID KEY값 */ List idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getVarListMap().size()); -// for (int i = 0; i < kakaoSendAdvcListVO.size(); i++) { -// kakaoSendAdvcListVO.get(i).setMsgId(idList.get(i)); -// kakaoSendAdvcListVO.get(i).setBizJsonName(idList.get(i)); -// } - - + + + Map> placeholders = new HashMap<>(); + placeholders.put("[*이름*]", MjonFTSendVO::getName); + placeholders.put("[*1*]", MjonFTSendVO::getRep1); + placeholders.put("[*2*]", MjonFTSendVO::getRep2); + placeholders.put("[*3*]", MjonFTSendVO::getRep3); + placeholders.put("[*4*]", MjonFTSendVO::getRep4); + + + String msgTypeResult = null; + List mjonFTSendVOList = kakaoVO.getMjonFTSendVOList(); + // 분할 건수 카운터 int counter = 0; - /** @Map에 총 갯수가 수신자 갯수와 동일함 */ - List> varList = kakaoVO.getVarListMap(); - for (int i = 0; i < varList.size(); i++) { - // for(Map variables : kakaoVO.getVarListMap()) { - // 치환 데이터 - Map variables = varList.get(i); - log.info(""); + for (MjonFTSendVO sendVO : mjonFTSendVOList) { + KakaoSendAdvcVO kakaoSendAdvcVO = new KakaoSendAdvcVO(); - /** @공통 기본값 */ - KakaoSendAdvcVO sendVO = createSendVO(kakaoVO); - String msgId = idList.get(i); - sendVO.setMsgId(msgId); - - // step1 - // Step 1-1: 값 치환 및 수신번호 셋팅 - // Step 1-2: 수신자 정보 설정 (callToList는 항상 설정). - if (variables.containsKey("callToList")) { - sendVO.setCallTo(variables.get("callToList")); - variables.remove("callToList"); // 사용 후 제거. - } - - /** @Step1-3: 템플릿 치환데이터 설정 */ - String templateContentTemp = templateContent; - String templateTitleTemp = templateTitle; - if (hasContentReplacement) { - templateContentTemp = mjonCommon.ATReplaceTemplateVariables(templateContent, variables); - if(hasTitleReplacement) { - templateTitleTemp = mjonCommon.ATReplaceTemplateVariables(templateTitle, variables); + kakaoSendAdvcVO.setCallFrom(kakaoVO.getCallFrom()); + kakaoSendAdvcVO.setCallTo(sendVO.getPhone()); + kakaoSendAdvcVO.setUserId(kakaoVO.getUserId()); + + String smsTxt = smsTxtTemp; + // 치환 문자면 + if(replaceYN) { + + // 각 치환 구문을 확인하고 치환할 값이 없으면 오류 반환 + for (Map.Entry> entry : placeholders.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue().apply(sendVO); +// log.info(" + smsTxtTemp [{}]", smsTxtTemp); +// log.info(" + placeholder [{}]", placeholder); +// log.info(" + value [{}]", value); +// log.info(" + smsTxtTemp.contains(placeholder) [{}]", smsTxtTemp.contains(placeholder)); + if (smsTxt.contains(placeholder)) { + if (StringUtils.isEmpty(value)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다."); + return false; + } + smsTxt = smsTxt.replace(placeholder, value); +// log.info(" + smsTxt [{}]", smsTxt); + + } } } - /** @버튼 치환 */ // 버튼 리스트가 있으면 치환 수행, 항상 sendVO에 설정 - List buttonList = templateDetail.getButtonList(); - if(hasButtonReplacement) { - buttonList = replaceButtonLinks(buttonList, variables); + + String smsSpamChkTxt = smsTxt; + if(StringUtils.isNotEmpty(smsTxt)) { + smsSpamChkTxt = smsTxt.replaceAll(String.valueOf((char) 13), ""); } - sendVO.setButtonList(buttonList); - - sendVO.setTemplateTitle(templateTitleTemp); - sendVO.setTemplateContent(templateContentTemp); + - // Step 1-4: 실패 대체 문자 치환데이터 설정 - if("Y".equals(kakaoVO.getSubMsgSendYn())) { // 대체문자가 있나? - if ("Y".equals(kakaoVO.getSubMsgTxtReplYn())) { // 치환데이터가 있나? - subMsgTxt = mjonCommon.ATReplaceTemplateVariables(subMsgTxt, variables); + // == 치환 여부에 따라 처리 로직 분기 == + // 치환 문자가 아닌 경우 + if (!replaceYN) { + if (!hasPerformedMsgType) { + msgTypeResult = getMsgTypeWithByteValidation(sendVO, smsTxt); + if ("INVALID".equals(msgTypeResult)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "문자 치환 후 전송 문자 길이를 초과하였습니다."); + return null; + } + hasPerformedMsgType = true; } - sendVO.setSubMsgTxt(subMsgTxt);// 실패 - } - sendVO.setSubMsgSendYn(kakaoVO.getSubMsgSendYn()); - - - /* - log.info("kakaoSendAdvcVO Details: [callTo={}\n, templateContent=\n{}\n, subMsgTxt=\n{}]\n\n\n\n", - kakaoSendAdvcVO.getCallTo(), - kakaoSendAdvcVO.getTemplateContent(), - kakaoSendAdvcVO.getSubMsgTxt() - ); - */ - - // Step1 END - - -// step3 -// 바이트 수 체크 및 금액설정 - - - Float kakaoAtPrice = mberManageVO.getKakaoAtPrice(); - // 유효한 단가 계산 - float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); - float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice()); - - - String shortPStr = Float.toString(shortPrice); - String mmsPStr = Float.toString(longPrice); - - // 공통 가격 설정 - sendVO.setSmsPrice(shortPStr); - sendVO.setMmsPrice(mmsPStr); - - - if("Y".equals(kakaoVO.getSubMsgSendYn())) { - int smsTxtByte = mjonCommon.getSmsTxtBytes(sendVO.getSubMsgTxt()); - String sendType = getMsgType(smsTxtByte); - sendVO.setSubMsgType(sendType); - - if ("INVALID".equals(sendType)) { - statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다.");return kakaoSendAdvcListVO; + } + else + {// 치환 문자인 경우 + + // 메시지 타입 체크는 매번 수행 + msgTypeResult = getMsgTypeWithByteValidation(sendVO, smsTxt); + if ("INVALID".equals(msgTypeResult)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "문자 치환 후 전송 문자 길이를 초과하였습니다."); + return null; } - - boolean isMms = "MMS".equals(sendType); - sendVO.setEachPrice(isMms ? mmsPStr : shortPStr); - - - } else { - kakaoAtPrice = getValidPrice(mberManageVO.getKakaoAtPrice(), sysJoinSetVO.getKakaoAtPrice()); - sendVO.setEachPrice( Float.toString(kakaoAtPrice) ); } - // step4 - // 예약 시간 설정 및 분할 데이터 설정 + + kakaoSendAdvcVO.setTemplateContent(smsTxt); + kakaoSendAdvcVO.setMsgType(msgTypeResult); + + + + + // 예약 여부 확인 if ("Y".equalsIgnoreCase(kakaoVO.getReserveYn()) - && "Y".equalsIgnoreCase(kakaoVO.getDivideChk()) - && counter == Integer.parseInt(kakaoVO.getDivideCnt())) + && "Y".equalsIgnoreCase(kakaoVO.getDivideChk()) + && counter == Integer.parseInt(kakaoVO.getDivideCnt())) { counter = 0; calendar.add(Calendar.MINUTE, Integer.parseInt(kakaoVO.getDivideTime())); @@ -448,36 +432,46 @@ public class KakaoSendUtil { counter++; // 즉시 발송인경우 현재 시간 // 예약인 경우 위에 설정한 시간 입력 - sendVO.setReqDate(DATE_FORMATTER.format(calendar.getTime())); + kakaoSendAdvcVO.setReqDate(DATE_FORMATTER.format(calendar.getTime())); + + kakaoSendAdvcListVO.add(kakaoSendAdvcVO); - - - /** @step5 전송 메세지 설정 json파일 만들기*/ - // 타이틀과 버튼이 있고 - if(hasTitleOrButtons) { - // 버튼과 타이틀에 치환데이터가 있으면 json String을 계속 생성 - if(needsJsonReplacement) { - sharedJsonStr = kakaoApiJsonSave.kakaoApiJsonSave_advc(sendVO, templateDetail); - sendVO.setBizJsonName(msgId); - sendVO.setJsonStr(sharedJsonStr); - } else if (StringUtils.isEmpty(sharedJsonStr)) { - // 치환 데이터가 없고 아직 생성되지 않았으면 한 번만 생성 - sharedJsonStr = kakaoApiJsonSave.kakaoApiJsonSave_advc(sendVO, templateDetail); - sendVO.setBizJsonName(idList.get(0)); - sendVO.setJsonStr(sharedJsonStr); - }else { - sendVO.setBizJsonName(idList.get(0)); - } - - } - log.info(" sendVO :: [{}]", sendVO); - kakaoSendAdvcListVO.add(sendVO); } return kakaoSendAdvcListVO; } + public static String getMsgTypeWithByteValidation(MjonFTSendVO sendVO, String p_smsTxt) throws UnsupportedEncodingException { + + + // // 내문자저장함에 저장 후 문자를 발송하는 경우 문자 타입이 숫자가 아닌 문자로 넘어와서 변경 처리함 + // if ("P".equals(msgType) || "L".equals(msgType)) { + // msgType = "6"; + // } else if ("S".equals(msgType)) { + // msgType = "4"; + // } + + int smsTxtByte = MjonCommon.getSmsTxtBytes(p_smsTxt); + String msgType = SHORT_MSG_TYPE; + + // 1. 2000 Byte 초과는 에러 처리 + if (smsTxtByte > 2000) { + return "INVALID"; + } + + // 2. 첨부파일 여부 확인 (첨부파일이 있으면 장문으로 설정) + if (StringUtils.isNotEmpty(sendVO.getFilePath1())) { + msgType = LONG_MSG_TYPE; + } + // 3. 문자 길이에 따라 메시지 타입 설정 (90 Byte 초과는 장문) + else if (smsTxtByte > 90) { + msgType = LONG_MSG_TYPE; + } + return msgType; + } + + private Calendar setupBaseDate(KakaoVO kakaoVO, boolean isNotified) throws ParseException { // 예약 시간 기본값 설정 Date now = new Date();