친구톡 발송 속도 개선중

This commit is contained in:
hehihoho3@gmail.com 2025-04-25 11:24:29 +09:00
parent 81a027740b
commit 81d31fc55f
10 changed files with 582 additions and 580 deletions

View File

@ -796,9 +796,16 @@ public class MjonKakaoATController {
String lastUpdtPnttm = resultChannelList.get(i).getLastUpdtPnttm();
kakaoProfileVO.setSenderKey(senderKey);
kakaoProfileVO.setProfileId(profileId);
KakaoReturnVO tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO);
KakaoReturnVO tmpProfileVO = null;
// try {
//
// tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO);
// } catch (Exception e) {
// e.printStackTrace();
// // TODO: handle exception
// }
tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO);
ChannelIDVO returnChannelVO = new ChannelIDVO();
returnChannelVO.setSenderKey(tmpProfileVO.getSenderKey());

View File

@ -83,7 +83,7 @@ public class KakaoSendAdvcVO implements Serializable {
"\n , msgType=[" + msgType + "]" +
"\n , templateContent=[" + templateContent + "]" +
"\n , templateTitle=[" + templateTitle + "]" +
"\n , buttonList=[" + buttonList.toString() + "]" +
"\n , buttonList=[" + (buttonList != null ? buttonList.toString() : "") + "]" +
"\n , subMsgSendYn=[" + subMsgSendYn + "]" +
"\n , subMsgTxt=[" + subMsgTxt + "]" +
"\n , subMsgType=[" + subMsgType + "]" +

View File

@ -1,6 +1,8 @@
package itn.let.kakao.kakaoComm;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -28,6 +30,7 @@ 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;
import itn.let.kakao.user.kakaoAt.service.impl.KakaoAlimTalkDAO;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.msg.service.MjonMsgVO;
@ -44,6 +47,9 @@ public class KakaoSendUtil {
@Autowired
KakaoApiJsonSave kakaoApiJsonSave;
@Resource(name="kakaoAlimTalkDAO")
private KakaoAlimTalkDAO kakaoAlimTalkDAO;
@Resource(name = "MjonMsgDataService")
private MjonMsgDataService mjonMsgDataService;
@ -57,6 +63,7 @@ public class KakaoSendUtil {
@Autowired
private MjonCommon mjonCommon;
// 클래스 수준에서 정적 Pattern 정의 (성능 최적화)
private static final Pattern REPLACEMENT_PATTERN = Pattern.compile("#\\{[^}]+\\}");
@ -142,7 +149,7 @@ public class KakaoSendUtil {
log.info("");
/** @공통 기본값 */
KakaoSendAdvcVO sendVO = createSendVO(kakaoVO);
KakaoSendAdvcVO sendVO = createATSendVO(kakaoVO);
String msgId = idList.get(i);
sendVO.setMsgId(msgId);
@ -293,33 +300,16 @@ public class KakaoSendUtil {
//사용자 현재 보유 금액 불러오기(문자 발송 금액 차감 이전 금액)
// String befCash = kakaoVO.getBefCash();
log.info(" [{}]", kakaoVO.ftToString());
List<KakaoSendAdvcVO> kakaoSendAdvcListVO = new ArrayList<>();
Calendar calendar = setupBaseDate(kakaoVO, isNotified);
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());
/** @jsonStr 필요유무 */
boolean hasTitleOrButtons = CollectionUtils.isNotEmpty(kakaoVO.getButtonVOList());
/** @jsonStr 반복유무 */
// boolean needsJsonReplacement = hasTitleReplacement || hasButtonReplacement;
String sharedJsonStr = null;
String subMsgTxt = kakaoVO.getSubMsgTxt(); // 실패 대체 문자
// 친구톡 내용
String templateContent = kakaoVO.getTemplateContent();
// 실패 대체 문자
String subMsgTxt = kakaoVO.getSubMsgTxt();
// 시스템 기본 단가 정보 불러오기
JoinSettingVO sysJoinSetVO = mjonMsgDataService.selectJoinSettingInfo();
@ -327,14 +317,15 @@ public class KakaoSendUtil {
MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(kakaoVO.getUserId());
String smsTxtTemp = templateContent;
// 치환 문구가 있는지 확인
Boolean replaceYN = MsgSendUtils.getReplaceYN(templateContent);
Boolean replaceSubYN = MsgSendUtils.getReplaceYN(subMsgTxt);
boolean hasPerformedMsgType = false; // 치환 문자가 없는 경우, 스팸 체크가 번만 수행되도록 제어
/** @MSGID KEY값 */
List<String> idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getVarListMap().size());
List<String> idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getMjonFTSendVOList().size());
Map<String, Function<MjonFTSendVO, String>> placeholders = new HashMap<>();
@ -345,97 +336,114 @@ public class KakaoSendUtil {
placeholders.put("[*4*]", MjonFTSendVO::getRep4);
// 친구통 금액
Float kakaoFtPrice = mberManageVO.getKakaoFtPrice();
// 대체문자가 있을경우 사용
float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice());
float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice());
String shortPStr = Float.toString(shortPrice);
String mmsPStr = Float.toString(longPrice);
/** @jsonStr 필요유무 */
boolean hasTitleOrButtons = CollectionUtils.isNotEmpty(kakaoVO.getButtonVOList());
String sharedJsonStr = null;
String msgTypeResult = null;
List<MjonFTSendVO> mjonFTSendVOList = kakaoVO.getMjonFTSendVOList();
// 분할 건수 카운터
int counter = 0;
for (MjonFTSendVO sendVO : mjonFTSendVOList) {
KakaoSendAdvcVO kakaoSendAdvcVO = new KakaoSendAdvcVO();
kakaoSendAdvcVO.setCallFrom(kakaoVO.getCallFrom());
kakaoSendAdvcVO.setCallTo(sendVO.getPhone());
kakaoSendAdvcVO.setUserId(kakaoVO.getUserId());
for (int i = 0; i < mjonFTSendVOList.size(); i++) {
MjonFTSendVO mjonFTSendVO = mjonFTSendVOList.get(i);
String smsTxt = smsTxtTemp;
KakaoSendAdvcVO sendVO = createFTSendVO(kakaoVO, calendar);
// 공통 가격 설정
sendVO.setSmsPrice(shortPStr);
sendVO.setMmsPrice(mmsPStr);
sendVO.setCallTo(mjonFTSendVO.getPhone());
sendVO.setMsgId(idList.get(i));
String smsTxt = templateContent;
// 치환 문자면
if(replaceYN) {
// 치환 구문을 확인하고 치환할 값이 없으면 오류 반환
for (Map.Entry<String, Function<MjonFTSendVO, String>> 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));
String value = entry.getValue().apply(mjonFTSendVO);
if (smsTxt.contains(placeholder)) {
if (StringUtils.isEmpty(value)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다.");
return false;
return null;
}
smsTxt = smsTxt.replace(placeholder, value);
// log.info(" + smsTxt [{}]", smsTxt);
}
}
}
String smsSpamChkTxt = smsTxt;
if(StringUtils.isNotEmpty(smsTxt)) {
smsSpamChkTxt = smsTxt.replaceAll(String.valueOf((char) 13), "");
}
sendVO.setTemplateContent(smsTxt);
// == 치환 여부에 따라 처리 로직 분기 ==
// 치환 문자가 아닌 경우
if (!replaceYN) {
if (!hasPerformedMsgType) {
msgTypeResult = getMsgTypeWithByteValidation(sendVO, smsTxt);
if ("INVALID".equals(msgTypeResult)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "문자 치환 후 전송 문자 길이를 초과하였습니다.");
return null;
String subMsgTxtTemp = null;
if(StringUtils.isNotEmpty(subMsgTxt)) {
subMsgTxtTemp = subMsgTxt;
// 치환 구문을 확인하고 치환할 값이 없으면 오류 반환
for (Map.Entry<String, Function<MjonFTSendVO, String>> entry : placeholders.entrySet()) {
String placeholder = entry.getKey();
String value = entry.getValue().apply(mjonFTSendVO);
if (subMsgTxtTemp.contains(placeholder)) {
if (StringUtils.isEmpty(value)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다.");
return null;
}
subMsgTxtTemp = subMsgTxtTemp.replace(placeholder, value);
}
hasPerformedMsgType = true;
}
}
else
{// 치환 문자인 경우
// 메시지 타입 체크는 매번 수행
msgTypeResult = getMsgTypeWithByteValidation(sendVO, smsTxt);
if ("INVALID".equals(msgTypeResult)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "문자 치환 후 전송 문자 길이를 초과하였습니다.");
return null;
}
}
sendVO.setSubMsgTxt(subMsgTxtTemp);
kakaoSendAdvcVO.setTemplateContent(smsTxt);
kakaoSendAdvcVO.setMsgType(msgTypeResult);
//대체문자가 있으면
// Step 1-4: 실패 대체 문자 치환데이터 설정
if(StringUtils.isNotEmpty(subMsgTxtTemp)) { // 대체문자가 있나?
int smsTxtByte = mjonCommon.getSmsTxtBytes(subMsgTxtTemp);
String sendType = getMsgType(smsTxtByte);
sendVO.setSubMsgType(sendType);
// 예약 여부 확인
if ("Y".equalsIgnoreCase(kakaoVO.getReserveYn())
&& "Y".equalsIgnoreCase(kakaoVO.getDivideChk())
&& counter == Integer.parseInt(kakaoVO.getDivideCnt()))
{
counter = 0;
calendar.add(Calendar.MINUTE, Integer.parseInt(kakaoVO.getDivideTime()));
if ("INVALID".equals(sendType)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다.");return kakaoSendAdvcListVO;
}
boolean isMms = "MMS".equals(sendType);
sendVO.setEachPrice(isMms ? mmsPStr : shortPStr);
sendVO.setSubMsgTxt(subMsgTxt);// 실패
}else {
kakaoFtPrice = getValidPrice(mberManageVO.getKakaoAtPrice(), sysJoinSetVO.getKakaoAtPrice());
sendVO.setEachPrice( Float.toString(kakaoFtPrice) );
}
counter++;
// 즉시 발송인경우 현재 시간
// 예약인 경우 위에 설정한 시간 입력
kakaoSendAdvcVO.setReqDate(DATE_FORMATTER.format(calendar.getTime()));
kakaoSendAdvcListVO.add(kakaoSendAdvcVO);
// 타이틀과 버튼이 있고
if(hasTitleOrButtons) {
//
if (StringUtils.isEmpty(sharedJsonStr)) {
// 치환 데이터가 없고 아직 생성되지 않았으면 번만 생성
sharedJsonStr = kakaoApiJsonSave.kakaoApiFTJsonSave_advc(kakaoVO);
sendVO.setJsonStr(sharedJsonStr);
}
sendVO.setBizJsonName(idList.get(0));
}
kakaoSendAdvcListVO.add(sendVO);
log.info(" sendVO.toString() :: [{}]",sendVO.toString());
}
@ -508,14 +516,40 @@ public class KakaoSendUtil {
* @return
*
*/
private KakaoSendAdvcVO createSendVO(KakaoVO kakaoVO) {
private KakaoSendAdvcVO createATSendVO(KakaoVO kakaoVO) {
KakaoSendAdvcVO sendVO = new KakaoSendAdvcVO();
sendVO.setMsgType("8");
sendVO.setAgentCode("04");
sendVO.setSenderKey(kakaoVO.getSenderKey());
sendVO.setTemplateCode(kakaoVO.getTemplateCode());
sendVO.setUserId(kakaoVO.getUserId());
sendVO.setCallFrom(kakaoVO.getCallFrom());
return sendVO;
}
/**
* @methodName : createFTSendVO
* @author : 이호영
* @date : 2025. 4. 23.
* @description :
* @return : KakaoSendAdvcVO
* @param kakaoVO
* @return
*
*/
private KakaoSendAdvcVO createFTSendVO(KakaoVO kakaoVO, Calendar calendar) {
KakaoSendAdvcVO sendVO = new KakaoSendAdvcVO();
sendVO.setMsgType("9"); // 알림톡 8 친구톡 9
sendVO.setAgentCode("04");
// 발송시간 : 친구톡은 분할 발송이 없어 처음 vo 생성 입력
sendVO.setReqDate(DATE_FORMATTER.format(calendar.getTime()));
sendVO.setSenderKey(kakaoVO.getSenderKey());
sendVO.setTemplateCode(kakaoVO.getTemplateCode());
sendVO.setUserId(kakaoVO.getUserId());
sendVO.setCallFrom(kakaoVO.getCallFrom());
return sendVO;
}
@ -1401,4 +1435,165 @@ public class KakaoSendUtil {
statusResponse.setMessage(msg);
}
// 보유 금액이 충분한지 확인하는 메서드
public boolean isCashSufficient(String userId, List<KakaoSendAdvcVO> kakaoSendAdvcListVO) throws Exception {
String userMoney = priceAndPoint.getBefCash(userId);
// 쉼표 제거
userMoney = userMoney.replace(",", "");
// 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용)
BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN);
// 메시지 금액 계산 (HALF_EVEN 적용)
BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream()
.map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지
// 비교 수행
return befCash.compareTo(totalEachPrice) >= 0;
}
/**
* @methodName : insertKakaoAtDataJsonInfo_advc
* @author : 이호영
* @date : 2025. 4. 24.
* @description : INSERT INTO BIZ_ATTACHMENTS
* @return : void
* @param kakaoSendAdvcListVO
*
*/
public void insertKakaoAtDataJsonInfo_advc(List<KakaoSendAdvcVO> kakaoSendAdvcListVO) {
List<KakaoSendAdvcVO> jsonInfoData = new ArrayList<>(kakaoSendAdvcListVO);
jsonInfoData.removeIf(t -> StringUtils.isBlank(t.getJsonStr()));
log.info(" + jsonInfoData Insert :: [{}]", jsonInfoData.size());
if(jsonInfoData.size() > 0) {
kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc(jsonInfoData);
}
}
/**
* @methodName : insertKakaoData_advc
* @author : 이호영
* @date : 2025. 3. 20.
* @description : 카카오 batch 발송 => mj_msg_data
* @return : int
* @param kakaoSendAdvcVOList
* @param parentLoopCount
* @param isJsonNotEmpty
* @param isJsonNameAllSame
* @return
*
*/
public int insertKakaoData_advc(List<KakaoSendAdvcVO> kakaoSendAdvcVOList) {
// 시작 시간 측정
long totalStartTime = System.currentTimeMillis();
int totalSize = kakaoSendAdvcVOList.size(); // 데이터 개수
// Batch 크기 설정 (고정값)
// int batchSize = 10000; 465
int batchSize = 50000; // 9분 18초
log.info("총 데이터 개수 :: [{}] ", totalSize);
log.info("설정된 Batch 크기 :: [{}] ", batchSize);
// insert 카운트
int instCnt = 0;
int batchCount = 0;
// 배치별 실행 시간 기록
List<Double> batchExecutionTimes = new ArrayList<>();
// 번째 배치에서만 삽입했는지 추적하는 플래그
for (int i = 0; i < totalSize; i += batchSize) {
// Batch 시작 시간 측정
long batchStartTime = System.currentTimeMillis();
// Batch 리스트 생성
List<KakaoSendAdvcVO> batchList = kakaoSendAdvcVOList.subList(i, Math.min(i + batchSize, totalSize));
System.out.println("Batch 시작 인덱스: " + i);
// mj_msg_data 테이블 insert
int insertedCount = kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc(batchList);
/** @kakaoSendUtil.populateSendLists
* 하단에서
* getJsonStr 데이터 처리 활용
* */
instCnt += insertedCount;
// Batch 종료 시간 측정 실행 시간 계산
long batchEndTime = System.currentTimeMillis();
double batchExecutionTimeInSeconds = (batchEndTime - batchStartTime) / 1000.0;
// 실행 시간 기록
batchExecutionTimes.add(batchExecutionTimeInSeconds);
batchCount++;
}
// 종료 시간 측정
long totalEndTime = System.currentTimeMillis();
// 실행 시간 계산 (밀리초 -> 초로 변환)
double totalExecutionTimeInSeconds = (totalEndTime - totalStartTime) / 1000.0;
// 실행 시간 출력
log.info("총 배치 실행 횟수 :: [{}] ", batchCount);
log.info("batchSize :: [{}] ", batchSize);
log.info("총 실행 시간 :: [{}] ", totalExecutionTimeInSeconds + "");
log.info("총 삽입 건수 :: [{}] ", instCnt);
// 배치별 실행 시간 출력
for (int k = 0; k < batchExecutionTimes.size(); k++) {
System.out.println("배치 " + (k + 1) + " 실행 시간 :: " + batchExecutionTimes.get(k) + "");
}
return instCnt;
}
public void insertKakaoGroupDataTb_advc(int instCnt, KakaoVO kakaoVO, KakaoSendAdvcVO sendVO) throws Exception {
// TODO Auto-generated method stub
// log.info(" + insertKakaoGroupDataTb_advc kakaoVO :: \n[{}]", kakaoVO.toString());;
// log.info(" + insertKakaoGroupDataTb_advc kakaoSendAdvcVOList :: \n[{}]", sendVO.toString());
sendVO.setMsgGroupCnt(Integer.toString(instCnt));
sendVO.setReserveYn(kakaoVO.getReserveYn());
sendVO.setBefCash(priceAndPoint.getBefCash(sendVO.getUserId()));
sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId()));
Float eachPrice = Float.parseFloat(sendVO.getEachPrice());
Float totPrice = eachPrice * instCnt;
sendVO.setTotPrice(String.format("%.1f", totPrice));
sendVO.setAtDelayYn(kakaoVO.getAtSmishingYn());
sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt());
sendVO.setBizKakaoResendType(sendVO.getSubMsgType());
kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc(sendVO);
}
}

