친구톡 발송 완료
This commit is contained in:
parent
f5029faba2
commit
2376446be3
@ -351,9 +351,12 @@ public class LogAspect {
|
|||||||
case "MjKakaoProfileInfoVO":
|
case "MjKakaoProfileInfoVO":
|
||||||
case "BizTemplateRequest":
|
case "BizTemplateRequest":
|
||||||
case "MsgAtRequestVO":
|
case "MsgAtRequestVO":
|
||||||
|
case "MsgFtRequestVO":
|
||||||
|
case "String":
|
||||||
|
case "ArrayList":
|
||||||
return ApiObjectUtil.toJson(returnValue);
|
return ApiObjectUtil.toJson(returnValue);
|
||||||
default:
|
default:
|
||||||
log.info("데이터를 추가해 주세요");
|
log.info("데이터를 추가해 주세요 [{}]", classNm);
|
||||||
return "데이터를 추가해 주세요";
|
return "데이터를 추가해 주세요";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -145,6 +145,9 @@ public class ApiService <T> {
|
|||||||
if (msgFtRequestVO.getSendKind() != null) {
|
if (msgFtRequestVO.getSendKind() != null) {
|
||||||
body.add("sendKind", msgFtRequestVO.getSendKind());
|
body.add("sendKind", msgFtRequestVO.getSendKind());
|
||||||
}
|
}
|
||||||
|
if ( msgFtRequestVO.getTemplateMsgType() != null) {
|
||||||
|
body.add("imageType", msgFtRequestVO.getTemplateMsgType());
|
||||||
|
}
|
||||||
if (msgFtRequestVO.getTemplateCode() != null) {
|
if (msgFtRequestVO.getTemplateCode() != null) {
|
||||||
body.add("templateCode", msgFtRequestVO.getTemplateCode());
|
body.add("templateCode", msgFtRequestVO.getTemplateCode());
|
||||||
}
|
}
|
||||||
@ -159,7 +162,7 @@ public class ApiService <T> {
|
|||||||
StatusResponse.class
|
StatusResponse.class
|
||||||
);
|
);
|
||||||
|
|
||||||
log.info("Upload response :: [{}]", response.getBody());
|
// log.info("Upload response :: [{}]", response.getBody());
|
||||||
return response.getBody();
|
return response.getBody();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,7 @@ public enum StatMsg {
|
|||||||
, STAT_2040("2040","본문 데이터 오류")
|
, STAT_2040("2040","본문 데이터 오류")
|
||||||
, STAT_2041("2041","타이틀 데이터 오류")
|
, STAT_2041("2041","타이틀 데이터 오류")
|
||||||
, STAT_2042("2042","대체문자 데이터 오류")
|
, STAT_2042("2042","대체문자 데이터 오류")
|
||||||
|
, STAT_2043("2043","대체문자 발송 시 발신번호가 필요합니다.")
|
||||||
|
|
||||||
, STAT_2050("2050","지원하지 않는 이미지 형식입니다.")
|
, STAT_2050("2050","지원하지 않는 이미지 형식입니다.")
|
||||||
, STAT_2051("2051","이미지 용량은 5MB 이내여야 합니다.")
|
, STAT_2051("2051","이미지 용량은 5MB 이내여야 합니다.")
|
||||||
@ -60,6 +61,8 @@ public enum StatMsg {
|
|||||||
, STAT_2056("2056","비율 2:1 이상 또는 3:4 이하만 허용됩니다.")
|
, STAT_2056("2056","비율 2:1 이상 또는 3:4 이하만 허용됩니다.")
|
||||||
, STAT_2057("2057","대체문자(MMS) 이미지는 10MB를 초과할 수 없습니다.")
|
, STAT_2057("2057","대체문자(MMS) 이미지는 10MB를 초과할 수 없습니다.")
|
||||||
|
|
||||||
|
, STAT_2080("2080","친구톡은 20시 50분부터 익일 08시까지 발송이 제한됩니다.")
|
||||||
|
|
||||||
, STAT_2099("2099","기타 시스템 오류")
|
, STAT_2099("2099","기타 시스템 오류")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@ToString
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class KakaoFTSendVO {
|
||||||
|
|
||||||
|
// 카카오 발신 관련
|
||||||
|
private String mberId; // mberId
|
||||||
|
private String senderKey; // 카카오 발신 키 (필수)
|
||||||
|
private String adFlag; // 카카오 발신 키 (필수)
|
||||||
|
|
||||||
|
// 이미지 관련
|
||||||
|
private String imageFileName; // 이미지 파일명
|
||||||
|
private String imageType; // 이미지 타입 (I: 이미지, null: 텍스트만)
|
||||||
|
private String atchFileId; // 첨부파일 ID
|
||||||
|
private String templateImageUrl; // 친구톡 이미지 URL
|
||||||
|
|
||||||
|
// 메시지 내용
|
||||||
|
private String templateContent; // 친구톡 발송 내용 (개별 수신자별)
|
||||||
|
private String subMsgSendYn; // 대체문자 발송여부
|
||||||
|
private String subMsgTxt; // 대체문자 내용 (개별 수신자별)
|
||||||
|
|
||||||
|
// 발송 관련
|
||||||
|
private String reserveYn; // 예약발송 여부 (기본: N)
|
||||||
|
private String callFrom; // 발신번호
|
||||||
|
private String reqDate; // 요청일시 (예약발송시)
|
||||||
|
private String sendKind; // 발송 구분 , A : API / H : 사이트
|
||||||
|
|
||||||
|
// 버튼 정보 (모든 수신자 공통)
|
||||||
|
@Builder.Default
|
||||||
|
private List<KakaoButtonVO> buttonVOList = new ArrayList<>();
|
||||||
|
|
||||||
|
// 수신자 목록 (핵심: 개별 발송시 1명만 포함)
|
||||||
|
@Builder.Default
|
||||||
|
private List<MjonFTSendVO> mjonFTSendVOList = new ArrayList<>();
|
||||||
|
}
|
||||||
@ -55,9 +55,6 @@ public class MsgFtRequestVO implements Serializable {
|
|||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
private MultipartFile templateImage;
|
private MultipartFile templateImage;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
@ToString.Exclude
|
|
||||||
private MultipartFile subImage;
|
|
||||||
|
|
||||||
// ====== ⬇️ AOP/DB 저장용(문자열/숫자만) 메타데이터 필드들 ======
|
// ====== ⬇️ AOP/DB 저장용(문자열/숫자만) 메타데이터 필드들 ======
|
||||||
// template
|
// template
|
||||||
@ -70,9 +67,31 @@ public class MsgFtRequestVO implements Serializable {
|
|||||||
private String templateImageSavedPath; // 서버 저장 경로(선택)
|
private String templateImageSavedPath; // 서버 저장 경로(선택)
|
||||||
private String templateAtchFileId; // 내부 첨부ID(선택)
|
private String templateAtchFileId; // 내부 첨부ID(선택)
|
||||||
private String templateMsgType;
|
private String templateMsgType;
|
||||||
private String templateImageUrl;
|
|
||||||
|
/**
|
||||||
|
* @description : 친구톡 이미지 등록된 URL
|
||||||
|
*/
|
||||||
|
private String templateImageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : 치환문자 이미지
|
||||||
|
* 이미지 문자가 있고 대체문자가 있으면(subMsgSendYn="Y") filepath에 atchFileId 있어야함
|
||||||
|
*/
|
||||||
|
private String filePath1;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : 버튼 사용
|
||||||
|
*/
|
||||||
|
private List<FtButtonVO> buttons = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
// sub
|
// sub
|
||||||
|
|
||||||
|
// @JsonIgnore
|
||||||
|
// @ToString.Exclude
|
||||||
|
// private MultipartFile subImage;
|
||||||
|
|
||||||
// private String subImageName;
|
// private String subImageName;
|
||||||
// private String subImageContentType;
|
// private String subImageContentType;
|
||||||
// private Long subImageSize;
|
// private Long subImageSize;
|
||||||
|
|||||||
@ -5,9 +5,6 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
@ -29,15 +26,6 @@ public class VarFtListMapVO {
|
|||||||
*/
|
*/
|
||||||
private String subMsgTxt;
|
private String subMsgTxt;
|
||||||
|
|
||||||
/**
|
|
||||||
* @description : 치환문자 이미지
|
|
||||||
*/
|
|
||||||
private String filePath1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description : 버튼 사용
|
|
||||||
*/
|
|
||||||
private List<FtButtonVO> buttons = new ArrayList<>();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// /**
|
// /**
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public class FtIndexedParameterParserService {
|
|||||||
* @param request HTTP 요청 객체
|
* @param request HTTP 요청 객체
|
||||||
* @return 파싱된 VarListMapVO 리스트
|
* @return 파싱된 VarListMapVO 리스트
|
||||||
*/
|
*/
|
||||||
public List<VarFtListMapVO> parseIndexedParameters(MsgFtRequestVO msgAtRequestVO, HttpServletRequest request) {
|
public List<VarFtListMapVO> parseIndexedParameters(MsgFtRequestVO msgFtRequestVO, HttpServletRequest request) {
|
||||||
List<VarFtListMapVO> varListMap = new ArrayList<>();
|
List<VarFtListMapVO> varListMap = new ArrayList<>();
|
||||||
|
|
||||||
// 모든 파라미터 맵 가져오기
|
// 모든 파라미터 맵 가져오기
|
||||||
@ -51,7 +51,7 @@ public class FtIndexedParameterParserService {
|
|||||||
Map<Integer, Map<String, String>> indexedDataMap = new HashMap<>();
|
Map<Integer, Map<String, String>> indexedDataMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
String subMsgSendYn = msgAtRequestVO.getSubMsgSendYn();
|
String subMsgSendYn = msgFtRequestVO.getSubMsgSendYn();
|
||||||
|
|
||||||
// 모든 파라미터를 순회하며 인덱스된 파라미터 찾기
|
// 모든 파라미터를 순회하며 인덱스된 파라미터 찾기
|
||||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||||
@ -84,18 +84,24 @@ public class FtIndexedParameterParserService {
|
|||||||
if("Y".equals(subMsgSendYn)){
|
if("Y".equals(subMsgSendYn)){
|
||||||
vo.setSubMsgTxt(dataMap.get("subMsgTxt"));
|
vo.setSubMsgTxt(dataMap.get("subMsgTxt"));
|
||||||
}
|
}
|
||||||
|
// 필수 필드 중 하나라도 있으면 리스트에 추가
|
||||||
|
if (vo.getPhone() != null || vo.getTemplateContent() != null) {
|
||||||
|
varListMap.add(vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 버튼 데이터 처리
|
// 버튼 파라미터를 요청 레벨에서 한 번만 파싱
|
||||||
String buttonData = dataMap.get("button");
|
String buttonData = request.getParameter("button");
|
||||||
if (buttonData != null && !buttonData.trim().isEmpty()) {
|
|
||||||
try {
|
|
||||||
JsonNode buttonJson = objectMapper.readTree(buttonData);
|
|
||||||
JsonNode buttonArray = buttonJson.get("button");
|
|
||||||
|
|
||||||
List<FtButtonVO> buttonList = new ArrayList<>();
|
if (buttonData != null && !buttonData.trim().isEmpty()) {
|
||||||
if (buttonArray != null && buttonArray.isArray()) {
|
try {
|
||||||
for (JsonNode button : buttonArray) {
|
JsonNode buttonJson = objectMapper.readTree(buttonData);
|
||||||
FtButtonVO ftButton = FtButtonVO.builder()
|
JsonNode buttonArray = buttonJson.get("button");
|
||||||
|
|
||||||
|
List<FtButtonVO> buttonList = new ArrayList<>();
|
||||||
|
if (buttonArray != null && buttonArray.isArray()) {
|
||||||
|
for (JsonNode button : buttonArray) {
|
||||||
|
FtButtonVO ftButton = FtButtonVO.builder()
|
||||||
.name(getJsonText(button, "name"))
|
.name(getJsonText(button, "name"))
|
||||||
.linkType(getJsonText(button, "linkType"))
|
.linkType(getJsonText(button, "linkType"))
|
||||||
.linkTypeName(getJsonText(button, "linkTypeName"))
|
.linkTypeName(getJsonText(button, "linkTypeName"))
|
||||||
@ -104,25 +110,18 @@ public class FtIndexedParameterParserService {
|
|||||||
.linkIos(getJsonText(button, "linkIos"))
|
.linkIos(getJsonText(button, "linkIos"))
|
||||||
.linkAnd(getJsonText(button, "linkAnd"))
|
.linkAnd(getJsonText(button, "linkAnd"))
|
||||||
.build();
|
.build();
|
||||||
buttonList.add(ftButton);
|
buttonList.add(ftButton);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vo.setButtons(buttonList);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("버튼 JSON 파싱 실패 - index: {}, data: {}", index, buttonData, e);
|
|
||||||
vo.setButtons(new ArrayList<>());
|
|
||||||
}
|
}
|
||||||
|
// ✅ MsgFtRequestVO에 버튼 설정 (모든 수신자 공통)
|
||||||
|
msgFtRequestVO.setButtons(buttonList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("버튼 JSON 파싱 실패: {}", buttonData, e);
|
||||||
|
msgFtRequestVO.setButtons(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 필수 필드 중 하나라도 있으면 리스트에 추가
|
|
||||||
if (vo.getPhone() != null || vo.getTemplateContent() != null) {
|
|
||||||
varListMap.add(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return varListMap;
|
return varListMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +1,25 @@
|
|||||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service;
|
package com.itn.mjonApi.mjon.api.kakao.ft.send.service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.itn.mjonApi.cmn.domain.StatusResponse;
|
||||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
|
||||||
import com.itn.mjonApi.cmn.domain.biz.template.detail.TemplateDetailResponse;
|
|
||||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
|
||||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain.MjKakaoProfileInfoVO;
|
import com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain.MjKakaoProfileInfoVO;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.service.InqryService;
|
import com.itn.mjonApi.mjon.api.kakao.at.inqry.service.InqryService;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.VarFtListMapVO;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.VarFtListMapVO;
|
||||||
|
import com.itn.mjonApi.mjon.api.kakao.utils.FtFileMetaUtil;
|
||||||
import com.itn.mjonApi.util.MunjaUtil;
|
import com.itn.mjonApi.util.MunjaUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fileName : AtParameterProcessingService.java
|
* fileName : AtParameterProcessingService.java
|
||||||
@ -40,6 +42,12 @@ public class FtParameterProcessingService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private InqryService inqryService;
|
private InqryService inqryService;
|
||||||
|
|
||||||
|
private ApiService<Response> apiService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FtParameterProcessingService(ApiService<Response> apiService) {
|
||||||
|
this.apiService = apiService;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하고 검증하여
|
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하고 검증하여
|
||||||
* MsgAtRequestVO의 varListMap에 설정
|
* MsgAtRequestVO의 varListMap에 설정
|
||||||
@ -63,11 +71,12 @@ public class FtParameterProcessingService {
|
|||||||
// if (STAT_2030 != null) return STAT_2030;
|
// if (STAT_2030 != null) return STAT_2030;
|
||||||
|
|
||||||
// 파싱 로직을 IndexedParameterParserService에 위임
|
// 파싱 로직을 IndexedParameterParserService에 위임
|
||||||
|
log.info("msgFtRequestVO.getAdFlag() :: [{}]", msgFtRequestVO.getAdFlag());
|
||||||
List<VarFtListMapVO> parsedList = indexedParameterParserService.parseIndexedParameters(msgFtRequestVO, request);
|
List<VarFtListMapVO> parsedList = indexedParameterParserService.parseIndexedParameters(msgFtRequestVO, request);
|
||||||
|
|
||||||
// 파싱된 각 VO에 대해 검증 수행
|
// 파싱된 각 VO에 대해 검증 수행
|
||||||
for (VarFtListMapVO vo : parsedList) {
|
for (VarFtListMapVO vo : parsedList) {
|
||||||
String validationError = MunjaUtil.kakaoFtValidate(vo, msgFtRequestVO.getSubMsgSendYn());
|
String validationError = MunjaUtil.kakaoFtValidate(vo, msgFtRequestVO);
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(validationError)) {
|
if (StringUtils.isNotEmpty(validationError)) {
|
||||||
return validationError; // 검증 실패 시 오류 코드 반환
|
return validationError; // 검증 실패 시 오류 코드 반환
|
||||||
@ -80,35 +89,6 @@ public class FtParameterProcessingService {
|
|||||||
return null; // 모든 검증 통과
|
return null; // 모든 검증 통과
|
||||||
}
|
}
|
||||||
|
|
||||||
private String validateTemplateCode(String mberId, String senderKey, String templateCode) {
|
|
||||||
try {
|
|
||||||
BizTemplateRequest request = BizTemplateRequest.builder()
|
|
||||||
.mberId(mberId)
|
|
||||||
.senderKey(senderKey)
|
|
||||||
.templateCode(templateCode)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
RestResponse response = inqryService.getTemplateDetail(request);
|
|
||||||
JsonNode node = new ObjectMapper().valueToTree(response.getData());
|
|
||||||
// 전체 출력
|
|
||||||
// log.info("data 전체 :: {}", node.toPrettyString());
|
|
||||||
// resultCode가 있으면 채널ID 오류 + inqryService.getTemplateDetail 참조
|
|
||||||
if (node.has("resultCode")) {
|
|
||||||
return "STAT_"+node.get("resultCode").asText();
|
|
||||||
}
|
|
||||||
|
|
||||||
TemplateDetailResponse detail = (TemplateDetailResponse)
|
|
||||||
response.getData();
|
|
||||||
|
|
||||||
// 템플릿 상세 정보 활용
|
|
||||||
log.info("template detail :: [{}]", detail);
|
|
||||||
return "200".equals(detail.getCode()) ? null : "STAT_2030";
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return "STAT_2099";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String validateSenderKey(String mberId, String senderKey) {
|
public String validateSenderKey(String mberId, String senderKey) {
|
||||||
if (StringUtils.isEmpty(senderKey)) {
|
if (StringUtils.isEmpty(senderKey)) {
|
||||||
@ -120,6 +100,41 @@ public class FtParameterProcessingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getImagesInfo(MsgFtRequestVO msgFtRequestVO) throws IOException, NoSuchAlgorithmException {
|
||||||
|
|
||||||
|
log.info("msgFtRequestVO.getTemplateImage() : [{}]", msgFtRequestVO.getTemplateImage());
|
||||||
|
if (FtFileMetaUtil.hasFile(msgFtRequestVO.getTemplateImage())) {
|
||||||
|
String code = FtFileMetaUtil.fillTemplateMeta(msgFtRequestVO);
|
||||||
|
if (StringUtils.isNotEmpty(code)) return code;
|
||||||
|
|
||||||
|
// 메타데이터 처리 성공 후 업로드 API 호출
|
||||||
|
try {
|
||||||
|
// Option 1: ApiService에 multipart 메소드 추가
|
||||||
|
StatusResponse uploadResponse = apiService.postMultipartForEntity(
|
||||||
|
"/web/mjon/kakao/template/sendKakaoFriendsTemplateImageUploadAjax_advc.do",
|
||||||
|
msgFtRequestVO,
|
||||||
|
msgFtRequestVO.getTemplateImage()
|
||||||
|
);
|
||||||
|
// .is2xxSuccessful() 상태코드가 200번대(200 ~ 299)인지 확인
|
||||||
|
if (uploadResponse != null && uploadResponse.getStatus().is2xxSuccessful()) {
|
||||||
|
Map<String, Object> obj = (Map<String, Object>) uploadResponse.getObject();
|
||||||
|
String imgUrl = (String) obj.get("imgUrl");
|
||||||
|
String atchFileId = (String) obj.get("atchFileId");
|
||||||
|
|
||||||
|
log.info("imgUrl: {}, atchFileId: {}", imgUrl, atchFileId);
|
||||||
|
msgFtRequestVO.setTemplateImageUrl(imgUrl);
|
||||||
|
msgFtRequestVO.setFilePath1(atchFileId);
|
||||||
|
}else{
|
||||||
|
// return new RestResponse(new FailRestResponse("STAT_2099", ""));
|
||||||
|
return "STAT_2099";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("템플릿 이미지 업로드 실패", e);
|
||||||
|
return "STAT_2099";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +1,14 @@
|
|||||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service.impl;
|
package com.itn.mjonApi.mjon.api.kakao.ft.send.service.impl;
|
||||||
|
|
||||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||||
import com.itn.mjonApi.cmn.domain.StatusResponse;
|
|
||||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.*;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.service.FtParameterProcessingService;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.service.FtParameterProcessingService;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.service.SendFtService;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.service.SendFtService;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.utils.FtFileMetaUtil;
|
|
||||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.PriceMapper;
|
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.PriceMapper;
|
||||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.SendMapper;
|
import com.itn.mjonApi.mjon.api.msg.send.mapper.SendMapper;
|
||||||
|
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MjonResponseVO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -19,6 +18,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -60,48 +61,7 @@ public class SendFtServiceImpl implements SendFtService {
|
|||||||
// return this._getTestMsgReturnData(msgRequestVO.getTest_yn());
|
// return this._getTestMsgReturnData(msgRequestVO.getTest_yn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 데이터
|
||||||
|
|
||||||
if (FtFileMetaUtil.hasFile(msgFtRequestVO.getTemplateImage())) {
|
|
||||||
String code = FtFileMetaUtil.fillTemplateMeta(msgFtRequestVO);
|
|
||||||
if (StringUtils.isNotEmpty(code)) return new RestResponse(new FailRestResponse(code, ""));
|
|
||||||
}
|
|
||||||
// if (FtFileMetaUtil.hasFile(msgFtRequestVO.getSubImage())) {
|
|
||||||
// code = FtFileMetaUtil.fillSubMeta(msgFtRequestVO);
|
|
||||||
// if (StringUtils.isNotEmpty(code)) return new RestResponse(new FailRestResponse(code, ""));
|
|
||||||
// }
|
|
||||||
if (FtFileMetaUtil.hasFile(msgFtRequestVO.getTemplateImage())) {
|
|
||||||
String code = FtFileMetaUtil.fillTemplateMeta(msgFtRequestVO);
|
|
||||||
if (StringUtils.isNotEmpty(code)) return new RestResponse(new FailRestResponse(code, ""));
|
|
||||||
|
|
||||||
// 메타데이터 처리 성공 후 업로드 API 호출
|
|
||||||
try {
|
|
||||||
// Option 1: ApiService에 multipart 메소드 추가
|
|
||||||
StatusResponse uploadResponse = apiService.postMultipartForEntity(
|
|
||||||
"/web/mjon/kakao/template/sendKakaoFriendsTemplateImageUploadAjax_advc.do",
|
|
||||||
msgFtRequestVO,
|
|
||||||
msgFtRequestVO.getTemplateImage()
|
|
||||||
);
|
|
||||||
|
|
||||||
log.info("전체 StatusResponse :: [{}]", uploadResponse);
|
|
||||||
log.info("object 필드만 :: [{}]", uploadResponse.getObject());
|
|
||||||
|
|
||||||
// 업로드 결과 처리
|
|
||||||
// if ("OK".equals(uploadResponse.getResult())) {
|
|
||||||
// // 성공 처리
|
|
||||||
// log.info("템플릿 이미지 업로드 성공");
|
|
||||||
// } else {
|
|
||||||
// // 실패 처리
|
|
||||||
// return new RestResponse(new FailRestResponse(uploadResponse.getStatCode(), ""));
|
|
||||||
// }
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("템플릿 이미지 업로드 실패", e);
|
|
||||||
return new RestResponse(new FailRestResponse("UPLOAD_ERROR", ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Form-data의 인덱스된 파라미터들을 VarListMapVO 리스트로 변환 (동적 처리 _1~_100)
|
// Form-data의 인덱스된 파라미터들을 VarListMapVO 리스트로 변환 (동적 처리 _1~_100)
|
||||||
String falseCode = ftParameterProcessingService.processIndexedParameters(msgFtRequestVO, request);
|
String falseCode = ftParameterProcessingService.processIndexedParameters(msgFtRequestVO, request);
|
||||||
if(StringUtils.isNotEmpty(falseCode)){
|
if(StringUtils.isNotEmpty(falseCode)){
|
||||||
@ -109,29 +69,128 @@ public class SendFtServiceImpl implements SendFtService {
|
|||||||
return new RestResponse(new FailRestResponse(falseCode,""));
|
return new RestResponse(new FailRestResponse(falseCode,""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 이미지 정제
|
||||||
|
String falseImageCode = ftParameterProcessingService.getImagesInfo(msgFtRequestVO);
|
||||||
|
if(StringUtils.isNotEmpty(falseImageCode)) return new RestResponse(new FailRestResponse(falseImageCode,""));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
// ========== 새로운 개별 발송 코드 ==========
|
||||||
//
|
List<MjonResponseVO> responses = new ArrayList<>();
|
||||||
//
|
List<String> successList = new ArrayList<>();
|
||||||
//
|
List<String> failList = new ArrayList<>();
|
||||||
// MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
|
||||||
// "/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendAjax_advc.do"
|
|
||||||
// , msgFtRequestVO
|
|
||||||
// , String.class
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
|
||||||
// convertMjonDataToApiResponse => MjonResponseVO 데이터를 ApiResponse 데이터로 변환하는 메소드
|
log.info("msgFtRequestVO.toString() :: [{}]", msgFtRequestVO.toString());
|
||||||
// log.info(" + munjaSendResponse :: [{}]", munjaSendResponse.toString());
|
// 각 수신자별로 개별 발송 처리
|
||||||
// if("OK".equals(munjaSendResponse.getResult())){ // 성공
|
// List<KakaoFTSendVO> individualRequestList = new ArrayList<>();
|
||||||
// return new RestResponse(SendSucRestResponse.convertMjonDataToApiResponse(munjaSendResponse));
|
for (VarFtListMapVO recipient : msgFtRequestVO.getVarListMap()) {
|
||||||
// }else{ // 실패
|
try {
|
||||||
// return new RestResponse(new FailRestResponse(munjaSendResponse.getStatCode(),""));
|
// 개별 수신자용 KakaoFTSendVO 생성
|
||||||
// }
|
KakaoFTSendVO individualRequest = createKakaoFTSendVO(msgFtRequestVO, recipient);
|
||||||
|
// individualRequestList.add(individualRequest);
|
||||||
|
|
||||||
return new RestResponse(msgFtRequestVO);
|
log.info("individualRequest: {}", individualRequest);
|
||||||
|
|
||||||
|
// 개별 API 호출
|
||||||
|
MjonResponseVO response = apiService.postForEntity(
|
||||||
|
"/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendAjax_advc.do",
|
||||||
|
individualRequest,
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
log.info("response: {}", response);
|
||||||
|
|
||||||
|
responses.add(response);
|
||||||
|
successList.add(recipient.getPhone());
|
||||||
|
|
||||||
|
log.info("개별 발송 성공 - 수신번호: {}", recipient.getPhone());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("개별 발송 실패 - 수신번호: {}, 오류: {}", recipient.getPhone(), e.getMessage());
|
||||||
|
failList.add(recipient.getPhone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMS API 형태의 응답 생성
|
||||||
|
FtSendSuccessResponse ftResponse = FtSendSuccessResponse.createFtResponse(
|
||||||
|
msgFtRequestVO.getVarListMap().size(),
|
||||||
|
successList.size(),
|
||||||
|
failList.size(),
|
||||||
|
successList
|
||||||
|
);
|
||||||
|
|
||||||
|
return new RestResponse(ftResponse);
|
||||||
|
// return new RestResponse(individualRequestList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MsgFtRequestVO + VarFtListMapVO를 KakaoFTSendVO로 변환
|
||||||
|
* (개별 수신자용 객체 생성)
|
||||||
|
*/
|
||||||
|
private KakaoFTSendVO createKakaoFTSendVO(MsgFtRequestVO source, VarFtListMapVO recipient) {
|
||||||
|
|
||||||
|
// 버튼 변환 (FtButtonVO → KakaoButtonVO)
|
||||||
|
List<KakaoButtonVO> kakaoButtons = source.getButtons().stream()
|
||||||
|
.map(this::convertToKakaoButton)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 개별 수신자 객체 생성
|
||||||
|
MjonFTSendVO mjonFTSend = MjonFTSendVO.builder()
|
||||||
|
.phone(recipient.getPhone()) // 핵심: 수신번호
|
||||||
|
// .callTo(recipient.getPhone()) // 동일값
|
||||||
|
// .eventYn("N") // 기본값
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// KakaoFTSendVO 생성
|
||||||
|
return KakaoFTSendVO.builder()
|
||||||
|
// 공통 정보 (모든 요청에 동일)
|
||||||
|
|
||||||
|
.mberId(source.getMberId())
|
||||||
|
.sendKind(source.getSendKind())
|
||||||
|
.reserveYn("N")
|
||||||
|
.adFlag(source.getAdFlag())
|
||||||
|
|
||||||
|
.senderKey(source.getSenderKey())
|
||||||
|
.callFrom(source.getCallFrom())
|
||||||
|
.buttonVOList(kakaoButtons)
|
||||||
|
|
||||||
|
// 이미지 관련
|
||||||
|
.templateImageUrl(source.getTemplateImageUrl())
|
||||||
|
.atchFileId(source.getFilePath1())
|
||||||
|
.imageType(source.getTemplateImageUrl() != null ? source.getTemplateMsgType() : null)
|
||||||
|
// .imageFileName(extractFileName(source.getTemplateImageUrl()))
|
||||||
|
.imageFileName(source.getTemplateImageName())
|
||||||
|
|
||||||
|
// 개별 수신자 정보
|
||||||
|
.templateContent(recipient.getTemplateContent()) // 개별 내용
|
||||||
|
.subMsgSendYn(source.getSubMsgSendYn()) // 개별 대체문자
|
||||||
|
.subMsgTxt(recipient.getSubMsgTxt()) // 개별 대체문자
|
||||||
|
.mjonFTSendVOList(Arrays.asList(mjonFTSend)) // 단일 수신자만
|
||||||
|
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FtButtonVO를 KakaoButtonVO로 변환
|
||||||
|
*/
|
||||||
|
private KakaoButtonVO convertToKakaoButton(FtButtonVO source) {
|
||||||
|
return KakaoButtonVO.builder()
|
||||||
|
.name(source.getName())
|
||||||
|
.linkType(source.getLinkType())
|
||||||
|
.linkTypeName(source.getLinkTypeName())
|
||||||
|
.linkMo(source.getLinkMo())
|
||||||
|
.linkPc(source.getLinkPc())
|
||||||
|
.linkIos(source.getLinkIos())
|
||||||
|
.linkAnd(source.getLinkAnd())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 이미지 URL에서 파일명 추출
|
||||||
|
*/
|
||||||
|
private String extractFileName(String imageUrl) {
|
||||||
|
if (imageUrl == null) return null;
|
||||||
|
return imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.itn.mjonApi.util;
|
package com.itn.mjonApi.util;
|
||||||
|
|
||||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.VarAtListMapVO;
|
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.VarAtListMapVO;
|
||||||
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
||||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.VarFtListMapVO;
|
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.VarFtListMapVO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
@ -141,7 +142,7 @@ public class MunjaUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String kakaoFtValidate(VarFtListMapVO vo, String subMsgSendYn) {
|
public static String kakaoFtValidate(VarFtListMapVO vo, MsgFtRequestVO msgFtRequestVO) {
|
||||||
|
|
||||||
log.info(" vo.toString() [{}]", vo.toString());
|
log.info(" vo.toString() [{}]", vo.toString());
|
||||||
|
|
||||||
@ -158,11 +159,17 @@ public class MunjaUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 대체문자 검증 (대체문자 발송이 활성화된 경우에만)
|
// 대체문자 검증 (대체문자 발송이 활성화된 경우에만)
|
||||||
if ("Y".equals(subMsgSendYn)) {
|
if ("Y".equals(msgFtRequestVO.getSubMsgSendYn())) {
|
||||||
String subMsgTxt = vo.getSubMsgTxt();
|
String subMsgTxt = vo.getSubMsgTxt();
|
||||||
if (StringUtils.isEmpty(subMsgTxt)) {
|
if (StringUtils.isEmpty(subMsgTxt)) {
|
||||||
return "STAT_2042"; // 대체문자 데이터 오류
|
return "STAT_2042"; // 대체문자 데이터 오류
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String callFrom = msgFtRequestVO.getCallFrom();
|
||||||
|
if (StringUtils.isEmpty(callFrom)) {
|
||||||
|
return "STAT_2043"; // 대체문자 발송 시 발신번호 필요
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 모든 검증 통과
|
// 모든 검증 통과
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user