diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..61f9604 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,225 @@ +# CLAUDE.md + +이 파일은 Claude Code (claude.ai/code)가 이 저장소에서 작업할 때 참고할 가이드입니다. + +## 프로젝트 개요 + +전자정부 표준프레임워크(eGovFramework) v3.9.0 기반의 Maven 빌드 Java 웹 애플리케이션입니다. 문자ON("MunjaON")이라는 SMS/MMS/카카오톡 메시징 서비스의 관리자 플랫폼입니다. + +**기술 스택:** +- Java 8 +- Spring Framework 4.3.22 +- 전자정부 표준프레임워크 3.9.0 +- iBATIS (전자정부프레임워크 경유) +- MySQL 5.1.31 +- Maven 빌드 시스템 +- JSP/JSTL 뷰 + SiteMesh 데코레이터 + +## 빌드 및 개발 + +### 빌드 명령어 + +```bash +# 컴파일 및 패키징 (WAR 파일 생성) +mvn clean install + +# 컴파일만 수행 +mvn compile + +# 내장 톰캣 실행 (설정된 경우) +mvn tomcat7:run +``` + +### 환경 설정 + +애플리케이션은 Spring 프로파일 기반 설정을 사용합니다: +- 환경 프로파일: `dev`, `local`, `prod` +- 시스템 속성으로 설정: `-Dspring.profiles.active=dev` +- 설정 파일 위치: `src/main/resources/egovframework/egovProps/globals_{profile}.properties` + +데이터베이스 설정은 활성 프로파일에 따라 `globals_{profile}.properties`에서 로드됩니다. + +## 프로젝트 아키텍처 + +### 패키지 구조 + +``` +src/main/java/ +├── egovframework.com/ # 전자정부 커스텀 서비스 +│ └── idgen/ # ID 생성 서비스 +├── itn.com/ # 공통 프레임워크 컴포넌트 +│ ├── api/ # REST API 컨트롤러 +│ ├── cmm/ # 공통 유틸리티 & 기본 클래스 +│ │ ├── aspect/ # AOP 로깅 +│ │ ├── filter/ # XSS/보안 필터 +│ │ ├── interceptor/ # 요청 인터셉터 +│ │ └── service/ # 공통 서비스 (파일, 사용자) +│ ├── sym/ # 시스템 관리 (로깅) +│ ├── uss/ # 사용자 지원 서비스 +│ │ ├── ion/ # 통합 (배너, 설정, API) +│ │ └── olh/ # 온라인 도움말 +│ └── utl/ # 유틸리티 +└── itn.let/ # 비즈니스 로직 모듈 + ├── kakao/ # 카카오톡 메시지 서비스 + ├── mail/ # 이메일 서비스 + ├── mjo/ # 핵심 메시징 (SMS/MMS) + ├── cert/ # 본인인증 + ├── fax/ # 팩스 서비스 + └── schdlr/ # 스케줄러 작업 +``` + +### 계층형 아키텍처 + +표준 MVC 계층형 아키텍처를 따릅니다: + +1. **컨트롤러 계층** (`*.web.*Controller`) + - 요청 처리 및 응답 생성 + - URL 패턴: `*.do` (Spring DispatcherServlet 매핑) + - `*.web` 패키지에 위치 + +2. **서비스 계층** (`*.service.*Service`, `*ServiceImpl`) + - 비즈니스 로직 구현 + - 트랜잭션 경계 정의 + - 인터페이스-구현체 패턴 + +3. **DAO 계층** (`*.service.impl.*DAO`) + - iBATIS SqlMapClient를 사용한 데이터 접근 + - 공통 작업을 위해 `EgovComAbstractDAO` 상속 + - SQL 매핑: `src/main/resources/egovframework/sqlmap/` + +4. **VO/DTO 계층** (`*VO`, `*DTO`) + - 데이터 전송 객체 + - 페이징을 위해 `ComDefaultVO` 상속 + +### 주요 기본 클래스 + +- **EgovComAbstractDAO**: iBATIS 작업(`insert`, `update`, `delete`, `select`, `selectList`)을 포함한 기본 DAO +- **ComDefaultVO**: 페이징 지원 기본 VO (`pageIndex`, `pageUnit`, `pageSize`) +- **ComDefaultCodeVO**: 코드 기반 엔티티용 기본 VO + +### 설정 파일 + +**Spring 설정:** +- `src/main/resources/egovframework/spring/com/context-*.xml` - 애플리케이션 컨텍스트 +- `src/main/webapp/WEB-INF/config/egovframework/springmvc/*.xml` - MVC 설정 +- 주요 컨텍스트: + - `context-datasource.xml` - 데이터베이스 연결 (프로파일 기반) + - `context-sqlMap.xml` - iBATIS SQL 매핑 설정 + - `context-security.xml` - Spring Security 설정 + - `context-aspect.xml` - AOP 로깅 설정 + +**SQL 매핑:** +- 위치: `src/main/resources/egovframework/sqlmap/config/mysql/` +- 패턴: `sql-map-config-mysql-{모듈명}.xml` +- SQL 정의: `src/main/resources/egovframework/sqlmap/com/**/*_SQL_Mysql.xml` + +**뷰 설정:** +- JSP 위치: `src/main/webapp/WEB-INF/jsp/` +- SiteMesh 데코레이터: `src/main/webapp/WEB-INF/decorators.xml` +- 레이아웃 템플릿: `src/main/webapp/WEB-INF/jsp/layout/` + +## 주요 기능 + +### 보안 및 필터 + +- **Spring Security**: `context-security.xml`을 통해 설정 +- **XSS 필터**: `XssFilter`가 요청을 래핑하여 입력값 검증 +- **문자 인코딩**: 기본 UTF-8, 특정 결제 엔드포인트는 EUC-KR +- **CORS**: `CORSFilter`를 통해 활성화 + +### 외부 연동 + +- **결제 게이트웨이**: KG 모빌리언스 (`globals.properties`에 설정) +- **본인인증**: NiceID, KMC, ARS 인증 +- **메시징 API**: 카카오톡, SMS/MMS 서비스 +- **파일 업로드**: Apache Commons FileUpload +- **PDF 처리**: Apache PDFBox +- **엑셀**: Apache POI + +### 스케줄 작업 + +- Quartz 스케줄러 설정: `context-scheduling-*.xml` +- 작업 구현: `itn.let.schdlr` 패키지 +- 분산 작업 잠금을 위해 ShedLock 사용 (JDBC 기반) + +## 개발 가이드 + +### 신규 기능 추가 절차 + +1. **VO 생성**: `ComDefaultVO` 또는 `ComDefaultCodeVO` 상속 +2. **SQL 매퍼 생성**: `src/main/resources/egovframework/sqlmap/`에 XML 추가 +3. **SQL 설정 등록**: `sql-map-config-mysql-{모듈명}.xml`에 등록 +4. **DAO 생성**: `EgovComAbstractDAO` 상속 +5. **서비스 생성**: 인터페이스 + 구현체 패턴 +6. **컨트롤러 생성**: `@Controller` 또는 `@RestController` 사용 +7. **JSP 생성**: `src/main/webapp/WEB-INF/jsp/{모듈명}/`에 배치 + +### 코드 규칙 + +- 전자정부 프레임워크 표준과 네이밍 규칙을 따름 +- 서비스 인터페이스는 `Service` 접미사 +- 서비스 구현체는 `ServiceImpl` 접미사 +- DAO 클래스는 `DAO` 접미사 +- 컨트롤러 클래스는 `Controller` 접미사 +- 의존성 주입은 `@Resource(name="빈이름")` 사용 + +### iBATIS SQL 매핑 + +SQL 구문은 네임스페이스.구문ID 패턴으로 참조: +```java +// EgovComAbstractDAO를 상속한 DAO에서 +insert("모듈명.insertData", vo); +selectList("모듈명.selectDataList", searchVO); +``` + +### 주요 작업 패턴 + +**페이징:** +```java +// VO에서 +ComDefaultVO를 상속하여 페이징 필드 사용 +// PaginationInfo와 ImagePaginationRenderer 활용 +``` + +**파일 업로드:** +```java +// 파일 작업은 EgovFileMngService 사용 +// Globals.file.saveDir 속성 기반으로 파일 저장 +``` + +**로깅:** +```java +// LoggerAspect를 통한 AOP 기반 로깅 +// log4jdbc를 통한 SQL 로깅 +``` + +## 테스트 + +현재 Maven 설정에서 테스트가 비활성화되어 있습니다(`pom.xml`의 `skipTests=true`). 활성화하려면: +```bash +# pom.xml의 surefire 플러그인 설정 수정 후 실행: +mvn test +``` + +## 배포 + +애플리케이션은 WAR 파일(`mjon.war`)로 빌드되어 Tomcat에 배포됩니다: +- 배포 경로: `/usr/local/tomcat` (운영) +- 포트: Tomcat server.xml에서 설정 +- 세션 타임아웃: 600분 (10시간) +- 에러 페이지: `/common/error.jsp` + +### 환경별 배포 + +1. 적절한 프로파일 설정: `-Dspring.profiles.active={dev|prod}` +2. `globals_{profile}.properties`에 데이터베이스 자격증명 확인 +3. properties에 파일 경로(ckeditor, fax 등) 설정 +4. WAR 파일을 Tomcat webapps 디렉토리에 배포 + +## 중요 사항 + +- **문자 인코딩**: 레거시 결제 시스템을 위한 UTF-8/EUC-KR 혼용 +- **데이터베이스**: MySQL 5.x - 구버전 iBATIS 사용 (MyBatis 아님) +- **보안**: Spring Security 통합, `EgovUserDetailsService`를 통한 사용자 정보 +- **프로파일 필수**: 애플리케이션 시작 시 `-Dspring.profiles.active` 필요 +- **외부 라이브러리**: `WEB-INF/lib`에 일부 JAR 파일 (결제, 인증 모듈) diff --git a/RESTAPI문자테스트_화면설계서_1차_250917_정다은 (1).pptx b/RESTAPI문자테스트_화면설계서_1차_250917_정다은 (1).pptx new file mode 100644 index 0000000..cb76a04 Binary files /dev/null and b/RESTAPI문자테스트_화면설계서_1차_250917_정다은 (1).pptx differ diff --git a/button_01.png b/button_01.png new file mode 100644 index 0000000..311c642 Binary files /dev/null and b/button_01.png differ diff --git a/src/main/java/itn/let/mail/service/StatusResponse.java b/src/main/java/itn/let/mail/service/StatusResponse.java index 50649c9..b2cf57b 100644 --- a/src/main/java/itn/let/mail/service/StatusResponse.java +++ b/src/main/java/itn/let/mail/service/StatusResponse.java @@ -73,6 +73,13 @@ public class StatusResponse { this.timestamp = timestamp; } + public StatusResponse(HttpStatus status, String message, Object object, LocalDateTime timestamp) { + this.status = status; + this.message = message; + this.object = object; + this.timestamp = timestamp; + } + public StatusResponse(HttpStatus status, String message, LocalDateTime timestamp) { this.status = status; this.message = message; diff --git a/src/main/java/itn/let/mjo/api/sms/service/ApiAccLogVO.java b/src/main/java/itn/let/mjo/api/sms/service/ApiAccLogVO.java new file mode 100644 index 0000000..f6d99df --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ApiAccLogVO.java @@ -0,0 +1,50 @@ +package itn.let.mjo.api.sms.service; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * api key 관리 + * @since 2025.11.05 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2025.11.05  이호영          최초 생성
+ *
+ * 
+ */ + + + +@Getter +@Setter +@ToString +public class ApiAccLogVO{ + + private String logId; + private String accessType; + private String accessKey; + private String accessToken; + private String reqUserId; + private String reqInfoMeth; + private String reqUrl; + private String resCode; + private String reqRegistPnttm; + private String reqRegisterId; + private String resUpdtPnttm; + private String resUpdusrId; + + private String reqCnStr; // JSON 문자열 임시 저장 + private String resCnStr; // JSON 문자열 임시 저장 + + private ReqCnVO reqCn; // JSON → 객체 변환 후 세팅 + private ResCnVO resCn; + + +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/ApiSmsTestMsgService.java b/src/main/java/itn/let/mjo/api/sms/service/ApiSmsTestMsgService.java new file mode 100644 index 0000000..172ee21 --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ApiSmsTestMsgService.java @@ -0,0 +1,56 @@ +package itn.let.mjo.api.sms.service; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import itn.let.mail.service.StatusResponse; +import itn.let.mjo.apikey.service.ApiKeyVO; + +/** + * api key 관리 + * @since 2009.04.10 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2009.04.10  조재영          최초 생성
+ *   2017.07.21  장동한 			로그인인증제한 작업
+ *
+ * 
+ */ +public interface ApiSmsTestMsgService { + + StatusResponse findByApiInfoWhereMberIdAjax(String checkId); + + Map selectSendHistry(ApiKeyVO searchVO) throws JsonParseException, JsonMappingException, IOException; + + +// //api key list +// public List selectMberApiKeyList(ApiKeyVO apiKeyVO) throws Exception; +// +// //api key 사용상태 변경 +// void deleteApiKey(ApiKeyVO apiKeyVO) throws Exception; +// +// //api key 중복키 확인 +// public List selectCheckApiKeyDup(ApiKeyVO apiKeyVO) throws Exception; +// +// //api key 변경 +// void updateApiKey(ApiKeyVO apiKeyVO) throws Exception; +// +// //api key 생성-초기생성 +// int insertApiKey(ApiKeyVO apiKeyVO) throws Exception; +// +// //REST API 신청상태 +// public List selectApiKeyApplyStatus(ApiKeyVO apiKeyVO) throws Exception; +// +// public int selectMberApiKeyChk(ApiKeyVO apiKeyVO) throws Exception; + +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/ReqCnVO.java b/src/main/java/itn/let/mjo/api/sms/service/ReqCnVO.java new file mode 100644 index 0000000..423a979 --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ReqCnVO.java @@ -0,0 +1,146 @@ +package itn.let.mjo.api.sms.service; + +import java.util.List; +import java.util.Map; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * api key 관리 + * @since 2025.11.05 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2025.11.05  이호영          최초 생성
+ *
+ * 
+ */ + + + +@Getter +@Setter +@ToString +public class ReqCnVO { + + // === 조회/페이징 === + private String page; + private String pageSize; + private String startDate; + private String endDate; + + // === 카카오 템플릿 전송 관련 === + private String bizId; + private String apiKey; + private String senderKey; + private String templateCode; + private Boolean hasTemplateTitle; + private String subMsgSendYn; // "Y"/"N" + private List> varListMap; + + + + + // ===== 공통 인증 관련 ===== + private String accessNo; + private String mberId; + private String accessKey; + private String useYn; + private String frstRegistPnttm; + private String frstRegisterId; + private String lastUpdtPnttm; + private String lastUpdusrId; + private String accessToken; + private String tokenObj; + private String expirePnttm; + private String callInfo; + private String remainMsgCnt; + + // ===== 문자 발송 요청 관련 ===== + private String smsTxt; + private String smsTxtArea; + private List callToList; + private String callFrom; + private String eachPrice; + private String sPrice; + private String mPrice; + private String pPrice; + private String p2Price; + private String p3Price; + private String totPrice; + private String fileCnt; + private String msgType; + private double smsPrice; + private double mmsPrice; + private List imgFilePath; + private String spamStatus; + private String txtReplYn; + private String nameStr; + private String rep1Str; + private String rep2Str; + private String rep3Str; + private String rep4Str; + private List nameList; + private List rep1List; + private List rep2List; + private List rep3List; + private List rep4List; + private String reserveYn; + private String shortMsgCnt; + private String longMsgCnt; + private String msgKind; + private String test_yn; + private String sendKind; + private Object mjonMsgSendVOList; // 리스트형이지만 구조 미정이므로 Object로 처리 + + // ===== 응답 (result/data 구조) ===== + private String resultCode; + private String msgGroupId; + private String successCnt; + private String blockCnt; + private String failCnt; + private String msgTypeList; + private String msgGroupIdList; + private String msg; + private String localDateTime; + + private String data; + private String dataResultCode; + private String dataMsgGroupId; + private String dataSuccessCnt; + private String dataBlockCnt; + private String dataFailCnt; + private String dataMsgType; + private String dataTestYn; + + + public String getsPrice() { + return sPrice; + } + public void setsPrice(String sPrice) { + this.sPrice = sPrice; + } + public String getmPrice() { + return mPrice; + } + public void setmPrice(String mPrice) { + this.mPrice = mPrice; + } + public String getpPrice() { + return pPrice; + } + public void setpPrice(String pPrice) { + this.pPrice = pPrice; + } + + + + // getter/setter +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/ResCnVO.java b/src/main/java/itn/let/mjo/api/sms/service/ResCnVO.java new file mode 100644 index 0000000..1a3c587 --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ResCnVO.java @@ -0,0 +1,55 @@ +package itn.let.mjo.api.sms.service; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * api key 관리 + * @since 2025.11.05 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2025.11.05  이호영          최초 생성
+ *
+ * 
+ */ + + + +@Getter +@Setter +@ToString +@JsonIgnoreProperties(ignoreUnknown = true) +public class ResCnVO { + + // ===== 요청정보(AccessKey) ===== + private String accessNo; + private String mberId; + private String accessKey; + private String useYn; + private String frstRegistPnttm; + private String frstRegisterId; + private String lastUpdtPnttm; + private String lastUpdusrId; + private String accessToken; + private String tokenObj; + private String expirePnttm; + private String callInfo; + private String remainMsgCnt; + + // ===== 최상위 응답 ===== + private String resultCode; + private ResData data; + private List localDateTime; // [2025,11,5,11,25,4,488000000] 형태 + +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/ResData.java b/src/main/java/itn/let/mjo/api/sms/service/ResData.java new file mode 100644 index 0000000..04aeac8 --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ResData.java @@ -0,0 +1,52 @@ +package itn.let.mjo.api.sms.service; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * api key 관리 + * @since 2025.11.05 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2025.11.05  이호영          최초 생성
+ *
+ * 
+ */ + + + +@Getter +@Setter +@ToString +@JsonIgnoreProperties(ignoreUnknown = true) +public class ResData { + + // ===== 최상위 응답 ===== + private String resultCode; + private List localDateTime; + private List objectList; + + private String msgGroupId; + private List msgGroupIdList; + private String successCnt; + private String blockCnt; + private String failCnt; + private String msgType; + private List msgTypeList; + @JsonProperty("test_yn") + private String testYn; + @JsonProperty("next_yn") + private String nextYn; +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/ResMsgObj.java b/src/main/java/itn/let/mjo/api/sms/service/ResMsgObj.java new file mode 100644 index 0000000..3f2d10c --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/ResMsgObj.java @@ -0,0 +1,52 @@ +package itn.let.mjo.api.sms.service; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * api key 관리 + * @since 2025.11.05 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2025.11.05  이호영          최초 생성
+ *
+ * 
+ */ + + + +@Getter +@Setter +@ToString +public class ResMsgObj { + + // ===== 최상위 응답 ===== + private String msgGroupId; + private String msgId; + private String totMsgCnt; + private String msgType; + private String msgTypeName; + private String msgResult; + private String msgGroupCnt; + private String smsTxt; + private String callFrom; + private String callTo; + private String curState; + private String userId; + private String remainMsgCnt; + private String reqdate; + private String regdate; + private String reserveCYn; + private String ttlCnt; + private String subject; + private String scnt; + private String fcnt; + private String wcnt; +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgDAO.java b/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgDAO.java new file mode 100644 index 0000000..d62bd3d --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgDAO.java @@ -0,0 +1,38 @@ +package itn.let.mjo.api.sms.service.impl; + +import java.util.List; + +import org.springframework.stereotype.Repository; + +import itn.com.cmm.service.impl.EgovComAbstractDAO; +import itn.let.mjo.api.sms.service.ApiAccLogVO; +import itn.let.mjo.apikey.service.ApiKeyVO; + +/** + * 일반회원관리에 관한 데이터 접근 클래스를 정의한다. + * @author 공통서비스 개발팀 조재영 + * @since 2009.04.10 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2009.04.10  조재영          최초 생성
+ *   2017.07.21  장동한 			로그인인증제한 작업
+ *
+ * 
+ */ +@Repository("apiSmsTestMsgDAO") +public class ApiSmsTestMsgDAO extends EgovComAbstractDAO{ + + public ApiKeyVO findByApiInfoWhereMberIdAjax(String checkId) { + return (ApiKeyVO) select("apiSmsTestMsgDAO.findByApiInfoWhereMberIdAjax", checkId); + } + + public List selectSendHistry(ApiKeyVO apiKeyVO) { + return (List) list("apiSmsTestMsgDAO.selectSendHistry", apiKeyVO); + } +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgServiceImpl.java b/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgServiceImpl.java new file mode 100644 index 0000000..0ee7956 --- /dev/null +++ b/src/main/java/itn/let/mjo/api/sms/service/impl/ApiSmsTestMsgServiceImpl.java @@ -0,0 +1,97 @@ +package itn.let.mjo.api.sms.service.impl; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + + +import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl; +import itn.let.mail.service.StatusResponse; +import itn.let.mjo.api.sms.service.ApiAccLogVO; +import itn.let.mjo.api.sms.service.ApiSmsTestMsgService; +import itn.let.mjo.api.sms.service.ReqCnVO; +import itn.let.mjo.api.sms.service.ResCnVO; +import itn.let.mjo.apikey.service.ApiKeyVO; +import lombok.extern.slf4j.Slf4j; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * 일반회원관리에 관한비지니스클래스를 정의한다. + * @author 공통서비스 개발팀 조재영 + * @since 2009.04.10 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *   수정일      수정자           수정내용
+ *  -------    --------    ---------------------------
+ *   2009.04.10  조재영          최초 생성
+ *   2014.12.08	 이기하			암호화방식 변경(EgovFileScrty.encryptPassword)
+ *   2017.07.21  장동한 			로그인인증제한 작업
+ *
+ * 
+ */ +@Slf4j +@Service("apiSmsTestMsgService") +public class ApiSmsTestMsgServiceImpl extends EgovAbstractServiceImpl implements ApiSmsTestMsgService { + + /*api call info */ + @Resource(name = "apiSmsTestMsgDAO") + private ApiSmsTestMsgDAO apiSmsTestMsgDAO; + + @Override + public StatusResponse findByApiInfoWhereMberIdAjax(String checkId) { + // TODO Auto-generated method stub + ApiKeyVO apiInfoListVO = apiSmsTestMsgDAO.findByApiInfoWhereMberIdAjax(checkId); + String msg = ""; + if(apiInfoListVO == null) { + msg = checkId+" 회원에 API 정보가 없습니다."; + } + + return new StatusResponse(HttpStatus.OK, msg, apiInfoListVO, LocalDateTime.now()); + } + + @Override + public Map selectSendHistry(ApiKeyVO apiKeyVO) throws JsonParseException, JsonMappingException, IOException { + + Map resultMap = new HashMap<>(); + + List apiInfoListVO = apiSmsTestMsgDAO.selectSendHistry(apiKeyVO); + + ObjectMapper mapper = new ObjectMapper(); + for (ApiAccLogVO vo : apiInfoListVO) { + if (vo.getReqCnStr() != null) { + log.info("vo.getReqCnStr() : [{}]", vo.getReqCnStr()); + vo.setReqCn(mapper.readValue(vo.getReqCnStr(), ReqCnVO.class)); + } + if (vo.getResCnStr() != null) { + vo.setResCn(mapper.readValue(vo.getResCnStr(), ResCnVO.class)); + } + } + + apiInfoListVO.stream().forEach(t->System.out.println(" t.toString() :: "+ t.toString())); + + + resultMap.put("apiInfoListVO", apiInfoListVO); + resultMap.put("listSize", apiInfoListVO.size()); + + + return resultMap; + } + + + +} \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/api/sms/web/ApiSmsTestMsgController.java b/src/main/java/itn/let/mjo/api/sms/web/ApiSmsTestMsgController.java index 4001ccc..e50eb06 100644 --- a/src/main/java/itn/let/mjo/api/sms/web/ApiSmsTestMsgController.java +++ b/src/main/java/itn/let/mjo/api/sms/web/ApiSmsTestMsgController.java @@ -1,14 +1,23 @@ package itn.let.mjo.api.sms.web; +import java.util.Map; + +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import itn.let.mail.service.StatusResponse; +import itn.let.mjo.api.sms.service.ApiSmsTestMsgService; +import itn.let.mjo.apikey.service.ApiKeyMngService; import itn.let.mjo.apikey.service.ApiKeyVO; +import lombok.extern.slf4j.Slf4j; /** * @@ -24,8 +33,14 @@ import itn.let.mjo.apikey.service.ApiKeyVO; * */ +@Slf4j @Controller public class ApiSmsTestMsgController { + + + //api key 정보 + @Resource(name = "apiSmsTestMsgService") + private ApiSmsTestMsgService apiSmsTestMsgService; /** xpedite 솔루션 ID*/ @@ -57,6 +72,7 @@ public class ApiSmsTestMsgController { HttpServletRequest request , ModelMap model) throws Exception{ + model.addAttribute("reqUrl", "/api/send/sendMsg"); return "/uss/ion/api/test/sms/sendMsgForm"; } @@ -99,4 +115,41 @@ public class ApiSmsTestMsgController { return "/uss/ion/api/test/sms/sendSelectPriceFrom"; } + + + // 금액 조회 + @RequestMapping(value= {"/uss/ion/api/test/sms/selectSendHistryAjax.do"}) + public String selectSendHistryAjax(@ModelAttribute("searchVO") ApiKeyVO searchVO, + HttpServletRequest request , + ModelMap model) throws Exception{ + + log.info("searchVO getReqUrl : [{}]", searchVO.getReqUrl()); + log.info("searchVO getMberId : [{}]", searchVO.getMberId()); + log.info("searchVO getAccessKey : [{}]", searchVO.getAccessKey()); + Map resultMap = apiSmsTestMsgService.selectSendHistry(searchVO); + + model.addAttribute("listSize", resultMap.get("listSize")); + model.addAttribute("resultList", resultMap.get("apiInfoListVO")); + + return "/uss/ion/api/test/sms/popup/sendHistory"; + + } + + @RequestMapping(value = "/uss/ion/api/test/sms/findByApiInfoWhereMberIdAjax.do") + public ResponseEntity selectMberIdAjax(@RequestParam String checkId) throws Exception { + return ResponseEntity.ok().body(apiSmsTestMsgService.findByApiInfoWhereMberIdAjax(checkId)); + } + + + + + + + + + + + + + } \ No newline at end of file diff --git a/src/main/java/itn/let/mjo/apikey/service/ApiKeyVO.java b/src/main/java/itn/let/mjo/apikey/service/ApiKeyVO.java index 4726d6c..fe2d59c 100644 --- a/src/main/java/itn/let/mjo/apikey/service/ApiKeyVO.java +++ b/src/main/java/itn/let/mjo/apikey/service/ApiKeyVO.java @@ -1,6 +1,8 @@ package itn.let.mjo.apikey.service; import itn.com.cmm.ComDefaultVO; +import lombok.Getter; +import lombok.Setter; /** * api key 관리 @@ -21,7 +23,8 @@ import itn.com.cmm.ComDefaultVO; - +@Getter +@Setter public class ApiKeyVO extends ComDefaultVO{ private static final long serialVersionUID = -7865729705175845268L; @@ -48,109 +51,8 @@ public class ApiKeyVO extends ComDefaultVO{ private String infoNo; //info 정보 순번 private String callType; //IP/URL private String callInfo; //주소 또는 IP 정보(referer) - - public String getAccessNo() { - return accessNo; - } - public void setAccessNo(String accessNo) { - this.accessNo = accessNo; - } - public String getMberId() { - return mberId; - } - public void setMberId(String mberId) { - this.mberId = mberId; - } - public String getAccessKey() { - return accessKey; - } - public void setAccessKey(String accessKey) { - this.accessKey = accessKey; - } - public String getUseYn() { - return useYn; - } - public void setUseYn(String useYn) { - this.useYn = useYn; - } - public String getFrstRegistPnttm() { - return frstRegistPnttm; - } - public void setFrstRegistPnttm(String frstRegistPnttm) { - this.frstRegistPnttm = frstRegistPnttm; - } - public String getFrstRegisterId() { - return frstRegisterId; - } - public void setFrstRegisterId(String frstRegisterId) { - this.frstRegisterId = frstRegisterId; - } - public String getLastUpdtPnttm() { - return lastUpdtPnttm; - } - public void setLastUpdtPnttm(String lastUpdtPnttm) { - this.lastUpdtPnttm = lastUpdtPnttm; - } - public String getLastUpdusrId() { - return lastUpdusrId; - } - public void setLastUpdusrId(String lastUpdusrId) { - this.lastUpdusrId = lastUpdusrId; - } - public String getAccessToken() { - return accessToken; - } - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - public String getTokenObj() { - return tokenObj; - } - public void setTokenObj(String tokenObj) { - this.tokenObj = tokenObj; - } - public String getExpirePnttm() { - return expirePnttm; - } - public void setExpirePnttm(String expirePnttm) { - this.expirePnttm = expirePnttm; - } - public String getMberNm() { - return mberNm; - } - public void setMberNm(String mberNm) { - this.mberNm = mberNm; - } - public String getMberSttus() { - return mberSttus; - } - public void setMberSttus(String mberSttus) { - this.mberSttus = mberSttus; - } - public String getDept() { - return dept; - } - public void setDept(String dept) { - this.dept = dept; - } - public String getInfoNo() { - return infoNo; - } - public void setInfoNo(String infoNo) { - this.infoNo = infoNo; - } - public String getCallType() { - return callType; - } - public void setCallType(String callType) { - this.callType = callType; - } - public String getCallInfo() { - return callInfo; - } - public void setCallInfo(String callInfo) { - this.callInfo = callInfo; - } + private String reqUrl; //주소 또는 IP 정보(referer) + } \ No newline at end of file diff --git a/src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-apiSms.xml b/src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-apiSms.xml new file mode 100644 index 0000000..fe2e3e0 --- /dev/null +++ b/src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-apiSms.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/src/main/resources/egovframework/sqlmap/let/mjo/apiSms/ApiSmsTestMsg_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/let/mjo/apiSms/ApiSmsTestMsg_SQL_Mysql.xml new file mode 100644 index 0000000..ddecba9 --- /dev/null +++ b/src/main/resources/egovframework/sqlmap/let/mjo/apiSms/ApiSmsTestMsg_SQL_Mysql.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/popupCmn.jsp b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/popupCmn.jsp new file mode 100644 index 0000000..3e4c28c --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/popupCmn.jsp @@ -0,0 +1,23 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + +
+
+
+
+ + 회원 아이디 검색 +
+
+ 검색할 아이디 +
+
+ 아이디를 검색하세요 +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/tab_include.jsp b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/tab_include.jsp index 6cb2e35..790ffb9 100644 --- a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/tab_include.jsp +++ b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/include/tab_include.jsp @@ -57,6 +57,7 @@ $(document).ready(function() { }); +
  • 문자발송
  • @@ -72,23 +73,23 @@ $(document).ready(function() { + + + +
    + +

    사용자정보.

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    사용자ID (mberId) + +
    API Key (apiKey)
    API 상태 (useYn)
    등록 IP (callInfo)
    + +
    + + + +
    + + diff --git a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/popup/sendHistory.jsp b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/popup/sendHistory.jsp new file mode 100644 index 0000000..03d24eb --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/popup/sendHistory.jsp @@ -0,0 +1,642 @@ +<%-- + Class Name : EgovGnrlUserSelectMsgDataListPop.jsp + Description : 사용자 문자전송리스트(전체) + Modification Information + + 수정일 수정자 수정내용 + ------- -------- --------------------------- + 2022.07.01 우영두 최초 생성 + + author : 우영두 + since : 2022.07.01 + + Copyright (C) 2009 by MOPAS All right reserved. +--%> +<%@ page contentType="text/html; charset=utf-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%> +<% pageContext.setAttribute("newLineChar", "\r\n"); %> +<% pageContext.setAttribute("newLineChar2", "\n"); %> +<% + response.setHeader("Cache-Control","no-store"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader("Expires",0); + if (request.getProtocol().equals("HTTP/1.1")) response.setHeader("Cache-Control", "no-cache"); +%> + + + +사용자 문자전송 관리 + + + + + + + + + + + + + + + + + +
    +
    +
    +
    Loading
    +
    +
    +<%--
    --%> + +<%-- --%> + + +<%-- --%> + +<%-- " /> --%> +<%-- " /> --%> + +<%-- --%> + + +<%-- --%> + +
    +
    + +

    ''의 API전송 리스트

    + +
    +
    + <%-- +
    + + + + + + + + + + + " > + + +   ~ + + " > + + + + 타임아웃 아이콘 + + +
    --%> +
    +

    + <%--

    +
    + + + +
    --%> +
    +
    + + + + + + + + + + + <%-- --%> + <%-- --%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <%-- + + + + + + + + + + + + + + + + + + --%> + +
    번호발신번호발송건수등록일시내용결과실패사유불러오기
    10100000000010009-09테스트응답실패지환 데이터 오류버튼
    + + + + + + + + + "> + + + + + + + + + + + + + + + + + + + /(%) + + + + 예약취소 + + + 예약 + + + 즉시 + + + ');" style="cursor:pointer;"> + + + + + 내용없음 + + + 그림문자 + + +
    + + + + + + + + + +
    +
    + +

    +
    + + + + + + + + + + + +
    +
    + + +
    +
    +
    +
    + + + 단문 + + + 그림(장) + + + 장문 + + + + + + API + + + WEB + + + + + + + + + [발송취소]
    + +
    +
    + + [미처리] + + + [승인] + +
    +
    + + - + +
    +
    + + + + + + + - + + + + + - + + + + + + + + +
    +
    +
    +
    + + <%-- +
    +
      + +
    +
    +
    --%> + +
    +
    +
    +<%--
    + + + +
    + --%> + + diff --git a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/sendMsgForm.jsp b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/sendMsgForm.jsp index 72c0743..a698c6a 100644 --- a/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/sendMsgForm.jsp +++ b/src/main/webapp/WEB-INF/jsp/uss/ion/api/test/sms/sendMsgForm.jsp @@ -3,6 +3,15 @@ <%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + + + +환불 등록 + + + + + @@ -64,97 +73,118 @@ height: 55px; } +/* 파란색 버튼 스타일 */ +.fillBlue { + margin-top: 5px; + height: 25px; + padding: 3px 10px; + font-size: 13px; + text-align: center; + color: #ffffff !important; + background: #456ded; + border: none; + border-radius: 3px; + cursor: pointer; +} + +.fillBlue:hover { + background: #3558d6; +} + + +
    @@ -164,10 +194,13 @@

    발송 테스트

    -
    +
    <%@include file="/WEB-INF/jsp/uss/ion/api/test/sms/include/tab_include.jsp" %> +
    + +

    발신정보.

    @@ -204,8 +237,8 @@
    - + +
    @@ -255,3 +288,9 @@
    + + +<%@include file="/WEB-INF/jsp/uss/ion/api/test/sms/include/popupCmn.jsp" %> + + + diff --git a/src/main/webapp/js/uss/ion/api/test/sms/cmn.js b/src/main/webapp/js/uss/ion/api/test/sms/cmn.js new file mode 100644 index 0000000..0cc8514 --- /dev/null +++ b/src/main/webapp/js/uss/ion/api/test/sms/cmn.js @@ -0,0 +1,121 @@ +$(document).ready(function(){ + + + $('#showMask').click(function(e){ + // preventDefault는 href의 링크 기본 행동을 막는 기능입니다. + e.preventDefault(); + // 화면의 높이와 너비를 변수로 만듭니다. + var maskHeight = $(document).height(); + var maskWidth = $(window).width(); + + // 마스크의 높이와 너비를 화면의 높이와 너비 변수로 설정합니다. + $('.mask').css({'width':maskWidth,'height':maskHeight}); + + // fade 애니메이션 : 1초 동안 검게 됐다가 80%의 불투명으로 변합니다. + $('.mask').fadeIn(1000); + $('.mask').fadeTo("slow",0.8); + + // 레이어 팝업을 가운데로 띄우기 위해 화면의 높이와 너비의 가운데 값과 스크롤 값을 더하여 변수로 만듭니다. + var left = ( $(window).scrollLeft() + ( $(window).width() - $('.window').width()) / 2 ); + var top = ( $(window).scrollTop() + ( $(window).height() - $('.window').height()) / 2 ); + + // css 스타일을 변경합니다. + $('.window').css({'left':left,'top':top, 'position':'absolute'}); + + // 레이어 팝업을 띄웁니다. + $('.window').show(); + $('#checkIdModal').focus(); + }); + // 닫기(close)를 눌렀을 때 작동합니다. + $('.window .close').click(function (e) { + e.preventDefault(); + $('.mask, .window').hide(); + $("input[name=emplyrId]").val(""); + }); + + $('#checkIdModal').on('keydown', function(e) { + if (e.key === 'Enter' || e.keyCode === 13) { + e.preventDefault(); // 폼 submit 막기 + fn_searchUser(); + } + }); + +}); + + + +//회원 조회 +function fn_searchUser(){ + $.ajax({ + type:"POST", +// url:"", + url:"/uss/ion/api/test/sms/findByApiInfoWhereMberIdAjax.do", + data:{ + "checkId": $("#checkIdModal").val() + }, + dataType:'json', + timeout:(1000*30), + success:function(data){ + + console.log('data ', data); + if(data?.message) + { + alert(data.message); + return false; + } + else + { + + var object = data.object; + console.log('object : ', object); + console.log('object.accessKey : ', object.accessKey); + + $('#mberId').val(object.mberId); + $('#apiKey').val(object.accessKey); + $('#useYn').val(object.useYn); + $('#callInfo').val(object.callInfo); + + + $('.mask, .window').hide(); + } + }, + error:function(request , status, error){ + console.log(' error ?'); + console.log('request : ', request); + console.log('status : ', status); + } + }); +} + + + +//최근 문자 전송내역 리스트 팝업 호출하기 +function fnSelectSendHistry() { + + var p_mberId = $('#mberId').val(); + var p_apiKey = $('#apiKey').val(); + var p_reqUrl = $('#reqUrl').val(); + + if (!p_mberId?.trim() || !p_apiKey?.trim()) { + alert("회원ID 또는 API Key가 비어있습니다."); + return; + } + + $('#apiInfoFomr').find('input[name="mberId"]').val(p_mberId); + $('#apiInfoFomr').find('input[name="accessKey"]').val(p_apiKey); + $('#apiInfoFomr').find('input[name="reqUrl"]').val(p_reqUrl); + + + var url = "/uss/ion/api/test/sms/selectSendHistryAjax.do"; + +// window.open("_blank", 'popupSelectSendHistry', 'width=1600, height=800, top=50, left=0, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbars=no'); + window.open("", 'popupSelectSendHistry', 'width=1600, height=800, top=50, left=0, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbars=no'); + + + $('#apiInfoFomr') + .attr('action', url) + .attr('target', 'popupSelectSendHistry') + .submit(); + +} +