View File

@ -344,6 +344,7 @@ public class KakaoVO extends MjonMsgVO{
sb.append("\n , subMsgSendYn=[").append(subMsgSendYn).append("]");
sb.append("\n , subMsgTxtReplYn=[").append(subMsgTxtReplYn).append("]");
sb.append("\n , subMsgType=[").append(subMsgType).append("]");
sb.append("\n , subMsgTxt=[").append(subMsgTxt).append("]");
sb.append("\n , reserveYn=[").append(getReserveYn()).append("]");
sb.append("\n , menuTopTab=[").append(menuTopTab).append("]");
sb.append("\n , bizJsonYn=[").append(bizJsonYn).append("]");

View File

@ -10,6 +10,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
@ -246,12 +247,12 @@ public class KakaoApiJsonSave {
JSONObject templateImageExtInfo = new JSONObject();
String imageType = kakaoVO.getImageType();
if(!imageType.equals("")) {
if(StringUtils.isNotEmpty(imageType)) {
templateImageInfo.put("img_url", kakaoVO.getTemplateImageUrl());
templateImageInfo.put("img_link", kakaoVO.getImgLink());
}
if(imageType.equals("W")) {
if("W".equals(imageType)) {
templateImageExtInfo.put("wide", "Y");
}

View File

@ -913,7 +913,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
/** @전송금액 확인 --------------------------------------------------*/
if (!isCashSufficient(userId, kakaoSendAdvcListVO)) {
if (!kakaoSendUtil.isCashSufficient(userId, kakaoSendAdvcListVO)) {
log.error("Insufficient balance for message sending.");
return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다.");
}
@ -921,7 +921,8 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
/** @json파일이 있을 떄 biz_attachments insert */
this.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO);
kakaoSendUtil.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO);
// this.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO);
Map<String, List<KakaoSendAdvcVO>> priceGroupedMessages = kakaoSendAdvcListVO.stream()
@ -941,7 +942,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
// 발송 데이터 삽입
int instCnt = this.insertKakaoData_advc(groupedMsgList);
int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList);
// int instCnt = 6;
if(instCnt > 0) {
@ -951,7 +952,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
KakaoSendAdvcVO sendVO = groupedMsgList.get(0);
/** @groupData 테이블 insert */
this.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO);
kakaoSendUtil.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO);
/** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/
@ -1032,146 +1033,26 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
private void insertKakaoAtDataJsonInfo_advc(List<KakaoSendAdvcVO> kakaoSendAdvcListVO) {
// TODO Auto-generated method stub
// 측정할 메소드 호출 시간 기록
List<KakaoSendAdvcVO> jsonInfoData = new ArrayList<>(kakaoSendAdvcListVO);
jsonInfoData.removeIf(t -> StringUtils.isBlank(t.getJsonStr()));
log.info(" + jsonInfoData Insert :: [{}]", jsonInfoData.size());
if(jsonInfoData.size() > 0) {
kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc(jsonInfoData);
}
}
private void insertKakaoGroupDataTb_advc(int instCnt, KakaoVO kakaoVO, KakaoSendAdvcVO sendVO) throws Exception {
// TODO Auto-generated method stub
// log.info(" + insertKakaoGroupDataTb_advc kakaoVO :: \n[{}]", kakaoVO.toString());;
// log.info(" + insertKakaoGroupDataTb_advc kakaoSendAdvcVOList :: \n[{}]", sendVO.toString());
sendVO.setMsgGroupCnt(Integer.toString(instCnt));
sendVO.setReserveYn(kakaoVO.getReserveYn());
sendVO.setBefCash(priceAndPoint.getBefCash(sendVO.getUserId()));
sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId()));
Float eachPrice = Float.parseFloat(sendVO.getEachPrice());
Float totPrice = eachPrice * instCnt;
sendVO.setTotPrice(String.format("%.1f", totPrice));
sendVO.setAtDelayYn(kakaoVO.getAtSmishingYn());
sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt());
sendVO.setBizKakaoResendType(sendVO.getSubMsgType());
kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc(sendVO);
}
/**
* @methodName : insertKakaoData_advc
* @author : 이호영
* @date : 2025. 3. 20.
* @description : 카카오 batch 발송 => mj_msg_data
* @return : int
* @param kakaoSendAdvcVOList
* @param parentLoopCount
* @param isJsonNotEmpty
* @param isJsonNameAllSame
* @return
*
*/
private int insertKakaoData_advc(List<KakaoSendAdvcVO> kakaoSendAdvcVOList) {
// 시작 시간 측정
long totalStartTime = System.currentTimeMillis();
int totalSize = kakaoSendAdvcVOList.size(); // 데이터 개수
// Batch 크기 설정 (고정값)
// int batchSize = 10000; 465
int batchSize = 50000; // 9분 18초
log.info("총 데이터 개수 :: [{}] ", totalSize);
log.info("설정된 Batch 크기 :: [{}] ", batchSize);
// insert 카운트
int instCnt = 0;
int batchCount = 0;
// 배치별 실행 시간 기록
List<Double> batchExecutionTimes = new ArrayList<>();
// 번째 배치에서만 삽입했는지 추적하는 플래그
for (int i = 0; i < totalSize; i += batchSize) {
// Batch 시작 시간 측정
long batchStartTime = System.currentTimeMillis();
// Batch 리스트 생성
List<KakaoSendAdvcVO> batchList = kakaoSendAdvcVOList.subList(i, Math.min(i + batchSize, totalSize));
System.out.println("Batch 시작 인덱스: " + i);
// mj_msg_data 테이블 insert
int insertedCount = kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc(batchList);
/** @kakaoSendUtil.populateSendLists
* 하단에서
* getJsonStr 데이터 처리 활용
* */
instCnt += insertedCount;
// Batch 종료 시간 측정 실행 시간 계산
long batchEndTime = System.currentTimeMillis();
double batchExecutionTimeInSeconds = (batchEndTime - batchStartTime) / 1000.0;
// 실행 시간 기록
batchExecutionTimes.add(batchExecutionTimeInSeconds);
batchCount++;
}
// 종료 시간 측정
long totalEndTime = System.currentTimeMillis();
// 실행 시간 계산 (밀리초 -> 초로 변환)
double totalExecutionTimeInSeconds = (totalEndTime - totalStartTime) / 1000.0;
// 실행 시간 출력
log.info("총 배치 실행 횟수 :: [{}] ", batchCount);
log.info("batchSize :: [{}] ", batchSize);
log.info("총 실행 시간 :: [{}] ", totalExecutionTimeInSeconds + "");
log.info("총 삽입 건수 :: [{}] ", instCnt);
// 배치별 실행 시간 출력
for (int k = 0; k < batchExecutionTimes.size(); k++) {
System.out.println("배치 " + (k + 1) + " 실행 시간 :: " + batchExecutionTimes.get(k) + "");
}
return instCnt;
}
// 보유 금액이 충분한지 확인하는 메서드
private boolean isCashSufficient(String userId, List<KakaoSendAdvcVO> kakaoSendAdvcListVO) throws Exception {
String userMoney = priceAndPoint.getBefCash(userId);
// 쉼표 제거
userMoney = userMoney.replace(",", "");
// 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용)
BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN);
// 메시지 금액 계산 (HALF_EVEN 적용)
BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream()
.map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지
// 비교 수행
return befCash.compareTo(totalEachPrice) >= 0;
}
// // 보유 금액이 충분한지 확인하는 메서드
// private boolean isCashSufficient(String userId, List<KakaoSendAdvcVO> kakaoSendAdvcListVO) throws Exception {
//
//
// String userMoney = priceAndPoint.getBefCash(userId);
// // 쉼표 제거
// userMoney = userMoney.replace(",", "");
//
// // 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용)
// BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN);
//
// // 메시지 금액 계산 (HALF_EVEN 적용)
// BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream()
// .map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지
// .reduce(BigDecimal.ZERO, BigDecimal::add)
// .setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지
//
// // 비교 수행
// return befCash.compareTo(totalEachPrice) >= 0;
// }

