Merge branch 'api_advc'
This commit is contained in:
commit
6700d30ba6
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
HELP.md
|
||||
target/
|
||||
log/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
@ -198,3 +199,4 @@ fabric.properties
|
||||
rebel.xml
|
||||
/mvnw
|
||||
/mvnw.cmd
|
||||
/log.config.path_IS_UNDEFINED/
|
||||
|
||||
5
pom.xml
5
pom.xml
@ -38,6 +38,11 @@
|
||||
<!-- <scope>test</scope>-->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
|
||||
<dependency>
|
||||
<groupId>org.modelmapper</groupId>
|
||||
|
||||
@ -4,10 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.idgen.service.IdgenService;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.access.mapper.domain.AccessKeyVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.SendSucRestResponse;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.SendSucRestResponse;
|
||||
import com.itn.mjonApi.mjon.log.service.mapper.LettnAccessLogMapper;
|
||||
import com.itn.mjonApi.mjon.log.service.mapper.LettnApiSendMsgLogMapper;
|
||||
import com.itn.mjonApi.mjon.log.service.mapper.MjMsgGroupDataMapper;
|
||||
@ -59,6 +56,7 @@ public class LogAspect {
|
||||
|
||||
@Autowired
|
||||
MjMsgGroupDataMapper mjMsgGroupDataMapper;
|
||||
|
||||
@Resource(name = "apiAccessLog")
|
||||
private IdgenService idgenApiAccessLogId;
|
||||
|
||||
@ -72,16 +70,28 @@ public class LogAspect {
|
||||
* - mberId
|
||||
* - accessKey
|
||||
*/
|
||||
@Before(value = "execution(* com.itn.mjonApi.mjon.api.*..*Impl.*(..))" )
|
||||
// @Before(value = "execution(* com.itn.mjonApi.mjon.api.*..*Impl.*(..))" )
|
||||
@Before("execution(* com.itn.mjonApi.mjon.api..*Controller.*(..)) || execution(* com.itn.mjonApi.mjon.api..*Impl.*(..))")
|
||||
public void before(JoinPoint joinPoint) throws IllegalAccessException, JsonProcessingException {
|
||||
log.info(" :: AOP before :: ");
|
||||
//
|
||||
// for (Object arg : joinPoint.getArgs()) {
|
||||
// if (arg == null) continue;
|
||||
//
|
||||
// // JSON 직렬화해서 VO 전체 출력
|
||||
// log.info("VO 전체: {}", new ObjectMapper().writeValueAsString(arg));
|
||||
// log.info("VO 클래스명: {}", arg.getClass().getName());
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
HttpServletRequest request = this.getHttpServletRequest();
|
||||
|
||||
// VO 객체를 가져옴
|
||||
Object objectVO = joinPoint.getArgs()[0];
|
||||
|
||||
log.info("joinPoint.getArgs()[0] :: [{}]", joinPoint.getArgs()[0]);
|
||||
// log.info("joinPoint.getArgs()[0] :: [{}]", joinPoint.getArgs()[0]);
|
||||
|
||||
|
||||
|
||||
@ -91,16 +101,27 @@ public class LogAspect {
|
||||
String mberId = "";
|
||||
String accessKey = "";
|
||||
for(Field field : objectVO.getClass().getDeclaredFields()){;
|
||||
field.setAccessible(true);
|
||||
|
||||
log.info("field.getName() :: [{}]", field.getName());
|
||||
log.info("field.get(objectVO) :: [{}]", field.get(objectVO));
|
||||
try {
|
||||
// JDK 내부 클래스 필드는 무시
|
||||
if (field.getDeclaringClass().getName().startsWith("java.")) continue;
|
||||
field.setAccessible(true);
|
||||
if ("mberId".equals(field.getName())) {
|
||||
mberId = String.valueOf(field.get(objectVO));
|
||||
log.info("mberId :: [{}]", mberId);
|
||||
}
|
||||
// log.info("field.get(objectVO) :: [{}]", field.get(objectVO));
|
||||
|
||||
|
||||
if("mberId".equals(field.getName())){ mberId=field.get(objectVO).toString(); }
|
||||
else if("accessKey".equals(field.getName())){ accessKey=field.get(objectVO).toString(); }
|
||||
if("mberId".equals(field.getName())){ mberId=field.get(objectVO).toString(); }
|
||||
else if("accessKey".equals(field.getName())){ accessKey=field.get(objectVO).toString(); }
|
||||
|
||||
if(StringUtils.isNotEmpty(mberId) && StringUtils.isNotEmpty(accessKey)){ break; }
|
||||
if(StringUtils.isNotEmpty(mberId) && StringUtils.isNotEmpty(accessKey)){ break; }
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.warn("접근 불가 필드 스킵: {}", field.getName());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String nextStringId = idgenApiAccessLogId.getNextStringId();
|
||||
@ -162,7 +183,9 @@ public class LogAspect {
|
||||
lettnApiSendMsgLogMapper.insert(apiSendMsgLogVO);
|
||||
|
||||
// 메세지 그룹 테이블에 발송 구분 업데이트
|
||||
this.updateMsgGroupTbSendKind(apiSendMsgLogVO);
|
||||
// mjon_git에서 처리하는걸로 수정
|
||||
// 20250729 이호영
|
||||
// this.updateMsgGroupTbSendKind(apiSendMsgLogVO);
|
||||
|
||||
}
|
||||
|
||||
@ -172,18 +195,18 @@ public class LogAspect {
|
||||
* @description 메세지 그룹 테이블에 발송 구분 업데이트
|
||||
* @param apiSendMsgLogVO
|
||||
*/
|
||||
private void updateMsgGroupTbSendKind(LettnApiSendMsgLogVO apiSendMsgLogVO) {
|
||||
if(StringUtils.isNotEmpty(apiSendMsgLogVO.getMsgGroupId()))
|
||||
{
|
||||
String[] msgGroupIds = null;
|
||||
if(apiSendMsgLogVO.getMsgGroupId().indexOf(",") > -1){
|
||||
msgGroupIds = apiSendMsgLogVO.getMsgGroupId().split(",");
|
||||
}else{
|
||||
msgGroupIds = new String[]{apiSendMsgLogVO.getMsgGroupId()};
|
||||
}
|
||||
mjMsgGroupDataMapper.update(msgGroupIds);
|
||||
}
|
||||
}
|
||||
// private void updateMsgGroupTbSendKind(LettnApiSendMsgLogVO apiSendMsgLogVO) {
|
||||
// if(StringUtils.isNotEmpty(apiSendMsgLogVO.getMsgGroupId()))
|
||||
// {
|
||||
// String[] msgGroupIds = null;
|
||||
// if(apiSendMsgLogVO.getMsgGroupId().indexOf(",") > -1){
|
||||
// msgGroupIds = apiSendMsgLogVO.getMsgGroupId().split(",");
|
||||
// }else{
|
||||
// msgGroupIds = new String[]{apiSendMsgLogVO.getMsgGroupId()};
|
||||
// }
|
||||
// mjMsgGroupDataMapper.update(msgGroupIds);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @description lettngnrlmber_api_send_msg_log 테이블에 저장할 데이터 만들기
|
||||
@ -252,6 +275,7 @@ public class LogAspect {
|
||||
@NotNull
|
||||
private static String getClassNmFromObject(Object returnValue) {
|
||||
String classNmTemp = returnValue.getClass().getName();
|
||||
log.info("getClassNmFromObject :: [{}]", classNmTemp);
|
||||
String classNm = classNmTemp.substring(classNmTemp.lastIndexOf(".")+1, classNmTemp.length());
|
||||
return classNm;
|
||||
}
|
||||
@ -312,37 +336,29 @@ public class LogAspect {
|
||||
* @return
|
||||
*/
|
||||
public String getJsonToString(Object returnValue) throws JsonProcessingException {
|
||||
|
||||
if(ObjectUtils.isEmpty(returnValue)){
|
||||
if (ObjectUtils.isEmpty(returnValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String classNm = this.getClassNmFromObject(returnValue);
|
||||
|
||||
/**
|
||||
* @description : return Class가 추가되면 여기에 추가
|
||||
*/
|
||||
if("AccessKeyVO".equals(classNm)) {
|
||||
AccessKeyVO accessKeyVO = (AccessKeyVO) returnValue;
|
||||
return ApiObjectUtil.getAccessKeyVOToJsonString(accessKeyVO);
|
||||
// 처리 대상 클래스 목록 (선택적으로 필터링하고 싶다면 여기에 조건)
|
||||
switch (classNm) {
|
||||
case "AccessKeyVO":
|
||||
case "RestResponse":
|
||||
case "MsgsRequestVO":
|
||||
case "MsgRequestVO":
|
||||
case "MjKakaoProfileInfoVO":
|
||||
case "BizTemplateRequest":
|
||||
case "MsgAtRequestVO":
|
||||
case "MsgFtRequestVO":
|
||||
case "String":
|
||||
case "ArrayList":
|
||||
return ApiObjectUtil.toJson(returnValue);
|
||||
default:
|
||||
log.info("데이터를 추가해 주세요 [{}]", classNm);
|
||||
return "데이터를 추가해 주세요";
|
||||
}
|
||||
else if("RestResponse".equals(classNm)){
|
||||
RestResponse restResponse = (RestResponse) returnValue;
|
||||
return ApiObjectUtil.getRestResponseToJsonString(restResponse);
|
||||
}
|
||||
else if("MsgsRequestVO".equals(classNm)){
|
||||
MsgsRequestVO msgsRequestVO = (MsgsRequestVO) returnValue;
|
||||
return ApiObjectUtil.getMsgsRequestVOToJsonString(msgsRequestVO);
|
||||
}
|
||||
else if("MsgRequestVO".equals(classNm)){
|
||||
MsgRequestVO restResponse = (MsgRequestVO) returnValue;
|
||||
return ApiObjectUtil.getMsgRequestVOToJsonString(restResponse);
|
||||
}
|
||||
else{
|
||||
return "데이터를 추가해 주세요";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,10 +1,22 @@
|
||||
package com.itn.mjonApi.cmn.apiServer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MjonResponseVO;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
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.domain.biz.template.list.TemplateListResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MjonResponseVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.cmn.apiServer
|
||||
@ -18,6 +30,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-15 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ApiService <T> {
|
||||
|
||||
@ -37,13 +50,120 @@ public class ApiService <T> {
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
public MjonResponseVO postForEntity(String url, Object request, Class<String> responseType) throws JsonProcessingException {
|
||||
ResponseEntity<String> spamChkEntity = (ResponseEntity<String>) restTemplate.postForEntity(
|
||||
ResponseEntity<String> returnEntity = (ResponseEntity<String>) restTemplate.postForEntity(
|
||||
url
|
||||
, request
|
||||
, responseType
|
||||
);
|
||||
MjonResponseVO spamResponse = MjonResponseVO.getMjonResponse(spamChkEntity);
|
||||
return spamResponse;
|
||||
log.info("returnEntity :: [{}]", returnEntity.toString());
|
||||
// ObjectMapper로 JSON 파싱
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode rootNode = mapper.readTree(returnEntity.getBody());
|
||||
|
||||
// log.info("rootNode :: [{}]", rootNode.toString());
|
||||
|
||||
|
||||
// "apiReturn" 필드만 추출
|
||||
JsonNode apiReturnNode = rootNode.get("apiReturn");
|
||||
if (apiReturnNode == null || apiReturnNode.isNull()) {
|
||||
log.warn("apiReturn 필드가 응답에 존재하지 않습니다.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return MjonResponseVO.getMjonResponse(apiReturnNode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 알림톡 템플릿 리스트 조회
|
||||
* @author hylee
|
||||
*/
|
||||
public TemplateListResponse postForBizTemplateListEntity(String url, BizTemplateRequest requestDto) throws JsonProcessingException {
|
||||
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
HttpEntity<BizTemplateRequest> requestEntity = new HttpEntity<>(requestDto, headers);
|
||||
|
||||
TemplateListResponse returnEntity = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
requestEntity,
|
||||
TemplateListResponse.class
|
||||
).getBody();
|
||||
|
||||
|
||||
|
||||
return returnEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 알림톡 템플릿 상세 조회
|
||||
* @author hylee
|
||||
*/
|
||||
public TemplateDetailResponse postForBizTemplateDetailEntity(String url, BizTemplateRequest requestDto) throws JsonProcessingException {
|
||||
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
HttpEntity<BizTemplateRequest> requestEntity = new HttpEntity<>(requestDto, headers);
|
||||
|
||||
TemplateDetailResponse returnEntity = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
requestEntity,
|
||||
TemplateDetailResponse.class
|
||||
).getBody();
|
||||
|
||||
log.info("returnEntity :: [{}]", returnEntity.toString());
|
||||
|
||||
|
||||
return returnEntity;
|
||||
}
|
||||
|
||||
public StatusResponse postMultipartForEntity(String url, MsgFtRequestVO msgFtRequestVO, MultipartFile templateImage) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
|
||||
// 파일 추가
|
||||
body.add("templateImage", templateImage.getResource());
|
||||
|
||||
// MsgFtRequestVO 필드들을 kakaoVO에 맞게 매핑
|
||||
if (msgFtRequestVO.getSendKind() != null) {
|
||||
body.add("sendKind", msgFtRequestVO.getSendKind());
|
||||
}
|
||||
if ( msgFtRequestVO.getTemplateMsgType() != null) {
|
||||
body.add("imageType", msgFtRequestVO.getTemplateMsgType());
|
||||
}
|
||||
if (msgFtRequestVO.getTemplateCode() != null) {
|
||||
body.add("templateCode", msgFtRequestVO.getTemplateCode());
|
||||
}
|
||||
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
|
||||
|
||||
ResponseEntity<StatusResponse> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
requestEntity,
|
||||
StatusResponse.class
|
||||
);
|
||||
|
||||
// log.info("Upload response :: [{}]", response.getBody());
|
||||
return response.getBody();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
19
src/main/java/com/itn/mjonApi/cmn/domain/CmnVO.java
Normal file
19
src/main/java/com/itn/mjonApi/cmn/domain/CmnVO.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.itn.mjonApi.cmn.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@SuperBuilder
|
||||
public class CmnVO {
|
||||
|
||||
private String mberId; // 사용자 ID
|
||||
|
||||
private String accessKey; // Api Key
|
||||
}
|
||||
@ -1,104 +1,15 @@
|
||||
package com.itn.mjonApi.mjon.api.send.mapper.domain;
|
||||
package com.itn.mjonApi.cmn.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.send.mapper.domain
|
||||
* fileName : MjonMsgVO
|
||||
* author : hylee
|
||||
* date : 2023-05-23
|
||||
* description : 문자 발송에 필요한 값들을 받는 vo
|
||||
* 1건~500건 대량 문자 개인별로 발송
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-09 hylee 최초 생성
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MsgsRequestVO implements Serializable {
|
||||
|
||||
/**
|
||||
* 값이 있는 경우
|
||||
* 문자온 프로젝트에서 처리해줌
|
||||
* null이면 에러
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String mberId; // 사용자 ID
|
||||
|
||||
private String accessKey; // Api Key
|
||||
|
||||
private String smsTxt; // SMS용 메시지본문
|
||||
|
||||
private String[] callToList; // 수신번호리스트
|
||||
|
||||
private String callFrom; // 발신번호 :: 정책이 필요함
|
||||
|
||||
private String eachPrice = "0"; // 전송문자 개별가격
|
||||
private String sPrice = "0"; // 임시
|
||||
|
||||
private String totPrice = "0"; // 전송문자 토탈가격
|
||||
|
||||
private String fileCnt = "0"; // 첨부파일 갯수
|
||||
|
||||
private String msgType = "4"; // 메시지의 (4: SMS 전송, 5: URL 전송, 6: MMS전송, 7: BARCODE전송, 8: 카카오 알림톡 전송)
|
||||
|
||||
// ==== 단가 ====
|
||||
private float smsPrice = 0; // sms 단가 null 이면 에러
|
||||
|
||||
private float mmsPrice = 0; // mms 단가 null 이면 에러
|
||||
// private float kakaoAtPrice; // 카카오 알림톡 단가
|
||||
// private float kakaoFtPrice; // 카카오 친구톡 단가
|
||||
// private float kakaoFtImgPrice;// 카카오 이미지 단가
|
||||
// private float kakaoFtWideImgPrice; // 카카오 와이드 이미지 단가
|
||||
|
||||
private String[] imgFilePath = new String[0]; // 그림 이미지 경로
|
||||
|
||||
|
||||
private String spamStatus; // 스팸문자 유무 (Y/N) - 서비스단에서 처리 함
|
||||
|
||||
private String txtReplYn = "N"; // 변환문자 유무 (Y/N) - 서비스단에서 처리 함
|
||||
|
||||
// private String nameStr; // value = "치환 이름 리스트 |로 구분", example = "홍길동1|홍길동2|홍길동3"
|
||||
|
||||
// private String rep1Str; // value = "치환 문자1 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep2Str; // value = "치환 문자2 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep3Str; // value = "치환 문자3 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep4Str; // value = "치환 문자4 리스트 |로 구분", example = ""
|
||||
|
||||
// private String[] nameList= new String[0]; // value = "nameStr 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep1List= new String[0]; // value = "rep1Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep2List= new String[0]; // value = "rep2Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep3List= new String[0]; // value = "rep3Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep4List= new String[0]; // value = "rep4Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
private String reserveYn = "N"; // value = "예약 유무 (Y/N)", example = "N"
|
||||
|
||||
// 치환 있을 경우 사용
|
||||
// private String shortMsgCnt; // value = "치환 후 단문 건수", example = ""
|
||||
|
||||
// private String longMsgCnt; // value = "치환 후 장문 건수", example = ""
|
||||
|
||||
|
||||
// @ApiModelProperty(value = "문자 종류 일반:N, 광고:A, 선거:C", example = "N", hidden = true)
|
||||
private String msgKind = "N"; // '문자 종류 일반:N, 광고:A, 선거:C',
|
||||
|
||||
private String test_yn; // 테스트 여부
|
||||
public class SendRequestCmnVO {
|
||||
|
||||
// 수신자 발송txt 각각 _1~_100
|
||||
// 교차로 있어야 로직이 가능함
|
||||
@ -1105,6 +1016,4 @@ public class MsgsRequestVO implements Serializable {
|
||||
// private String smsTxt_498;
|
||||
// private String smsTxt_499;
|
||||
// private String smsTxt_500;
|
||||
|
||||
|
||||
}
|
||||
41
src/main/java/com/itn/mjonApi/cmn/domain/StatusResponse.java
Normal file
41
src/main/java/com/itn/mjonApi/cmn/domain/StatusResponse.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.itn.mjonApi.cmn.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/*
|
||||
* • 1XX : 조건부 응답
|
||||
* • 2XX : 성공
|
||||
* • 3XX : 리다이렉션 완료
|
||||
* • 4XX : 요청 오류
|
||||
* • 500 : 서버 오류
|
||||
*
|
||||
* 참고 : https://km0830.tistory.com/33
|
||||
*
|
||||
* ====== 자주 사용하는 코드 =====
|
||||
* 200 : Ok : 서버가 클라이언트의 요청을 성공적으로 처리, 웹 페이지에서는 페이지 요청이 정상적으로 완료 (Ok)
|
||||
* 400 : Bad Request : 잘못 요청 (Bad Request)
|
||||
* 401 : Unauthorized : 권한 없음, 예를 들면, 로그인 페이지가 필요한 페이지를 로그인 없이 접속하려는 경우 반환되는 코드 (인증 실패) (Unauthorized)
|
||||
*
|
||||
* */
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class StatusResponse {
|
||||
|
||||
private HttpStatus status;
|
||||
|
||||
private String message;
|
||||
|
||||
private Object object;
|
||||
|
||||
private Object apiReturn;
|
||||
|
||||
private String messageTemp;
|
||||
|
||||
// private String timestamp;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template;
|
||||
|
||||
import com.itn.mjonApi.cmn.domain.CmnVO;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@SuperBuilder
|
||||
public class BizTemplateRequest extends CmnVO {
|
||||
private String bizId;
|
||||
private String apiKey;
|
||||
private String senderKey;
|
||||
private String templateCode;
|
||||
private String test_yn;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class CommentsAttachment {
|
||||
private String originalFileName;
|
||||
private String filePath;
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateButton {
|
||||
private String bizFormId;
|
||||
private String linkAnd;
|
||||
private String linkIos;
|
||||
private String linkMo;
|
||||
private String linkPc;
|
||||
private String linkType;
|
||||
private String name;
|
||||
private String ordering;
|
||||
private String pluginId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateComments {
|
||||
private String content;
|
||||
private String createdAt;
|
||||
private String status;
|
||||
private List<CommentsAttachment> attachment;
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateDetail {
|
||||
private String block;
|
||||
private String categoryCode;
|
||||
private String createdAt;
|
||||
private String dormant;
|
||||
private String inspectionStatus;
|
||||
private String modifiedAt;
|
||||
private String securityFlag;
|
||||
private String senderKey;
|
||||
private String senderKeyType;
|
||||
private String status;
|
||||
private String templateCode;
|
||||
private String templateContent;
|
||||
private String templateEmphasizeType;
|
||||
private String templateExtra;
|
||||
private String templateHeader;
|
||||
private String templateImageName;
|
||||
private String templateImageUrl;
|
||||
private String templateMessageType;
|
||||
private String templateName;
|
||||
private String templateSubtitle;
|
||||
private String templateTitle;
|
||||
private TemplateItemHighlight templateItemHighlight;
|
||||
private TemplateItem templateItem;
|
||||
private List<TemplateButton> buttons;
|
||||
private List<TemplateComments> comments;
|
||||
private List<TemplateQuickReplies> quickReplies;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateDetailResponse {
|
||||
|
||||
private String code;
|
||||
private String message;
|
||||
private TemplateDetail data;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateItem {
|
||||
private List<TemplateItemItem> list;
|
||||
private TemplateItemSummary summary;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateItemHighlight {
|
||||
private String title; // 아이템 타이틀
|
||||
private String description; // 상세 설명
|
||||
private String imageUrl; // 썸네일 이미지 주소
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateItemItem {
|
||||
private String title;
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateItemSummary {
|
||||
private String title;
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.detail;
|
||||
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TemplateQuickReplies {
|
||||
private String name;
|
||||
private String linkType;
|
||||
private String linkAnd;
|
||||
private String linkIos;
|
||||
private String linkMo;
|
||||
private String linkPc;
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.list;
|
||||
|
||||
/**
|
||||
* 템플릿 상태를 나타내는 열거형 클래스.
|
||||
* - API 응답의 상태 코드(EX: REG)를 사람이 읽기 쉽게 변환하는 데 사용됨.
|
||||
*/
|
||||
public enum ServiceStatusEnum {
|
||||
|
||||
REG("등록완료"), // REG: 등록 완료된 템플릿
|
||||
RDY("대기"), // RDY: 대기 상태
|
||||
ACT("활성"), // ACT: 활성화 상태
|
||||
DMT("중단"), // DMT: 중단된 템플릿
|
||||
REJ("반려"), // REJ: 반려된 템플릿
|
||||
UNKNOWN("알 수 없음"); // 정의되지 않은 상태
|
||||
|
||||
private final String label; // 한글 설명
|
||||
|
||||
/**
|
||||
* 생성자
|
||||
* @param label 상태의 한글 설명
|
||||
*/
|
||||
ServiceStatusEnum(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 한글 설명 반환
|
||||
*/
|
||||
public String getLabel() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드값을 받아 "[코드](한글설명)" 형태 문자열로 반환
|
||||
* @param code 상태 코드 (예: REG, ACT 등)
|
||||
* @return 예: "REG(등록완료)", "DMT(중단)", "FOO(알 수 없음)"
|
||||
*/
|
||||
public static String getLabelByCode(String code) {
|
||||
for (ServiceStatusEnum status : values()) {
|
||||
if (status.name().equalsIgnoreCase(code)) {
|
||||
return status.name() + "(" + status.getLabel() + ")";
|
||||
}
|
||||
}
|
||||
return code + "(알 수 없음)";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.list;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class TemplateInfo {
|
||||
private String senderKey;
|
||||
private String senderKeyType;
|
||||
private String templateCode;
|
||||
private String templateName;
|
||||
private String createdAt;
|
||||
private String modifiedAt;
|
||||
private String categoryCode;
|
||||
private String serviceStatus;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.list;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class TemplateListData {
|
||||
private List<TemplateInfo> list;
|
||||
private boolean hasNext;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.itn.mjonApi.cmn.domain.biz.template.list;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class TemplateListResponse {
|
||||
private String code;
|
||||
private String message;
|
||||
private int totalCount;
|
||||
private int totalPage;
|
||||
private int currentPage;
|
||||
private TemplateListData data;
|
||||
}
|
||||
@ -58,7 +58,6 @@ public class IdgenServiceImpl implements IdgenService {
|
||||
// nextId 값 만들기
|
||||
String nextId = prefixTemp + idgenVO.getNextId();
|
||||
|
||||
log.info(" userId : [{}]", nextId);
|
||||
return nextId;
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,33 @@ public class CertifInterceptor implements HandlerInterceptor{
|
||||
String serverIp = ""; //접속 server IP
|
||||
|
||||
try{
|
||||
/*
|
||||
|
||||
String contentType = request.getContentType();
|
||||
log.info("요청 contentType: {}", contentType);
|
||||
//
|
||||
if("application/json".equals(contentType) )
|
||||
{
|
||||
|
||||
BufferedReader reader = request.getReader();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
String body = sb.toString();
|
||||
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(body);
|
||||
String mberId = jsonNode.get("mberId").asText();
|
||||
String accessKey = jsonNode.get("accessKey").asText();
|
||||
|
||||
log.info("mberId :: [{}]", mberId);
|
||||
log.info("accessKey :: [{}]", accessKey);
|
||||
}
|
||||
*/
|
||||
|
||||
String clientIp = null;
|
||||
boolean isIpInHeader = false;
|
||||
|
||||
@ -150,8 +177,9 @@ public class CertifInterceptor implements HandlerInterceptor{
|
||||
//referer 값이 없으면 serverIP 값으로 대체한다.
|
||||
if ("".equals(referer) || referer==null) {
|
||||
referer = serverIp;
|
||||
}
|
||||
log.info("certi request.getParameter(\"accessKey\") :: [{}]", request.getParameter("accessKey"));
|
||||
}
|
||||
referer= "119.193.215.98";
|
||||
// log.info("certi request.getParameter(\"accessKey\") :: [{}]", request.getParameter("accessKey"));
|
||||
// hylee Builder 패턴으로 변경 => 20230516
|
||||
AccessKeyVO accessKeyVO = accessKeyService.selectRKey(
|
||||
new AccessKeyVO().builder()
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package com.itn.mjonApi.cmn.model;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.PriceMapper;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.PriceMapper;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.PriceVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -19,6 +20,7 @@ import java.util.Map;
|
||||
* 2023-07-03 hylee 최초 생성
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class Price {
|
||||
|
||||
@ -29,48 +31,88 @@ public class Price {
|
||||
double mberMoney = priceMapper.selectMberMoney(mberId);
|
||||
|
||||
//시스템 단가 변수
|
||||
double sys_shortPrice = 0.0f;
|
||||
double sys_longPrice = 0.0f;
|
||||
double sys_picturePrice = 0.0f;
|
||||
double sys_shortPrice = 0.0f;
|
||||
double sys_longPrice = 0.0f;
|
||||
double sys_picturePrice = 0.0f;
|
||||
double sys_kakaoAtPrice = 0.0f;
|
||||
double sys_kakaoFtPrice = 0.0f;
|
||||
double sys_kakaoFtImgPrice = 0.0f;
|
||||
double sys_kakaoFtWideImgPrice = 0.0f;
|
||||
|
||||
//최종 단가 변수
|
||||
double shortPrice = 0.0f;
|
||||
double longPrice = 0.0f;
|
||||
double picturePrice = 0.0f;
|
||||
double shortPrice = 0.0f;
|
||||
double longPrice = 0.0f;
|
||||
double picturePrice = 0.0f;
|
||||
double kakaoAtPrice = 0.0f;
|
||||
double kakaoFtPrice = 0.0f;
|
||||
double kakaoFtImgPrice = 0.0f;
|
||||
double kakaoFtWideImgPrice = 0.0f;
|
||||
|
||||
//1.시스템 기본 단가, 사용자 개인단가 정보 불러오기
|
||||
Map<String, String> priceMap = priceMapper.selectMberPriceInfo(mberId);
|
||||
|
||||
//1-2.단가 계산을 위한 set
|
||||
sys_shortPrice = Double.parseDouble(String.valueOf(priceMap.get("sysShortPrice")));
|
||||
sys_longPrice = Double.parseDouble(String.valueOf(priceMap.get("sysLongPrice")));
|
||||
sys_picturePrice = Double.parseDouble(String.valueOf(priceMap.get("sysPicturePrice")));
|
||||
sys_shortPrice = Double.parseDouble(String.valueOf(priceMap.get("sysShortPrice")));
|
||||
sys_longPrice = Double.parseDouble(String.valueOf(priceMap.get("sysLongPrice")));
|
||||
sys_picturePrice = Double.parseDouble(String.valueOf(priceMap.get("sysPicturePrice")));
|
||||
|
||||
sys_kakaoAtPrice = Double.parseDouble(String.valueOf(priceMap.get("sysKakaoAtPrice")));
|
||||
sys_kakaoFtPrice = Double.parseDouble(String.valueOf(priceMap.get("sysKakaoFtPrice")));
|
||||
sys_kakaoFtImgPrice = Double.parseDouble(String.valueOf(priceMap.get("sysKakaoFtImgPrice")));
|
||||
sys_kakaoFtWideImgPrice = Double.parseDouble(String.valueOf(priceMap.get("sysKakaoFtWideImgPrice")));
|
||||
|
||||
|
||||
|
||||
shortPrice = Double.parseDouble(String.valueOf(priceMap.get("shortPrice")));
|
||||
longPrice = Double.parseDouble(String.valueOf(priceMap.get("longPrice")));
|
||||
picturePrice = Double.parseDouble(String.valueOf(priceMap.get("picturePrice")));
|
||||
|
||||
kakaoAtPrice = Double.parseDouble(String.valueOf(priceMap.get("kakaoAtPrice")));
|
||||
kakaoFtPrice = Double.parseDouble(String.valueOf(priceMap.get("kakaoFtPrice")));
|
||||
kakaoFtImgPrice = Double.parseDouble(String.valueOf(priceMap.get("kakaoFtImgPrice")));
|
||||
kakaoFtWideImgPrice = Double.parseDouble(String.valueOf(priceMap.get("kakaoFtWideImgPrice")));
|
||||
|
||||
//1-3. 최종 단가 계산
|
||||
shortPrice = shortPrice == 0.0f ? sys_shortPrice : shortPrice;
|
||||
longPrice = longPrice == 0.0f ? sys_longPrice : longPrice;
|
||||
picturePrice = picturePrice == 0.0f ? sys_picturePrice : picturePrice;
|
||||
|
||||
kakaoAtPrice = kakaoAtPrice == 0.0f ? sys_kakaoAtPrice : kakaoAtPrice;
|
||||
kakaoFtPrice = kakaoFtPrice == 0.0f ? sys_kakaoFtPrice : kakaoFtPrice;
|
||||
kakaoFtImgPrice = kakaoFtImgPrice == 0.0f ? sys_kakaoFtImgPrice : kakaoFtImgPrice;
|
||||
kakaoFtWideImgPrice = kakaoFtWideImgPrice == 0.0f ? sys_kakaoFtWideImgPrice : kakaoFtWideImgPrice;
|
||||
|
||||
//2. 단가별 발송 가능건수 계산을위한 변수 set
|
||||
int shortSendPsbltEa = 0;
|
||||
int longSendPsbltEa = 0;
|
||||
int pictureSendPsbltEa = 0;
|
||||
|
||||
int kakaoAtSendPsbltEa = 0;
|
||||
int kakaoFtSendPsbltEa = 0;
|
||||
int kakaoFtImgSendPsbltEa = 0;
|
||||
int kakaoFtWideImgSendPsbltEa = 0;
|
||||
|
||||
//2-1. 소수점 연산을 위한 BigDecimal Casting
|
||||
BigDecimal mberMoney_big = new BigDecimal(String.valueOf(mberMoney));
|
||||
BigDecimal shortPrice_big = new BigDecimal(String.valueOf(priceMap.get("sysShortPrice")));
|
||||
BigDecimal longPrice_big = new BigDecimal(String.valueOf(priceMap.get("sysLongPrice")));
|
||||
BigDecimal picturePrice_big = new BigDecimal(String.valueOf(priceMap.get("sysPicturePrice")));
|
||||
BigDecimal shortPrice_big = new BigDecimal(String.valueOf(shortPrice));
|
||||
BigDecimal longPrice_big = new BigDecimal(String.valueOf(longPrice));
|
||||
BigDecimal picturePrice_big = new BigDecimal(String.valueOf(picturePrice));
|
||||
|
||||
BigDecimal kakaoAtPrice_big = new BigDecimal(String.valueOf(kakaoAtPrice));
|
||||
BigDecimal kakaoFtPrice_big = new BigDecimal(String.valueOf(kakaoFtPrice));
|
||||
BigDecimal kakaoFtImgPrice_big = new BigDecimal(String.valueOf(kakaoFtImgPrice));
|
||||
BigDecimal kakaoFtWideImgPrice_big = new BigDecimal(String.valueOf(kakaoFtWideImgPrice));
|
||||
|
||||
//2-2. mberMoney가 0일경우 제외
|
||||
if(mberMoney_big.compareTo(BigDecimal.ZERO) != 0) {
|
||||
shortSendPsbltEa = mberMoney_big.divide(shortPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
longSendPsbltEa = mberMoney_big.divide(longPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
pictureSendPsbltEa = mberMoney_big.divide(picturePrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
shortSendPsbltEa = mberMoney_big.divide(shortPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
longSendPsbltEa = mberMoney_big.divide(longPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
pictureSendPsbltEa = mberMoney_big.divide(picturePrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
|
||||
kakaoAtSendPsbltEa = mberMoney_big.divide(kakaoAtPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
kakaoFtSendPsbltEa = mberMoney_big.divide(kakaoFtPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
kakaoFtImgSendPsbltEa = mberMoney_big.divide(kakaoFtImgPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
kakaoFtWideImgSendPsbltEa = mberMoney_big.divide(kakaoFtWideImgPrice_big, BigDecimal.ROUND_DOWN).intValue();
|
||||
}
|
||||
|
||||
//result set
|
||||
@ -78,11 +120,28 @@ public class Price {
|
||||
.shortPrice(shortPrice)
|
||||
.longPrice(longPrice)
|
||||
.picturePrice(picturePrice)
|
||||
|
||||
.kakaoAtPrice(kakaoAtPrice)
|
||||
.kakaoFtPrice(kakaoFtPrice)
|
||||
.kakaoFtImgPrice(kakaoFtImgPrice)
|
||||
.kakaoFtWideImgPrice(kakaoFtWideImgPrice)
|
||||
|
||||
|
||||
.shortSendPsbltEa(shortSendPsbltEa)
|
||||
.longSendPsbltEa(longSendPsbltEa)
|
||||
.pictureSendPsbltEa(pictureSendPsbltEa)
|
||||
|
||||
.kakaoAtSendPsbltEa(kakaoAtSendPsbltEa)
|
||||
.kakaoFtSendPsbltEa(kakaoFtSendPsbltEa)
|
||||
.kakaoFtImgSendPsbltEa(kakaoFtImgSendPsbltEa)
|
||||
.kakaoFtWideImgSendPsbltEa(kakaoFtWideImgSendPsbltEa)
|
||||
|
||||
.mberMoney(mberMoney)
|
||||
.build();
|
||||
|
||||
log.info(" + priceVO :: [{}]", priceVO);
|
||||
|
||||
|
||||
return priceVO;
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package com.itn.mjonApi.cmn.msg;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@ -11,6 +8,7 @@ import java.time.LocalDateTime;
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class RestResponse{
|
||||
|
||||
private String resultCode = "0";
|
||||
|
||||
@ -33,7 +33,8 @@ public enum StatMsg {
|
||||
// 문자보내기 ======================================================================
|
||||
STAT_0("0","")
|
||||
, STAT_1010("1010","발신자 전화번호 사용 불가")
|
||||
, STAT_1020("1020","수신자 전화번호 오류")
|
||||
, STAT_1020("1020","수신자 전화번호 오류") // ㅂ
|
||||
, STAT_1021("1021","수신거부 번호 제거 후 수신자 목록 없음")
|
||||
, STAT_1030("1030","문자 내용 발송 불가")
|
||||
, STAT_1040("1040","치환 데이터 오류")
|
||||
, STAT_1050("1050","치환 후 문자 길이 초과")
|
||||
@ -43,6 +44,28 @@ public enum StatMsg {
|
||||
, STAT_1090("1090","요청 발송일시에 발송 불가") // 아직 사용 안함
|
||||
, STAT_1099("1099","기타 시스템 오류")
|
||||
|
||||
//카톡발송======================================================================
|
||||
, STAT_2010("2010","발신프로필 KEY 오류")
|
||||
, STAT_2030("2030","템플릿 코드 오류")
|
||||
, STAT_2040("2040","본문 데이터 오류")
|
||||
, STAT_2041("2041","타이틀 데이터 오류")
|
||||
, STAT_2042("2042","대체문자 데이터 오류")
|
||||
, STAT_2043("2043","대체문자 발송 시 발신번호가 필요합니다.")
|
||||
|
||||
, STAT_2050("2050","지원하지 않는 이미지 형식입니다.")
|
||||
, STAT_2051("2051","이미지 용량은 5MB 이내여야 합니다.")
|
||||
, STAT_2052("2052","이미지를 읽을 수 없습니다.")
|
||||
, STAT_2053("2053","지원하지 않는 이미지 형식입니다.")
|
||||
, STAT_2054("2054","이미지 가로폭인 500px 미만입니다.")
|
||||
, STAT_2055("2055","유효한 이미지 파일이 없습니다.")
|
||||
, STAT_2056("2056","비율 2:1 이상 또는 3:4 이하만 허용됩니다.")
|
||||
, STAT_2057("2057","대체문자(MMS) 이미지는 10MB를 초과할 수 없습니다.")
|
||||
|
||||
, STAT_2080("2080","친구톡은 20시 50분부터 익일 08시까지 발송이 제한됩니다.")
|
||||
|
||||
, STAT_2099("2099","기타 시스템 오류")
|
||||
|
||||
|
||||
//전체발송======================================================================
|
||||
, STAT_3099("3099","기타 시스템 오류")
|
||||
|
||||
@ -52,9 +75,12 @@ public enum StatMsg {
|
||||
//발송가능건수======================================================================
|
||||
, STAT_5099("5099","기타 시스템 오류")
|
||||
|
||||
|
||||
|
||||
//======================================================================
|
||||
, msgType4("단문","SMS")
|
||||
, msgType6("장문","LMS")
|
||||
, msgType8("알림톡","AT")
|
||||
|
||||
|
||||
;
|
||||
@ -68,13 +94,17 @@ public enum StatMsg {
|
||||
}
|
||||
|
||||
// Random을 만들기 위한 코드
|
||||
// 모든 enum 항목을 불변 리스트로 저장
|
||||
private static final List<StatMsg> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
|
||||
// 전체 항목 수
|
||||
private static final int SIZE = VALUES.size();
|
||||
// 랜덤 인스턴스
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
/**
|
||||
* @description : 랜덤한 에러코드를 반환한다.
|
||||
* @return errorCode
|
||||
* 랜덤한 에러코드를 반환한다.
|
||||
* 단, 코드 값이 3자리 이하(예: "단문", "장문")인 항목은 제외된다.
|
||||
* @return "STAT_코드" 형식의 문자열
|
||||
*/
|
||||
public static String randomErrorStatCode() {
|
||||
String errorCode = "";
|
||||
|
||||
@ -7,7 +7,6 @@ import com.itn.mjonApi.util.email.EmailVO;
|
||||
import com.itn.mjonApi.util.email.SendMail;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -16,7 +15,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.etc.ganpandaum.service.impl
|
||||
@ -70,33 +68,16 @@ public class GdServiceImpl implements GdService {
|
||||
SendMail sMail = new SendMail();
|
||||
|
||||
try {
|
||||
emailContent = Jsoup.connect(GANPANDAUP_ESTIMATE_TEMPLATE_URL)
|
||||
.data("query", "Java")
|
||||
.userAgent("Mozilla")
|
||||
.cookie("auth", "token")
|
||||
.timeout(3000)
|
||||
.post()
|
||||
.toString();
|
||||
// ./src/main/resources/templates/estimate.html
|
||||
emailContent = emailContent
|
||||
.replace("[[_Company_]]", gdVO.getGdCompany())
|
||||
.replace("[[_Name_]]", gdVO.getGdName())
|
||||
.replace("[[_Phone_]]", gdVO.getGdPhone())
|
||||
.replace("[[_Email_]]", gdVO.getGdEmail())
|
||||
.replace("[[_Addr_]]", gdVO.getGdAddr())
|
||||
.replace("[[_Content_]]", gdVO.getGdContent())
|
||||
;
|
||||
|
||||
|
||||
|
||||
// 메일 첨부파일을 위한 절대경로
|
||||
// 메일 제목
|
||||
String mailTitle = "[간판다움 견적의뢰] "+gdVO.getGdName()+"["+gdVO.getGdCompany()+"]님의 견적 의뢰입니다._"+LocalDate.now();
|
||||
|
||||
sMail.itnSendMail(
|
||||
EmailVO.builder()
|
||||
.title(mailTitle)
|
||||
.contents(emailContent)
|
||||
.title("현재달 월급명세서 전달드립니다.")
|
||||
.contents("안녕하세요 귀하에 노고에 감사드립니다. 비밀번호는 생년워일입니다.")
|
||||
.fileInfo(p_file)
|
||||
.atch_file_name(fileNm)
|
||||
.send_to(GANPANDAUP_RECEIVER_EMAIL)
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.mapper.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PriceVO implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -7865729705175845268L;
|
||||
|
||||
private String mberId; // 사용자 ID
|
||||
|
||||
private double shortPrice; // 단문 이용단가
|
||||
private double longPrice; // 장문 이용단가
|
||||
private double picturePrice; // 그림 이용단가
|
||||
|
||||
private double mberMoney; // 잔액
|
||||
|
||||
private int shortSendPsbltEa; // 단문 발송 가능건 수
|
||||
private int longSendPsbltEa; // 장문 발송 가능건 수
|
||||
private int pictureSendPsbltEa; // 그림 발송 가능건 수
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain.MjKakaoProfileInfoVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.kakao.inqry.mapper
|
||||
* fileName : InqryMapper
|
||||
* author : hylee
|
||||
* date : 2025-06-27
|
||||
* description :
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-06-27 hylee 최초 생성
|
||||
*/
|
||||
@Mapper
|
||||
public interface InqryMapper {
|
||||
|
||||
List<MjKakaoProfileInfoVO> getChnlIds(String mberId);
|
||||
|
||||
int isTemplateExist(Map<String, Object> params);
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.itn.mjonApi.cmn.domain.CmnVO;
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class MjKakaoProfileInfoVO extends CmnVO {
|
||||
private String profileId; // 회원 프로필 번호
|
||||
private String userId; // 회원 아이디
|
||||
private String senderKey; // 발신 프로필 키
|
||||
private String token; // 수신받은 인증 토큰정보
|
||||
private String phoneNumber; // 카카오톡 채널 핸드폰 번호
|
||||
private String yellowId; // 카카오톡 채널(@ID)
|
||||
private String categoryCode; // 카테고리 코드
|
||||
private String categoryName; // 카테고리 코드 명칭
|
||||
private String frstRegistPnttm; // 등록 일자
|
||||
private String frstRegisterId; // 등록자
|
||||
private String lastUpdtPnttm; // 수정 일자
|
||||
private String lastUpdusrId; // 수정자
|
||||
private String deleteYn; // 삭제 여부 (Y/N)
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.inqry.service.Impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.detail.TemplateDetailResponse;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.list.ServiceStatusEnum;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.list.TemplateInfo;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.list.TemplateListResponse;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.InqryMapper;
|
||||
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.util.TestDataUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.kakao.inqry.service.Impl
|
||||
* fileName : InqryServiceImpl
|
||||
* author : hylee
|
||||
* date : 2025-06-27
|
||||
* description :
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-06-27 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class InqryServiceImpl implements InqryService {
|
||||
|
||||
|
||||
private ApiService<Response> apiService;
|
||||
|
||||
@Value("${biz.root.url}")
|
||||
private String BIZ_ROOT_URL;
|
||||
@Value("${biz.api.key}")
|
||||
private String BIZ_API_KEY;
|
||||
@Value("${biz.id}")
|
||||
private String BIZ_ID;
|
||||
|
||||
|
||||
@Autowired
|
||||
InqryMapper inqryMapper;
|
||||
|
||||
@Autowired
|
||||
public InqryServiceImpl(ApiService<Response> apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse getChnlId(BizTemplateRequest bizTemplateRequest) {
|
||||
|
||||
String mberId = bizTemplateRequest.getMberId();
|
||||
String testYn = bizTemplateRequest.getTest_yn();
|
||||
|
||||
// 테스트 모드 확인
|
||||
if(StringUtils.isNotEmpty(bizTemplateRequest.getTest_yn())) {
|
||||
return TestDataUtil.getChnlIdTestData(testYn);
|
||||
}
|
||||
|
||||
List<MjKakaoProfileInfoVO> voList = inqryMapper.getChnlIds(mberId);
|
||||
|
||||
return new RestResponse(voList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse getTemplates(BizTemplateRequest bizTemplateRequest) throws JsonProcessingException {
|
||||
|
||||
|
||||
|
||||
// 테스트 모드 확인
|
||||
if(StringUtils.isNotEmpty(bizTemplateRequest.getTest_yn())) {
|
||||
return TestDataUtil.getTemplateListTestData(bizTemplateRequest.getTest_yn());
|
||||
}
|
||||
|
||||
// SenderKey 검증
|
||||
RestResponse STAT_2010 = isSenderKeyChk(bizTemplateRequest);
|
||||
if (STAT_2010 != null) return STAT_2010;
|
||||
|
||||
|
||||
// 1. 템플릿 목록 조회 요청 DTO 생성 (BIZ ID, API Key, senderKey 포함)
|
||||
BizTemplateRequest requestDto= BizTemplateRequest.builder()
|
||||
.bizId(BIZ_ID)
|
||||
.apiKey(BIZ_API_KEY)
|
||||
.senderKey(bizTemplateRequest.getSenderKey())
|
||||
.build();
|
||||
|
||||
// 2. 외부 API 호출 - 템플릿 목록 요청 (/v3/kakao/template/list)
|
||||
TemplateListResponse response = apiService.postForBizTemplateListEntity(
|
||||
BIZ_ROOT_URL+"/v3/kakao/template/list"
|
||||
, requestDto
|
||||
);
|
||||
|
||||
|
||||
// 3. 응답 코드가 "0" (성공) 이 **아닌 경우** => 실패 처리 (STAT_4099 반환 : 기타 시스템 오류)
|
||||
if(!"200".equals(response.getCode()) )
|
||||
{
|
||||
// STAT_4099 = 템플릿 조회 실패 (내부 enum 기반 메시지 사용)
|
||||
return new RestResponse(new FailRestResponse("STAT_4099",""));
|
||||
}
|
||||
|
||||
// 4. 성공 시 템플릿 리스트 추출
|
||||
List<TemplateInfo> templateList = response.getData().getList();
|
||||
|
||||
// 5. 각 템플릿 객체에 대해 가공 처리
|
||||
templateList.forEach(t -> {
|
||||
// log.info(" + t.toString() :: [{}]",t.toString());
|
||||
// 서비스 상태 코드 → 한글 라벨로 변환 ( 예: REG → REG(등록완료) )
|
||||
String originalCode = t.getServiceStatus();
|
||||
String convertedLabel = ServiceStatusEnum.getLabelByCode(originalCode);
|
||||
t.setServiceStatus(convertedLabel);
|
||||
|
||||
// 응답에 불필요한 필드 제거 (null 처리)
|
||||
t.setSenderKeyType(null);
|
||||
t.setCategoryCode(null);
|
||||
});
|
||||
|
||||
// 6. 최종 응답 반환 (가공된 템플릿 리스트 포함)
|
||||
return new RestResponse(templateList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse getTemplateDetail(BizTemplateRequest bizTemplateRequest) throws JsonProcessingException {
|
||||
|
||||
// 테스트 모드 확인
|
||||
if(StringUtils.isNotEmpty(bizTemplateRequest.getTest_yn())) {
|
||||
return TestDataUtil.getTemplateDetailTestData(bizTemplateRequest.getTest_yn());
|
||||
}
|
||||
|
||||
// SenderKey 검증
|
||||
RestResponse STAT_2010 = isSenderKeyChk(bizTemplateRequest);
|
||||
if (STAT_2010 != null) return STAT_2010;
|
||||
|
||||
// 1. 템플릿 목록 조회 요청 DTO 생성 (BIZ ID, API Key, senderKey 포함)
|
||||
BizTemplateRequest requestDto= BizTemplateRequest.builder()
|
||||
.bizId(BIZ_ID)
|
||||
.apiKey(BIZ_API_KEY)
|
||||
.senderKey(bizTemplateRequest.getSenderKey())
|
||||
.templateCode(bizTemplateRequest.getTemplateCode())
|
||||
.build();
|
||||
|
||||
// 2. 외부 API 호출 - 템플릿 목록 요청 (/v3/kakao/template/list)
|
||||
TemplateDetailResponse response = apiService.postForBizTemplateDetailEntity(
|
||||
BIZ_ROOT_URL+"/v3/kakao/template/detail"
|
||||
, requestDto
|
||||
);
|
||||
|
||||
log.info(" + response :: [{}]", response.toString());
|
||||
|
||||
|
||||
// 6. 최종 응답 반환 (가공된 템플릿 리스트 포함)
|
||||
return new RestResponse(response.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemplateExist(String senderKey, String templateCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("senderKey", senderKey);
|
||||
params.put("templateCode", templateCode);
|
||||
return inqryMapper.isTemplateExist(params) > 0;
|
||||
}
|
||||
|
||||
private @Nullable RestResponse isSenderKeyChk(BizTemplateRequest bizTemplateRequest) {
|
||||
List<MjKakaoProfileInfoVO> chnlIdList = (List<MjKakaoProfileInfoVO>) this.getChnlId(bizTemplateRequest).getData();
|
||||
|
||||
log.info("bizTemplateRequest.getSenderKey() :: [{}]", bizTemplateRequest.getSenderKey());
|
||||
log.info("chnlIdList :: [{}]", chnlIdList.toString());
|
||||
|
||||
boolean skErr = chnlIdList.stream()
|
||||
.anyMatch(p -> bizTemplateRequest.getSenderKey().equals(p.getSenderKey()));
|
||||
if(!skErr){
|
||||
return new RestResponse(new FailRestResponse("STAT_2010", ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.inqry.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
|
||||
public interface InqryService {
|
||||
RestResponse getChnlId(BizTemplateRequest bizTemplateRequest);
|
||||
|
||||
RestResponse getTemplates(BizTemplateRequest bizTemplateRequest) throws JsonProcessingException;
|
||||
|
||||
RestResponse getTemplateDetail(BizTemplateRequest bizTemplateRequest) throws JsonProcessingException;
|
||||
|
||||
boolean isTemplateExist(String senderKey, String templateCode);
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.inqry.web;
|
||||
|
||||
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.service.InqryService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
/**
|
||||
* fileName : InqryRestContoller.java
|
||||
* author : hylee
|
||||
* date : 2025-06-27
|
||||
* description :
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-06-27 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@CrossOrigin("*") // 모든 요청에 접근 허용
|
||||
@RestController
|
||||
public class InqryRestContoller {
|
||||
|
||||
@Autowired
|
||||
private InqryService inqryService;
|
||||
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-06-27
|
||||
* @author hylee
|
||||
*/
|
||||
@PostMapping("/api/kakao/inqry/chnlId")
|
||||
public ResponseEntity<RestResponse> getChnlId(BizTemplateRequest bizTemplateRequest) throws Exception {
|
||||
|
||||
// List<MjKakaoProfileInfoVO> resultList = inqryService.getChnlId(bizTemplateRequest.getMberId(), bizTemplateRequest.getTest_yn());
|
||||
// List<MjKakaoProfileInfoVO> resultList = inqryService.getChnlId(bizTemplateRequest.getMberId(), bizTemplateRequest.getTest_yn());
|
||||
|
||||
return ResponseEntity.ok().body(inqryService.getChnlId(bizTemplateRequest));
|
||||
// return ResponseEntity.ok().body(new RestResponse(resultList));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 템플릿 리스트 호출
|
||||
* @author hylee
|
||||
*/
|
||||
@PostMapping("/api/kakao/inqry/templates/list")
|
||||
public ResponseEntity<RestResponse> getTemplates(BizTemplateRequest bizTemplateRequest) throws Exception {
|
||||
|
||||
return ResponseEntity.ok().body(inqryService.getTemplates(bizTemplateRequest));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 템플릿 상세
|
||||
* @author hylee
|
||||
*/
|
||||
@PostMapping("/api/kakao/inqry/templates/detail")
|
||||
public ResponseEntity<RestResponse> getTemplateDetail(BizTemplateRequest bizTemplateRequest) throws Exception {
|
||||
|
||||
// log.info("bizTemplateRequest :: [{}]", bizTemplateRequest.toString());
|
||||
return ResponseEntity.ok().body(inqryService.getTemplateDetail(bizTemplateRequest));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
package com.itn.mjonApi.mjon.api.send.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.*;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.cmn.msg
|
||||
@ -21,7 +20,9 @@ import org.springframework.http.ResponseEntity;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MjonResponseVO {
|
||||
@JsonIgnoreProperties(ignoreUnknown = true) // JSON에 있지만 VO에 없는 필드를 무시하고 무사히 역직렬화해 줌
|
||||
@ToString
|
||||
public class MjonAtResponseVO {
|
||||
|
||||
private String result;
|
||||
private String message;
|
||||
@ -30,17 +31,16 @@ public class MjonResponseVO {
|
||||
private String msgGroupId;
|
||||
private String afterCash;
|
||||
private String msgType;
|
||||
private String statCode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param stringResponseEntity
|
||||
* @param apiReturnNode
|
||||
* @return ResponseEntity vo convert
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
public static MjonResponseVO getMjonResponse(ResponseEntity<String> stringResponseEntity) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
MjonResponseVO mjonResponseVO = objectMapper.readValue(stringResponseEntity.getBody(), MjonResponseVO.class);
|
||||
return mjonResponseVO;
|
||||
}
|
||||
|
||||
// public static MjonAtResponseVO getMjonResponse(JsonNode apiReturnNode) throws JsonProcessingException {
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
// return objectMapper.treeToValue(apiReturnNode, MjonAtResponseVO.class);
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* fileName : MsgAtRequestVO.java
|
||||
* author : hylee
|
||||
* date : 2025-07-29
|
||||
* description : 알림톡
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-07-29 hylee 최초 생성
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
public class MsgAtRequestVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String sendKind = "A";
|
||||
|
||||
private String mberId; // value = "사용자 ID", example = "goodgkdus"
|
||||
|
||||
private String accessKey; // value = "Api Key", example = "0367a25ec370d1141898a0b9767103"
|
||||
|
||||
private String senderKey; // 카카오 알림톡 채널ID
|
||||
|
||||
private String templateCode; // 카카오 알림톡 템플릿 코드
|
||||
|
||||
private String callFrom; // value = "발신번호 :: 정책이 필요함", example = "01011112222"
|
||||
|
||||
private String reserveYn = "N"; // 예약발송 여부 (기본: N)
|
||||
// 대체문자 여부
|
||||
private String subMsgSendYn;
|
||||
|
||||
private Boolean hasTemplateTitle = false; // 템플릿에 타이틀이 있으면 true
|
||||
|
||||
private String test_yn;
|
||||
|
||||
private List<VarAtListMapVO> varListMap = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class VarAtListMapVO {
|
||||
|
||||
|
||||
/**
|
||||
* @description : 수신자번호
|
||||
*/
|
||||
private String callToList;
|
||||
|
||||
/**
|
||||
* @description : 카카오 내용
|
||||
*/
|
||||
private String templateContent;
|
||||
|
||||
/**
|
||||
* @description : 카카오템플릿
|
||||
*/
|
||||
private String templateTitle;
|
||||
|
||||
/**
|
||||
* @description : 치환문자
|
||||
*/
|
||||
private String subMsgTxt;
|
||||
//
|
||||
// /**
|
||||
// * @description : [*3*] - 치환문자
|
||||
// */
|
||||
// private String rep3;
|
||||
//
|
||||
// /**
|
||||
// * @description : [*4*] - 치환문자
|
||||
// */
|
||||
// private String rep4;
|
||||
//
|
||||
// /**
|
||||
// * @description : 제목
|
||||
// */
|
||||
// private String subject;
|
||||
//
|
||||
// /**
|
||||
// * @description : 내용
|
||||
// */
|
||||
// private String message;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.service;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.VarAtListMapVO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* fileName : IndexedParameterParserService.java
|
||||
* author : hylee
|
||||
* date : 2025-08-18
|
||||
* description : 알림톡 인덱스된 파라미터 파싱 서비스
|
||||
* parseIndexedParametersFromRequest 메서드의 아키텍처 분리를 위해 생성
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-08-18 hylee 최초 생성
|
||||
*/
|
||||
@Service
|
||||
public class AtIndexedParameterParserService {
|
||||
|
||||
// 정규식 패턴을 static final로 캐싱하여 성능 최적화
|
||||
private static final Pattern INDEX_PATTERN =
|
||||
Pattern.compile("^(callTo|templateContent|templateTitle|subMsgTxt)_(\\d+)$");
|
||||
|
||||
/**
|
||||
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하여 VarListMapVO 리스트로 변환
|
||||
* callTo_1~100, templateContent_1~100, templateTitle_1~100, subMsgTxt_1~100 등을 동적 처리
|
||||
*
|
||||
* @param request HTTP 요청 객체
|
||||
* @return 파싱된 VarListMapVO 리스트
|
||||
*/
|
||||
public List<VarAtListMapVO> parseIndexedParameters(MsgAtRequestVO msgAtRequestVO, HttpServletRequest request) {
|
||||
List<VarAtListMapVO> varListMap = new ArrayList<>();
|
||||
|
||||
// 모든 파라미터 맵 가져오기
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
|
||||
// 인덱스별 데이터를 저장할 맵
|
||||
Map<Integer, Map<String, String>> indexedDataMap = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
// 모든 파라미터를 순회하며 인덱스된 파라미터 찾기
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
String paramName = entry.getKey();
|
||||
String[] paramValues = entry.getValue();
|
||||
|
||||
Matcher matcher = INDEX_PATTERN.matcher(paramName);
|
||||
if (matcher.matches() && paramValues.length > 0) {
|
||||
String fieldName = matcher.group(1); // callTo, templateContent 등
|
||||
int index = Integer.parseInt(matcher.group(2)); // 1, 2, 3 등
|
||||
String value = paramValues[0]; // 파라미터 값
|
||||
|
||||
// 인덱스별 데이터 맵에 저장
|
||||
indexedDataMap.computeIfAbsent(index, k -> new HashMap<>()).put(fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
// 인덱스 순서대로 VarListMapVO 생성
|
||||
List<Integer> sortedIndexes = new ArrayList<>(indexedDataMap.keySet());
|
||||
Collections.sort(sortedIndexes);
|
||||
|
||||
// 대체문자전송여부
|
||||
String subMsgSendYn = msgAtRequestVO.getSubMsgSendYn();
|
||||
for (Integer index : sortedIndexes) {
|
||||
Map<String, String> dataMap = indexedDataMap.get(index);
|
||||
|
||||
VarAtListMapVO vo = new VarAtListMapVO();
|
||||
vo.setCallToList(dataMap.get("callTo"));
|
||||
vo.setTemplateContent(dataMap.get("templateContent"));
|
||||
vo.setTemplateTitle(dataMap.get("templateTitle"));
|
||||
|
||||
// 치환 데이터는 subMsgSendYn 이 Y일때
|
||||
if("Y".equals(subMsgSendYn)){
|
||||
vo.setSubMsgTxt(dataMap.get("subMsgTxt"));
|
||||
}
|
||||
|
||||
// 필수 필드 중 하나라도 있으면 리스트에 추가
|
||||
if (vo.getCallToList() != null || vo.getTemplateContent() != null || vo.getTemplateTitle() != null) {
|
||||
varListMap.add(vo);
|
||||
}
|
||||
}
|
||||
|
||||
return varListMap;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.detail.TemplateDetail;
|
||||
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.service.InqryService;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.VarAtListMapVO;
|
||||
import com.itn.mjonApi.util.MunjaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* fileName : AtParameterProcessingService.java
|
||||
* author : hylee
|
||||
* date : 2025-08-18
|
||||
* description : 알림톡 파라미터 처리 서비스
|
||||
* MsgAtRequestVO의 비즈니스 로직을 담당
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-08-18 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AtParameterProcessingService {
|
||||
|
||||
@Autowired
|
||||
private AtIndexedParameterParserService indexedParameterParserService;
|
||||
|
||||
@Autowired
|
||||
private InqryService inqryService;
|
||||
|
||||
/**
|
||||
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하고 검증하여
|
||||
* MsgAtRequestVO의 varListMap에 설정
|
||||
*
|
||||
* @param msgAtRequestVO 요청 VO 객체
|
||||
* @param request HTTP 요청 객체
|
||||
* @return 검증 실패 시 오류 코드, 성공 시 null
|
||||
*/
|
||||
public String processIndexedParameters(MsgAtRequestVO msgAtRequestVO, HttpServletRequest request) {
|
||||
|
||||
// 기존 varListMap 초기화
|
||||
msgAtRequestVO.setVarListMap(new ArrayList<>());
|
||||
|
||||
|
||||
log.info(" msgAtRequestVO :: [{}]", msgAtRequestVO.toString());
|
||||
// 채널ID 확인
|
||||
String STAT_2010 = this.validateSenderKey(msgAtRequestVO.getMberId(), msgAtRequestVO.getSenderKey());
|
||||
if (STAT_2010 != null) return STAT_2010;
|
||||
|
||||
// 템플릿 코드 확인
|
||||
String STAT_2030 = this.validateTemplateCode(msgAtRequestVO);
|
||||
if (STAT_2030 != null) return STAT_2030;
|
||||
|
||||
// 파싱 로직을 IndexedParameterParserService에 위임
|
||||
List<VarAtListMapVO> parsedList = indexedParameterParserService.parseIndexedParameters(msgAtRequestVO, request);
|
||||
|
||||
// 파싱된 각 VO에 대해 검증 수행
|
||||
for (VarAtListMapVO vo : parsedList) {
|
||||
String validationError = MunjaUtil.kakaoAtValidate(vo, msgAtRequestVO);
|
||||
|
||||
if (StringUtils.isNotEmpty(validationError)) {
|
||||
return validationError; // 검증 실패 시 오류 코드 반환
|
||||
}
|
||||
|
||||
// 검증 통과한 VO를 리스트에 추가
|
||||
msgAtRequestVO.getVarListMap().add(vo);
|
||||
}
|
||||
|
||||
return null; // 모든 검증 통과
|
||||
}
|
||||
|
||||
private String validateTemplateCode(MsgAtRequestVO msgAtRequestVO) {
|
||||
// private String validateTemplateCode(String mberId, String senderKey, String templateCode) {
|
||||
|
||||
String mberId = msgAtRequestVO.getMberId();
|
||||
String senderKey = msgAtRequestVO.getSenderKey();
|
||||
String templateCode = msgAtRequestVO.getTemplateCode();
|
||||
|
||||
try {
|
||||
BizTemplateRequest request = BizTemplateRequest.builder()
|
||||
.mberId(mberId)
|
||||
.senderKey(senderKey)
|
||||
.templateCode(templateCode)
|
||||
.build();
|
||||
|
||||
RestResponse response = inqryService.getTemplateDetail(request);
|
||||
|
||||
if (response.getData() == null) {
|
||||
return "STAT_2030"; // 템플릿 상세 정보를 가져올 수 없음
|
||||
}
|
||||
|
||||
TemplateDetail detail = (TemplateDetail) response.getData();
|
||||
|
||||
// 로그 출력
|
||||
log.info("template detail :: [{}]", detail);
|
||||
|
||||
// templateTitle 존재 여부 확인
|
||||
if (StringUtils.isNotEmpty(detail.getTemplateTitle())) {
|
||||
msgAtRequestVO.setHasTemplateTitle(true);
|
||||
}
|
||||
|
||||
return detail != null ? null : "STAT_2030";
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "STAT_2099";
|
||||
}
|
||||
}
|
||||
|
||||
public String validateSenderKey(String mberId, String senderKey) {
|
||||
if (StringUtils.isEmpty(senderKey)) {
|
||||
return "STAT_2010";
|
||||
}
|
||||
|
||||
|
||||
List<MjKakaoProfileInfoVO> resultList = (List<MjKakaoProfileInfoVO>) inqryService.getChnlId(BizTemplateRequest.builder().mberId(mberId).build()).getData();
|
||||
boolean ok = resultList.stream().anyMatch(p -> senderKey.equals(p.getSenderKey()));
|
||||
return ok ? null : "STAT_2010";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface SendAtService {
|
||||
|
||||
|
||||
// RestResponse sendMsgData(MsgRequestVO msgRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgData_advc(MsgRequestVO msgRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgsData(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendAtData(MsgAtRequestVO msgAtRequestVO, HttpServletRequest request) throws JsonProcessingException;
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.service.AtParameterProcessingService;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.service.SendAtService;
|
||||
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.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.SendSucRestResponse;
|
||||
import com.itn.mjonApi.util.TestDataUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SendAtServiceImpl implements SendAtService {
|
||||
|
||||
@Autowired
|
||||
private AtParameterProcessingService atParameterProcessingService;
|
||||
|
||||
private ApiService<Response> apiService;
|
||||
|
||||
@Autowired
|
||||
SendMapper sendMapper;
|
||||
|
||||
@Autowired
|
||||
PriceMapper priceMapper;
|
||||
|
||||
@Autowired
|
||||
public SendAtServiceImpl(ApiService<Response> apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
|
||||
private static final String replaseStrList = "[*이름*],[*1*],[*2*],[*3*],[*4*]";
|
||||
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 치환없는 알림톡 데이터
|
||||
* @author hylee
|
||||
*/
|
||||
@Override
|
||||
public RestResponse sendAtData(MsgAtRequestVO msgAtRequestVO, HttpServletRequest request) throws JsonProcessingException {
|
||||
|
||||
|
||||
|
||||
if(StringUtils.isNotEmpty(msgAtRequestVO.getTest_yn())){
|
||||
// YF => 실패 테스트 데이터, YS => 성공 테스트 데이터 (알림톡 전용)
|
||||
return TestDataUtil.getTestAtSendReturnData(msgAtRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
|
||||
// Form-data의 인덱스된 파라미터들을 VarListMapVO 리스트로 변환 (동적 처리 _1~_100)
|
||||
String falseCode = atParameterProcessingService.processIndexedParameters(msgAtRequestVO, request);
|
||||
if(StringUtils.isNotEmpty(falseCode)){
|
||||
return new RestResponse(new FailRestResponse(falseCode,""));
|
||||
}
|
||||
|
||||
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax_advc.do"
|
||||
, msgAtRequestVO
|
||||
, String.class
|
||||
);
|
||||
|
||||
|
||||
// convertMjonDataToApiResponse => MjonResponseVO 데이터를 ApiResponse 데이터로 변환하는 메소드
|
||||
log.info(" + munjaSendResponse :: [{}]", munjaSendResponse.toString());
|
||||
if("OK".equals(munjaSendResponse.getResult())){ // 성공
|
||||
return new RestResponse(SendSucRestResponse.convertMjonDataToApiResponse(munjaSendResponse));
|
||||
}else{ // 실패
|
||||
return new RestResponse(new FailRestResponse(munjaSendResponse.getStatCode(),""));
|
||||
}
|
||||
|
||||
// return new RestResponse(msgAtRequestVO);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.at.send.web;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.service.SendAtService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.send.web
|
||||
* fileName : SendRestController
|
||||
* author : hylee
|
||||
* date : 2023-02-15
|
||||
* description :
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-02-15 hylee 최초 생성
|
||||
*/
|
||||
|
||||
// 치환문자가 있으면 , => §로 치환
|
||||
|
||||
@CrossOrigin("*") // 모든 요청에 접근 허용
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class SendAtRestController {
|
||||
|
||||
|
||||
@Autowired
|
||||
private SendAtService sendAtService;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param msgAtRequestVO
|
||||
* @param request
|
||||
* @Discription [문자 발송] 같은 내용으로 여려명에게 보냄
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/kakao/at/sendMsg")
|
||||
public ResponseEntity<RestResponse> sendMsg(MsgAtRequestVO msgAtRequestVO, HttpServletRequest request) throws Exception {
|
||||
|
||||
// https://smartsms.aligo.in/alimapi.html
|
||||
|
||||
return ResponseEntity.ok().body(sendAtService.sendAtData(msgAtRequestVO, request));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
public class FtButtonVO {
|
||||
private String name;
|
||||
private String linkType; // AC, DS, WL, AL, BK, MD
|
||||
private String linkTypeName; // 채널 추가, 배송조회, 웹링크, 앱링크, 봇키워드, 메시지전달
|
||||
private String linkMo; // 모바일 링크
|
||||
private String linkPc; // PC 링크
|
||||
private String linkIos; // iOS Scheme
|
||||
private String linkAnd; // Android Scheme
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class FtSendSuccessResponse {
|
||||
|
||||
private String resultCode = "0"; // 성공 코드
|
||||
|
||||
private String msgType = "FT"; // 메시지 타입 (친구톡 고정)
|
||||
|
||||
private List<String> msgGroupIdList; // 메시지 전송 그룹 ID 리스트
|
||||
|
||||
private String successCnt; // 성공 건수
|
||||
|
||||
private String failCnt; // 실패 건수
|
||||
|
||||
private String test_yn; // 테스트 여부
|
||||
|
||||
/**
|
||||
* 친구톡 발송 결과를 SMS API 형태로 변환
|
||||
* @param totalCount 총 발송 건수
|
||||
* @param successCount 성공 건수
|
||||
* @param failCount 실패 건수
|
||||
* @param successPhoneList 성공한 전화번호 리스트
|
||||
* @return FtSendSuccessResponse
|
||||
*/
|
||||
public static FtSendSuccessResponse createFtResponse(int totalCount, int successCount, int failCount,
|
||||
List<String> successPhoneList) {
|
||||
|
||||
// 성공한 발송별로 msgGroupId 생성
|
||||
List<String> msgGroupIdList = new ArrayList<>();
|
||||
for (int i = 0; i < successCount; i++) {
|
||||
msgGroupIdList.add(generateMsgGroupId());
|
||||
}
|
||||
|
||||
return FtSendSuccessResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupIdList(msgGroupIdList)
|
||||
.msgType("FT") // 친구톡 고정
|
||||
.successCnt(String.valueOf(successCount))
|
||||
.failCnt(String.valueOf(failCount))
|
||||
.test_yn(null)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 메시지 그룹 ID 생성 (SMS API와 동일한 형태)
|
||||
* MSGGID_0000000013451, MSGGID_0000000013452 형태
|
||||
* @return MSGGID_xxxxxxxxxxxx 형태의 ID
|
||||
*/
|
||||
private static String generateMsgGroupId() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
// 13자리 숫자로 맞추기 위해 currentTime을 조정
|
||||
String msgId = String.format("%013d", currentTime % 10000000000000L);
|
||||
return "MSGGID_" + msgId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
public class KakaoButtonVO {
|
||||
|
||||
private String name; // 버튼명
|
||||
private String linkType; // 링크타입 (WL: 웹링크, AL: 앱링크)
|
||||
private String linkTypeName; // 링크타입명
|
||||
|
||||
// 웹링크용
|
||||
private String linkMo; // 모바일 웹링크
|
||||
private String linkPc; // PC 웹링크
|
||||
|
||||
// 앱링크용
|
||||
private String linkIos; // iOS 앱링크
|
||||
private String linkAnd; // Android 앱링크
|
||||
|
||||
// 기타
|
||||
private String pluginId; // 플러그인 ID
|
||||
}
|
||||
@ -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<>();
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
public class MjonFTSendVO {
|
||||
|
||||
// 수신자 정보 (핵심)
|
||||
private String phone; // 수신번호 (필수)
|
||||
private String name; // 수신자명
|
||||
|
||||
// 치환문자 (현재 사용안함)
|
||||
private String rep1; // 치환문자1
|
||||
private String rep2; // 치환문자2
|
||||
private String rep3; // 치환문자3
|
||||
private String rep4; // 치환문자4
|
||||
|
||||
// 메시지 관련
|
||||
private String msgId; // 메시지 ID
|
||||
private String msgGroupId; // 메시지 그룹 ID
|
||||
private String userId; // 사용자 ID
|
||||
private String callFrom; // 발신번호
|
||||
private String callTo; // 수신번호 (phone과 동일)
|
||||
private String reqDate; // 요청일시
|
||||
private String agentCode; // 에이전트 코드
|
||||
private String subject; // 제목
|
||||
private String smsTxt; // SMS 내용
|
||||
private String msgType; // 메시지 타입
|
||||
|
||||
// 파일 관련
|
||||
private String fileCnt; // 파일 개수
|
||||
private String filePath1; // 파일경로1
|
||||
private String filePath2; // 파일경로2
|
||||
private String filePath3; // 파일경로3
|
||||
|
||||
// 기타
|
||||
// @Builder.Default
|
||||
// private String eventYn = "N"; // 이벤트 여부 (기본: N)
|
||||
private String eachPrice; // 개별 가격
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.cmn.msg
|
||||
* fileName : mjonResponse
|
||||
* author : hylee
|
||||
* date : 2023-05-12
|
||||
* description : 문자온 프로젝트에서 받은 리턴값
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-12 hylee 최초 생성
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true) // JSON에 있지만 VO에 없는 필드를 무시하고 무사히 역직렬화해 줌
|
||||
@ToString
|
||||
public class MjonFtResponseVO {
|
||||
|
||||
private String result;
|
||||
private String message;
|
||||
private String resultSts; // 전송결과 갯수
|
||||
private String resultBlockSts; // 수신거부 갯수
|
||||
private String msgGroupId;
|
||||
private String afterCash;
|
||||
private String msgType;
|
||||
private String statCode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param apiReturnNode
|
||||
* @return ResponseEntity vo convert
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
// public static MjonAtResponseVO getMjonResponse(JsonNode apiReturnNode) throws JsonProcessingException {
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
// return objectMapper.treeToValue(apiReturnNode, MjonAtResponseVO.class);
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* fileName : MsgAtRequestVO.java
|
||||
* author : hylee
|
||||
* date : 2025-07-29
|
||||
* description : 알림톡
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-07-29 hylee 최초 생성
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
public class MsgFtRequestVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String sendKind = "A";
|
||||
|
||||
private String mberId; // value = "사용자 ID", example = "goodgkdus"
|
||||
|
||||
private String accessKey; // value = "Api Key", example = "0367a25ec370d1141898a0b9767103"
|
||||
|
||||
private String senderKey; // 카카오 알림톡 채널ID
|
||||
|
||||
private String templateCode; // 카카오 알림톡 템플릿 코드
|
||||
|
||||
private String callFrom; // value = "발신번호 :: 정책이 필요함", example = "01011112222"
|
||||
|
||||
// 대체문자 여부
|
||||
private String subMsgSendYn;
|
||||
|
||||
// 광고 여부
|
||||
private String adFlag;
|
||||
|
||||
private String test_yn;
|
||||
|
||||
|
||||
// 실제 업로드 파일(로그/직렬화 제외)
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private MultipartFile templateImage;
|
||||
|
||||
|
||||
// ====== ⬇️ AOP/DB 저장용(문자열/숫자만) 메타데이터 필드들 ======
|
||||
// template
|
||||
private String templateImageName;
|
||||
private String templateImageContentType;
|
||||
private Long templateImageSize; // bytes
|
||||
private Integer templateImageWidth; // px
|
||||
private Integer templateImageHeight; // px
|
||||
private String templateImageSha256; // hexdigest
|
||||
private String templateImageSavedPath; // 서버 저장 경로(선택)
|
||||
private String templateAtchFileId; // 내부 첨부ID(선택)
|
||||
private String templateMsgType;
|
||||
|
||||
/**
|
||||
* @description : 친구톡 이미지 등록된 URL
|
||||
*/
|
||||
private String templateImageUrl;
|
||||
|
||||
/**
|
||||
* @description : 치환문자 이미지
|
||||
* 이미지 문자가 있고 대체문자가 있으면(subMsgSendYn="Y") filepath에 atchFileId 있어야함
|
||||
*/
|
||||
private String filePath1;
|
||||
|
||||
|
||||
/**
|
||||
* @description : 버튼 사용
|
||||
*/
|
||||
private List<FtButtonVO> buttons = new ArrayList<>();
|
||||
|
||||
|
||||
// sub
|
||||
|
||||
// @JsonIgnore
|
||||
// @ToString.Exclude
|
||||
// private MultipartFile subImage;
|
||||
|
||||
// private String subImageName;
|
||||
// private String subImageContentType;
|
||||
// private Long subImageSize;
|
||||
// private Integer subImageWidth;
|
||||
// private Integer subImageHeight;
|
||||
// private String subImageSha256;
|
||||
// private String subImageSavedPath;
|
||||
// private String subAtchFileId;
|
||||
// private String subMsgType;
|
||||
|
||||
private List<VarFtListMapVO> varListMap = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class VarFtListMapVO {
|
||||
|
||||
|
||||
/**
|
||||
* @description : 수신자번호
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* @description : 친구톡 내용
|
||||
*/
|
||||
private String templateContent;
|
||||
|
||||
/**
|
||||
* @description : 치환문자
|
||||
*/
|
||||
private String subMsgTxt;
|
||||
|
||||
|
||||
//
|
||||
// /**
|
||||
// * @description : [*3*] - 치환문자
|
||||
// */
|
||||
// private String rep3;
|
||||
//
|
||||
// /**
|
||||
// * @description : [*4*] - 치환문자
|
||||
// */
|
||||
// private String rep4;
|
||||
//
|
||||
// /**
|
||||
// * @description : 제목
|
||||
// */
|
||||
// private String subject;
|
||||
//
|
||||
// /**
|
||||
// * @description : 내용
|
||||
// */
|
||||
// private String message;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.FtButtonVO;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* fileName : IndexedParameterParserService.java
|
||||
* author : hylee
|
||||
* date : 2025-08-18
|
||||
* description : 알림톡 인덱스된 파라미터 파싱 서비스
|
||||
* parseIndexedParametersFromRequest 메서드의 아키텍처 분리를 위해 생성
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-08-18 hylee 최초 생성
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FtIndexedParameterParserService {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 정규식 패턴을 static final로 캐싱하여 성능 최적화
|
||||
private static final Pattern INDEX_PATTERN =
|
||||
Pattern.compile("^(callTo|templateContent|subMsgTxt|button)_(\\d+)$");
|
||||
|
||||
/**
|
||||
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하여 VarListMapVO 리스트로 변환
|
||||
* callTo_1~100, templateContent_1~100, templateTitle_1~100, subMsgTxt_1~100 등을 동적 처리
|
||||
*
|
||||
* @param request HTTP 요청 객체
|
||||
* @return 파싱된 VarListMapVO 리스트
|
||||
*/
|
||||
public List<VarFtListMapVO> parseIndexedParameters(MsgFtRequestVO msgFtRequestVO, HttpServletRequest request) {
|
||||
List<VarFtListMapVO> varListMap = new ArrayList<>();
|
||||
|
||||
// 모든 파라미터 맵 가져오기
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
|
||||
// 인덱스별 데이터를 저장할 맵
|
||||
Map<Integer, Map<String, String>> indexedDataMap = new HashMap<>();
|
||||
|
||||
|
||||
String subMsgSendYn = msgFtRequestVO.getSubMsgSendYn();
|
||||
|
||||
// 모든 파라미터를 순회하며 인덱스된 파라미터 찾기
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
String paramName = entry.getKey();
|
||||
String[] paramValues = entry.getValue();
|
||||
|
||||
Matcher matcher = INDEX_PATTERN.matcher(paramName);
|
||||
if (matcher.matches() && paramValues.length > 0) {
|
||||
String fieldName = matcher.group(1); // callTo, templateContent 등
|
||||
int index = Integer.parseInt(matcher.group(2)); // 1, 2, 3 등
|
||||
String value = paramValues[0]; // 파라미터 값
|
||||
|
||||
// 인덱스별 데이터 맵에 저장
|
||||
indexedDataMap.computeIfAbsent(index, k -> new HashMap<>()).put(fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
// 인덱스 순서대로 VarListMapVO 생성
|
||||
List<Integer> sortedIndexes = new ArrayList<>(indexedDataMap.keySet());
|
||||
Collections.sort(sortedIndexes);
|
||||
|
||||
for (Integer index : sortedIndexes) {
|
||||
Map<String, String> dataMap = indexedDataMap.get(index);
|
||||
|
||||
VarFtListMapVO vo = new VarFtListMapVO();
|
||||
vo.setPhone(dataMap.get("callTo"));
|
||||
vo.setTemplateContent(dataMap.get("templateContent"));
|
||||
|
||||
// 치환 데이터는 subMsgSendYn 이 Y일때
|
||||
if("Y".equals(subMsgSendYn)){
|
||||
vo.setSubMsgTxt(dataMap.get("subMsgTxt"));
|
||||
}
|
||||
// 필수 필드 중 하나라도 있으면 리스트에 추가
|
||||
if (vo.getPhone() != null || vo.getTemplateContent() != null) {
|
||||
varListMap.add(vo);
|
||||
}
|
||||
}
|
||||
|
||||
// 버튼 파라미터를 요청 레벨에서 한 번만 파싱
|
||||
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 (buttonArray != null && buttonArray.isArray()) {
|
||||
for (JsonNode button : buttonArray) {
|
||||
FtButtonVO ftButton = FtButtonVO.builder()
|
||||
.name(getJsonText(button, "name"))
|
||||
.linkType(getJsonText(button, "linkType"))
|
||||
.linkTypeName(getJsonText(button, "linkTypeName"))
|
||||
.linkMo(getJsonText(button, "linkMo"))
|
||||
.linkPc(getJsonText(button, "linkPc"))
|
||||
.linkIos(getJsonText(button, "linkIos"))
|
||||
.linkAnd(getJsonText(button, "linkAnd"))
|
||||
.build();
|
||||
buttonList.add(ftButton);
|
||||
}
|
||||
}
|
||||
// ✅ MsgFtRequestVO에 버튼 설정 (모든 수신자 공통)
|
||||
msgFtRequestVO.setButtons(buttonList);
|
||||
} catch (Exception e) {
|
||||
log.error("버튼 JSON 파싱 실패: {}", buttonData, e);
|
||||
msgFtRequestVO.setButtons(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return varListMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* JsonNode에서 안전하게 텍스트 값을 추출하는 헬퍼 메서드
|
||||
*
|
||||
* @param node JSON 노드
|
||||
* @param fieldName 필드명
|
||||
* @return 텍스트 값 (null 또는 빈 값일 경우 null 반환)
|
||||
*/
|
||||
private String getJsonText(JsonNode node, String fieldName) {
|
||||
if (node != null && node.has(fieldName)) {
|
||||
JsonNode fieldNode = node.get(fieldName);
|
||||
if (!fieldNode.isNull()) {
|
||||
String text = fieldNode.asText();
|
||||
return text.isEmpty() ? null : text;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.domain.StatusResponse;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.BizTemplateRequest;
|
||||
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.ft.send.mapper.domain.MsgFtRequestVO;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* fileName : AtParameterProcessingService.java
|
||||
* author : hylee
|
||||
* date : 2025-08-18
|
||||
* description : 알림톡 파라미터 처리 서비스
|
||||
* MsgAtRequestVO의 비즈니스 로직을 담당
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2025-08-18 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FtParameterProcessingService {
|
||||
|
||||
@Autowired
|
||||
private FtIndexedParameterParserService indexedParameterParserService;
|
||||
|
||||
@Autowired
|
||||
private InqryService inqryService;
|
||||
|
||||
private ApiService<Response> apiService;
|
||||
|
||||
@Autowired
|
||||
public FtParameterProcessingService(ApiService<Response> apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
/**
|
||||
* HttpServletRequest에서 동적으로 인덱스된 파라미터들을 파싱하고 검증하여
|
||||
* MsgAtRequestVO의 varListMap에 설정
|
||||
*
|
||||
* @param msgFtRequestVO 요청 VO 객체
|
||||
* @param request HTTP 요청 객체
|
||||
* @return 검증 실패 시 오류 코드, 성공 시 null
|
||||
*/
|
||||
public String processIndexedParameters(MsgFtRequestVO msgFtRequestVO, HttpServletRequest request) {
|
||||
|
||||
// 기존 varListMap 초기화
|
||||
msgFtRequestVO.setVarListMap(new ArrayList<>());
|
||||
|
||||
|
||||
// 채널ID 확인
|
||||
String STAT_2010 = this.validateSenderKey(msgFtRequestVO.getMberId(), msgFtRequestVO.getSenderKey());
|
||||
if (STAT_2010 != null) return STAT_2010;
|
||||
|
||||
// 템플릿 코드 확인
|
||||
// String STAT_2030 = this.validateTemplateCode(msgFtRequestVO.getMberId(), msgFtRequestVO.getSenderKey(), msgFtRequestVO.getTemplateCode());
|
||||
// if (STAT_2030 != null) return STAT_2030;
|
||||
|
||||
// 파싱 로직을 IndexedParameterParserService에 위임
|
||||
List<VarFtListMapVO> parsedList = indexedParameterParserService.parseIndexedParameters(msgFtRequestVO, request);
|
||||
|
||||
// 파싱된 각 VO에 대해 검증 수행
|
||||
for (VarFtListMapVO vo : parsedList) {
|
||||
String validationError = MunjaUtil.kakaoFtValidate(vo, msgFtRequestVO);
|
||||
|
||||
if (StringUtils.isNotEmpty(validationError)) {
|
||||
return validationError; // 검증 실패 시 오류 코드 반환
|
||||
}
|
||||
|
||||
// 검증 통과한 VO를 리스트에 추가
|
||||
msgFtRequestVO.getVarListMap().add(vo);
|
||||
}
|
||||
|
||||
return null; // 모든 검증 통과
|
||||
}
|
||||
|
||||
|
||||
public String validateSenderKey(String mberId, String senderKey) {
|
||||
if (StringUtils.isEmpty(senderKey)) {
|
||||
return "STAT_2010";
|
||||
}
|
||||
|
||||
List<MjKakaoProfileInfoVO> resultList = (List<MjKakaoProfileInfoVO>) inqryService.getChnlId(BizTemplateRequest.builder().mberId(mberId).build()).getData();
|
||||
boolean ok = resultList.stream().anyMatch(p -> senderKey.equals(p.getSenderKey()));
|
||||
return ok ? null : "STAT_2010";
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public interface SendFtService {
|
||||
|
||||
|
||||
// RestResponse sendMsgData(MsgRequestVO msgRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgData_advc(MsgRequestVO msgRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgsData(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
//
|
||||
// RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendFtData(MsgFtRequestVO msgFtRequestVO, HttpServletRequest request) throws IOException, NoSuchAlgorithmException;
|
||||
}
|
||||
@ -0,0 +1,197 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.service.impl;
|
||||
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
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.SendFtService;
|
||||
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.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.util.TestDataUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SendFtServiceImpl implements SendFtService {
|
||||
|
||||
@Autowired
|
||||
private FtParameterProcessingService ftParameterProcessingService;
|
||||
|
||||
private ApiService<Response> apiService;
|
||||
|
||||
@Autowired
|
||||
SendMapper sendMapper;
|
||||
|
||||
@Autowired
|
||||
PriceMapper priceMapper;
|
||||
|
||||
@Autowired
|
||||
public SendFtServiceImpl(ApiService<Response> apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
|
||||
private static final String replaseStrList = "[*이름*],[*1*],[*2*],[*3*],[*4*]";
|
||||
|
||||
|
||||
/**
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception 처리 중 예외 발생 가능
|
||||
* @date 2025-07-29
|
||||
* @Discription 치환없는 알림톡 데이터
|
||||
* @author hylee
|
||||
*/
|
||||
@Override
|
||||
public RestResponse sendFtData(MsgFtRequestVO msgFtRequestVO, HttpServletRequest request) throws IOException, NoSuchAlgorithmException {
|
||||
|
||||
if(StringUtils.isNotEmpty(msgFtRequestVO.getTest_yn())){
|
||||
// YF => 실패 테스트 데이터, YS => 성공 테스트 데이터 (친구톡 전용)
|
||||
return TestDataUtil.getTestFtSendReturnData(msgFtRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
// 데이터
|
||||
// Form-data의 인덱스된 파라미터들을 VarListMapVO 리스트로 변환 (동적 처리 _1~_100)
|
||||
String falseCode = ftParameterProcessingService.processIndexedParameters(msgFtRequestVO, request);
|
||||
if(StringUtils.isNotEmpty(falseCode)){
|
||||
log.info("falseCode :: [{}]", 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<>();
|
||||
|
||||
|
||||
log.info("msgFtRequestVO.toString() :: [{}]", msgFtRequestVO.toString());
|
||||
// 각 수신자별로 개별 발송 처리
|
||||
// List<KakaoFTSendVO> individualRequestList = new ArrayList<>();
|
||||
for (VarFtListMapVO recipient : msgFtRequestVO.getVarListMap()) {
|
||||
try {
|
||||
// 개별 수신자용 KakaoFTSendVO 생성
|
||||
KakaoFTSendVO individualRequest = createKakaoFTSendVO(msgFtRequestVO, recipient);
|
||||
// individualRequestList.add(individualRequest);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.ft.send.web;
|
||||
|
||||
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.service.SendFtService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.send.web
|
||||
* fileName : SendRestController
|
||||
* author : hylee
|
||||
* date : 2023-02-15
|
||||
* description :
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-02-15 hylee 최초 생성
|
||||
*/
|
||||
|
||||
// 치환문자가 있으면 , => §로 치환
|
||||
|
||||
@CrossOrigin("*") // 모든 요청에 접근 허용
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class SendFtRestController {
|
||||
|
||||
|
||||
@Autowired
|
||||
private SendFtService sendFtService;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param msgFtRequestVO
|
||||
* @param request
|
||||
* @Discription [문자 발송] 같은 내용으로 여려명에게 보냄
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/api/kakao/ft/sendMsg",
|
||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public ResponseEntity<RestResponse> sendMsg(
|
||||
@ModelAttribute MsgFtRequestVO msgFtRequestVO // 폼 텍스트들 바인딩
|
||||
, HttpServletRequest request) throws Exception {
|
||||
|
||||
// https://smartsms.aligo.in/friendapi.html
|
||||
|
||||
return ResponseEntity.ok().body(sendFtService.sendFtData(msgFtRequestVO, request));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,279 @@
|
||||
package com.itn.mjonApi.mjon.api.kakao.utils;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.kakao.ft.send.mapper.domain.MsgFtRequestVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Kakao FT 이미지 메타데이터 유틸리티.
|
||||
* - 템플릿/서브 이미지의 파일명, 용량, 폭/높이, SHA-256 해시 세팅
|
||||
* - 템플릿: I/W 타입 판정(2:1, 4:3, 가로≥500) 및 검증
|
||||
* - 서브(MMS): jpg/jpeg/png/gif, ≤10MB만 검증(권장 640×960은 안내 수준)
|
||||
* - 실패 시 코드 문자열 반환(성공 시 null)
|
||||
*/
|
||||
@Slf4j
|
||||
public class FtFileMetaUtil {
|
||||
|
||||
// ===== 실패코드 상수 정의 =====
|
||||
private static final String OK = null; // 성공 시 null 반환
|
||||
private static final String FT_E_EMPTY = "STAT_2055"; // 파일이 비어있음
|
||||
private static final String FT_E_IMG_READ_FAIL = "STAT_2052"; // 이미지 읽기 실패
|
||||
private static final String FT_E_WIDTH_LT_500 = "STAT_2054"; // 가로폭 500px 미만
|
||||
private static final String FT_E_RATIO_OUT_OF_RANGE = "STAT_2056"; // 비율이 2:1~4:3 범위 밖
|
||||
private static final String FT_E_SIZE_GT_5MB = "STAT_2051"; // 파일 크기 초과(5MB 이상)
|
||||
private static final String FT_E_CONTENT_TYPE = "STAT_2050"; // 허용되지 않는 콘텐츠 타입// 추가
|
||||
private static final String FT_E_SIZE_GT_10MB = "STAT_2057"; // 대체문자(MMS) 이미지는 10MB를 초과할 수 없습니다.
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 템플릿 이미지의 메타데이터(파일명, 용량, 폭/높이, 해시, 타입)를 MsgFtRequestVO에 채움
|
||||
* @param vo 메타데이터를 세팅할 VO
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static String fillTemplateMeta(MsgFtRequestVO vo) throws IOException, NoSuchAlgorithmException {
|
||||
return fillMeta(vo.getTemplateImage(),
|
||||
(name) -> vo.setTemplateImageName(name),
|
||||
(ct) -> vo.setTemplateImageContentType(ct),
|
||||
(size) -> vo.setTemplateImageSize(size),
|
||||
(w) -> vo.setTemplateImageWidth(w),
|
||||
(h) -> vo.setTemplateImageHeight(h),
|
||||
(hash) -> vo.setTemplateImageSha256(hash),
|
||||
(type) -> vo.setTemplateMsgType(type) // I/W 세팅
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 서브(와이드) 이미지의 메타데이터를 MsgFtRequestVO에 채움
|
||||
* - MMS 규격 검증(타입/10MB)만 수행, I/W 판정 없음
|
||||
* @param vo 메타데이터를 세팅할 VO
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
// public static String fillSubMeta(MsgFtRequestVO vo) throws IOException, NoSuchAlgorithmException {
|
||||
// return fillMetaForSubImage(vo.getSubImage(),
|
||||
// (name) -> vo.setSubImageName(name),
|
||||
// (ct) -> vo.setSubImageContentType(ct),
|
||||
// (size) -> vo.setSubImageSize(size),
|
||||
// (w) -> vo.setSubImageWidth(w),
|
||||
// (h) -> vo.setSubImageHeight(h),
|
||||
// (hash) -> vo.setSubImageSha256(hash)
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* subImage(MMS) 전용 메타데이터 수집/검증 메서드
|
||||
* - 검증: 파일 존재 여부, 용량(≤10MB), Content-Type(jpg/jpeg/png/gif)
|
||||
* - 세팅: 파일명, Content-Type, 파일 크기, width/height, SHA-256
|
||||
* - 비율/가로 500px 검증은 하지 않음 (권장 640×960은 안내 수준)
|
||||
*
|
||||
* @param f 업로드된 서브 이미지 파일
|
||||
* @param nameC 파일명 setter
|
||||
* @param ctC Content-Type setter
|
||||
* @param sizeC 파일 크기 setter
|
||||
* @param wC width setter
|
||||
* @param hC height setter
|
||||
* @param hashC SHA-256 setter
|
||||
* @return 실패코드(String), 성공 시 null(OK)
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
private static String fillMetaForSubImage(
|
||||
MultipartFile f,
|
||||
Consumer<String> nameC,
|
||||
Consumer<String> ctC,
|
||||
Consumer<Long> sizeC,
|
||||
Consumer<Integer> wC,
|
||||
Consumer<Integer> hC,
|
||||
Consumer<String> hashC
|
||||
) throws IOException, NoSuchAlgorithmException {
|
||||
// 1) 파일 존재/빈 파일 체크
|
||||
if (f == null || f.isEmpty()) return FT_E_EMPTY;
|
||||
|
||||
// 2) 용량(10MB) 제한
|
||||
if (f.getSize() > 10L * 1024 * 1024) return FT_E_SIZE_GT_10MB;
|
||||
|
||||
// 3) 허용 Content-Type 확인 (jpg/jpeg/png/gif)
|
||||
String ct = f.getContentType();
|
||||
if (!isAllowedSubCt(ct)) return FT_E_CONTENT_TYPE;
|
||||
|
||||
// 4) 기본 메타 세팅
|
||||
nameC.accept(f.getOriginalFilename());
|
||||
ctC.accept(ct);
|
||||
sizeC.accept(f.getSize());
|
||||
|
||||
// 5) 이미지 읽기 → width/height 세팅 (비율 제한 없음)
|
||||
int w = 0, h = 0;
|
||||
try (InputStream is = f.getInputStream()) {
|
||||
BufferedImage img = ImageIO.read(is);
|
||||
if (img == null) return FT_E_IMG_READ_FAIL;
|
||||
w = img.getWidth();
|
||||
h = img.getHeight();
|
||||
wC.accept(w);
|
||||
hC.accept(h);
|
||||
} catch (Exception e) {
|
||||
return FT_E_IMG_READ_FAIL;
|
||||
}
|
||||
|
||||
// sha-256
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(f.getBytes());
|
||||
hashC.accept(bytesToHex(md.digest()));
|
||||
|
||||
// 권장 사이즈(640×960)는 안내사항이므로 실패코드 미반환
|
||||
return OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통 메타데이터 채우기 유틸
|
||||
* - 파일명, Content-Type, 파일 크기
|
||||
* - 이미지 폭/높이
|
||||
* - 파일 SHA-256 해시
|
||||
* - 가로/세로 비율 기반의 메시지 타입(I/W) 판정
|
||||
*
|
||||
* @param f MultipartFile (이미지 파일)
|
||||
* @param nameC 파일명 setter
|
||||
* @param ctC ContentType setter
|
||||
* @param sizeC 파일 크기 setter
|
||||
* @param wC width setter
|
||||
* @param hC height setter
|
||||
* @param hashC SHA-256 setter
|
||||
* @param typeC 이미지 타입(I/W) setter
|
||||
* @return 실패코드(String), 성공 시 null 반환
|
||||
*/
|
||||
private static String fillMeta(MultipartFile f,
|
||||
Consumer<String> nameC,
|
||||
Consumer<String> ctC,
|
||||
Consumer<Long> sizeC,
|
||||
Consumer<Integer> wC,
|
||||
Consumer<Integer> hC,
|
||||
Consumer<String> hashC,
|
||||
Consumer<String> typeC
|
||||
) throws IOException, NoSuchAlgorithmException {
|
||||
if (f == null || f.isEmpty()) return FT_E_EMPTY;
|
||||
|
||||
// 용량/콘텐츠타입 1차 검증
|
||||
if (f.getSize() > 5L * 1024 * 1024) return FT_E_SIZE_GT_5MB;
|
||||
|
||||
String ct = f.getContentType();
|
||||
log.info(" + ct :: [{}]", ct);
|
||||
|
||||
// MIME 타입이 application/octet-stream이면 파일명으로 추정
|
||||
if ("application/octet-stream".equalsIgnoreCase(ct)) {
|
||||
String filename = f.getOriginalFilename();
|
||||
if (filename != null) {
|
||||
String ext = filename.toLowerCase();
|
||||
if (ext.endsWith(".jpg") || ext.endsWith(".jpeg")) {
|
||||
ct = "image/jpeg";
|
||||
} else if (ext.endsWith(".png")) {
|
||||
ct = "image/png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ct == null || !(ct.equalsIgnoreCase("image/jpeg")
|
||||
|| ct.equalsIgnoreCase("image/png"))) {
|
||||
return FT_E_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
nameC.accept(f.getOriginalFilename());
|
||||
ctC.accept(ct);
|
||||
sizeC.accept(f.getSize());
|
||||
|
||||
int w = 0, h = 0;
|
||||
try (InputStream is = f.getInputStream()) {
|
||||
BufferedImage img = ImageIO.read(is);
|
||||
if (img == null) return FT_E_IMG_READ_FAIL;
|
||||
w = img.getWidth();
|
||||
h = img.getHeight();
|
||||
wC.accept(w);
|
||||
hC.accept(h);
|
||||
} catch (Exception e) {
|
||||
return FT_E_IMG_READ_FAIL;
|
||||
}
|
||||
|
||||
// sha-256
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(f.getBytes());
|
||||
hashC.accept(bytesToHex(md.digest()));
|
||||
|
||||
// 규칙 검증 + 타입(I/W) 판정
|
||||
String typeOrCode = calcFtMsgTypeOrCode(w, h);
|
||||
if (typeOrCode.length() == 1) { // "I" or "W"
|
||||
typeC.accept(typeOrCode);
|
||||
return OK;
|
||||
}
|
||||
return typeOrCode; // 실패코드 리턴
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] → 16진수 문자열 변환
|
||||
* @param bytes SHA-256 결과 바이트 배열
|
||||
* @return Hex 문자열
|
||||
*/
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes) sb.append(String.format("%02x", b));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 가로/세로 크기를 기반으로 이미지 타입 판정
|
||||
* - 폭 < 500px → 오류코드 반환
|
||||
* - 비율이 2:1(약 2.0) ±10% → "I"
|
||||
* - 비율이 4:3(약 1.333) ±10% → "W"
|
||||
* - 그 외 → 오류코드 반환
|
||||
*
|
||||
* @param width 이미지 가로 폭
|
||||
* @param height 이미지 세로 높이
|
||||
* @return "I" 또는 "W" / 실패코드
|
||||
*/
|
||||
public static String calcFtMsgTypeOrCode(int width, int height) {
|
||||
if (width < 500 || height <= 0) return FT_E_WIDTH_LT_500;
|
||||
|
||||
double r = (double) width / (double) height;
|
||||
// 2:1 ~= 2.0, 4:3 ~= 1.333... (±10%)
|
||||
boolean isI = (r >= 1.8 && r <= 2.2);
|
||||
boolean isW = (r >= 1.28 && r <= 1.36);
|
||||
|
||||
if (isI) return "I";
|
||||
if (isW) return "W";
|
||||
return FT_E_RATIO_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* MultipartFile 존재 여부 헬퍼
|
||||
* @param f 업로드 파일
|
||||
* @return 파일이 null이 아니고 비어있지 않으면 true
|
||||
*/
|
||||
public static boolean hasFile(MultipartFile f){ return f != null && !f.isEmpty(); }
|
||||
|
||||
|
||||
/**
|
||||
* 서브(MMS) 허용 Content-Type 검사
|
||||
* 허용: image/jpeg, image/jpg, image/png, image/gif
|
||||
* @param ct 요청의 Content-Type
|
||||
* @return 허용 타입이면 true
|
||||
*/
|
||||
private static boolean isAllowedSubCt(String ct) {
|
||||
return ct != null && (
|
||||
ct.equalsIgnoreCase("image/jpeg") ||
|
||||
ct.equalsIgnoreCase("image/jpg") || // 일부 클라이언트 대비
|
||||
ct.equalsIgnoreCase("image/png") ||
|
||||
ct.equalsIgnoreCase("image/gif")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.mapper;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.MjonResponseVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @packageName : com.itn.mjonApi.mjon.api.inqry.service.mapper
|
||||
* @packageName : com.itn.mjonApi.mjon.api.msg.inqry.service.mapper
|
||||
* @fileName : PriceMapper.java
|
||||
* @author : JunHo Lee
|
||||
* @date : 2023.05.15
|
||||
@ -1,11 +1,11 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.mapper;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @packageName : com.itn.mjonApi.mjon.api.inqry.service.mapper
|
||||
* @packageName : com.itn.mjonApi.mjon.api.msg.inqry.service.mapper
|
||||
* @fileName : PriceMapper.java
|
||||
* @author : JunHo Lee
|
||||
* @date : 2023.05.15
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@ -1,14 +1,9 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.mapper.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@ -27,13 +22,23 @@ public class PriceResponse {
|
||||
private double shortPrice; // 단문 이용단가
|
||||
private double longPrice; // 장문 이용단가
|
||||
private double picturePrice; // 그림 이용단가
|
||||
|
||||
|
||||
private double kakaoAtPrice; // 그림 이용단가
|
||||
private double kakaoFtPrice; // 그림 이용단가
|
||||
private double kakaoFtImgPrice; // 그림 이용단가
|
||||
private double kakaoFtWideImgPrice; // 그림 이용단가
|
||||
|
||||
private double mberMoney; // 잔액
|
||||
|
||||
private int shortSendPsbltEa; // 단문 발송 가능건 수
|
||||
private int longSendPsbltEa; // 장문 발송 가능건 수
|
||||
private int pictureSendPsbltEa; // 그림 발송 가능건 수
|
||||
|
||||
private int kakaoAtSendPsbltEa; // 그림 발송 가능건 수
|
||||
private int kakaoFtSendPsbltEa; // 그림 발송 가능건 수
|
||||
private int kakaoFtImgSendPsbltEa; // 그림 발송 가능건 수
|
||||
private int kakaoFtWideImgSendPsbltEa; // 그림 발송 가능건 수
|
||||
|
||||
/*
|
||||
* 200-OK : 정상접속
|
||||
* 401-Unauthorized : 인증실패
|
||||
@ -0,0 +1,39 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PriceVO implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -7865729705175845268L;
|
||||
|
||||
private String mberId; // 사용자 ID
|
||||
|
||||
private double shortPrice; // 단문 이용단가
|
||||
private double longPrice; // 장문 이용단가
|
||||
private double picturePrice; // 그림 이용단가
|
||||
|
||||
private double kakaoAtPrice; // 알림톡 이용단가
|
||||
private double kakaoFtPrice; // 친구톡 이용단가
|
||||
private double kakaoFtImgPrice; // 친구톡 그림 이용단가
|
||||
private double kakaoFtWideImgPrice; // 친구톡 와이드 그림 이용단가
|
||||
|
||||
private double mberMoney; // 잔액
|
||||
|
||||
private int shortSendPsbltEa; // 단문 발송 가능건 수
|
||||
private int longSendPsbltEa; // 장문 발송 가능건 수
|
||||
private int pictureSendPsbltEa; // 그림 발송 가능건 수
|
||||
|
||||
private int kakaoAtSendPsbltEa; // 알림톡 발송 가능건 수
|
||||
private int kakaoFtSendPsbltEa; // 친구톡 발송 가능건 수
|
||||
private int kakaoFtImgSendPsbltEa; // 친구톡 그림 발송 가능건 수
|
||||
private int kakaoFtWideImgSendPsbltEa; // 친구톡 와이드 그림 발송 가능건 수
|
||||
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryVO;
|
||||
|
||||
public interface HstryService {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
|
||||
/**
|
||||
* @packageName : com.itn.mjonApi.mjon.api.inqry.service
|
||||
* @packageName : com.itn.mjonApi.mjon.api.msg.inqry.service
|
||||
* @fileName : PriceService.java
|
||||
* @author : JunHo Lee
|
||||
* @date : 2023.05.15
|
||||
@ -1,15 +1,15 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.impl;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.service.impl;
|
||||
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.HstryMapper;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.HstryService;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.SendMapper;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.HstryMapper;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.service.HstryService;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryResponse;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.SendMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -28,9 +28,7 @@ public class HstryServiceImpl implements HstryService {
|
||||
|
||||
@Autowired
|
||||
HstryMapper hstryMapper;
|
||||
|
||||
@Autowired
|
||||
SendMapper sendMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
public HstryServiceImpl(ApiService<Response> apiService) {
|
||||
@ -1,13 +1,13 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.service.impl;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.service.impl;
|
||||
|
||||
import com.itn.mjonApi.cmn.model.Price;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.StatMsg;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.PriceMapper;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.domain.PriceResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.PriceService;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.PriceMapper;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.PriceResponse;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.service.PriceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -16,7 +16,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @packageName : com.itn.mjonApi.mjon.api.inqry.service.impl
|
||||
* @packageName : com.itn.mjonApi.mjon.api.msg.inqry.service.impl
|
||||
* @fileName : PriceServiceImpl.java
|
||||
* @author : JunHo Lee
|
||||
* @date : 2023.05.15
|
||||
@ -59,10 +59,20 @@ public class PriceServiceImpl implements PriceService {
|
||||
.shortPrice(priceVO.getShortPrice())
|
||||
.longPrice(priceVO.getLongPrice())
|
||||
.picturePrice(priceVO.getPicturePrice())
|
||||
|
||||
.kakaoAtPrice(priceVO.getKakaoAtPrice())
|
||||
.kakaoFtPrice(priceVO.getKakaoFtPrice())
|
||||
.kakaoFtImgPrice(priceVO.getKakaoFtImgPrice())
|
||||
.kakaoFtWideImgPrice(priceVO.getKakaoFtWideImgPrice())
|
||||
//3. 발송가능건수
|
||||
.shortSendPsbltEa(priceVO.getShortSendPsbltEa())
|
||||
.longSendPsbltEa(priceVO.getLongSendPsbltEa())
|
||||
.pictureSendPsbltEa(priceVO.getPictureSendPsbltEa())
|
||||
|
||||
.kakaoAtSendPsbltEa(priceVO.getKakaoAtSendPsbltEa())
|
||||
.kakaoFtSendPsbltEa(priceVO.getKakaoFtSendPsbltEa())
|
||||
.kakaoFtImgSendPsbltEa(priceVO.getKakaoFtImgSendPsbltEa())
|
||||
.kakaoFtWideImgSendPsbltEa(priceVO.getKakaoFtWideImgSendPsbltEa())
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -1,9 +1,9 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.web;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.web;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.HstryService;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.HstryVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.service.HstryService;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryDetailVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.HstryVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -24,7 +24,6 @@ import org.springframework.web.client.RestTemplate;
|
||||
* 2023-02-15 hylee 최초 생성
|
||||
*/
|
||||
|
||||
// 치환문자가 있으면 , => §로 치환
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.inqry.web;
|
||||
package com.itn.mjonApi.mjon.api.msg.inqry.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -6,11 +6,11 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.inqry.service.PriceService;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.inqry.service.PriceService;
|
||||
|
||||
/**
|
||||
* @packageName : com.itn.mjonApi.mjon.api.inqry.web
|
||||
* @packageName : com.itn.mjonApi.mjon.api.msg.inqry.web
|
||||
* @fileName : PriceRestController.java
|
||||
* @author : JunHo Lee
|
||||
* @date : 2023.05.15
|
||||
@ -1,10 +1,10 @@
|
||||
package com.itn.mjonApi.mjon.api.send.mapper;
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MsgRequestVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.send.mapper.domain
|
||||
* packageName : com.itn.mjonApi.mjon.api.msg.send.mapper.domain
|
||||
* fileName : SendMapper
|
||||
* author : hylee
|
||||
* date : 2023-05-19
|
||||
@ -0,0 +1,44 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper.domain;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class MjonMsgSendVO{
|
||||
|
||||
|
||||
/**
|
||||
* @description : 수신자번호
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* @description : [*이름*] - 치환문자
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @description : [*1*] - 치환문자
|
||||
*/
|
||||
private String rep1;
|
||||
|
||||
/**
|
||||
* @description : [*2*] - 치환문자
|
||||
*/
|
||||
private String rep2;
|
||||
|
||||
/**
|
||||
* @description : [*3*] - 치환문자
|
||||
*/
|
||||
private String rep3;
|
||||
|
||||
/**
|
||||
* @description : [*4*] - 치환문자
|
||||
*/
|
||||
private String rep4;
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.cmn.msg
|
||||
* fileName : mjonResponse
|
||||
* author : hylee
|
||||
* date : 2023-05-12
|
||||
* description : 문자온 프로젝트에서 받은 리턴값
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-12 hylee 최초 생성
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true) // JSON에 있지만 VO에 없는 필드를 무시하고 무사히 역직렬화해 줌
|
||||
@ToString
|
||||
public class MjonResponseVO {
|
||||
|
||||
private String result;
|
||||
private String message;
|
||||
private String resultSts; // 전송결과 갯수
|
||||
private String resultBlockSts; // 수신거부 갯수
|
||||
private String msgGroupId;
|
||||
private String afterCash;
|
||||
private String msgType;
|
||||
private String statCode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param apiReturnNode
|
||||
* @return ResponseEntity vo convert
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
public static MjonResponseVO getMjonResponse(JsonNode apiReturnNode) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.treeToValue(apiReturnNode, MjonResponseVO.class);
|
||||
}
|
||||
// public static MjonResponseVO getMjonResponse(ResponseEntity<String> stringResponseEntity) throws JsonProcessingException {
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
// return objectMapper.readValue(stringResponseEntity.getBody(), MjonResponseVO.class);
|
||||
// }
|
||||
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
package com.itn.mjonApi.mjon.api.send.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.send.mapper.domain
|
||||
* packageName : com.itn.mjonApi.mjon.api.msg.send.mapper.domain
|
||||
* fileName : MjonMsgVO
|
||||
* author : hylee
|
||||
* date : 2023-05-09
|
||||
@ -18,6 +19,7 @@ import java.io.Serializable;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ToString
|
||||
public class MsgRequestVO implements Serializable {
|
||||
|
||||
/**
|
||||
@ -33,6 +35,8 @@ public class MsgRequestVO implements Serializable {
|
||||
|
||||
private String smsTxt; // value = "SMS용 메시지본문", example = "문자 메세지 본문"
|
||||
|
||||
private String smsTxtArea;//문자 작성 화면 본문 내용
|
||||
|
||||
private String[] callToList; // value = "수신번호리스트", dataType = "[Ljava.lang.String;", example = "01011112222,01022223333"
|
||||
|
||||
private String callFrom; // value = "발신번호 :: 정책이 필요함", example = "01011112222"
|
||||
@ -98,6 +102,10 @@ public class MsgRequestVO implements Serializable {
|
||||
|
||||
private String test_yn; // 테스트 여부
|
||||
|
||||
private String sendKind; // 문자종류
|
||||
|
||||
|
||||
List<MjonMsgSendVO> mjonMsgSendVOList;
|
||||
|
||||
// private String msgId ;// '문자ID',
|
||||
// private String userId ; // '문자온 일반회원ID',
|
||||
@ -113,7 +121,6 @@ public class MsgRequestVO implements Serializable {
|
||||
// private String rsltCode2; // '결과처리 상세코드',
|
||||
// private String rsltNet; // '결과처리 통신사',
|
||||
// private String subject; // 'MMS용 메시지제목',
|
||||
// private String smsTxtArea;//문자 작성 화면 본문 내용
|
||||
// private String msgPayCode; // '재전송 기능에 의한 최종전송콘텐트 종류 저장',
|
||||
// private String contSeq; // COMMENT 'MMS의 콘텐츠 Key(MMS_CONTENTS_INFO의 CONT_SEQ)',
|
||||
// private String msgTypeResend; // '재전송할 문자 타입. 값이 있으면 재전송. 없으면 단 건 전송',
|
||||
@ -228,6 +235,14 @@ public class MsgRequestVO implements Serializable {
|
||||
this.smsTxt = smsTxt;
|
||||
}
|
||||
|
||||
public String getSmsTxtArea() {
|
||||
return smsTxtArea;
|
||||
}
|
||||
|
||||
public void setSmsTxtArea(String smsTxtArea) {
|
||||
this.smsTxtArea = smsTxtArea;
|
||||
}
|
||||
|
||||
public String[] getCallToList() {
|
||||
return callToList;
|
||||
}
|
||||
@ -475,4 +490,20 @@ public class MsgRequestVO implements Serializable {
|
||||
public void setTest_yn(String test_yn) {
|
||||
this.test_yn = test_yn;
|
||||
}
|
||||
|
||||
public String getSendKind() {
|
||||
return sendKind;
|
||||
}
|
||||
|
||||
public void setSendKind(String sendKind) {
|
||||
this.sendKind = sendKind;
|
||||
}
|
||||
|
||||
public List<MjonMsgSendVO> getMjonMsgSendVOList() {
|
||||
return mjonMsgSendVOList;
|
||||
}
|
||||
|
||||
public void setMjonMsgSendVOList(List<MjonMsgSendVO> mjonMsgSendVOList) {
|
||||
this.mjonMsgSendVOList = mjonMsgSendVOList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper.domain;
|
||||
|
||||
import com.itn.mjonApi.cmn.domain.SendRequestCmnVO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.api.msg.send.mapper.domain
|
||||
* fileName : MjonMsgVO
|
||||
* author : hylee
|
||||
* date : 2023-05-23
|
||||
* description : 문자 발송에 필요한 값들을 받는 vo
|
||||
* 1건~500건 대량 문자 개인별로 발송
|
||||
* ===========================================================
|
||||
* DATE AUTHOR NOTE
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-09 hylee 최초 생성
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MsgsRequestVO extends SendRequestCmnVO implements Serializable {
|
||||
|
||||
/**
|
||||
* 값이 있는 경우
|
||||
* 문자온 프로젝트에서 처리해줌
|
||||
* null이면 에러
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String mberId; // 사용자 ID
|
||||
|
||||
private String accessKey; // Api Key
|
||||
|
||||
private String smsTxt; // SMS용 메시지본문
|
||||
|
||||
private String[] callToList; // 수신번호리스트
|
||||
|
||||
private String callFrom; // 발신번호 :: 정책이 필요함
|
||||
|
||||
private String eachPrice = "0"; // 전송문자 개별가격
|
||||
private String sPrice = "0"; // 임시
|
||||
|
||||
private String totPrice = "0"; // 전송문자 토탈가격
|
||||
|
||||
private String fileCnt = "0"; // 첨부파일 갯수
|
||||
|
||||
private String msgType = "4"; // 메시지의 (4: SMS 전송, 5: URL 전송, 6: MMS전송, 7: BARCODE전송, 8: 카카오 알림톡 전송)
|
||||
|
||||
// ==== 단가 ====
|
||||
private float smsPrice = 0; // sms 단가 null 이면 에러
|
||||
|
||||
private float mmsPrice = 0; // mms 단가 null 이면 에러
|
||||
// private float kakaoAtPrice; // 카카오 알림톡 단가
|
||||
// private float kakaoFtPrice; // 카카오 친구톡 단가
|
||||
// private float kakaoFtImgPrice;// 카카오 이미지 단가
|
||||
// private float kakaoFtWideImgPrice; // 카카오 와이드 이미지 단가
|
||||
|
||||
private String[] imgFilePath = new String[0]; // 그림 이미지 경로
|
||||
|
||||
|
||||
private String spamStatus; // 스팸문자 유무 (Y/N) - 서비스단에서 처리 함
|
||||
|
||||
private String txtReplYn = "N"; // 변환문자 유무 (Y/N) - 서비스단에서 처리 함
|
||||
|
||||
// private String nameStr; // value = "치환 이름 리스트 |로 구분", example = "홍길동1|홍길동2|홍길동3"
|
||||
|
||||
// private String rep1Str; // value = "치환 문자1 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep2Str; // value = "치환 문자2 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep3Str; // value = "치환 문자3 리스트 |로 구분", example = ""
|
||||
|
||||
// private String rep4Str; // value = "치환 문자4 리스트 |로 구분", example = ""
|
||||
|
||||
// private String[] nameList= new String[0]; // value = "nameStr 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep1List= new String[0]; // value = "rep1Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep2List= new String[0]; // value = "rep2Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep3List= new String[0]; // value = "rep3Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
// private String[] rep4List= new String[0]; // value = "rep4Str 을 |로 split 후 담는 변수", example = ""
|
||||
|
||||
private String reserveYn = "N"; // value = "예약 유무 (Y/N)", example = "N"
|
||||
|
||||
// 치환 있을 경우 사용
|
||||
// private String shortMsgCnt; // value = "치환 후 단문 건수", example = ""
|
||||
|
||||
// private String longMsgCnt; // value = "치환 후 장문 건수", example = ""
|
||||
|
||||
|
||||
// @ApiModelProperty(value = "문자 종류 일반:N, 광고:A, 선거:C", example = "N", hidden = true)
|
||||
private String msgKind = "N"; // '문자 종류 일반:N, 광고:A, 선거:C',
|
||||
|
||||
private String test_yn; // 테스트 여부
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.itn.mjonApi.mjon.api.send.mapper.domain;
|
||||
package com.itn.mjonApi.mjon.api.msg.send.mapper.domain;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.StatMsg;
|
||||
import lombok.*;
|
||||
@ -67,13 +67,31 @@ public class SendSucRestResponse {
|
||||
private static List<String> getMsgType(String msgType) {
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
// msgType이 null이거나 빈 문자열인 경우 빈 리스트 반환
|
||||
if (msgType == null || msgType.trim().isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if(msgType.indexOf(",") > 0)
|
||||
{
|
||||
result = Arrays.stream(msgType.split(","))
|
||||
.map(s -> StatMsg.valueOf("msgType"+s).getMsg())
|
||||
.filter(s -> s != null && !s.trim().isEmpty()) // 빈 문자열 필터링
|
||||
.map(s -> {
|
||||
try {
|
||||
return StatMsg.valueOf("msgType" + s.trim()).getMsg();
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Unknown msgType: {}, skipping", s.trim());
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(s -> s != null) // null 값 제거
|
||||
.collect(Collectors.toList());
|
||||
}else{
|
||||
result.add(StatMsg.valueOf("msgType"+ msgType).getMsg());
|
||||
try {
|
||||
result.add(StatMsg.valueOf("msgType" + msgType.trim()).getMsg());
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Unknown msgType: {}, returning empty list", msgType.trim());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -85,31 +103,41 @@ public class SendSucRestResponse {
|
||||
*/
|
||||
public static SendSucRestResponse SendSuccessMsgsRestResponse(List<MjonResponseVO> mjonResponseVOList) {
|
||||
|
||||
mjonResponseVOList.forEach(t->log.info(t.toString()));
|
||||
|
||||
// 실패 카운트
|
||||
int failCnt = (int) mjonResponseVOList.stream()
|
||||
.filter(s->"fail".equals(s.getResult()))
|
||||
.filter(s->!"OK".equals(s.getResult()))
|
||||
.count();
|
||||
// 성공 카운트
|
||||
int successCnt = mjonResponseVOList.parallelStream()
|
||||
.filter(s->!"fail".equals(s.getResult()))
|
||||
.mapToInt(s -> Integer.parseInt(s.getResultSts()))
|
||||
.sum();
|
||||
int successCnt = (int) mjonResponseVOList.parallelStream()
|
||||
.filter(s->"OK".equals(s.getResult()))
|
||||
.count();
|
||||
// 수신거부 카운트
|
||||
int blockCnt = mjonResponseVOList.parallelStream()
|
||||
.filter(s->!"fail".equals(s.getResult()))
|
||||
.mapToInt(s -> Integer.parseInt(s.getResultBlockSts()))
|
||||
.sum();
|
||||
// int blockCnt = mjonResponseVOList.parallelStream()
|
||||
// .filter(s->!"OK".equals(s.getResult()))
|
||||
// .mapToInt(s -> Integer.parseInt(s.getResultBlockSts()))
|
||||
// .sum();
|
||||
|
||||
// 성공한 메세지 그룹 아이디
|
||||
List<String> msgGroupIdList = mjonResponseVOList.stream()
|
||||
.filter(s->!"fail".equals(s.getResult()))
|
||||
.filter(s->"OK".equals(s.getResult()))
|
||||
.map(s -> s.getMsgGroupId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 성공한 메세지 그룹 아이디
|
||||
// 메세지 타입
|
||||
List<String> msgTypeList = mjonResponseVOList.stream()
|
||||
.map(s -> StatMsg.valueOf("msgType"+s.getMsgType()).getMsg())
|
||||
.collect(Collectors.toList());
|
||||
.filter(s -> s.getMsgType() != null && !s.getMsgType().trim().isEmpty())
|
||||
.map(s -> {
|
||||
try {
|
||||
return StatMsg.valueOf("msgType" + s.getMsgType().trim()).getMsg();
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Unknown msgType in list: {}, skipping", s.getMsgType().trim());
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(s -> s != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
|
||||
@ -118,8 +146,8 @@ public class SendSucRestResponse {
|
||||
.resultCode(StatMsg.valueOf("STAT_0").getCode()) // 성공 코드 0 - StatMsg 참고
|
||||
.msgGroupIdList(msgGroupIdList) // 전송 메세지 그룹 ID
|
||||
.successCnt(Integer.toString(successCnt)) // 성공 건수
|
||||
.blockCnt(Integer.toString(blockCnt)) // 수신거부 건수
|
||||
.failCnt(Integer.toString(failCnt)) // 수신거부 건수
|
||||
// .blockCnt(Integer.toString(blockCnt)) // 수신거부 건수
|
||||
.failCnt(Integer.toString(failCnt)) // 실패 건수
|
||||
.msgTypeList(msgTypeList) // msgType List
|
||||
.build();
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.send.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MsgsRequestVO;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface SendService {
|
||||
|
||||
|
||||
// RestResponse sendMsgData(MsgRequestVO msgRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendMsgData_advc(MsgRequestVO msgRequestVO) throws Exception;
|
||||
|
||||
// RestResponse sendMsgsData(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO, Map<String, String> allParams) throws Exception;
|
||||
}
|
||||
@ -0,0 +1,367 @@
|
||||
package com.itn.mjonApi.mjon.api.msg.send.service.impl;
|
||||
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
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.domain.*;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.service.SendService;
|
||||
import com.itn.mjonApi.util.MunjaUtil;
|
||||
import com.itn.mjonApi.util.TestDataUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SendServiceImpl implements SendService {
|
||||
|
||||
private ApiService apiService;
|
||||
|
||||
@Autowired
|
||||
SendMapper sendMapper;
|
||||
|
||||
@Autowired
|
||||
PriceMapper priceMapper;
|
||||
|
||||
@Autowired
|
||||
public SendServiceImpl(ApiService apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
|
||||
private static final String replaseStrList = "[*이름*],[*1*],[*2*],[*3*],[*4*]";
|
||||
|
||||
@Override
|
||||
public RestResponse sendMsgData_advc(MsgRequestVO msgRequestVO) throws Exception {
|
||||
log.info(" :: sendMsgData_advc ::");
|
||||
|
||||
msgRequestVO.setSendKind("A");
|
||||
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getTest_yn())){
|
||||
// YF => 실패 테스트 데이터
|
||||
return TestDataUtil._getTestMsgReturnData(msgRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
// step2.수신자 전화번호 정상 여부 체크(정상 번호에 대해서만 발송 가능)
|
||||
// 1020
|
||||
// 폰번호 확인 - 빈 값 -> 유효성 정규식
|
||||
if(MunjaUtil.getCallToListChk(msgRequestVO.getCallToList())){
|
||||
return new RestResponse(new FailRestResponse("STAT_1020",""));
|
||||
}
|
||||
|
||||
// 치환 데이터 및 수신자 번호 VO 생성
|
||||
msgRequestVO.setMjonMsgSendVOList(this.buildMsgSendVOList(msgRequestVO));
|
||||
|
||||
// sms 변수 변경
|
||||
msgRequestVO.setSmsTxtArea(msgRequestVO.getSmsTxt());
|
||||
|
||||
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/mjon/msgdata/sendMsgDataAjax_advc.do"
|
||||
, msgRequestVO
|
||||
, String.class
|
||||
);
|
||||
|
||||
// convertMjonDataToApiResponse => MjonResponseVO 데이터를 ApiResponse 데이터로 변환하는 메소드
|
||||
log.info(" + munjaSendResponse :: [{}]", munjaSendResponse.toString());
|
||||
if("OK".equals(munjaSendResponse.getResult())){ // 성공
|
||||
return new RestResponse(SendSucRestResponse.convertMjonDataToApiResponse(munjaSendResponse));
|
||||
}else{ // 실패
|
||||
return new RestResponse(new FailRestResponse(munjaSendResponse.getStatCode(),""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* MsgRequestVO 내 nameStr, rep1Str~rep4Str, callToList 를 기반으로
|
||||
* 각 항목을 MjonMsgSendVO 리스트로 매핑한다.
|
||||
*
|
||||
* @param msgRequestVO 메시지 요청 VO
|
||||
* @return 수신자별 메시지 전송 VO 리스트
|
||||
*/
|
||||
public List<MjonMsgSendVO> buildMsgSendVOList(MsgRequestVO msgRequestVO) {
|
||||
|
||||
// 수신자 이름 및 치환 문자들 파싱 (null-safe 처리)
|
||||
String[] nameArr = Optional.ofNullable(msgRequestVO.getNameStr()).orElse("").split("\\|");
|
||||
String[] rep1Arr = Optional.ofNullable(msgRequestVO.getRep1Str()).orElse("").split("\\|");
|
||||
String[] rep2Arr = Optional.ofNullable(msgRequestVO.getRep2Str()).orElse("").split("\\|");
|
||||
String[] rep3Arr = Optional.ofNullable(msgRequestVO.getRep3Str()).orElse("").split("\\|");
|
||||
String[] rep4Arr = Optional.ofNullable(msgRequestVO.getRep4Str()).orElse("").split("\\|");
|
||||
|
||||
// 콤마(,) 기준으로 수신 번호 문자열을 파싱
|
||||
String[] phoneArr = Optional.ofNullable(msgRequestVO.getCallToList())
|
||||
.orElse(new String[0]);
|
||||
|
||||
|
||||
|
||||
List<MjonMsgSendVO> mjonMsgSendVOList = new ArrayList<>();
|
||||
|
||||
// 수신 번호 개수만큼 반복
|
||||
for (int i = 0; i < phoneArr.length; i++) {
|
||||
MjonMsgSendVO vo = new MjonMsgSendVO();
|
||||
|
||||
// 1. 수신 번호 세팅
|
||||
vo.setPhone(phoneArr[i].trim());
|
||||
|
||||
// 2. 이름/치환문자 세팅
|
||||
if (i < nameArr.length) vo.setName(nameArr[i].trim());
|
||||
if (i < rep1Arr.length) vo.setRep1(rep1Arr[i].trim());
|
||||
if (i < rep2Arr.length) vo.setRep2(rep2Arr[i].trim());
|
||||
if (i < rep3Arr.length) vo.setRep3(rep3Arr[i].trim());
|
||||
if (i < rep4Arr.length) vo.setRep4(rep4Arr[i].trim());
|
||||
|
||||
mjonMsgSendVOList.add(vo);
|
||||
}
|
||||
|
||||
return mjonMsgSendVOList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO) throws Exception {
|
||||
|
||||
|
||||
log.info(" :: sendMsgData_advc ::");
|
||||
|
||||
|
||||
if(StringUtils.isNotEmpty(msgsRequestVO.getTest_yn())){
|
||||
return TestDataUtil._getTestMsgsReturnData(msgsRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
// msgsVO -> msgVO List로 변환
|
||||
List<MsgRequestVO> msgRequestVOList = this.getDataCleaning_advc(msgsRequestVO);
|
||||
msgRequestVOList.forEach(t->log.info(" + t.toString() :: [{}]", t.toString()));
|
||||
|
||||
log.info("msgRequestVOList :: [{}]", msgRequestVOList.size());
|
||||
|
||||
|
||||
List<MjonResponseVO> mjonResponseVOList = new ArrayList<MjonResponseVO>();
|
||||
for(MsgRequestVO aa : msgRequestVOList){
|
||||
|
||||
aa.setSmsTxtArea(aa.getSmsTxt());
|
||||
aa.setSendKind("A");
|
||||
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/mjon/msgdata/sendMsgDataAjax_advc.do"
|
||||
, aa
|
||||
, String.class
|
||||
);
|
||||
|
||||
log.info("munjaSendResponse :: [{}]", munjaSendResponse.toString());
|
||||
mjonResponseVOList.add(munjaSendResponse);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return new RestResponse(SendSucRestResponse.SendSuccessMsgsRestResponse(mjonResponseVOList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse sendMsgsData_advc(MsgsRequestVO msgsRequestVO, Map<String, String> allParams) throws Exception {
|
||||
|
||||
|
||||
log.info(" :: sendMsgData_advc with Map params ::");
|
||||
|
||||
|
||||
if(StringUtils.isNotEmpty(msgsRequestVO.getTest_yn())){
|
||||
return TestDataUtil._getTestMsgsReturnData(msgsRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
// Map 기반 동적 파라미터 처리
|
||||
List<MsgRequestVO> msgRequestVOList = this.getDataCleaning_advc_withMap(msgsRequestVO, allParams);
|
||||
|
||||
log.info("msgRequestVOList :: [{}]", msgRequestVOList.size());
|
||||
|
||||
|
||||
List<MjonResponseVO> mjonResponseVOList = new ArrayList<MjonResponseVO>();
|
||||
for(MsgRequestVO aa : msgRequestVOList){
|
||||
|
||||
aa.setSmsTxtArea(aa.getSmsTxt());
|
||||
aa.setSendKind("A");
|
||||
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/mjon/msgdata/sendMsgDataAjax_advc.do"
|
||||
, aa
|
||||
, String.class
|
||||
);
|
||||
|
||||
log.info("munjaSendResponse :: [{}]", munjaSendResponse.toString());
|
||||
mjonResponseVOList.add(munjaSendResponse);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return new RestResponse(SendSucRestResponse.SendSuccessMsgsRestResponse(mjonResponseVOList));
|
||||
}
|
||||
|
||||
private static RestResponse callToErrorReturnData(MsgRequestVO msgRequestVO) {
|
||||
|
||||
FailRestResponse stat1020 = new FailRestResponse("STAT_1020","");
|
||||
String errorMsg = stat1020.getMsg();
|
||||
errorMsg.replace("수신자", "수신자(" + msgRequestVO.getCallToList()[0] + ")");
|
||||
stat1020.setMsg(errorMsg);
|
||||
|
||||
return new RestResponse(stat1020);
|
||||
}
|
||||
|
||||
|
||||
private static List<MsgRequestVO> getDataCleaning_advc(MsgsRequestVO msgsRequestVO) {
|
||||
|
||||
|
||||
List<MsgRequestVO> msgRequestVOList = new ArrayList<>();
|
||||
|
||||
// Reflection으로 Object Field에 접근한다.
|
||||
Field[] declaredFields = msgsRequestVO.getClass().getDeclaredFields();
|
||||
|
||||
String mberId = msgsRequestVO.getMberId(); // 사용자 ID
|
||||
String accessKey = msgsRequestVO.getAccessKey(); // accessKey
|
||||
String callFrom = msgsRequestVO.getCallFrom(); // 발신자 번호
|
||||
String callTo = null; // 수신자 번호
|
||||
|
||||
List<MjonMsgSendVO> mjonMsgSendVOList = new ArrayList<>();
|
||||
for (Field field : declaredFields) {
|
||||
|
||||
Object value = null;
|
||||
// private Field일 경우 접근을 허용한다.
|
||||
field.setAccessible(true);
|
||||
|
||||
try {
|
||||
// Field Value를 참조한다.
|
||||
value = field.get(msgsRequestVO);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.info("Reflection Error. {}", e);
|
||||
}
|
||||
|
||||
// nullPointException 방지
|
||||
if(value != null)
|
||||
{
|
||||
log.info("field.getName() : [{}]", field.getName());
|
||||
log.info("value.toString() : [{}]", value.toString());
|
||||
/**
|
||||
* 필드 이름으로 분기하여
|
||||
* 각각에 맞는 위치에 값을 넣어준다.
|
||||
*/
|
||||
if(field.getName().startsWith("callTo")){ // 수신자 번호
|
||||
callTo = value.toString();
|
||||
}else if(field.getName().startsWith("smsTxt")){ // 문자 내용
|
||||
|
||||
// 값이 비여 있으면 다음 반복문으로 넘어간다.
|
||||
if(StringUtils.isEmpty(value.toString())){
|
||||
callTo = "";
|
||||
continue;
|
||||
}
|
||||
MjonMsgSendVO vo = new MjonMsgSendVO();
|
||||
vo.setPhone(callTo);
|
||||
mjonMsgSendVOList.add(vo);
|
||||
|
||||
msgRequestVOList.add(
|
||||
MsgRequestVO.builder()
|
||||
.mberId(mberId)
|
||||
.accessKey(accessKey)
|
||||
.callFrom(callFrom)
|
||||
.smsTxt(value.toString())
|
||||
.mjonMsgSendVOList(mjonMsgSendVOList)
|
||||
.build()
|
||||
);
|
||||
// 초기화
|
||||
callTo = "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return msgRequestVOList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map 기반 동적 파라미터 처리를 위한 새로운 메소드
|
||||
* callTo_1, smsTxt_1, callTo_2, smsTxt_2 등의 동적 파라미터를 처리
|
||||
*/
|
||||
private List<MsgRequestVO> getDataCleaning_advc_withMap(MsgsRequestVO msgsRequestVO, Map<String, String> allParams) {
|
||||
|
||||
List<MsgRequestVO> msgRequestVOList = new ArrayList<>();
|
||||
|
||||
String mberId = msgsRequestVO.getMberId();
|
||||
String accessKey = msgsRequestVO.getAccessKey();
|
||||
String callFrom = msgsRequestVO.getCallFrom();
|
||||
|
||||
// 동적 파라미터를 순서대로 처리하기 위해 인덱스 기반으로 처리
|
||||
Map<Integer, String> callToMap = new HashMap<>();
|
||||
Map<Integer, String> smsTxtMap = new HashMap<>();
|
||||
|
||||
// 파라미터를 분석하여 인덱스별로 분류
|
||||
for (Map.Entry<String, String> entry : allParams.entrySet()) {
|
||||
String paramName = entry.getKey();
|
||||
String paramValue = entry.getValue();
|
||||
|
||||
log.info("Processing param: [{}] = [{}]", paramName, paramValue);
|
||||
|
||||
if (paramName.startsWith("callTo_")) {
|
||||
try {
|
||||
int index = Integer.parseInt(paramName.substring(7)); // "callTo_" 이후 숫자
|
||||
callToMap.put(index, paramValue);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("Invalid callTo parameter format: [{}]", paramName);
|
||||
}
|
||||
} else if (paramName.startsWith("smsTxt_")) {
|
||||
try {
|
||||
int index = Integer.parseInt(paramName.substring(7)); // "smsTxt_" 이후 숫자
|
||||
if (StringUtils.isNotEmpty(paramValue)) {
|
||||
smsTxtMap.put(index, paramValue);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("Invalid smsTxt parameter format: [{}]", paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 인덱스별로 메시지 요청 VO 생성
|
||||
for (Integer index : smsTxtMap.keySet()) {
|
||||
String callTo = callToMap.get(index);
|
||||
String smsTxt = smsTxtMap.get(index);
|
||||
|
||||
if (StringUtils.isNotEmpty(callTo) && StringUtils.isNotEmpty(smsTxt)) {
|
||||
List<MjonMsgSendVO> mjonMsgSendVOList = new ArrayList<>();
|
||||
MjonMsgSendVO vo = new MjonMsgSendVO();
|
||||
vo.setPhone(callTo);
|
||||
mjonMsgSendVOList.add(vo);
|
||||
|
||||
msgRequestVOList.add(
|
||||
MsgRequestVO.builder()
|
||||
.mberId(mberId)
|
||||
.accessKey(accessKey)
|
||||
.callFrom(callFrom)
|
||||
.smsTxt(smsTxt)
|
||||
.reserveYn("N")
|
||||
.mjonMsgSendVOList(mjonMsgSendVOList)
|
||||
.build()
|
||||
);
|
||||
|
||||
log.info("Created MsgRequestVO for index [{}]: callTo=[{}], smsTxt=[{}]",
|
||||
index, callTo, smsTxt);
|
||||
}
|
||||
// else {
|
||||
// log.warn("Skipping index [{}]: callTo=[{}], smsTxt=[{}]", index, callTo, smsTxt);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
msgRequestVOList.forEach(t->log.info("+ t.getReserveYn() :: [{}]", t.getReserveYn()));
|
||||
|
||||
return msgRequestVOList;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,16 +1,18 @@
|
||||
package com.itn.mjonApi.mjon.api.send.web;
|
||||
package com.itn.mjonApi.mjon.api.msg.send.web;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.service.SendService;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.MsgsRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.service.SendService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.mjon.send.web
|
||||
@ -24,18 +26,11 @@ import org.springframework.web.client.RestTemplate;
|
||||
* 2023-02-15 hylee 최초 생성
|
||||
*/
|
||||
|
||||
// 치환문자가 있으면 , => §로 치환
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class SendRestController {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public SendRestController(RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private SendService sendService;
|
||||
|
||||
@ -49,20 +44,24 @@ public class SendRestController {
|
||||
@CrossOrigin("*") // 모든 요청에 접근 허용
|
||||
@PostMapping("/api/send/sendMsg")
|
||||
public ResponseEntity<RestResponse> sendMsg(MsgRequestVO msgRequestVO) throws Exception {
|
||||
return ResponseEntity.ok().body(sendService.sendMsgData(msgRequestVO));
|
||||
return ResponseEntity.ok().body(sendService.sendMsgData_advc(msgRequestVO));
|
||||
// return ResponseEntity.ok().body(sendService.sendMsgData(msgRequestVO));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param msgsRequestVO
|
||||
* @description [문자 발송] 다른 내용으로 여려명에게 보냄
|
||||
* @param allParams
|
||||
* @description [문자 발송] 다른 내용으로 여려명에게 보냄 - Map 기반 동적 파라미터 처리
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@CrossOrigin("*") // 모든 요청에 접근 허용
|
||||
@PostMapping("/api/send/sendMsgs")
|
||||
public ResponseEntity<RestResponse> sendMsgs(MsgsRequestVO msgsRequestVO) throws Exception {
|
||||
return ResponseEntity.ok().body(sendService.sendMsgsData(msgsRequestVO));
|
||||
public ResponseEntity<RestResponse> sendMsgs(MsgsRequestVO msgsRequestVO,
|
||||
@RequestParam Map<String, String> allParams) throws Exception {
|
||||
return ResponseEntity.ok().body(sendService.sendMsgsData_advc(msgsRequestVO, allParams));
|
||||
// return ResponseEntity.ok().body(sendService.sendMsgsData(msgsRequestVO));
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
package com.itn.mjonApi.mjon.api.send.service;
|
||||
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
|
||||
public interface SendService {
|
||||
|
||||
|
||||
RestResponse sendMsgData(MsgRequestVO msgRequestVO) throws Exception;
|
||||
|
||||
RestResponse sendMsgsData(MsgsRequestVO msgsRequestVO) throws Exception;
|
||||
}
|
||||
@ -1,625 +0,0 @@
|
||||
package com.itn.mjonApi.mjon.api.send.service.impl;
|
||||
|
||||
import com.itn.mjonApi.cmn.apiServer.ApiService;
|
||||
import com.itn.mjonApi.cmn.model.Price;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.StatMsg;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.PriceMapper;
|
||||
import com.itn.mjonApi.mjon.api.inqry.mapper.domain.PriceVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.SendMapper;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MjonResponseVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.SendSucRestResponse;
|
||||
import com.itn.mjonApi.mjon.api.send.service.SendService;
|
||||
import com.itn.mjonApi.util.MunjaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SendServiceImpl implements SendService {
|
||||
|
||||
private ApiService<Response> apiService;
|
||||
|
||||
@Autowired
|
||||
SendMapper sendMapper;
|
||||
|
||||
@Autowired
|
||||
PriceMapper priceMapper;
|
||||
|
||||
@Autowired
|
||||
public SendServiceImpl(ApiService<Response> apiService) {
|
||||
this.apiService = apiService;
|
||||
}
|
||||
|
||||
private static final String replaseStrList = "[*이름*],[*1*],[*2*],[*3*],[*4*]";
|
||||
|
||||
@Override
|
||||
public RestResponse sendMsgData(MsgRequestVO msgRequestVO) throws Exception {
|
||||
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getTest_yn())){
|
||||
// YF => 실패 테스트 데이터
|
||||
return this._getTestMsgReturnData(msgRequestVO.getTest_yn());
|
||||
}
|
||||
//sendMsg 문자 발송 전 체크 사항
|
||||
|
||||
//step1.발신자 전화번호 사용 가능 여부 체크(해당 사용자의 기 등록된 번호만 발송 가능)
|
||||
// 1010
|
||||
msgRequestVO.setCallFrom(MunjaUtil.removeCharactersWithRegex(msgRequestVO.getCallFrom()));
|
||||
if(!sendMapper.findByCallFrom(msgRequestVO)){
|
||||
return new RestResponse(new FailRestResponse("STAT_1010",""));
|
||||
}
|
||||
|
||||
|
||||
// step2.수신자 전화번호 정상 여부 체크(정상 번호에 대해서만 발송 가능)
|
||||
// 1020
|
||||
// 폰번호 확인 - 빈 값 -> 유효성 정규식
|
||||
if(this.getCallToListChk(msgRequestVO)){
|
||||
return new RestResponse(new FailRestResponse("STAT_1020",""));
|
||||
}
|
||||
|
||||
//step3.문자 내용 정상 여부 확인 - 스미싱 문구는 발송 30분 지연으로 처리됨
|
||||
// 1030 => 현재 사용안함
|
||||
// 스팸체크 하는 부분
|
||||
// apiService.postForEntity => restTemplate.postForEntity 호출 후 MjonResponseVO에 맞게 데이터 정제하는 메소드
|
||||
MjonResponseVO spamChkEntity = apiService.postForEntity(
|
||||
"/web/user/login/selectSpamTxtChkAjax.do"
|
||||
, msgRequestVO
|
||||
, String.class
|
||||
);
|
||||
// 스팸체크 결과값이 spams 이면 스팸문자로 처리
|
||||
if("spams".equals(spamChkEntity.getResult())){
|
||||
msgRequestVO.setSpamStatus("Y");
|
||||
};
|
||||
|
||||
//step4.치환명 정상 여부 확인
|
||||
// 1040
|
||||
msgRequestVO.setTxtReplYn(this.getTxtReplYn(msgRequestVO));
|
||||
// 치환데이터가 있을 경우
|
||||
if("Y".equals(msgRequestVO.getTxtReplYn())){
|
||||
//일괄변환 문자에 콤마(,)가 들어가있으면 배열로 넘길때 문제가 발생하여 특수문자(§)로 치환하여 넘겨주도록 한다.
|
||||
msgRequestVO = this.getReplaceCommaToStrSymbol(msgRequestVO);
|
||||
// 치환 후 단문 장문 개수 구하기
|
||||
msgRequestVO = this.getLengthOfShortAndLongMsg(msgRequestVO);
|
||||
}
|
||||
|
||||
|
||||
PriceVO priceVO = Price.priceRefine(msgRequestVO.getMberId(), priceMapper);
|
||||
|
||||
|
||||
// +""; => Double to String 와 같은 기능
|
||||
msgRequestVO.setsPrice(priceVO.getShortPrice()+"");
|
||||
msgRequestVO.setmPrice(priceVO.getLongPrice()+"");
|
||||
msgRequestVO.setpPrice(priceVO.getPicturePrice()+"");
|
||||
|
||||
|
||||
//문자열 길이 체크 해주기
|
||||
// 문자 바이트 계산에 필요한 캐릭터 셋 : 한글 2Byte로 계산
|
||||
int FrBytes = getFrBytes(msgRequestVO);
|
||||
// 단문 장문 단가과 타입 지정
|
||||
if(FrBytes > 90){
|
||||
msgRequestVO.setEachPrice(msgRequestVO.getsPrice());
|
||||
msgRequestVO.setMsgType("6");
|
||||
}else {
|
||||
msgRequestVO.setEachPrice(msgRequestVO.getmPrice());
|
||||
msgRequestVO.setMsgType("4");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 문자 전송하는 부분
|
||||
// apiService.postForEntity => restTemplate.postForEntity 호출 후 MjonResponseVO에 맞게 데이터 정제하는 메소드
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/user/login/sendMsgDataAjax.do"
|
||||
, msgRequestVO
|
||||
, String.class
|
||||
);
|
||||
log.info("munjaSendResponse : [{}]", munjaSendResponse.toString());
|
||||
log.info("munjaSendResponse : [{}]", munjaSendResponse.getResult());
|
||||
|
||||
// convertMjonDataToApiResponse => MjonResponseVO 데이터를 ApiResponse 데이터로 변환하는 메소드
|
||||
if(!munjaSendResponse.getResult().equals("fail")){ // 성공
|
||||
return new RestResponse(SendSucRestResponse.convertMjonDataToApiResponse(munjaSendResponse));
|
||||
}else{ // 실패
|
||||
return new RestResponse(new FailRestResponse(StatMsg.randomErrorStatCode(),""));
|
||||
}
|
||||
|
||||
//step5.발송일시 정상여부 확인
|
||||
// 1050
|
||||
//step6.문자 타입에 따른 비용 처리 가능 여부 확인
|
||||
// 1060
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static int getFrBytes(MsgRequestVO msgRequestVO) throws UnsupportedEncodingException {
|
||||
String smsCont = msgRequestVO.getSmsTxt().replace("\r\n", "\n");
|
||||
int FrBytes = smsCont.getBytes("euc-kr").length;
|
||||
return FrBytes;
|
||||
}
|
||||
|
||||
private RestResponse _getTestMsgReturnData(String testYn)
|
||||
{
|
||||
// YF => 실패 테스트 데이터
|
||||
if("YF".equals(testYn))
|
||||
{
|
||||
// 실패 코드 중 랜덤으로 리턴
|
||||
return new RestResponse(new FailRestResponse(StatMsg.randomErrorStatCode(),"YF"));
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupId("MSGGID_0000000000000") // 전송 메세지 그룹 ID
|
||||
.successCnt("5") // 성공 건수
|
||||
.blockCnt("2") // 수신거부 건수
|
||||
.msgType("LMS")
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private RestResponse _getTestMsgsReturnData(String testYn)
|
||||
{
|
||||
// YF => 실패 테스트 데이터
|
||||
if("YF".equals(testYn))
|
||||
{
|
||||
return new RestResponse(new FailRestResponse(StatMsg.randomErrorStatCode(),"YF"));
|
||||
}else{ // YS => 성공 테스트 데이터
|
||||
|
||||
|
||||
|
||||
List<String> gIdList = new ArrayList<>();
|
||||
gIdList.add("MSGGID_0000000000000");
|
||||
gIdList.add("MSGGID_0000000000001");
|
||||
gIdList.add("MSGGID_0000000000002");
|
||||
|
||||
List<String> msgTypeList = new ArrayList<>();
|
||||
msgTypeList.add("SMS");
|
||||
msgTypeList.add("LMS");
|
||||
msgTypeList.add("LMS");
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupIdList(gIdList) // 전송 메세지 그룹 ID
|
||||
.successCnt("2") // 성공 건수
|
||||
.blockCnt("1") // 수신거부 건수
|
||||
.msgTypeList(msgTypeList)
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public RestResponse sendMsgsData(MsgsRequestVO msgsRequestVO) throws Exception {
|
||||
|
||||
if(StringUtils.isNotEmpty(msgsRequestVO.getTest_yn())){
|
||||
return this._getTestMsgsReturnData(msgsRequestVO.getTest_yn());
|
||||
}
|
||||
|
||||
// msgsVO -> msgVO List로 변환
|
||||
List<MsgRequestVO> msgRequestVOList = this.getDataCleaning(msgsRequestVO);
|
||||
|
||||
|
||||
//step1.발신자 전화번호 사용 가능 여부 체크(해당 사용자의 기 등록된 번호만 발송 가능)
|
||||
// 1010
|
||||
if(!sendMapper.findByCallFrom(msgRequestVOList.get(0))){
|
||||
return new RestResponse(new FailRestResponse("STAT_1010",""));
|
||||
}
|
||||
|
||||
|
||||
// step2.수신자 전화번호 정상 여부 체크(정상 번호에 대해서만 발송 가능)
|
||||
// 1020
|
||||
// 폰번호 확인 - 빈 값 -> 유효성 정규식
|
||||
for(MsgRequestVO msgRequestVO : msgRequestVOList){
|
||||
if(this.getCallToListChk(msgRequestVO)){
|
||||
// if(StringUtils.isNotEmpty(this.getCallToListChk(msgRequestVO))){
|
||||
return this.callToErrorReturnData(msgRequestVO);
|
||||
}
|
||||
}
|
||||
|
||||
//사용자 잔액
|
||||
// double mberMoney = priceMapper.selectMberMoney(mberId);
|
||||
// 이용단가, 발송가능 건수
|
||||
// PriceVO priceVO = this.price_refine(mberId, mberMoney, priceMapper);
|
||||
|
||||
|
||||
PriceVO priceVO = Price.priceRefine(msgsRequestVO.getMberId(), priceMapper);
|
||||
|
||||
// +""; => Double to String 와 같은 기능
|
||||
String sPrice = priceVO.getShortPrice()+"";
|
||||
String mPrice = priceVO.getLongPrice()+"";
|
||||
String pPrice = priceVO.getPicturePrice()+"";
|
||||
List<MjonResponseVO> mjonResponseVOList = new ArrayList<MjonResponseVO>();
|
||||
for(MsgRequestVO msgRequestVO : msgRequestVOList){
|
||||
|
||||
|
||||
|
||||
//문자열 길이 체크 해주기
|
||||
// 문자 바이트 계산에 필요한 캐릭터 셋 : 한글 2Byte로 계산
|
||||
int FrBytes = getFrBytes(msgRequestVO);
|
||||
// 단문 장문 단가과 타입 지정
|
||||
if(FrBytes > 90){
|
||||
msgRequestVO.setEachPrice(sPrice);
|
||||
msgRequestVO.setMsgType("6");
|
||||
}else {
|
||||
msgRequestVO.setEachPrice(mPrice);
|
||||
msgRequestVO.setMsgType("4");
|
||||
}
|
||||
|
||||
// 단가 셋팅
|
||||
msgRequestVO.setsPrice(sPrice); // 단문
|
||||
msgRequestVO.setmPrice(mPrice); // 장문
|
||||
msgRequestVO.setpPrice(pPrice); // 사진
|
||||
|
||||
|
||||
//step3.문자 내용 정상 여부 확인 - 스미싱 문구는 발송 30분 지연으로 처리됨
|
||||
// 1030 => 현재 사용안함
|
||||
// 스팸체크 하는 부분
|
||||
MjonResponseVO spamChkEntity = apiService.postForEntity(
|
||||
"/web/user/login/selectSpamTxtChkAjax.do"
|
||||
, msgRequestVO
|
||||
, String.class
|
||||
);
|
||||
// 스팸체크 결과값이 spams 이면 스팸문자로 처리
|
||||
if("spams".equals(spamChkEntity.getResult())){
|
||||
msgRequestVO.setSpamStatus("Y");
|
||||
};
|
||||
|
||||
// 문자 전송하는 부분
|
||||
// apiService.postForEntity => restTemplate.postForEntity 호출 후 MjonResponseVO에 맞게 데이터 정제하는 메소드
|
||||
MjonResponseVO munjaSendResponse = apiService.postForEntity(
|
||||
"/web/user/login/sendMsgDataAjax.do"
|
||||
, msgRequestVO
|
||||
, String.class
|
||||
);
|
||||
//
|
||||
mjonResponseVOList.add(munjaSendResponse);
|
||||
}
|
||||
|
||||
|
||||
return new RestResponse(SendSucRestResponse.SendSuccessMsgsRestResponse(mjonResponseVOList));
|
||||
}
|
||||
|
||||
private static RestResponse callToErrorReturnData(MsgRequestVO msgRequestVO) {
|
||||
|
||||
FailRestResponse stat1020 = new FailRestResponse("STAT_1020","");
|
||||
String errorMsg = stat1020.getMsg();
|
||||
errorMsg.replace("수신자", "수신자(" + msgRequestVO.getCallToList()[0] + ")");
|
||||
stat1020.setMsg(errorMsg);
|
||||
|
||||
return new RestResponse(stat1020);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 최대 1~100개의 수신번호와 메세지를 MsgRequestVO로 정재하는 메소드.
|
||||
* @param msgsRequestVO
|
||||
* @return
|
||||
*/
|
||||
private static List<MsgRequestVO> getDataCleaning(MsgsRequestVO msgsRequestVO) {
|
||||
|
||||
|
||||
List<MsgRequestVO> msgRequestVOList = new ArrayList<>();
|
||||
|
||||
// Reflection으로 Object Field에 접근한다.
|
||||
Field[] declaredFields = msgsRequestVO.getClass().getDeclaredFields();
|
||||
|
||||
String mberId = null; // 사용자 ID
|
||||
String accessKey = null; // accessKey
|
||||
String callFrom = null; // 발신자 번호
|
||||
String callTo = null; // 수신자 번호
|
||||
|
||||
for (Field field : declaredFields) {
|
||||
|
||||
Object value = null;
|
||||
// private Field일 경우 접근을 허용한다.
|
||||
field.setAccessible(true);
|
||||
|
||||
try {
|
||||
// Field Value를 참조한다.
|
||||
value = field.get(msgsRequestVO);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.info("Reflection Error. {}", e);
|
||||
}
|
||||
|
||||
// nullPointException 방지
|
||||
if(value != null)
|
||||
{
|
||||
/**
|
||||
* 필드 이름으로 분기하여
|
||||
* 각각에 맞는 위치에 값을 넣어준다.
|
||||
*/
|
||||
if("mberId".equals(field.getName())){ // 사용자 ID
|
||||
mberId = value.toString();
|
||||
}else if("accessKey".equals(field.getName())){ // accessKey
|
||||
accessKey = value.toString();
|
||||
}else if("callFrom".equals(field.getName())){ // 발신자 번호
|
||||
callFrom = value.toString();
|
||||
}else if(field.getName().startsWith("callTo")){ // 수신자 번호
|
||||
callTo = value.toString();
|
||||
}else if(field.getName().startsWith("smsTxt")){ // 문자 내용
|
||||
|
||||
// 값이 비여 있으면 다음 반복문으로 넘어간다.
|
||||
if(StringUtils.isEmpty(value.toString())){
|
||||
callTo = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
msgRequestVOList.add(
|
||||
MsgRequestVO.builder()
|
||||
.mberId(mberId)
|
||||
.accessKey(accessKey)
|
||||
.callFrom(callFrom)
|
||||
.callToList(new String[]{callTo})
|
||||
.smsTxt(value.toString())
|
||||
.eachPrice("0") // 디폴트
|
||||
.sPrice("0") // 디폴트
|
||||
.totPrice("0") // 디폴트
|
||||
.fileCnt("0") // 디폴트
|
||||
.msgType("4") // 디폴트
|
||||
.smsPrice(0) // 디폴트
|
||||
.mmsPrice(0) // 디폴트
|
||||
.imgFilePath(new String[0]) // 디폴트
|
||||
.txtReplYn("N") // 디폴트
|
||||
.reserveYn("N") // 디폴트
|
||||
.msgKind("N") // 디폴트
|
||||
.build()
|
||||
);
|
||||
// 초기화
|
||||
callTo = "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return msgRequestVOList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 치환 후 단문 장문 msg 개수 구하기
|
||||
* @param msgRequestVO
|
||||
* @return msgRequestVO
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private static MsgRequestVO getLengthOfShortAndLongMsg(MsgRequestVO msgRequestVO) throws UnsupportedEncodingException {
|
||||
String charset = "euc-kr";
|
||||
int totListCnt = msgRequestVO.getCallToList().length;
|
||||
|
||||
int shortMsgCnt=0; // 치환 후 단문 개수
|
||||
int longMsgCnt=0; // 치환 후 장문 개수
|
||||
for(int i=0; i < totListCnt; i ++) {
|
||||
String smsTxt = msgRequestVO.getSmsTxt().replaceAll(String.valueOf((char)13), ""); //발송 문자 내용
|
||||
|
||||
String[] nameList = msgRequestVO.getNameList(); //치환 이름 리스트
|
||||
String[] phone = msgRequestVO.getCallToList(); //수신자 휴대폰 번호
|
||||
String[] rep1 = msgRequestVO.getRep1List(); //치환 문자1 리스트
|
||||
String[] rep2 = msgRequestVO.getRep2List(); //치환 문자2 리스트
|
||||
String[] rep3 = msgRequestVO.getRep3List(); //치환 문자3 리스트
|
||||
String[] rep4 = msgRequestVO.getRep4List(); //치환 문자4 리스트
|
||||
|
||||
if (smsTxt.indexOf("[*이름*]") > -1) {
|
||||
if(nameList.length > i && StringUtils.isNotEmpty(nameList[i])) {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*이름\\*\\]", MunjaUtil.getString(nameList[i].replaceAll("§", ",")));
|
||||
}else {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*이름\\*\\]", "");
|
||||
}
|
||||
}
|
||||
if (smsTxt.indexOf("[*1*]") > -1) {
|
||||
if(rep1.length > i && StringUtils.isNotEmpty(rep1[i])) {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*1\\*\\]", MunjaUtil.getString(rep1[i].replaceAll("§", ",")));
|
||||
}else {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*1\\*\\]", "");
|
||||
}
|
||||
}
|
||||
if (smsTxt.indexOf("[*2*]") > -1) {
|
||||
if(rep2.length > i && StringUtils.isNotEmpty(rep2[i])) {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*2\\*\\]", MunjaUtil.getString(rep2[i].replaceAll("§", ",")));
|
||||
}else {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*2\\*\\]", "");
|
||||
}
|
||||
}
|
||||
if (smsTxt.indexOf("[*3*]") > -1) {
|
||||
if(rep3.length > i && StringUtils.isNotEmpty(rep3[i])) {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*3\\*\\]", MunjaUtil.getString(rep3[i].replaceAll("§", ",")));
|
||||
}else {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*3\\*\\]", "");
|
||||
}
|
||||
}
|
||||
if (smsTxt.indexOf("[*4*]") > -1) {
|
||||
if(rep4.length > i && StringUtils.isNotEmpty(rep4[i])) {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*4\\*\\]", MunjaUtil.getString(rep4[i].replaceAll("§", ",")));
|
||||
}else {
|
||||
smsTxt = smsTxt.replaceAll("\\[\\*4\\*\\]", "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int bytes = smsTxt.getBytes(charset).length;
|
||||
|
||||
if(bytes > 90) {//장문문자 리스트 만들기
|
||||
longMsgCnt++;
|
||||
}else {//단문문자 리스트 만들기
|
||||
shortMsgCnt++;
|
||||
}
|
||||
}
|
||||
msgRequestVO.setLongMsgCnt(Integer.toString(longMsgCnt));
|
||||
msgRequestVO.setShortMsgCnt(Integer.toString(shortMsgCnt));
|
||||
|
||||
return msgRequestVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 치환문자가 있으면 , => §로 치환
|
||||
* @param msgRequestVO
|
||||
* @return
|
||||
*/
|
||||
private static MsgRequestVO getReplaceCommaToStrSymbol(MsgRequestVO msgRequestVO) {
|
||||
|
||||
AtomicInteger index = new AtomicInteger();
|
||||
|
||||
// 이름 배열
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getNameStr()))
|
||||
{
|
||||
msgRequestVO.setNameList(msgRequestVO.getNameStr().split("\\|"));
|
||||
String[] nameList = new String[msgRequestVO.getNameList().length];
|
||||
Arrays.stream(msgRequestVO.getNameList()).forEach(name -> {
|
||||
nameList[index.getAndIncrement()] = MunjaUtil.replaceCommaToStrSymbol(name);
|
||||
});
|
||||
msgRequestVO.setNameList(nameList);
|
||||
}
|
||||
|
||||
// Rep1 배열
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getRep1Str()))
|
||||
{
|
||||
index.set(0);
|
||||
msgRequestVO.setRep1List(msgRequestVO.getRep1Str().split("\\|"));
|
||||
String[] rep1List = new String[msgRequestVO.getRep1List().length];
|
||||
Arrays.stream(msgRequestVO.getRep1List()).forEach(str -> {
|
||||
rep1List[index.getAndIncrement()] = MunjaUtil.replaceCommaToStrSymbol(str);
|
||||
});
|
||||
msgRequestVO.setRep1List(rep1List);
|
||||
|
||||
}
|
||||
|
||||
// Rep2 배열
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getRep2Str()))
|
||||
{
|
||||
index.set(0);
|
||||
msgRequestVO.setRep2List(msgRequestVO.getRep2Str().split("\\|"));
|
||||
String[] rep2List = new String[msgRequestVO.getRep2List().length];
|
||||
Arrays.stream(msgRequestVO.getRep2List()).forEach(str -> {
|
||||
rep2List[index.getAndIncrement()] = MunjaUtil.replaceCommaToStrSymbol(str);
|
||||
});
|
||||
msgRequestVO.setRep2List(rep2List);
|
||||
}
|
||||
|
||||
// Rep3 배열
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getRep3Str()))
|
||||
{
|
||||
index.set(0);
|
||||
msgRequestVO.setRep3List(msgRequestVO.getRep3Str().split("\\|"));
|
||||
String[] rep3List = new String[msgRequestVO.getRep3List().length];
|
||||
Arrays.stream(msgRequestVO.getRep3List()).forEach(str -> {
|
||||
rep3List[index.getAndIncrement()] = MunjaUtil.replaceCommaToStrSymbol(str);
|
||||
});
|
||||
msgRequestVO.setRep3List(rep3List);
|
||||
}
|
||||
|
||||
// Rep4 배열
|
||||
if(StringUtils.isNotEmpty(msgRequestVO.getRep4Str()))
|
||||
{
|
||||
index.set(0);
|
||||
msgRequestVO.setRep4List(msgRequestVO.getRep4Str().split("\\|"));
|
||||
String[] rep4List = new String[msgRequestVO.getRep4List().length];
|
||||
Arrays.stream(msgRequestVO.getRep4List()).forEach(str -> {
|
||||
rep4List[index.getAndIncrement()] = MunjaUtil.replaceCommaToStrSymbol(str);
|
||||
});
|
||||
msgRequestVO.setRep4List(rep4List);
|
||||
}
|
||||
return msgRequestVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 치환 문자 여부 확인
|
||||
* @param msgRequestVO
|
||||
* @return
|
||||
*/
|
||||
private static String getTxtReplYn(MsgRequestVO msgRequestVO) {
|
||||
|
||||
int callLen = msgRequestVO.getCallToList().length;
|
||||
// 치환 데이터 확인
|
||||
Arrays.stream(replaseStrList.split(",")).forEach(
|
||||
str -> {
|
||||
if(msgRequestVO.getSmsTxt().indexOf(str) > -1){
|
||||
msgRequestVO.setTxtReplYn("Y");
|
||||
}
|
||||
}
|
||||
);
|
||||
return msgRequestVO.getTxtReplYn();
|
||||
}
|
||||
|
||||
/**
|
||||
* 수신자 목록 번호 검증
|
||||
* message가 없으면 정상
|
||||
* @param msgRequestVO
|
||||
* @return String
|
||||
*/
|
||||
private static Boolean getCallToListChk(MsgRequestVO msgRequestVO) {
|
||||
Boolean returnData = false;
|
||||
for(String callTo : msgRequestVO.getCallToList()){
|
||||
/*
|
||||
if(!MunjaUtil.checkPhoneNumberEmpty(callTo)){
|
||||
message = "수신 목록에 핸드폰 번호가 없는 항목이 있습니다."; break;};
|
||||
if(!MunjaUtil.validatePNumWithRegex(callTo)){
|
||||
message = "휴대폰 번호가 올바르지 않습니다. : " + callTo; break;};
|
||||
*/
|
||||
if(!MunjaUtil.validatePNumWithRegex(callTo) // 비여있는지 체크
|
||||
|| !MunjaUtil.validatePNumWithRegex(callTo) // 정규식으로 번호 체크
|
||||
)
|
||||
{
|
||||
returnData = true;
|
||||
break;
|
||||
};
|
||||
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MjonResponseVO -> 변환 -> SendFailRestResponse
|
||||
* @param mjonResponseVO
|
||||
* @return
|
||||
*/
|
||||
public static String convertMjonDataToApiResponse(MjonResponseVO mjonResponseVO) {
|
||||
String result = mjonResponseVO.getResult();
|
||||
log.info("convertMjonDataToApiResponse : [{}]", result);
|
||||
|
||||
String message = mjonResponseVO.getMessage();
|
||||
log.info("convertMjonDataToApiResponse : [{}]", message);
|
||||
|
||||
String statCode = "";
|
||||
switch (result) {
|
||||
case "statusFail" : statCode = "1070"; // 회원 정지
|
||||
break;
|
||||
case "smsLengFail" : statCode = "1080"; // 문자 길이 초과
|
||||
break;
|
||||
case "fail" : // 문자온 프로젝트에서 result가 fail로 다양한 에러가 리턴하여 분기처리함
|
||||
if(message.indexOf("문자 치환 후 전송 문자 길이를 초과하였습니다.")>-1)
|
||||
statCode = "1050"; // 치환 후 문자 길이 초과
|
||||
else if(message.indexOf("치환문자 데이터가 없습니다")>-1)
|
||||
statCode = "1040"; // 치환 데이터 오류
|
||||
else if(message.indexOf("치환 후 전송 문자 길이를 초과")>-1)
|
||||
statCode = "1050"; // 치환 데이터 오류
|
||||
else
|
||||
statCode = "1099"; // 기타 시스템 오류
|
||||
break;
|
||||
default: statCode = "1099"; // 기타 시스템 오류
|
||||
break;
|
||||
}
|
||||
|
||||
return "STAT_"+statCode;
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,10 +3,6 @@ package com.itn.mjonApi.util;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.mjon.api.access.mapper.domain.AccessKeyVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgRequestVO;
|
||||
import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
|
||||
/**
|
||||
* packageName : com.itn.mjonApi.util
|
||||
@ -21,45 +17,10 @@ import com.itn.mjonApi.mjon.api.send.mapper.domain.MsgsRequestVO;
|
||||
*/
|
||||
public class ApiObjectUtil {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description : VO를 json으로 변환
|
||||
* @param restResponse
|
||||
* @return String
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
public static String getRestResponseToJsonString(RestResponse restResponse) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// .registerModule(new JavaTimeModule()) : LocalDateTime을 json으로 변환하기 위함
|
||||
return objectMapper.registerModule(new JavaTimeModule()).writeValueAsString(restResponse);
|
||||
public static String toJson(Object obj) throws JsonProcessingException {
|
||||
if (obj == null) return null;
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
}
|
||||
public static String getMsgsRequestVOToJsonString(MsgsRequestVO msgsRequestVO) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// .registerModule(new JavaTimeModule()) : LocalDateTime을 json으로 변환하기 위함
|
||||
return objectMapper.registerModule(new JavaTimeModule()).writeValueAsString(msgsRequestVO);
|
||||
}
|
||||
public static String getMsgRequestVOToJsonString(MsgRequestVO msgRequestVO) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// .registerModule(new JavaTimeModule()) : LocalDateTime을 json으로 변환하기 위함
|
||||
return objectMapper.registerModule(new JavaTimeModule()).writeValueAsString(msgRequestVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : VO를 json으로 변환
|
||||
* @param accessKeyVO
|
||||
* @return String
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
public static String getAccessKeyVOToJsonString(AccessKeyVO accessKeyVO) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// .registerModule(new JavaTimeModule()) : LocalDateTime을 json으로 변환하기 위함
|
||||
return objectMapper.registerModule(new JavaTimeModule()).writeValueAsString(accessKeyVO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
package com.itn.mjonApi.util;
|
||||
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.send.mapper.domain.MsgAtRequestVO;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
@ -13,19 +19,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
* -----------------------------------------------------------
|
||||
* 2023-05-17 hylee 최초 생성
|
||||
*/
|
||||
@Slf4j
|
||||
public class MunjaUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 폰번호 유효성 검사
|
||||
* @param callTo
|
||||
* @return
|
||||
*/
|
||||
public static Boolean validatePNumWithRegex(String callTo){
|
||||
// 핸드폰 정규식
|
||||
String regex = "^01(?:0|1|[6-9])(?:\\d{3}|\\d{4})\\d{4}$";
|
||||
return callTo.matches(regex) ? true : false;
|
||||
}
|
||||
/**
|
||||
* 폰번호 빈값 검사
|
||||
* @param str
|
||||
@ -49,7 +46,7 @@ public class MunjaUtil {
|
||||
* 파라미터를 String 타입으로 가져옵니다.<br>
|
||||
* - null일 경우 빈 문자열을 가져옵니다.<br>
|
||||
* Get String(if object is null, return empty string).
|
||||
* @param Object
|
||||
* @param obj
|
||||
* @return String
|
||||
*/
|
||||
public static String getString(Object obj) {
|
||||
@ -59,5 +56,128 @@ public class MunjaUtil {
|
||||
return String.valueOf(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 수신자 목록 번호 검증
|
||||
* message가 없으면 정상
|
||||
* @param callToList
|
||||
* @return String
|
||||
*/
|
||||
public static Boolean getCallToListChk(String[] callToList) {
|
||||
Boolean returnData = false;
|
||||
|
||||
|
||||
if (ArrayUtils.isEmpty(callToList)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for(String callTo : callToList){
|
||||
if(!MunjaUtil.checkPhoneNumberEmpty(callTo) // 비여있는지 체크
|
||||
|| !MunjaUtil.validatePNumWithRegex(callTo) // 정규식으로 번호 체크
|
||||
)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
public static Boolean getCallToChk(String callTo) {
|
||||
Boolean returnData = false;
|
||||
|
||||
if(!MunjaUtil.checkPhoneNumberEmpty(callTo) // 비여있는지 체크
|
||||
|| !MunjaUtil.validatePNumWithRegex(callTo) // 정규식으로 번호 체크
|
||||
)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 기존 정규식 검사 메서드 (변경 없음)
|
||||
public static boolean validatePNumWithRegex(String pNum) {
|
||||
return pNum != null && pNum.matches("^\\d{10,11}$");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* VarListMapVO의 필드들을 검증
|
||||
*
|
||||
* @param vo 검증할 VarListMapVO 객체
|
||||
* @param msgAtRequestVO
|
||||
* @return 검증 실패 시 오류 코드, 성공 시 null
|
||||
*/
|
||||
public static String kakaoAtValidate(VarAtListMapVO vo, MsgAtRequestVO msgAtRequestVO) {
|
||||
|
||||
|
||||
String subMsgSendYn = msgAtRequestVO.getSubMsgSendYn();
|
||||
Boolean hasTemplateTitle = msgAtRequestVO.getHasTemplateTitle();
|
||||
// 수신번호 검증
|
||||
String callTo = vo.getCallToList();
|
||||
if (MunjaUtil.getCallToChk(callTo)) {
|
||||
return "STAT_1020"; // 수신자 전화번호 오류
|
||||
}
|
||||
|
||||
// 본문 데이터 검증
|
||||
String templateContent = vo.getTemplateContent();
|
||||
if (StringUtils.isEmpty(templateContent)) {
|
||||
return "STAT_2040"; // 본문 데이터 오류
|
||||
}
|
||||
|
||||
// 템플릿에 타이틀이 있으면 값 확인
|
||||
if (hasTemplateTitle && StringUtils.isEmpty(vo.getTemplateTitle())) {
|
||||
return "STAT_2041"; // 타이틀 데이터 오류
|
||||
}
|
||||
|
||||
// 대체문자 검증 (대체문자 발송이 활성화된 경우에만)
|
||||
if ("Y".equals(subMsgSendYn)) {
|
||||
String subMsgTxt = vo.getSubMsgTxt();
|
||||
if (StringUtils.isEmpty(subMsgTxt)) {
|
||||
return "STAT_2042"; // 대체문자 데이터 오류
|
||||
}
|
||||
}
|
||||
|
||||
// 모든 검증 통과
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static String kakaoFtValidate(VarFtListMapVO vo, MsgFtRequestVO msgFtRequestVO) {
|
||||
|
||||
log.info(" vo.toString() [{}]", vo.toString());
|
||||
String ok = null;
|
||||
// 수신번호 검증
|
||||
String callTo = vo.getPhone();
|
||||
if (MunjaUtil.getCallToChk(callTo)) {
|
||||
return "STAT_1020"; // 수신자 전화번호 오류
|
||||
}
|
||||
|
||||
// 본문 데이터 검증
|
||||
String smsTxt = vo.getTemplateContent();
|
||||
if (StringUtils.isEmpty(smsTxt)) {
|
||||
return "STAT_2040"; // 본문 데이터 오류
|
||||
}
|
||||
|
||||
// 대체문자 검증 (대체문자 발송이 활성화된 경우에만)
|
||||
if ("Y".equals(msgFtRequestVO.getSubMsgSendYn())) {
|
||||
String subMsgTxt = vo.getSubMsgTxt();
|
||||
if (StringUtils.isEmpty(subMsgTxt)) {
|
||||
return "STAT_2042"; // 대체문자 데이터 오류
|
||||
}
|
||||
|
||||
String callFrom = msgFtRequestVO.getCallFrom();
|
||||
if (StringUtils.isEmpty(callFrom)) {
|
||||
return "STAT_2043"; // 대체문자 발송 시 발신번호 필요
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 모든 검증 통과
|
||||
return ok;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
299
src/main/java/com/itn/mjonApi/util/TestDataUtil.java
Normal file
299
src/main/java/com/itn/mjonApi/util/TestDataUtil.java
Normal file
@ -0,0 +1,299 @@
|
||||
package com.itn.mjonApi.util;
|
||||
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.detail.TemplateComments;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.detail.TemplateDetail;
|
||||
import com.itn.mjonApi.cmn.domain.biz.template.list.TemplateInfo;
|
||||
import com.itn.mjonApi.cmn.msg.FailRestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.RestResponse;
|
||||
import com.itn.mjonApi.cmn.msg.StatMsg;
|
||||
import com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain.MjKakaoProfileInfoVO;
|
||||
import com.itn.mjonApi.mjon.api.msg.send.mapper.domain.SendSucRestResponse;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 카카오 조회 API 테스트 데이터 유틸리티 클래스
|
||||
* 기존 SMS/LMS 테스트 패턴을 재사용하여 일관성 유지
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-09
|
||||
*/
|
||||
public class TestDataUtil {
|
||||
|
||||
|
||||
private static FailRestResponse randomFail(){
|
||||
|
||||
return new FailRestResponse(StatMsg.randomErrorStatCode(),"YF");
|
||||
}
|
||||
|
||||
public static RestResponse _getTestMsgReturnData(String testYn)
|
||||
{
|
||||
// YF => 실패 테스트 데이터
|
||||
|
||||
if("YF".equals(testYn))
|
||||
{
|
||||
// 실패 코드 중 랜덤으로 리턴
|
||||
return new RestResponse(randomFail());
|
||||
}else{
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupId("MSGGID_0000000000000") // 전송 메세지 그룹 ID
|
||||
.successCnt("5") // 성공 건수
|
||||
.blockCnt("2") // 수신거부 건수
|
||||
.msgType("LMS")
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 다중문자발송
|
||||
*
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse _getTestMsgsReturnData(String testYn)
|
||||
{
|
||||
// YF => 실패 테스트 데이터
|
||||
if("YF".equals(testYn))
|
||||
{
|
||||
return new RestResponse(randomFail());
|
||||
}else{ // YS => 성공 테스트 데이터
|
||||
|
||||
|
||||
|
||||
List<String> gIdList = new ArrayList<>();
|
||||
gIdList.add("MSGGID_0000000000000");
|
||||
gIdList.add("MSGGID_0000000000001");
|
||||
gIdList.add("MSGGID_0000000000002");
|
||||
|
||||
List<String> msgTypeList = new ArrayList<>();
|
||||
msgTypeList.add("SMS");
|
||||
msgTypeList.add("LMS");
|
||||
msgTypeList.add("LMS");
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupIdList(gIdList) // 전송 메세지 그룹 ID
|
||||
.successCnt("2") // 성공 건수
|
||||
.blockCnt("1") // 수신거부 건수
|
||||
.msgTypeList(msgTypeList)
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 알림톡 발송 테스트 데이터 생성
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse getTestAtSendReturnData(String testYn) {
|
||||
if("YF".equals(testYn)) {
|
||||
// 실패 테스트 데이터
|
||||
return new RestResponse(randomFail());
|
||||
} else {
|
||||
// 성공 테스트: 알림톡 발송 성공 응답
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgGroupId("MSGGID_AT_" + System.currentTimeMillis()) // 알림톡 전용 그룹 ID
|
||||
.successCnt("2") // 성공 건수
|
||||
.blockCnt("0") // 수신거부 건수
|
||||
.msgType("AT") // 알림톡 타입
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 친구톡 발송 테스트 데이터 생성
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse getTestFtSendReturnData(String testYn) {
|
||||
if("YF".equals(testYn)) {
|
||||
// 실패 테스트 데이터
|
||||
return new RestResponse(randomFail());
|
||||
} else {
|
||||
// 친구톡용 msgGroupIdList 생성
|
||||
List<String> msgGroupIdList = new ArrayList<>();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
msgGroupIdList.add("MSGGID_" + timestamp);
|
||||
msgGroupIdList.add("MSGGID_" + timestamp);
|
||||
|
||||
// 성공 테스트: 친구톡 발송 성공 응답
|
||||
return new RestResponse(
|
||||
SendSucRestResponse.builder()
|
||||
.resultCode("0")
|
||||
.msgType("FT") // 친구톡 타입
|
||||
.msgGroupIdList(msgGroupIdList) // 친구톡은 msgGroupIdList 사용
|
||||
.successCnt("2") // 성공 건수
|
||||
.failCnt("0")
|
||||
.test_yn("YS")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 채널 ID 조회 테스트 데이터 생성
|
||||
*
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse getChnlIdTestData(String testYn) {
|
||||
if ("YF".equals(testYn)) {
|
||||
return new RestResponse(randomFail());
|
||||
} else {
|
||||
|
||||
|
||||
Date now = new Date();
|
||||
// 원하는 포맷
|
||||
String nowDate = DateFormatUtils.format(now, "yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// 성공 테스트: 모킹된 채널 정보 반환
|
||||
List<MjKakaoProfileInfoVO> mockData = new ArrayList<>();
|
||||
|
||||
MjKakaoProfileInfoVO channel1 = new MjKakaoProfileInfoVO();
|
||||
channel1.setSenderKey("test_sender_key_001");
|
||||
channel1.setPhoneNumber("02-1234-0000");
|
||||
channel1.setYellowId("@test_channel_001");
|
||||
channel1.setFrstRegisterId("test_id_one");
|
||||
channel1.setFrstRegistPnttm(nowDate);
|
||||
|
||||
MjKakaoProfileInfoVO channel2 = new MjKakaoProfileInfoVO();
|
||||
channel2.setSenderKey("test_sender_key_002");
|
||||
channel2.setPhoneNumber("02-1234-0001");
|
||||
channel2.setYellowId("@test_channel_002");
|
||||
channel2.setFrstRegisterId("test_id_tow");
|
||||
channel2.setFrstRegistPnttm(nowDate);
|
||||
|
||||
mockData.add(channel1);
|
||||
mockData.add(channel2);
|
||||
|
||||
return new RestResponse(mockData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 목록 조회 테스트 데이터 생성
|
||||
*
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse getTemplateListTestData(String testYn) {
|
||||
if ("YF".equals(testYn)) {
|
||||
return new RestResponse(randomFail());
|
||||
} else {
|
||||
// 성공 테스트: 모킹된 템플릿 목록 반환
|
||||
List<TemplateInfo> mockData = new ArrayList<>();
|
||||
|
||||
TemplateInfo template1 = new TemplateInfo();
|
||||
template1.setSenderKey("test_sender_key_001");
|
||||
template1.setTemplateCode("TEST_TEMPLATE_001");
|
||||
template1.setTemplateName("테스트 템플릿 001");
|
||||
template1.setCreatedAt("2025-01-01 10:00:00");
|
||||
template1.setModifiedAt("2025-01-01 10:00:00");
|
||||
template1.setServiceStatus("REG(등록완료)");
|
||||
|
||||
TemplateInfo template2 = new TemplateInfo();
|
||||
template2.setSenderKey("test_sender_key_001");
|
||||
template2.setTemplateCode("TEST_TEMPLATE_002");
|
||||
template2.setTemplateName("테스트 템플릿 002");
|
||||
template2.setCreatedAt("2025-01-01 11:00:00");
|
||||
template2.setModifiedAt("2025-01-01 11:00:00");
|
||||
template2.setServiceStatus("REG(등록완료)");
|
||||
|
||||
TemplateInfo template3 = new TemplateInfo();
|
||||
template3.setSenderKey("test_sender_key_002");
|
||||
template3.setTemplateCode("TEST_TEMPLATE_003");
|
||||
template3.setTemplateName("테스트 템플릿 003");
|
||||
template3.setCreatedAt("2025-01-01 12:00:00");
|
||||
template3.setModifiedAt("2025-01-01 12:00:00");
|
||||
template3.setServiceStatus("REJ(반려)");
|
||||
|
||||
|
||||
mockData.add(template1);
|
||||
mockData.add(template2);
|
||||
mockData.add(template3);
|
||||
|
||||
return new RestResponse(mockData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 상세 조회 테스트 데이터 생성
|
||||
*
|
||||
* @param testYn 테스트 모드 (YS: 성공, YF: 실패)
|
||||
* @return RestResponse 래핑된 테스트 데이터
|
||||
*/
|
||||
public static RestResponse getTemplateDetailTestData(String testYn) {
|
||||
if ("YF".equals(testYn)) {
|
||||
return new RestResponse(randomFail());
|
||||
} else {
|
||||
// 성공 테스트: 실제 API 응답 구조를 반영한 템플릿 상세 반환
|
||||
TemplateDetail templateDetail = TemplateDetail.builder()
|
||||
.block("false")
|
||||
.categoryCode("0000000")
|
||||
.createdAt("2024-08-29 10:10:06")
|
||||
.dormant("false")
|
||||
.inspectionStatus("APR")
|
||||
.modifiedAt("2025-03-27 15:41:57")
|
||||
.securityFlag("false")
|
||||
.senderKey("test_sender_key_1215123251234234234")
|
||||
.senderKeyType("S")
|
||||
.status("A")
|
||||
.templateCode("bizp_test_template_0000000000000000")
|
||||
.templateContent("[테스트]\\n안녕하세요 #{이름}님\\n테스트 물건1 #{물건1}\\n테스트 물건2 #{물건2}\\n테스트 물건3 #{물건3}\\n테스트 물건4 #{물건4}\\n테스트 물건5 #{물건5}\\n테스트 물건6 #{물건6}\\n입니다.")
|
||||
.templateEmphasizeType("NONE")
|
||||
.templateExtra("")
|
||||
.templateHeader("")
|
||||
.templateImageName("")
|
||||
.templateImageUrl("")
|
||||
.templateMessageType("BA")
|
||||
.templateName("테스트 변수 템플릿")
|
||||
.templateSubtitle("")
|
||||
.templateTitle("")
|
||||
.templateItemHighlight(null)
|
||||
.templateItem(null)
|
||||
.buttons(new ArrayList<>())
|
||||
.comments(createMockComments())
|
||||
.quickReplies(new ArrayList<>())
|
||||
.build();
|
||||
|
||||
return new RestResponse(templateDetail);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트용 Mock Comments 생성 헬퍼 메서드
|
||||
* 실제 API 응답의 comments 구조를 반영
|
||||
*/
|
||||
private static List<TemplateComments> createMockComments() {
|
||||
List<TemplateComments> comments = new ArrayList<>();
|
||||
|
||||
// 실제 API 응답과 유사한 comment 구조
|
||||
TemplateComments comment = new TemplateComments();
|
||||
comment.setContent("안녕하세요. 카카오톡 알림톡 검수 담당자입니다.\\r\\n\\r\\n테스트 템플릿으로 확인되어 승인합니다.\\r\\n\\r\\n감사합니다.");
|
||||
comment.setCreatedAt("2024-08-29 13:44:13");
|
||||
comment.setStatus("APR");
|
||||
comment.setAttachment(new ArrayList<>());
|
||||
|
||||
comments.add(comment);
|
||||
return comments;
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
# DB INFO
|
||||
spring.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
|
||||
spring.datasource.url=jdbc:log4jdbc:mysql://192.168.0.125:3306/mjon?serverTimezone=Asia/Seoul
|
||||
spring.datasource.url=jdbc:log4jdbc:mysql://192.168.0.60:3308/mjon_advc?serverTimezone=Asia/Seoul
|
||||
#spring.datasource.url=jdbc:log4jdbc:mysql://139.150.72.157:3306/mjon?serverTimezone=Asia/Seoul
|
||||
|
||||
spring.datasource.username=mjonUr
|
||||
@ -10,11 +10,17 @@ spring.datasource.password=mjon!@#$
|
||||
|
||||
server.port=8088
|
||||
|
||||
#logging.level.root=info
|
||||
# Logging Configuration
|
||||
logging.level.root=info
|
||||
logging.level.jdbc.sqltiming=info
|
||||
logging.level.jdbc.resultset=info
|
||||
logging.level.jdbc.resultsettable=info
|
||||
logging.level.jdbc.sqlonly=debug
|
||||
logging.level.jdbc.audit=warn
|
||||
logging.level.jdbc.connection=warn
|
||||
|
||||
#??? ?? ??
|
||||
api.root.url=http://192.168.0.60:8085/
|
||||
#api.root.url=https://www.munjaon.co.kr/
|
||||
api.root.url=http://192.168.0.176:9080/
|
||||
|
||||
Ganpandaup.receiver.email=hylee250@kakao.com
|
||||
|
||||
|
||||
30
src/main/resources/application-local.properties
Normal file
30
src/main/resources/application-local.properties
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
# DB INFO
|
||||
spring.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
|
||||
spring.datasource.url=jdbc:log4jdbc:mysql://192.168.0.60:3308/mjon_advc?serverTimezone=Asia/Seoul
|
||||
#spring.datasource.url=jdbc:log4jdbc:mysql://139.150.72.157:3306/mjon?serverTimezone=Asia/Seoul
|
||||
|
||||
spring.datasource.username=mjonUr
|
||||
spring.datasource.password=mjon!@#$
|
||||
|
||||
server.port=8088
|
||||
|
||||
# Logging Configuration
|
||||
logging.level.root=info
|
||||
logging.level.jdbc.sqltiming=info
|
||||
logging.level.jdbc.resultset=info
|
||||
logging.level.jdbc.resultsettable=info
|
||||
logging.level.jdbc.sqlonly=debug
|
||||
logging.level.jdbc.audit=warn
|
||||
logging.level.jdbc.connection=warn
|
||||
|
||||
#??? ?? ??
|
||||
api.root.url=http://localhost:8080/
|
||||
#api.root.url=http://192.168.0.60:8085/
|
||||
#api.root.url=https://www.munjaon.co.kr/
|
||||
|
||||
Ganpandaup.receiver.email=hylee250@kakao.com
|
||||
|
||||
|
||||
server.tomcat.ajp.port=8009
|
||||
@ -1,12 +1,14 @@
|
||||
|
||||
|
||||
spring.profiles.active=dev
|
||||
spring.profiles.active=local
|
||||
|
||||
|
||||
# mybatis setting
|
||||
mybatis.config-location=classpath:mybatis-config.xml
|
||||
mybatis.mapper-locations=classpath:mapper/**/*.xml
|
||||
# model camel case set
|
||||
mybatis.configuration.map-underscore-to-camel-case=true
|
||||
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
|
||||
|
||||
#sql \ucd9c\ub825 log \uc124\uc815
|
||||
logging.level.jdbc.sqlonly=off
|
||||
@ -34,4 +36,21 @@ spring.servlet.multipart.max-request-size=20MB
|
||||
#management.endpoints.web.exposure.include=*
|
||||
#management.endpoint.health.show-details=always
|
||||
#
|
||||
Ganpandaup.estimate.template.url=https://www.munjaon.co.kr/publish/email_form_ganpandaum_contact.html
|
||||
Ganpandaup.estimate.template.url=https://www.munjaon.co.kr/publish/email_form_ganpandaum_contact.html
|
||||
|
||||
|
||||
biz.root.url=https://kapi.ppurio.com
|
||||
biz.api.key=dheBWCONP6J5
|
||||
biz.id=itn0202
|
||||
|
||||
|
||||
# ?? ?? actuator ?? ???? ?? ?
|
||||
# management.server.port=8081
|
||||
|
||||
# actuator base path ?? (???: /actuator)
|
||||
# management.endpoints.web.base-path=/manage
|
||||
|
||||
# health ?? ?? ??
|
||||
management.endpoint.health.show-details=always
|
||||
# actuator endpoint ?? ??
|
||||
management.endpoints.web.exposure.include=health,info,metrics
|
||||
|
||||
@ -1,2 +1,20 @@
|
||||
# log4jdbc 설정
|
||||
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
|
||||
log4jdbc.dump.sql.maxlinelength=0
|
||||
|
||||
# SQL 출력 설정
|
||||
log4jdbc.dump.sql.maxlinelength=0
|
||||
log4jdbc.trim.sql=true
|
||||
log4jdbc.trim.sql.extrablanklines=false
|
||||
|
||||
# ResultSet 출력 활성화 (가장 중요한 설정)
|
||||
log4jdbc.dump.sql.select=true
|
||||
log4jdbc.dump.sql.insert=true
|
||||
log4jdbc.dump.sql.update=true
|
||||
log4jdbc.dump.sql.delete=true
|
||||
|
||||
# ResultSet 테이블 형태 출력을 위한 추가 설정
|
||||
log4jdbc.dump.fulldebugstacktrace=false
|
||||
log4jdbc.suppress.generated.keys.exception=false
|
||||
|
||||
# 에러 억제 설정
|
||||
log4jdbc.auto.load.popular.drivers=false
|
||||
@ -81,6 +81,23 @@
|
||||
</appender>
|
||||
|
||||
<!-- Loggers -->
|
||||
|
||||
<!-- log4jdbc 로거 설정 - SQL 쿼리와 결과값 출력 -->
|
||||
<logger name="jdbc.sqltiming" level="INFO" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="jdbc.sqlonly" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="jdbc.audit" level="WARN" />
|
||||
<logger name="jdbc.resultset" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="jdbc.resultsettable" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="jdbc.connection" level="WARN" />
|
||||
|
||||
<!-- <logger name="org.apache.catalina" level="ERROR">
|
||||
</logger>
|
||||
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.inqry.mapper.PriceMapper">
|
||||
|
||||
<select id="selectMberMoney"
|
||||
resultType="double"
|
||||
>
|
||||
|
||||
SELECT a.USER_MONEY AS mberMoney
|
||||
FROM lettngnrlmber a
|
||||
WHERE a.MBER_ID = #{mberId}
|
||||
|
||||
</select>
|
||||
|
||||
<select id="selectMberPriceInfo"
|
||||
resultType="hashmap"
|
||||
>
|
||||
|
||||
SELECT a.SHORT_PRICE AS sysShortPrice,
|
||||
a.LONG_PRICE AS sysLongPrice,
|
||||
a.PICTURE_PRICE AS sysPicturePrice,
|
||||
a.PICTURE2_PRICE AS sysPicturePrice2,
|
||||
a.PICTURE3_PRICE AS sysPicturePrice3,
|
||||
b.SHORT_PRICE AS shortPrice,
|
||||
b.LONG_PRICE AS longPrice,
|
||||
b.PICTURE_PRICE AS picturePrice,
|
||||
b.PICTURE2_PRICE AS picturePrice2,
|
||||
b.PICTURE3_PRICE AS picturePrice3
|
||||
FROM mj_mber_setting a ,
|
||||
lettngnrlmber b
|
||||
WHERE b.mber_id = #{mberId}
|
||||
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
43
src/main/resources/mapper/api/kakao/inqry/InqryMapper.xml
Normal file
43
src/main/resources/mapper/api/kakao/inqry/InqryMapper.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.InqryMapper">
|
||||
|
||||
<select id="getChnlIds" resultType="com.itn.mjonApi.mjon.api.kakao.at.inqry.mapper.domain.MjKakaoProfileInfoVO">
|
||||
/* kakao at getChnlIds */
|
||||
SELECT
|
||||
-- USER_ID
|
||||
-- , PROFILE_ID
|
||||
SENDER_KEY
|
||||
-- , TOKEN
|
||||
, PHONE_NUMBER
|
||||
, YELLOW_ID
|
||||
-- , CATEGORY_CODE
|
||||
-- , CATEGORY_NAME
|
||||
, FRST_REGIST_PNTTM
|
||||
, FRST_REGISTER_ID
|
||||
-- , LAST_UPDT_PNTTM
|
||||
-- , LAST_UPDUSR_ID
|
||||
-- , DELETE_YN
|
||||
FROM mj_kakao_profile_info
|
||||
WHERE DELETE_YN = 'N'
|
||||
AND USER_ID = #{mberId}
|
||||
|
||||
</select>
|
||||
|
||||
<select id="isTemplateExist" parameterType="map" resultType="int">
|
||||
/* kakao at isTemplateExist */
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
mj_kakao_profile_info
|
||||
WHERE
|
||||
SENDER_KEY = #{senderKey}
|
||||
AND TEMPLATE_CODE = #{templateCode}
|
||||
AND DELETE_YN = 'N'
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@ -3,9 +3,9 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.inqry.mapper.HstryMapper">
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.msg.inqry.mapper.HstryMapper">
|
||||
|
||||
<select id="selectApiInqryHstry" resultType="com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.MjonResponseVO">
|
||||
<select id="selectApiInqryHstry" resultType="com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.MjonResponseVO">
|
||||
|
||||
/* 문자온 발송결과 페이지 쿼리를 그대로 사용함 - http://localhost:9080/web/mjon/msgsent/selectMsgSentView.do */
|
||||
SELECT
|
||||
@ -102,23 +102,21 @@
|
||||
A.RSLT_CODE ,
|
||||
A.RSLT_CODE2 ,
|
||||
CASE
|
||||
WHEN B.MSG_TYPE = '6'
|
||||
AND B.FILE_CNT > 0
|
||||
THEN '그림(MMS)'
|
||||
WHEN B.MSG_TYPE = '6'
|
||||
AND B.FILE_CNT = 0
|
||||
THEN '장문(LMS)'
|
||||
ELSE '단문(SMS)'
|
||||
END msgTypeName ,
|
||||
WHEN B.MSG_TYPE = '6' AND B.FILE_CNT > 0 THEN '그림(MMS)'
|
||||
WHEN B.MSG_TYPE = '6' AND B.FILE_CNT = 0 THEN '장문(LMS)'
|
||||
WHEN B.MSG_TYPE = '4' THEN '단문(SMS)'
|
||||
WHEN B.MSG_TYPE = '8' THEN '알림톡(AT)'
|
||||
WHEN B.MSG_TYPE = '9' THEN '친구톡(FT)'
|
||||
ELSE '기타'
|
||||
END msgTypeName ,
|
||||
CASE
|
||||
WHEN B.MSG_TYPE = '6'
|
||||
AND B.FILE_CNT > 0
|
||||
THEN '3'
|
||||
WHEN B.MSG_TYPE = '6'
|
||||
AND B.FILE_CNT = 0
|
||||
THEN '2'
|
||||
ELSE '1'
|
||||
END orderByCode , (
|
||||
WHEN B.MSG_TYPE = '6' AND B.FILE_CNT > 0 THEN '3'
|
||||
WHEN B.MSG_TYPE = '6' AND B.FILE_CNT = 0 THEN '2'
|
||||
WHEN B.MSG_TYPE = '4' THEN '1'
|
||||
WHEN B.MSG_TYPE = '8' THEN '4'
|
||||
WHEN B.MSG_TYPE = '9' THEN '5'
|
||||
ELSE '9'
|
||||
END orderByCode ,(
|
||||
CASE
|
||||
WHEN A.AGENT_CODE = '01'
|
||||
AND
|
||||
@ -182,14 +180,23 @@
|
||||
AND DATE_ADD(NOW(), INTERVAL 60 MINUTE) >= B.REQ_DATE
|
||||
|
||||
<if test="startDate != null and startDate != ''">
|
||||
AND b.regdate >= STR_TO_DATE(CONCAT(#{startDate}, '000000'), '%Y%m%d%H%i%s')
|
||||
AND (
|
||||
(b.regdate <![CDATA[ >= ]]> STR_TO_DATE(CONCAT(#{startDate}, '000000'), '%Y%m%d%H%i%s'))
|
||||
OR
|
||||
(b.req_date <![CDATA[ >= ]]> STR_TO_DATE(CONCAT(#{startDate}, '000000'), '%Y%m%d%H%i%s'))
|
||||
)
|
||||
</if>
|
||||
<if test="startDate == null or startDate == ''">
|
||||
AND b.regdate >= STR_TO_DATE(date_format(now(),'%Y%m%d000000'), '%Y%m%d%H%i%s')
|
||||
<!-- AND b.regdate >= STR_TO_DATE(date_format(now(),'%Y%m%d000000'), '%Y%m%d%H%i%s')-->
|
||||
AND b.regdate <![CDATA[ < ]]> DATE_ADD(CURDATE(), INTERVAL 1 DAY)
|
||||
</if>
|
||||
|
||||
<if test="endDate != null and endDate != ''">
|
||||
AND STR_TO_DATE(CONCAT(#{endDate}, '235959'), '%Y%m%d%H%i%s') >= b.regdate
|
||||
AND (
|
||||
(b.regdate <![CDATA[ <= ]]> STR_TO_DATE(CONCAT(#{endDate}, '235959'), '%Y%m%d%H%i%s'))
|
||||
OR
|
||||
(b.req_date <![CDATA[ <= ]]> STR_TO_DATE(CONCAT(#{endDate}, '235959'), '%Y%m%d%H%i%s'))
|
||||
)
|
||||
</if>
|
||||
<if test="startDate == null or startDate == ''">
|
||||
AND STR_TO_DATE(date_format(DATE_ADD(NOW(), INTERVAL 1 day),'%Y%m%d000000'), '%Y%m%d%H%i%s') >= b.regdate
|
||||
@ -214,7 +221,10 @@
|
||||
'2',
|
||||
'3')
|
||||
AND MSG_TYPE IN ('4',
|
||||
'6')
|
||||
'6',
|
||||
'8',
|
||||
'9'
|
||||
)
|
||||
GROUP BY MSG_GROUP_ID
|
||||
/*
|
||||
ORDER BY 1=1,
|
||||
@ -301,7 +311,10 @@
|
||||
WHERE 1 =1
|
||||
AND MD.DEL_FLAG = 'N'
|
||||
AND MD.MSG_TYPE IN ('4',
|
||||
'6')
|
||||
'6',
|
||||
'8',
|
||||
'9'
|
||||
)
|
||||
)
|
||||
A
|
||||
GROUP BY A.MSG_GROUP_ID,
|
||||
@ -336,7 +349,7 @@
|
||||
|
||||
|
||||
<select id="selectApiInqryHstryDetail"
|
||||
resultType="com.itn.mjonApi.mjon.api.inqry.service.mapper.domain.MjonResponseVO"
|
||||
resultType="com.itn.mjonApi.mjon.api.msg.inqry.mapper.domain.MjonResponseVO"
|
||||
>
|
||||
|
||||
/* 문자온 발송결과 페이지 실패 건수 팝업을 변형해서 사용함 - http://localhost:9080/web/mjon/msgsent/selectMsgSFDetailListAjax.do */
|
||||
@ -366,24 +379,23 @@
|
||||
DEL_FLAG AS delFlag ,
|
||||
*/
|
||||
MSG_TYPE AS msgType ,
|
||||
|
||||
|
||||
|
||||
CASE
|
||||
WHEN MSG_TYPE = '6' AND FILE_CNT > 0 THEN '그림(MMS)'
|
||||
WHEN MSG_TYPE = '6' AND FILE_CNT = 0 THEN '장문(LMS)'
|
||||
WHEN MSG_TYPE = '4' THEN '단문(SMS)'
|
||||
WHEN MSG_TYPE = '8' THEN '알림톡(AT)'
|
||||
WHEN MSG_TYPE = '9' THEN '친구톡(FT)'
|
||||
ELSE '기타'
|
||||
END msgTypeName ,
|
||||
CASE
|
||||
WHEN MSG_TYPE = '6'
|
||||
AND FILE_CNT > 0
|
||||
THEN '그림(MMS)'
|
||||
WHEN MSG_TYPE = '6'
|
||||
AND FILE_CNT = 0
|
||||
THEN '장문(LMS)'
|
||||
ELSE '단문(SMS)'
|
||||
END msgTypeName ,
|
||||
CASE
|
||||
WHEN MSG_TYPE = '6'
|
||||
AND FILE_CNT > 0
|
||||
THEN '3'
|
||||
WHEN MSG_TYPE = '6'
|
||||
AND FILE_CNT = 0
|
||||
THEN '2'
|
||||
ELSE '1'
|
||||
WHEN MSG_TYPE = '6' AND FILE_CNT > 0 THEN '3'
|
||||
WHEN MSG_TYPE = '6' AND FILE_CNT = 0 THEN '2'
|
||||
WHEN MSG_TYPE = '4' THEN '1'
|
||||
WHEN MSG_TYPE = '8' THEN '4'
|
||||
WHEN MSG_TYPE = '9' THEN '5'
|
||||
ELSE '9'
|
||||
END orderByCode ,
|
||||
|
||||
/*
|
||||
46
src/main/resources/mapper/api/msg/inqry/PriceMapper.xml
Normal file
46
src/main/resources/mapper/api/msg/inqry/PriceMapper.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.msg.inqry.mapper.PriceMapper">
|
||||
|
||||
<select id="selectMberMoney"
|
||||
resultType="double"
|
||||
>
|
||||
|
||||
SELECT a.USER_MONEY AS mberMoney
|
||||
FROM lettngnrlmber a
|
||||
WHERE a.MBER_ID = #{mberId}
|
||||
|
||||
</select>
|
||||
|
||||
<select id="selectMberPriceInfo"
|
||||
resultType="hashmap"
|
||||
>
|
||||
|
||||
SELECT a.SHORT_PRICE AS sysShortPrice
|
||||
, a.LONG_PRICE AS sysLongPrice
|
||||
, a.PICTURE_PRICE AS sysPicturePrice
|
||||
, a.PICTURE2_PRICE AS sysPicturePrice2
|
||||
, a.PICTURE3_PRICE AS sysPicturePrice3
|
||||
, a.KAKAO_AT_PRICE AS sysKakaoAtPrice
|
||||
, a.KAKAO_FT_PRICE AS sysKakaoFtPrice
|
||||
, a.KAKAO_FT_IMG_PRICE AS sysKakaoFtImgPrice
|
||||
, a.KAKAO_FT_WIDE_IMG_PRICE AS sysKakaoFtWideImgPrice
|
||||
, b.SHORT_PRICE AS shortPrice
|
||||
, b.LONG_PRICE AS longPrice
|
||||
, b.PICTURE_PRICE AS picturePrice
|
||||
, b.PICTURE2_PRICE AS picturePrice2
|
||||
, b.PICTURE3_PRICE AS picturePrice3
|
||||
, b.KAKAO_AT_PRICE AS kakaoAtPrice
|
||||
, b.KAKAO_FT_PRICE AS kakaoFtPrice
|
||||
, b.KAKAO_FT_IMG_PRICE AS kakaoFtImgPrice
|
||||
, b.KAKAO_FT_WIDE_IMG_PRICE AS kakaoFtWideImgPrice
|
||||
FROM mj_mber_setting a ,
|
||||
lettngnrlmber b
|
||||
WHERE b.mber_id = #{mberId}
|
||||
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.send.mapper.SendMapper">
|
||||
<mapper namespace="com.itn.mjonApi.mjon.api.msg.send.mapper.SendMapper">
|
||||
|
||||
<select id="findByCallFrom" resultType="boolean">
|
||||
SELECT IF(COUNT(*), 1, 0)
|
||||
14
src/main/resources/mybatis-config.xml
Normal file
14
src/main/resources/mybatis-config.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration
|
||||
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
|
||||
<configuration>
|
||||
<settings>
|
||||
<setting name="mapUnderscoreToCamelCase" value="true"/>
|
||||
</settings>
|
||||
|
||||
<typeAliases>
|
||||
<package name="com.itn.mjonApi.mjon.api.kakao.inqry.mapper.domain"/>
|
||||
</typeAliases>
|
||||
</configuration>
|
||||
Loading…
Reference in New Issue
Block a user