View File

@ -1,9 +1,12 @@
package itn.let.kakao.user.kakaoFt.service.impl;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@ -20,9 +23,13 @@ import itn.com.utl.fcc.service.EgovStringUtil;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoSendUtil;
import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.kakao.user.kakaoAt.service.impl.KakaoAlimTalkDAO;
import itn.let.kakao.user.kakaoFt.service.KakaoFriendsTalkService;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.msg.service.MjonMsgVO;
import itn.let.mjo.msg.service.impl.MjonMsgDAO;
import itn.let.module.base.PriceAndPoint;
import itn.let.uss.umt.service.EgovUserManageService;
import lombok.extern.slf4j.Slf4j;
@ -36,17 +43,29 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem
@Resource(name="kakaoFriendsTalkTemplateDAO")
private KakaoFriendsTalkTemplateDAO kakaoFriendsTalkTemplateDAO;
@Resource(name="mjonMsgDAO")
private MjonMsgDAO mjonMsgDAO;
/** userManageService */
@Resource(name = "userManageService")
private EgovUserManageService userManageService;
@Autowired
private MjonCommon mjonCommon;
@Resource(name = "egovMjonMsgGroupIdGnrService")
private EgovIdGnrService idgenMjonMsgGroupId;
@Resource(name="kakaoAlimTalkDAO")
private KakaoAlimTalkDAO kakaoAlimTalkDAO;
@Autowired
KakaoSendUtil kakaoSendUtil;
@Autowired
private MjonCommon mjonCommon;
@Autowired
private PriceAndPoint priceAndPoint;
@Override
public StatusResponse insertKakaoFtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception {
StatusResponse statusResponse = new StatusResponse();
@ -103,29 +122,122 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem
/** @전송금액 확인 --------------------------------------------------*/
if (!kakaoSendUtil.isCashSufficient(userId, kakaoSendAdvcListVO)) {
log.error("Insufficient balance for message sending.");
return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다.");
}
// KakaoSendAdvcVO 발송 VO
/** @json파일이 있을 떄 biz_attachments insert */
kakaoSendUtil.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO);
Map<String, List<KakaoSendAdvcVO>> priceGroupedMessages = kakaoSendAdvcListVO.stream()
.collect(Collectors.groupingBy(KakaoSendAdvcVO::getEachPrice));
// instTotalCnt : 화면에서 보여줄 발송건수
int instTotalCnt = 0;
// 임시
List<String> nextMsgGroupIdA = new ArrayList<>();
// 대안: entrySet() 직접 사용
for (Map.Entry<String, List<KakaoSendAdvcVO>> entry : priceGroupedMessages.entrySet()) {
// entry 사용
List<KakaoSendAdvcVO> groupedMsgList = entry.getValue(); // 해당 가격의 메시지 리스트
String nextMsgGroupId = idgenMjonMsgGroupId.getNextStringId();
groupedMsgList.forEach(t -> t.setMsgGroupId(nextMsgGroupId));
// 발송 데이터 삽입
int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList);
// int instCnt = 6;
if(instCnt > 0) {
instTotalCnt += instCnt;
KakaoSendAdvcVO sendVO = groupedMsgList.get(0);
/** @groupData 테이블 insert */
kakaoSendUtil.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO);
/** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/
kakaoVO.setMsgGroupId(sendVO.getMsgGroupId());
kakaoVO.setKakaoAtPrice(Float.parseFloat(sendVO.getEachPrice()));
kakaoVO.setSmsPrice(Float.parseFloat(sendVO.getSmsPrice()));
kakaoVO.setMmsPrice(Float.parseFloat(sendVO.getMmsPrice()));
kakaoAlimTalkDAO.insertKakaoSendPrice(kakaoVO);
priceAndPoint.insertCashAndPoint(kakaoVO.getUserId()
, -Float.parseFloat(sendVO.getTotPrice())
, "카카오 알림톡 총 "+groupedMsgList.size()+"건 중 " + instCnt + "건 발송"
, nextMsgGroupId
);
/** @SLACK발송 */
/** @발송조건이되면 발송 */
if(isNotified) {
mjonCommon.getAdminKakaoAtSendSlack(sendVO);
}else if("Y".equals(kakaoVO.getAtSmishingYn())){
/** @발송조건이 안되면 DB INSERT */
mjonMsgDAO.insertSpamPassMsgData(MjonMsgVO.builder()
.msgGroupId(nextMsgGroupId)
.userId(kakaoVO.getUserId())
.reqDate(kakaoVO.getReqDate())
.smsTxt(groupedMsgList.get(0).getTemplateContent())
.totalCallCnt(instCnt)
.callFrom(kakaoVO.getCallFrom())
.msgType("8")
.reserveYn(kakaoVO.getReserveYn())
.build()
);
}
nextMsgGroupIdA.add(nextMsgGroupId);
}
}
returnMap.put("resultSts", instTotalCnt);
returnMap.put("reserYn", kakaoVO.getReserveYn());
returnMap.put("groupIds", nextMsgGroupIdA);
// 측정할 메소드 호출 시간 기록
Instant end = Instant.now();
log.info(" + start :: [{}]", start);
// 실행 시간 계산 (나노초, 밀리초, )
long seconds = Duration.between(start, end).getSeconds();
log.info("메소드 실행 시간 (초): {} s", seconds);
double minutes = seconds / 60.0; // 소수점 포함을 위해 60.0으로 나눔
returnMap.put("second", seconds+" s");
returnMap.put("minutes", minutes+" min");
// System.out.println("메소드 실행 시간 (분): " + minutes + " min");
// priceAndPoint.getBefCash(userId);
statusResponse.setStatus(HttpStatus.OK);
// statusResponse.setObject(returnMap);
statusResponse.setObject(returnMap);
return statusResponse;
}

View File

@ -700,7 +700,7 @@ function sendTemplateInfo(){
success: function (data) {
console.log('data : ', data);
var status = data.status;
/* var status = data.status;
if("OK" == status){
var resultSts = data.object.resultSts;
var reserYn = data.object.reserYn;
@ -715,7 +715,7 @@ function sendTemplateInfo(){
}else{
alert(data.message);
return false;
}
} */
// if(data == 'success'){

View File

@ -313,17 +313,12 @@ function upImgClick(){
alert("이미지 클릭시 이동할 URL 주소를 http:// 또는 https:// 포함하여 입력해 주세요.");
return false;
}else{
if(link.search("http://") == -1 && link.search("https://") == -1){
$("#imgNm").text("");
$("#imgFile").val("");
alert("이미지 URL 주소에는 http:// 또는 https://를 포함하여 입력해야 합니다.");
return false;
}
}else if(link.search("http://") == -1 && link.search("https://") == -1){
$("#imgNm").text("");
$("#imgFile").val("");
alert("이미지 URL 주소에는 http:// 또는 https://를 포함하여 입력해야 합니다.");
return false;
}
//첨부파일 선택 팝업 호출해주기
@ -891,8 +886,10 @@ function fn_sendMsgData(){
var subMsgSendYn = "N";
if($("#send_fail_check").is(":checked")){
subMsgSendYn = 'Y'
$('#callFrom').val($('#callFromList').val())
}
$("#subMsgSendYn").val(subMsgSendYn);
$("#subMsgTxt").val( $('#smsTxtArea').val());
@ -912,166 +909,120 @@ function fn_sendMsgData(){
}
var spamChk = true;
// 타블레이터 호출
var $selectedData = tableL.getData(); // 데이터 가져오기
var spmData = new FormData(document.bizForm);
$.ajax({
type: "POST"
, url: "/web/mjon/kakao/friendstalk/selectSpamKakaoFriendsTalkMsgChkAjax.do"
, data: spmData
, dataType:'json'
, async: false
, processData: false
, contentType: false
, cache: false
, success: function (returnData, status) {
if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
if("fail" == returnData.result){
alert(returnData.message);
spamChk = false;
return false;
}else if("loginFail" == returnData.result){
alert(returnData.message);
spamChk = false;
return false;
}else if("spams" == returnData.result){
//alert("전송 내용에 스팸문구가 포함되어 있습니다.")
$("#spamStatus").val("Y");
return false;
}else{
spamChk = true;
return false;
}
} else if(status== 'fail'){
alert(returnData.message);
return false;
}
}
, error: function (e) {
alert("문자 발송에 실패하였습니다.");
console.log("ERROR : ", e);
return false;
var data = $('#bizForm');
var formDataArray = data.serializeArray();
// 배열을 객체로 변환
var formData = {};
$.each(formDataArray, function(index, field) {
formData[field.name] = field.value;
});
// 2. buttonVOList 수동으로 수집
var buttonList = [];
$('input[name^="buttonVOList"]').each(function() {
let nameAttr = $(this).attr('name');
let match = nameAttr.match(/buttonVOList\[(\d+)\]\.(\w+)/);
if (match) {
let index = parseInt(match[1]);
let key = match[2];
let value = $(this).val();
if (!buttonList[index]) buttonList[index] = {};
buttonList[index][key] = value;
}
});
// 3. formData에 배열로 추가
formData["buttonVOList"] = buttonList;
// 4. 기존의 buttonVOList[0].xxx 형태 제거
Object.keys(formData).forEach(function(key) {
if (/^buttonVOList\[\d+\]\./.test(key)) {
delete formData[key];
}
});
if(spamChk){
// VO에 정의되어있지 않는 필요없는 값은 제거
["adFlag", "img_file_add", "userMoney", "callToList"].forEach(function(key) {
delete formData[key];
});
// 타블레이터 호출
var $selectedData = tableL.getData(); // 데이터 가져오기
var data = $('#bizForm');
var formDataArray = data.serializeArray();
// 배열을 객체로 변환
var formData = {};
$.each(formDataArray, function(index, field) {
formData[field.name] = field.value;
});
// 2. buttonVOList 수동으로 수집
var buttonList = [];
$('input[name^="buttonVOList"]').each(function() {
let nameAttr = $(this).attr('name');
let match = nameAttr.match(/buttonVOList\[(\d+)\]\.(\w+)/);
if (match) {
let index = parseInt(match[1]);
let key = match[2];
let value = $(this).val();
if (!buttonList[index]) buttonList[index] = {};
buttonList[index][key] = value;
}
});
// 3. formData에 배열로 추가
formData["buttonVOList"] = buttonList;
// 4. 기존의 buttonVOList[0].xxx 형태 제거
Object.keys(formData).forEach(function(key) {
if (/^buttonVOList\[\d+\]\./.test(key)) {
delete formData[key];
}
});
// VO에 정의되어있지 않는 필요없는 값은 제거
["adFlag", "img_file_add", "userMoney", "callToList"].forEach(function(key) {
delete formData[key];
});
// 빈 값 제거
removeEmptyValues(formData);
// 선택된 데이터 추가
formData["mjonFTSendVOList"] = $selectedData;
// JSON 데이터 확인
console.log("최종 formData:", JSON.stringify(formData));
$.ajax({
type: "POST"
, url: "/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendAjax_advc.do"
, data: JSON.stringify(formData)
, contentType: 'application/json'
, dataType: 'json'
, success: function (returnData) {
console.log('returnData : ', returnData);
/*
if(status == 'success'){
if("loginFail" == returnData.result){
alert(returnData.message);
return false;
}else if('fail' == returnData.result){
alert(returnData.message);
return false;
}else if('authFail' == returnData.result){
alert(returnData.message);
location.reload();
} else if(status == 'success'){
var kakaoSendCnt = returnData.resultSts;
$('.pop_msg_success').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
//예약발송 건의 경우 결과 팝업 문구 변경
if(reserYn == 'Y'){
$('.pop_msg_success .msg_text').html("예약 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>친구톡이 예약 되었습니다.");
}else{
$('.pop_msg_success .msg_text').html("발송 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>친구톡이 발송 되었습니다.");
}
$('.mask').addClass('on');
// 빈 값 제거
removeEmptyValues(formData);
// 선택된 데이터 추가
formData["mjonFTSendVOList"] = $selectedData;
// JSON 데이터 확인
console.log("최종 formData:", JSON.stringify(formData));
$.ajax({
type: "POST"
, url: "/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendAjax_advc.do"
, data: JSON.stringify(formData)
, contentType: 'application/json'
, dataType: 'json'
, success: function (returnData) {
console.log('returnData : ', returnData);
/*
if(status == 'success'){
if("loginFail" == returnData.result){
alert(returnData.message);
return false;
}else if('fail' == returnData.result){
alert(returnData.message);
return false;
}else if('authFail' == returnData.result){
alert(returnData.message);
location.reload();
} else if(status == 'success'){
var kakaoSendCnt = returnData.resultSts;
$('.pop_msg_success').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
//예약발송 건의 경우 결과 팝업 문구 변경
if(reserYn == 'Y'){
$('.pop_msg_success .msg_text').html("예약 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>친구톡이 예약 되었습니다.");
}else{
$('.pop_msg_success .msg_text').html("발송 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>친구톡이 발송 되었습니다.");
}
} */
}
,beforeSend : function(xmlHttpRequest) {
//로딩창 show
$('.loading_layer').addClass('active');
}
,complete : function(xhr, textStatus) {
//로딩창 hide
$('.loading_layer').removeClass('active');
}
,error: function (e) {
console.log("ERROR : ", e);
alert("카카오 친구톡 전송에 실패하였습니다.");
}
});
}
$('.mask').addClass('on');
}
} */
}
,beforeSend : function(xmlHttpRequest) {
//로딩창 show
$('.loading_layer').addClass('active');
}
,complete : function(xhr, textStatus) {
//로딩창 hide
$('.loading_layer').removeClass('active');
}
,error: function (e) {
console.log("ERROR : ", e);
alert("카카오 친구톡 전송에 실패하였습니다.");
}
});
}
@ -1119,6 +1070,8 @@ function fn_insertErrorYN(val){
}
//문자 바이트수 계산하기 함수
function thisFnByteString(contents){
var totalByte = 0;
@ -1282,154 +1235,6 @@ function goToKakaoTestPopUp(){
alert("받는사람 주소를 한 건 이상 입력해주세요.");
return false;
}else{
//치환문구 변환
var txtReplYn = $("#txtReplYn").val();
if(txtReplYn == 'Y'){
var name = tableL.getRows()[0].getData().name;
var phone = removeDash(tableL.getRows()[0].getData().phone);
var rep1 = tableL.getRows()[0].getData().rep1;
var rep2 = tableL.getRows()[0].getData().rep2;
var rep3 = tableL.getRows()[0].getData().rep3;
var rep4 = tableL.getRows()[0].getData().rep4;
var varValList = []; //치환문자 연결시킬 변수 셋팅
var nmStatus = false;
var rep1Status = false;
var rep2Status = false;
var rep3Status = false;
var rep4Status = false;
var varValStr = "";
var varValStatus = true;
if(tmpContents.indexOf("\#{이름}") > -1){
nmStatus = true;
}
if(tmpContents.indexOf("\#{1}") > -1){
rep1Status = true;
}
if(tmpContents.indexOf("\#{2}") > -1){
rep2Status = true;
}
if(tmpContents.indexOf("\#{3}") > -1){
rep3Status = true;
}
if(tmpContents.indexOf("\#{4}") > -1){
rep4Status = true;
}
if(nmStatus && (typeof(name) != 'undefined' && name != null && name !="")){
if(varValStr == ''){
varValStr = name.replaceAll(",","§");
}else{
varValStr = varValStr + "¶" + name.replaceAll(",","§");
}
}else{
if(nmStatus){
varValStatus = false;
}
}
if(varValStr == ''){
varValStr = phone;
}else{
varValStr = varValStr + "¶" + phone;
}
if(rep1Status && (typeof(rep1) != 'undefined' && rep1 != null && rep1 !="")){
if(varValStr == ''){
varValStr = rep1.replaceAll(",","§");
}else{
varValStr = varValStr + "¶" + rep1.replaceAll(",","§");
}
}else{
if(rep1Status){
varValStatus = false;
}
}
if(rep2Status && (typeof(rep2) != 'undefined' && rep2 != null && rep2 !="")){
if(varValStr == ''){
varValStr = rep2.replaceAll(",","§");
}else{
varValStr = varValStr + "¶" + rep2.replaceAll(",","§");
}
}else{
if(rep2Status){
varValStatus = false;
}
}
if(rep3Status && (typeof(rep3) != 'undefined' && rep3 != null && rep3 !="")){
if(varValStr == ''){
varValStr = rep3.replaceAll(",","§");
}else{
varValStr = varValStr + "¶" + rep3.replaceAll(",","§");
}
}else{
if(rep3Status){
varValStatus = false;
}
}
if(rep4Status && (typeof(rep4) != 'undefined' && rep4 != null && rep4 !="")){
if(varValStr == ''){
varValStr = rep4.replaceAll(",","§");
}else{
varValStr = varValStr + "¶" + rep4.replaceAll(",","§");
}
}else{
if(rep4Status){
varValStatus = false;
}
}
if(!varValStatus){
alert("특정문구 일괄변환에 대한 일부 데이터가 누락된 부분이 있습니다. 데이터를 확인해 주세요.");
return false;
}
varValList[0] = varValStr;
$("#varValList").val(varValList);
}
}
form.method = "post";
@ -1730,13 +1535,13 @@ function updateButtons(){
<p>주소록, 엑셀에 입력된 내용을 이용해 수신자마다 다른 내용의 메시지를 발송하는 기능</p>
</div>
<div class="convers_middle">
<a href="javascript:void(0)" class="changeWord" value="\#{이름}"><c:out value="\#{이름}"/></a>
<a href="javascript:void(0)" class="changeWord" value="[*이름*]"><c:out value="[*이름*]"/></a>
</div>
<div class="convers_bottom">
<a href="javascript:void(0)" class="changeWord" value="\#{1}"><c:out value="\#{1}"/></a>
<a href="javascript:void(0)" class="changeWord" value="\#{2}"><c:out value="\#{2}"/></a>
<a href="javascript:void(0)" class="changeWord" value="\#{3}"><c:out value="\#{3}"/></a>
<a href="javascript:void(0)" class="changeWord" value="\#{4}"><c:out value="\#{4}"/></a>
<a href="javascript:void(0)" class="changeWord" value="[*1*]"><c:out value="[*1*]"/></a>
<a href="javascript:void(0)" class="changeWord" value="[*2*]"><c:out value="[*2*]"/></a>
<a href="javascript:void(0)" class="changeWord" value="[*3*]"><c:out value="[*3*]"/></a>
<a href="javascript:void(0)" class="changeWord" value="[*4*]"><c:out value="[*4*]"/></a>
</div>
</div>
<button type="button" class="btn_close" onclick="miniPopup(this)">닫기</button>
@ -2053,7 +1858,7 @@ function updateButtons(){
<ul class="thumb_wrap liOnImg ui-sortable"></ul>
<!-- //업로드한 이미지의 썸네일 영역 -->
<label for="smsTxtArea" class="label"></label>
<textarea id="smsTxtArea" name="smsTxtArea" class="put_text"></textarea>
<textarea id="smsTxtArea" class="put_text"></textarea>
<div class="text_length">
<div name="afterDeny">
<p>
@ -2066,7 +1871,7 @@ function updateButtons(){
</div>
<div class="put_right">
<button type="button" class="btnType btnType9" id="failCheckInit">초기화</button>
<button type="button" class="btnType btnType7" onclick="javascript:fn_errorChk(); return false;">오류검사<i class="qmMark"></i></button>
<!-- <button type="button" class="btnType btnType7" onclick="javascript:fn_errorChk(); return false;">오류검사<i class="qmMark"></i></button> -->
</div>
</div>
</td>

View File

@ -557,10 +557,10 @@ function fn_sentDetailView(msgGroupId) {
<ul class="list_tab">
<li class="tab active"><button type="button" onclick="fnTabLoad('',0); return false;">전체</button></li>
<li class="tab"><button type="button" onclick="fnTabLoad('at', 1); return false;">알림톡</button></li>
<%-- <c:if test="${pageContext.request.serverName == 'localhost'
<c:if test="${pageContext.request.serverName == 'localhost'
|| pageContext.request.serverName == '119.193.215.98'}">
<li class="tab"><button type="button" onclick="fnTabLoad('ft', 2); return false;">친구톡</button></li>
</c:if> --%>
</c:if>
</ul><!--// tab button -->
</div>
<!-- 예약관리 > 전체 -->