Merge remote-tracking branch 'origin/main' into V2026012702
This commit is contained in:
226
ERP_SYNC_README.md
Normal file
226
ERP_SYNC_README.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# ERP API 데이터 동기화 배치 시스템
|
||||
|
||||
## 개요
|
||||
이 시스템은 외부 ERP API로부터 거래처, 부서, 사원 정보를 자동으로 가져와 PLM 시스템의 데이터베이스에 동기화하는 배치 프로그램입니다.
|
||||
|
||||
## 주요 기능
|
||||
|
||||
### 1. 거래처 정보 동기화 (CustomerApiClient)
|
||||
- **API 엔드포인트**: `/apiproxy/api16S11`
|
||||
- **대상 테이블**: `client_mng`
|
||||
- **동기화 데이터**:
|
||||
- 거래처코드, 거래처명, 거래처약칭
|
||||
- 사업자등록번호, 대표자명
|
||||
- 업태, 종목
|
||||
- 주소, 연락처 정보
|
||||
- 사용여부
|
||||
|
||||
### 2. 부서 정보 동기화 (DepartmentApiClient)
|
||||
- **API 엔드포인트**: `/apiproxy/api16S10`
|
||||
- **대상 테이블**: `dept_info`
|
||||
- **동기화 데이터**:
|
||||
- 부서코드, 부서명
|
||||
- 회사코드, 부서레벨
|
||||
- 상위부서 정보
|
||||
- 정렬순서, 등록일/종료일
|
||||
|
||||
### 3. 사원 정보 동기화 (EmployeeApiClient)
|
||||
- **API 엔드포인트**: `/apiproxy/api16S05`
|
||||
- **대상 테이블**: `user_info`
|
||||
- **동기화 데이터**:
|
||||
- 사원번호, 사원코드, 사원명
|
||||
- 부서 정보
|
||||
- 직급, 직책
|
||||
- 연락처 (이메일, 휴대폰)
|
||||
- 재직구분, 입사일, 생년월일
|
||||
|
||||
## 배치 실행 스케줄
|
||||
|
||||
### 자동 실행
|
||||
- **실행 시간**: 매일 새벽 00시 00분
|
||||
- **Cron 표현식**: `0 0 0 * * ?`
|
||||
- **실행 메서드**: `BatchService.syncErpData()`
|
||||
|
||||
### 수동 실행
|
||||
필요시 `BatchService.syncErpData()` 메서드를 직접 호출하여 수동 실행 가능
|
||||
|
||||
## 설치 및 설정
|
||||
|
||||
### 1. 데이터베이스 설정
|
||||
```bash
|
||||
# PostgreSQL에 접속하여 테이블 생성 스크립트 실행
|
||||
psql -U [사용자명] -d [데이터베이스명] -f database/create_erp_sync_tables.sql
|
||||
```
|
||||
|
||||
### 2. 소스 파일 구조
|
||||
```
|
||||
wace_plm/
|
||||
├── src/com/pms/
|
||||
│ ├── api/
|
||||
│ │ ├── CustomerApiClient.java # 거래처 API 클라이언트
|
||||
│ │ ├── DepartmentApiClient.java # 부서 API 클라이언트
|
||||
│ │ └── EmployeeApiClient.java # 사원 API 클라이언트
|
||||
│ ├── service/
|
||||
│ │ └── BatchService.java # 배치 서비스 (동기화 로직)
|
||||
│ └── mapper/
|
||||
│ └── batch.xml # MyBatis 매퍼 (SQL 쿼리)
|
||||
└── database/
|
||||
└── create_erp_sync_tables.sql # 테이블 생성 스크립트
|
||||
```
|
||||
|
||||
### 3. MyBatis 설정
|
||||
`mybatisConf.xml`에 batch 매퍼가 등록되어 있는지 확인:
|
||||
```xml
|
||||
<mapper resource="/com/pms/mapper/batch.xml" />
|
||||
```
|
||||
|
||||
### 4. API 인증 정보
|
||||
API 클라이언트에 다음 정보가 설정되어 있습니다:
|
||||
- **Base URL**: `https://erp.rps-korea.com`
|
||||
- **회사코드**: `1000`
|
||||
- **Caller Name**: `API_gcmsAmaranth40578`
|
||||
- **Access Token**: (소스 코드 참조)
|
||||
- **Hash Key**: (소스 코드 참조)
|
||||
|
||||
## 동작 방식
|
||||
|
||||
### 1. API 호출
|
||||
각 API 클라이언트가 ERP 시스템에 HTTPS POST 요청을 전송합니다.
|
||||
- TLS 1.2 프로토콜 사용
|
||||
- HMacSHA256 기반 인증
|
||||
- JSON 형식 데이터 송수신
|
||||
|
||||
### 2. 데이터 파싱
|
||||
API 응답 JSON을 파싱하여 Map 객체로 변환합니다.
|
||||
- JDK 1.7 호환 방식의 수동 JSON 파싱
|
||||
- 필요한 필드만 추출
|
||||
|
||||
### 3. 데이터베이스 저장
|
||||
- 기존 데이터 존재 여부 확인 (코드 기준)
|
||||
- 신규 데이터: INSERT
|
||||
- 기존 데이터: UPDATE
|
||||
- 트랜잭션 처리로 데이터 무결성 보장
|
||||
|
||||
### 4. 로깅
|
||||
- 각 단계별 진행 상황 콘솔 출력
|
||||
- 성공/실패 건수 집계
|
||||
- 오류 발생 시 상세 로그 출력
|
||||
|
||||
## 에러 처리
|
||||
|
||||
### API 호출 실패
|
||||
- 연결 타임아웃: 30초
|
||||
- 리다이렉트 자동 처리
|
||||
- HTTP 에러 코드 확인 및 로깅
|
||||
|
||||
### 데이터 파싱 오류
|
||||
- JSON 파싱 실패 시 해당 레코드 스킵
|
||||
- 오류 로그 출력 후 다음 레코드 처리 계속
|
||||
|
||||
### 데이터베이스 오류
|
||||
- 트랜잭션 롤백
|
||||
- 전체 배치 실패 처리
|
||||
- 상세 오류 메시지 출력
|
||||
|
||||
## 모니터링
|
||||
|
||||
### 로그 확인
|
||||
배치 실행 시 다음 정보가 출력됩니다:
|
||||
```
|
||||
====================================
|
||||
ERP 데이터 동기화 배치 시작
|
||||
====================================
|
||||
거래처 정보 동기화 시작...
|
||||
거래처 정보 동기화 완료 - 신규: X건, 수정: Y건
|
||||
부서 정보 동기화 시작...
|
||||
부서 정보 동기화 완료 - 신규: X건, 수정: Y건
|
||||
사원 정보 동기화 시작...
|
||||
사원 정보 동기화 완료 - 신규: X건, 수정: Y건
|
||||
ERP 데이터 동기화 배치 완료
|
||||
```
|
||||
|
||||
### 데이터 확인
|
||||
```sql
|
||||
-- 거래처 정보 확인
|
||||
SELECT COUNT(*) FROM client_mng WHERE reg_user = 'batch_system';
|
||||
|
||||
-- 부서 정보 확인
|
||||
SELECT COUNT(*) FROM dept_info WHERE reg_user = 'batch_system';
|
||||
|
||||
-- 사원 정보 확인
|
||||
SELECT COUNT(*) FROM user_info WHERE reg_user = 'batch_system';
|
||||
|
||||
-- 최근 동기화 데이터 확인
|
||||
SELECT * FROM client_mng WHERE reg_user = 'batch_system'
|
||||
ORDER BY reg_date DESC LIMIT 10;
|
||||
```
|
||||
|
||||
## 주의사항
|
||||
|
||||
1. **데이터 중복 방지**
|
||||
- 거래처: `tr_cd` (거래처코드) 기준
|
||||
- 부서: `dept_cd` (부서코드) 기준
|
||||
- 사원: `emp_cd` (사원코드) 기준
|
||||
|
||||
2. **네트워크 환경**
|
||||
- ERP API 서버 접근 가능 여부 확인
|
||||
- 방화벽 설정 확인
|
||||
- SSL 인증서 검증 우회 (개발 환경)
|
||||
|
||||
3. **성능 고려사항**
|
||||
- 대량 데이터 처리 시 시간 소요 가능
|
||||
- 배치 실행 시간대 조정 가능 (현재: 새벽 00시)
|
||||
- 필요시 페이징 처리 추가 고려
|
||||
|
||||
4. **데이터 정합성**
|
||||
- 배치 실행 전 데이터 백업 권장
|
||||
- 테스트 환경에서 충분한 검증 후 운영 적용
|
||||
|
||||
## 트러블슈팅
|
||||
|
||||
### API 호출 실패
|
||||
```
|
||||
원인: 네트워크 연결 문제, 인증 실패
|
||||
해결:
|
||||
- 네트워크 연결 확인
|
||||
- API 인증 정보 확인
|
||||
- ERP 서버 상태 확인
|
||||
```
|
||||
|
||||
### JSON 파싱 오류
|
||||
```
|
||||
원인: API 응답 형식 변경
|
||||
해결:
|
||||
- API 응답 로그 확인
|
||||
- 파싱 로직 수정
|
||||
```
|
||||
|
||||
### 데이터베이스 오류
|
||||
```
|
||||
원인: 테이블 구조 불일치, 권한 문제
|
||||
해결:
|
||||
- 테이블 생성 스크립트 재실행
|
||||
- 데이터베이스 권한 확인
|
||||
```
|
||||
|
||||
## 향후 개선 사항
|
||||
|
||||
1. **성능 최적화**
|
||||
- 배치 INSERT/UPDATE 처리
|
||||
- 페이징 처리 추가
|
||||
|
||||
2. **모니터링 강화**
|
||||
- 배치 실행 이력 테이블 추가
|
||||
- 알림 기능 추가 (이메일, 슬랙 등)
|
||||
|
||||
3. **에러 복구**
|
||||
- 실패 레코드 재처리 로직
|
||||
- 부분 실패 시 이어서 처리
|
||||
|
||||
4. **설정 외부화**
|
||||
- API URL, 인증 정보를 설정 파일로 분리
|
||||
- 환경별 설정 관리
|
||||
|
||||
## 문의
|
||||
|
||||
기술 지원이 필요한 경우 개발팀에 문의하시기 바랍니다.
|
||||
255
src/com/pms/api/CustomerApiClient.java
Normal file
255
src/com/pms/api/CustomerApiClient.java
Normal file
@@ -0,0 +1,255 @@
|
||||
package com.pms.api;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 거래처 정보 조회 API 클라이언트
|
||||
* 복수의 일반, 금융 거래처 정보를 조회하는 API를 호출합니다.
|
||||
*/
|
||||
public class CustomerApiClient {
|
||||
|
||||
private static final String API_URL = "~/apiproxy/api16S11";
|
||||
private static final String CALLER_NAME = "API_gcmsAmaranth40578";
|
||||
private static final String ACCESS_TOKEN = "MN5KzKBWRAa92BPxDlRLl3GcsxeZXc";
|
||||
private static final String HASH_KEY = "22519103205540290721741689643674301018832465";
|
||||
private static final String GROUP_SEQ = "gcmsAmaranth40578";
|
||||
|
||||
/**
|
||||
* 거래처 정보를 조회합니다.
|
||||
*
|
||||
* @param baseUrl API 서버의 기본 URL (예: https://erp.rps-korea.com)
|
||||
* @param coCd 회사코드 (4자리, 필수)
|
||||
* @return API 응답 결과 (JSON 문자열)
|
||||
* @throws Exception API 호출 중 발생하는 예외
|
||||
*/
|
||||
public String getCustomerList(String baseUrl, String coCd) throws Exception {
|
||||
if (coCd == null || coCd.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("회사코드(coCd)는 필수입니다.");
|
||||
}
|
||||
|
||||
// JDK 1.7에서 TLS 1.2 활성화
|
||||
System.setProperty("https.protocols", "TLSv1.2");
|
||||
|
||||
// SSL 인증서 검증 우회 (개발 환경용)
|
||||
TrustManager[] trustAllCerts = new TrustManager[] {
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
|
||||
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// API URL 구성
|
||||
String urlPath = API_URL.replace("~", "");
|
||||
String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
String fullUrl = cleanBaseUrl + urlPath;
|
||||
URL url = new URL(fullUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 연결 타임아웃 설정 (30초)
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
|
||||
try {
|
||||
// HTTP 메서드 설정
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
// 인증 헤더 설정
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
|
||||
String transactionId = generateTransactionId();
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
|
||||
String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
// 요청 본문 작성
|
||||
String requestBody = buildRequestBody(coCd);
|
||||
|
||||
// 요청 전송 설정
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
// 요청 본문 전송
|
||||
OutputStreamWriter writer = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
writer.write(requestBody);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
// 응답 코드 확인
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
// 리다이렉트 처리
|
||||
if (responseCode == 301 || responseCode == 302 || responseCode == 303 ||
|
||||
responseCode == 307 || responseCode == 308) {
|
||||
String location = connection.getHeaderField("Location");
|
||||
connection.disconnect();
|
||||
|
||||
if (location != null) {
|
||||
URL redirectUrl = new URL(location);
|
||||
connection = (HttpURLConnection) redirectUrl.openConnection();
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
OutputStreamWriter redirectWriter = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
redirectWriter.write(requestBody);
|
||||
redirectWriter.flush();
|
||||
redirectWriter.close();
|
||||
|
||||
responseCode = connection.getResponseCode();
|
||||
}
|
||||
}
|
||||
|
||||
// 응답 읽기
|
||||
BufferedReader reader = null;
|
||||
StringBuilder response = new StringBuilder();
|
||||
|
||||
try {
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
connection.getInputStream(), StandardCharsets.UTF_8));
|
||||
} else {
|
||||
java.io.InputStream errorStream = connection.getErrorStream();
|
||||
if (errorStream != null) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
errorStream, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " (에러 응답 본문 없음)");
|
||||
}
|
||||
}
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
return response.toString();
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " - " + response.toString());
|
||||
}
|
||||
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 본문 JSON을 생성합니다.
|
||||
*/
|
||||
private String buildRequestBody(String coCd) {
|
||||
StringBuilder json = new StringBuilder();
|
||||
json.append("{");
|
||||
json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
|
||||
json.append("}");
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 문자열 이스케이프 처리
|
||||
*/
|
||||
private String escapeJson(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* 32자리 랜덤 transaction-id 생성
|
||||
*/
|
||||
private String generateTransactionId() {
|
||||
String chars = "0123456789abcdef";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sb.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wehago-sign 생성
|
||||
*/
|
||||
private String generateWehagoSign(String accessToken, String transactionId,
|
||||
String timestamp, String urlPath) throws Exception {
|
||||
try {
|
||||
String value = accessToken + transactionId + timestamp + urlPath;
|
||||
|
||||
SecretKeySpec keySpec = new SecretKeySpec(
|
||||
HASH_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(keySpec);
|
||||
byte[] encrypted = mac.doFinal(value.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
String base64Binary = Base64.encodeBase64String(encrypted);
|
||||
return base64Binary;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Wehago-sign 생성 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
261
src/com/pms/api/DepartmentApiClient.java
Normal file
261
src/com/pms/api/DepartmentApiClient.java
Normal file
@@ -0,0 +1,261 @@
|
||||
package com.pms.api;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 부서 정보 조회 API 클라이언트
|
||||
* 회사의 부서정보를 조회하는 API를 호출합니다.
|
||||
*/
|
||||
public class DepartmentApiClient {
|
||||
|
||||
private static final String API_URL = "~/apiproxy/api16S10";
|
||||
private static final String CALLER_NAME = "API_gcmsAmaranth40578";
|
||||
private static final String ACCESS_TOKEN = "MN5KzKBWRAa92BPxDlRLl3GcsxeZXc";
|
||||
private static final String HASH_KEY = "22519103205540290721741689643674301018832465";
|
||||
private static final String GROUP_SEQ = "gcmsAmaranth40578";
|
||||
|
||||
/**
|
||||
* 부서 정보를 조회합니다.
|
||||
*
|
||||
* @param baseUrl API 서버의 기본 URL (예: https://erp.rps-korea.com)
|
||||
* @param coCd 회사코드 (4자리, 필수)
|
||||
* @param searchText 검색명 (부서코드 또는 부서명, 선택사항, 미입력 시 전체 조회)
|
||||
* @return API 응답 결과 (JSON 문자열)
|
||||
* @throws Exception API 호출 중 발생하는 예외
|
||||
*/
|
||||
public String getDepartmentList(String baseUrl, String coCd, String searchText) throws Exception {
|
||||
if (coCd == null || coCd.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("회사코드(coCd)는 필수입니다.");
|
||||
}
|
||||
|
||||
// JDK 1.7에서 TLS 1.2 활성화
|
||||
System.setProperty("https.protocols", "TLSv1.2");
|
||||
|
||||
// SSL 인증서 검증 우회 (개발 환경용)
|
||||
TrustManager[] trustAllCerts = new TrustManager[] {
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
|
||||
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// API URL 구성
|
||||
String urlPath = API_URL.replace("~", "");
|
||||
String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
String fullUrl = cleanBaseUrl + urlPath;
|
||||
URL url = new URL(fullUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 연결 타임아웃 설정 (30초)
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
|
||||
try {
|
||||
// HTTP 메서드 설정
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
// 인증 헤더 설정
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
|
||||
String transactionId = generateTransactionId();
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
|
||||
String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
// 요청 본문 작성
|
||||
String requestBody = buildRequestBody(coCd, searchText);
|
||||
|
||||
// 요청 전송 설정
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
// 요청 본문 전송
|
||||
OutputStreamWriter writer = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
writer.write(requestBody);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
// 응답 코드 확인
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
// 리다이렉트 처리
|
||||
if (responseCode == 301 || responseCode == 302 || responseCode == 303 ||
|
||||
responseCode == 307 || responseCode == 308) {
|
||||
String location = connection.getHeaderField("Location");
|
||||
connection.disconnect();
|
||||
|
||||
if (location != null) {
|
||||
URL redirectUrl = new URL(location);
|
||||
connection = (HttpURLConnection) redirectUrl.openConnection();
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
OutputStreamWriter redirectWriter = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
redirectWriter.write(requestBody);
|
||||
redirectWriter.flush();
|
||||
redirectWriter.close();
|
||||
|
||||
responseCode = connection.getResponseCode();
|
||||
}
|
||||
}
|
||||
|
||||
// 응답 읽기
|
||||
BufferedReader reader = null;
|
||||
StringBuilder response = new StringBuilder();
|
||||
|
||||
try {
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
connection.getInputStream(), StandardCharsets.UTF_8));
|
||||
} else {
|
||||
java.io.InputStream errorStream = connection.getErrorStream();
|
||||
if (errorStream != null) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
errorStream, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " (에러 응답 본문 없음)");
|
||||
}
|
||||
}
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
return response.toString();
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " - " + response.toString());
|
||||
}
|
||||
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 본문 JSON을 생성합니다.
|
||||
*/
|
||||
private String buildRequestBody(String coCd, String searchText) {
|
||||
StringBuilder json = new StringBuilder();
|
||||
json.append("{");
|
||||
json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
|
||||
|
||||
if (searchText != null && !searchText.trim().isEmpty()) {
|
||||
json.append(",\"searchText\":\"").append(escapeJson(searchText)).append("\"");
|
||||
}
|
||||
|
||||
json.append("}");
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 문자열 이스케이프 처리
|
||||
*/
|
||||
private String escapeJson(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* 32자리 랜덤 transaction-id 생성
|
||||
*/
|
||||
private String generateTransactionId() {
|
||||
String chars = "0123456789abcdef";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sb.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wehago-sign 생성
|
||||
*/
|
||||
private String generateWehagoSign(String accessToken, String transactionId,
|
||||
String timestamp, String urlPath) throws Exception {
|
||||
try {
|
||||
String value = accessToken + transactionId + timestamp + urlPath;
|
||||
|
||||
SecretKeySpec keySpec = new SecretKeySpec(
|
||||
HASH_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(keySpec);
|
||||
byte[] encrypted = mac.doFinal(value.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
String base64Binary = Base64.encodeBase64String(encrypted);
|
||||
return base64Binary;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Wehago-sign 생성 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
268
src/com/pms/api/EmployeeApiClient.java
Normal file
268
src/com/pms/api/EmployeeApiClient.java
Normal file
@@ -0,0 +1,268 @@
|
||||
package com.pms.api;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 사원 정보 조회 API 클라이언트
|
||||
* 사원의 목록을 조회하는 API를 호출합니다.
|
||||
*/
|
||||
public class EmployeeApiClient {
|
||||
|
||||
private static final String API_URL = "~/apiproxy/api16S05";
|
||||
private static final String CALLER_NAME = "API_gcmsAmaranth40578";
|
||||
private static final String ACCESS_TOKEN = "MN5KzKBWRAa92BPxDlRLl3GcsxeZXc";
|
||||
private static final String HASH_KEY = "22519103205540290721741689643674301018832465";
|
||||
private static final String GROUP_SEQ = "gcmsAmaranth40578";
|
||||
|
||||
/**
|
||||
* 사원 정보를 조회합니다.
|
||||
*
|
||||
* @param baseUrl API 서버의 기본 URL (예: https://erp.rps-korea.com)
|
||||
* @param coCd 회사코드 (4자리, 필수)
|
||||
* @return API 응답 결과 (JSON 문자열)
|
||||
* @throws Exception API 호출 중 발생하는 예외
|
||||
*/
|
||||
public String getEmployeeList(String baseUrl, String coCd) throws Exception {
|
||||
if (coCd == null || coCd.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("회사코드(coCd)는 필수입니다.");
|
||||
}
|
||||
|
||||
// JDK 1.7에서 TLS 1.2 활성화
|
||||
System.setProperty("https.protocols", "TLSv1.2");
|
||||
|
||||
// SSL 인증서 검증 우회 (개발 환경용)
|
||||
TrustManager[] trustAllCerts = new TrustManager[] {
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
|
||||
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// API URL 구성
|
||||
String urlPath = API_URL.replace("~", "");
|
||||
String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
String fullUrl = cleanBaseUrl + urlPath;
|
||||
URL url = new URL(fullUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 연결 타임아웃 설정 (30초)
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
|
||||
try {
|
||||
// HTTP 메서드 설정
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
// 인증 헤더 설정
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
|
||||
String transactionId = generateTransactionId();
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
|
||||
String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
// 요청 본문 작성
|
||||
String requestBody = buildRequestBody(coCd);
|
||||
|
||||
// 요청 전송 설정
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
// 요청 본문 전송
|
||||
OutputStreamWriter writer = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
writer.write(requestBody);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
// 응답 코드 확인
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
// 리다이렉트 처리
|
||||
if (responseCode == 301 || responseCode == 302 || responseCode == 303 ||
|
||||
responseCode == 307 || responseCode == 308) {
|
||||
String location = connection.getHeaderField("Location");
|
||||
connection.disconnect();
|
||||
|
||||
if (location != null) {
|
||||
URL redirectUrl = new URL(location);
|
||||
connection = (HttpURLConnection) redirectUrl.openConnection();
|
||||
connection.setConnectTimeout(30000);
|
||||
connection.setReadTimeout(30000);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
connection.setRequestProperty("callerName", CALLER_NAME);
|
||||
connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
|
||||
connection.setRequestProperty("transaction-id", transactionId);
|
||||
connection.setRequestProperty("timestamp", timestamp);
|
||||
connection.setRequestProperty("groupSeq", GROUP_SEQ);
|
||||
connection.setRequestProperty("wehago-sign", wehagoSign);
|
||||
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
|
||||
OutputStreamWriter redirectWriter = new OutputStreamWriter(
|
||||
connection.getOutputStream(), StandardCharsets.UTF_8);
|
||||
redirectWriter.write(requestBody);
|
||||
redirectWriter.flush();
|
||||
redirectWriter.close();
|
||||
|
||||
responseCode = connection.getResponseCode();
|
||||
}
|
||||
}
|
||||
|
||||
// 응답 읽기
|
||||
BufferedReader reader = null;
|
||||
StringBuilder response = new StringBuilder();
|
||||
|
||||
try {
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
connection.getInputStream(), StandardCharsets.UTF_8));
|
||||
} else {
|
||||
java.io.InputStream errorStream = connection.getErrorStream();
|
||||
if (errorStream != null) {
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
errorStream, StandardCharsets.UTF_8));
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " (에러 응답 본문 없음)");
|
||||
}
|
||||
}
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (responseCode >= 200 && responseCode < 300) {
|
||||
return response.toString();
|
||||
} else {
|
||||
throw new Exception("API 호출 실패: HTTP " + responseCode + " - " + response.toString());
|
||||
}
|
||||
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 본문 JSON을 생성합니다.
|
||||
*/
|
||||
private String buildRequestBody(String coCd) {
|
||||
StringBuilder json = new StringBuilder();
|
||||
json.append("{");
|
||||
|
||||
// header 섹션
|
||||
json.append("\"header\":{");
|
||||
json.append("\"groupSeq\":\"").append(escapeJson(GROUP_SEQ)).append("\"");
|
||||
json.append(",\"empSeq\":\"\"");
|
||||
json.append(",\"tId\":\"\"");
|
||||
json.append(",\"pId\":\"\"");
|
||||
json.append("}");
|
||||
|
||||
// body 섹션
|
||||
json.append(",\"body\":{");
|
||||
json.append("\"coCd\":\"").append(escapeJson(coCd)).append("\"");
|
||||
json.append("}");
|
||||
|
||||
json.append("}");
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 문자열 이스케이프 처리
|
||||
*/
|
||||
private String escapeJson(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* 32자리 랜덤 transaction-id 생성
|
||||
*/
|
||||
private String generateTransactionId() {
|
||||
String chars = "0123456789abcdef";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sb.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wehago-sign 생성
|
||||
*/
|
||||
private String generateWehagoSign(String accessToken, String transactionId,
|
||||
String timestamp, String urlPath) throws Exception {
|
||||
try {
|
||||
String value = accessToken + transactionId + timestamp + urlPath;
|
||||
|
||||
SecretKeySpec keySpec = new SecretKeySpec(
|
||||
HASH_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(keySpec);
|
||||
byte[] encrypted = mac.doFinal(value.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
String base64Binary = Base64.encodeBase64String(encrypted);
|
||||
return base64Binary;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Wehago-sign 생성 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.pms.common.utils.Constants;
|
||||
import com.pms.common.SqlMapConfig;
|
||||
import com.pms.service.AdminService;
|
||||
import com.pms.service.CommonService;
|
||||
import com.pms.service.BatchService;
|
||||
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
||||
@@ -39,6 +40,9 @@ public class AdminController extends BaseService {
|
||||
@Autowired
|
||||
CommonService commonService;
|
||||
|
||||
@Autowired
|
||||
BatchService batchService;
|
||||
|
||||
@RequestMapping("/admin/adminMainFS.do")
|
||||
public String adminMainFS(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
//관리자 메뉴 호출 전 관리자 권한 여부 확인
|
||||
@@ -5196,4 +5200,85 @@ public String clientImportFileProc(HttpServletRequest request, HttpSession sessi
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP 사원 정보 동기화 수동 실행
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/admin/syncEmployeeDataManual.do")
|
||||
@ResponseBody
|
||||
public Map<String, Object> syncEmployeeDataManual(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
|
||||
try {
|
||||
System.out.println("====================================");
|
||||
System.out.println("관리자 수동 ERP 사원 동기화 실행 요청");
|
||||
System.out.println("====================================");
|
||||
|
||||
resultMap = batchService.syncEmployeeDataManual();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("success", false);
|
||||
resultMap.put("message", "사원 동기화 실행 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP 부서 정보 동기화 수동 실행
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/admin/syncDepartmentDataManual.do")
|
||||
@ResponseBody
|
||||
public Map<String, Object> syncDepartmentDataManual(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
|
||||
try {
|
||||
System.out.println("====================================");
|
||||
System.out.println("관리자 수동 ERP 부서 동기화 실행 요청");
|
||||
System.out.println("====================================");
|
||||
|
||||
resultMap = batchService.syncDepartmentDataManual();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("success", false);
|
||||
resultMap.put("message", "부서 동기화 실행 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP 거래처 정보 동기화 수동 실행
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/admin/syncCustomerDataManual.do")
|
||||
@ResponseBody
|
||||
public Map<String, Object> syncCustomerDataManual(HttpServletRequest request, @RequestParam Map<String, Object> paramMap) {
|
||||
Map<String, Object> resultMap = new HashMap<String, Object>();
|
||||
|
||||
try {
|
||||
System.out.println("====================================");
|
||||
System.out.println("관리자 수동 ERP 거래처 동기화 실행 요청");
|
||||
System.out.println("====================================");
|
||||
|
||||
resultMap = batchService.syncCustomerDataManual();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
resultMap.put("success", false);
|
||||
resultMap.put("message", "거래처 동기화 실행 중 오류가 발생했습니다: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
178
src/com/pms/mapper/batch.xml
Normal file
178
src/com/pms/mapper/batch.xml
Normal file
@@ -0,0 +1,178 @@
|
||||
<?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="batch">
|
||||
|
||||
<!-- 거래처 정보 UPSERT (실제 테이블 컬럼 기준) -->
|
||||
<insert id="upsertCustomer" parameterType="map">
|
||||
INSERT INTO client_mng (
|
||||
objid, client_cd, client_nm, tr_nmk, client_nmk, attr_nmk, client_type,
|
||||
bus_reg_no, resident_no, ceo_nm, ceo_nmk, bus_type, bus_item,
|
||||
post_no, addr1, addr2, tel_no, fax_no, homepage, email,
|
||||
liq_rs, tr_fg, country_nm, class_cd, class_nm, grade_cd, grade_nm,
|
||||
collect_client_cd, collect_client_nm, region_cd, region_nm,
|
||||
trade_start_dt, trade_end_dt, use_yn, contract_start_dt, contract_end_dt,
|
||||
trade_type, discount_rate, contract_amt, monthly_fee, payment_term, rcp_tp,
|
||||
credit_limit, limit_return_day,
|
||||
pur_bank_cd, pur_bank_nm, pur_branch_nm, pur_account_no, pur_account_holder,
|
||||
pur_pay_plan, pur_slip_type, pur_tax_type,
|
||||
sale_bank_cd, sale_bank_nm, sale_branch_nm, sale_account_no,
|
||||
sale_collect_plan, sale_slip_type, sale_tax_type,
|
||||
vendor_dept_nm, vendor_position, vendor_duty, vendor_manager_nm,
|
||||
vendor_tel, vendor_ext, vendor_mobile, vendor_email,
|
||||
mgr_dept_cd, mgr_dept_nm, mgr_position, mgr_duty, mgr_emp_cd, mgr_emp_nm,
|
||||
mgr_tel, mgr_ext, mgr_mobile, mgr_email, mgr_remark,
|
||||
rec_remark, rec_post_no, rec_addr1, rec_addr2, rec_tel, rec_fax,
|
||||
project_cd, project_nm, pjt_nmk, ext_data_cd, e_tax_yn,
|
||||
unit_report_client, sub_bus_no, procurement_yn, use_fg, for_yn,
|
||||
plan_day_type, plan_day, purpose_type,
|
||||
insert_id, insert_dt, modify_id, modify_dt
|
||||
) VALUES (
|
||||
#{objid}::numeric, #{client_cd}, #{client_nm}, #{tr_nmk}, #{client_nmk}, #{attr_nmk}, #{client_type},
|
||||
#{bus_reg_no}, #{resident_no}, #{ceo_nm}, #{ceo_nmk}, #{bus_type}, #{bus_item},
|
||||
#{post_no}, #{addr1}, #{addr2}, #{tel_no}, #{fax_no}, #{homepage}, #{email},
|
||||
#{liq_rs}, #{tr_fg}, #{country_nm}, #{class_cd}, #{class_nm}, #{grade_cd}, #{grade_nm},
|
||||
#{collect_client_cd}, #{collect_client_nm}, #{region_cd}, #{region_nm},
|
||||
#{trade_start_dt}, #{trade_end_dt}, #{use_yn}, #{contract_start_dt}, #{contract_end_dt},
|
||||
#{trade_type}, #{discount_rate}, #{contract_amt}, #{monthly_fee}, #{payment_term}, #{rcp_tp},
|
||||
#{credit_limit}, #{limit_return_day},
|
||||
#{pur_bank_cd}, #{pur_bank_nm}, #{pur_branch_nm}, #{pur_account_no}, #{pur_account_holder},
|
||||
#{pur_pay_plan}, #{pur_slip_type}, #{pur_tax_type},
|
||||
#{sale_bank_cd}, #{sale_bank_nm}, #{sale_branch_nm}, #{sale_account_no},
|
||||
#{sale_collect_plan}, #{sale_slip_type}, #{sale_tax_type},
|
||||
#{vendor_dept_nm}, #{vendor_position}, #{vendor_duty}, #{vendor_manager_nm},
|
||||
#{vendor_tel}, #{vendor_ext}, #{vendor_mobile}, #{vendor_email},
|
||||
#{mgr_dept_cd}, #{mgr_dept_nm}, #{mgr_position}, #{mgr_duty}, #{mgr_emp_cd}, #{mgr_emp_nm},
|
||||
#{mgr_tel}, #{mgr_ext}, #{mgr_mobile}, #{mgr_email}, #{mgr_remark},
|
||||
#{rec_remark}, #{rec_post_no}, #{rec_addr1}, #{rec_addr2}, #{rec_tel}, #{rec_fax},
|
||||
#{project_cd}, #{project_nm}, #{pjt_nmk}, #{ext_data_cd}, #{e_tax_yn},
|
||||
#{unit_report_client}, #{sub_bus_no}, #{procurement_yn}, #{use_fg}, #{for_yn},
|
||||
#{plan_day_type}, #{plan_day}, #{purpose_type},
|
||||
#{insert_id}, now()
|
||||
) ON CONFLICT (client_cd) DO
|
||||
UPDATE SET
|
||||
client_nm = #{client_nm}, tr_nmk = #{tr_nmk}, client_nmk = #{client_nmk}, attr_nmk = #{attr_nmk},
|
||||
client_type = #{client_type}, bus_reg_no = #{bus_reg_no}, resident_no = #{resident_no},
|
||||
ceo_nm = #{ceo_nm}, ceo_nmk = #{ceo_nmk}, bus_type = #{bus_type}, bus_item = #{bus_item},
|
||||
post_no = #{post_no}, addr1 = #{addr1}, addr2 = #{addr2}, tel_no = #{tel_no}, fax_no = #{fax_no},
|
||||
homepage = #{homepage}, email = #{email}, liq_rs = #{liq_rs}, tr_fg = #{tr_fg},
|
||||
country_nm = #{country_nm}, class_cd = #{class_cd}, class_nm = #{class_nm},
|
||||
grade_cd = #{grade_cd}, grade_nm = #{grade_nm}, collect_client_cd = #{collect_client_cd},
|
||||
collect_client_nm = #{collect_client_nm}, region_cd = #{region_cd}, region_nm = #{region_nm},
|
||||
trade_start_dt = #{trade_start_dt}, trade_end_dt = #{trade_end_dt}, use_yn = #{use_yn},
|
||||
contract_start_dt = #{contract_start_dt}, contract_end_dt = #{contract_end_dt},
|
||||
trade_type = #{trade_type}, discount_rate = #{discount_rate}, contract_amt = #{contract_amt},
|
||||
monthly_fee = #{monthly_fee}, payment_term = #{payment_term}, rcp_tp = #{rcp_tp},
|
||||
credit_limit = #{credit_limit}, limit_return_day = #{limit_return_day},
|
||||
pur_bank_cd = #{pur_bank_cd}, pur_bank_nm = #{pur_bank_nm}, pur_branch_nm = #{pur_branch_nm},
|
||||
pur_account_no = #{pur_account_no}, pur_account_holder = #{pur_account_holder},
|
||||
pur_pay_plan = #{pur_pay_plan}, pur_slip_type = #{pur_slip_type}, pur_tax_type = #{pur_tax_type},
|
||||
sale_bank_cd = #{sale_bank_cd}, sale_bank_nm = #{sale_bank_nm}, sale_branch_nm = #{sale_branch_nm},
|
||||
sale_account_no = #{sale_account_no}, sale_collect_plan = #{sale_collect_plan},
|
||||
sale_slip_type = #{sale_slip_type}, sale_tax_type = #{sale_tax_type},
|
||||
vendor_dept_nm = #{vendor_dept_nm}, vendor_position = #{vendor_position}, vendor_duty = #{vendor_duty},
|
||||
vendor_manager_nm = #{vendor_manager_nm}, vendor_tel = #{vendor_tel}, vendor_ext = #{vendor_ext},
|
||||
vendor_mobile = #{vendor_mobile}, vendor_email = #{vendor_email},
|
||||
mgr_dept_cd = #{mgr_dept_cd}, mgr_dept_nm = #{mgr_dept_nm}, mgr_position = #{mgr_position},
|
||||
mgr_duty = #{mgr_duty}, mgr_emp_cd = #{mgr_emp_cd}, mgr_emp_nm = #{mgr_emp_nm},
|
||||
mgr_tel = #{mgr_tel}, mgr_ext = #{mgr_ext}, mgr_mobile = #{mgr_mobile},
|
||||
mgr_email = #{mgr_email}, mgr_remark = #{mgr_remark},
|
||||
rec_remark = #{rec_remark}, rec_post_no = #{rec_post_no}, rec_addr1 = #{rec_addr1},
|
||||
rec_addr2 = #{rec_addr2}, rec_tel = #{rec_tel}, rec_fax = #{rec_fax},
|
||||
project_cd = #{project_cd}, project_nm = #{project_nm}, pjt_nmk = #{pjt_nmk},
|
||||
ext_data_cd = #{ext_data_cd}, e_tax_yn = #{e_tax_yn}, unit_report_client = #{unit_report_client},
|
||||
sub_bus_no = #{sub_bus_no}, procurement_yn = #{procurement_yn}, use_fg = #{use_fg},
|
||||
for_yn = #{for_yn}, plan_day_type = #{plan_day_type}, plan_day = #{plan_day},
|
||||
purpose_type = #{purpose_type}, modify_id = #{modify_id}, modify_dt = now()
|
||||
</insert>
|
||||
|
||||
<!-- 부서 정보 UPSERT (실제 JSON 응답 기준) -->
|
||||
<insert id="upsertDepartment" parameterType="map">
|
||||
INSERT INTO dept_info (
|
||||
dept_code,
|
||||
parent_dept_code,
|
||||
dept_name,
|
||||
status,
|
||||
data_type,
|
||||
regdate
|
||||
) VALUES (
|
||||
#{dept_code},
|
||||
#{parent_dept_code},
|
||||
#{dept_name},
|
||||
#{status},
|
||||
#{data_type},
|
||||
NOW()
|
||||
) ON CONFLICT (dept_code) DO
|
||||
UPDATE SET
|
||||
parent_dept_code = #{parent_dept_code},
|
||||
dept_name = #{dept_name},
|
||||
status = #{status},
|
||||
data_type = #{data_type}
|
||||
</insert>
|
||||
|
||||
<!-- 사원 정보 UPSERT (실제 JSON 응답 기준) -->
|
||||
<insert id="upsertEmployee" parameterType="map">
|
||||
INSERT INTO user_info (
|
||||
sabun,
|
||||
user_id,
|
||||
user_password,
|
||||
user_name,
|
||||
user_name_eng,
|
||||
dept_code,
|
||||
dept_name,
|
||||
position_code,
|
||||
position_name,
|
||||
rank,
|
||||
email,
|
||||
cell_phone,
|
||||
user_type,
|
||||
user_type_name,
|
||||
status,
|
||||
end_date,
|
||||
data_type,
|
||||
regdate
|
||||
) VALUES (
|
||||
#{sabun},
|
||||
#{user_id},
|
||||
#{user_password},
|
||||
#{user_name},
|
||||
#{user_name_eng},
|
||||
#{dept_code},
|
||||
#{dept_name},
|
||||
#{position_code},
|
||||
#{position_name},
|
||||
#{rank},
|
||||
#{email},
|
||||
#{cell_phone},
|
||||
#{user_type},
|
||||
#{user_type_name},
|
||||
#{status},
|
||||
CASE
|
||||
WHEN #{end_date} IS NULL OR #{end_date} = '' THEN NULL
|
||||
ELSE TO_TIMESTAMP(#{end_date}, 'YYYYMMDD')
|
||||
END,
|
||||
#{data_type},
|
||||
NOW()
|
||||
) ON CONFLICT (user_id) DO
|
||||
UPDATE SET
|
||||
sabun = #{sabun},
|
||||
user_name = #{user_name},
|
||||
user_name_eng = #{user_name_eng},
|
||||
dept_code = #{dept_code},
|
||||
dept_name = #{dept_name},
|
||||
position_code = #{position_code},
|
||||
position_name = #{position_name},
|
||||
rank = #{rank},
|
||||
email = #{email},
|
||||
cell_phone = #{cell_phone},
|
||||
user_type = #{user_type},
|
||||
user_type_name = #{user_type_name},
|
||||
status = #{status},
|
||||
end_date = CASE
|
||||
WHEN #{end_date} IS NULL OR #{end_date} = '' THEN NULL
|
||||
ELSE TO_TIMESTAMP(#{end_date}, 'YYYYMMDD')
|
||||
END,
|
||||
data_type = #{data_type}
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
@@ -89,10 +89,11 @@
|
||||
<mapper resource="/com/pms/ions/itemmgmt/mapper/materialWarehousing.xml" />
|
||||
<mapper resource="/com/pms/ions/itemmgmt/mapper/standardComponent.xml" />
|
||||
<mapper resource="/com/pms/ions/itemmgmt/mapper/bom.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/ProductionInventory.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/RequiredAmount.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/Magam.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/ExcelRegInven.xml" />
|
||||
|
||||
</mappers>
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/ProductionInventory.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/RequiredAmount.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/Magam.xml" />
|
||||
<mapper resource="/com/pms/ions/productioninventory/mapper/ExcelRegInven.xml" />
|
||||
<mapper resource="/com/pms/mapper/batch.xml" />
|
||||
|
||||
</mappers>
|
||||
</configuration>
|
||||
@@ -17,6 +17,9 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.pms.api.CustomerApiClient;
|
||||
import com.pms.api.DepartmentApiClient;
|
||||
import com.pms.api.EmployeeApiClient;
|
||||
import com.pms.common.Message;
|
||||
import com.pms.common.SqlMapConfig;
|
||||
import com.pms.common.bean.PersonBean;
|
||||
@@ -35,6 +38,8 @@ public class BatchService extends BaseService {
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
// 파트 도면 파일 자동 연결 배치 - 주석 처리
|
||||
/*
|
||||
static List<File> targetFileList = new ArrayList();
|
||||
|
||||
@Scheduled(cron="0 59 23 * * ?")
|
||||
@@ -160,9 +165,657 @@ public class BatchService extends BaseService {
|
||||
}
|
||||
return targetFileList;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ERP API 데이터 동기화 배치 (매일 새벽 00시 실행)
|
||||
* 거래처, 부서, 사원 정보를 ERP API로부터 가져와 DB에 저장
|
||||
*/
|
||||
@Scheduled(cron="0 0 0 * * ?")
|
||||
public void syncErpData() {
|
||||
System.out.println("====================================");
|
||||
System.out.println("ERP 데이터 동기화 배치 시작 (자동)");
|
||||
System.out.println("====================================");
|
||||
|
||||
executeSyncErpData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사원 정보만 동기화 (수동 실행)
|
||||
* @return 성공 여부 Map
|
||||
*/
|
||||
public Map<String, Object> syncEmployeeDataManual() {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("ERP 사원 정보 동기화 시작 (수동)");
|
||||
System.out.println("====================================");
|
||||
|
||||
try {
|
||||
String baseUrl = "https://erp.rps-korea.com";
|
||||
String coCd = "1000";
|
||||
|
||||
syncEmployeeData(sqlSession, baseUrl, coCd);
|
||||
|
||||
sqlSession.commit();
|
||||
result.put("success", true);
|
||||
result.put("message", "사원 정보 동기화가 완료되었습니다.");
|
||||
System.out.println("ERP 사원 정보 동기화 완료");
|
||||
} catch (Exception e) {
|
||||
sqlSession.rollback();
|
||||
result.put("success", false);
|
||||
result.put("message", "사원 정보 동기화 중 오류가 발생했습니다: " + e.getMessage());
|
||||
System.err.println("사원 정보 동기화 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 정보만 동기화 (수동 실행)
|
||||
* @return 성공 여부 Map
|
||||
*/
|
||||
public Map<String, Object> syncDepartmentDataManual() {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("ERP 부서 정보 동기화 시작 (수동)");
|
||||
System.out.println("====================================");
|
||||
|
||||
try {
|
||||
String baseUrl = "https://erp.rps-korea.com";
|
||||
String coCd = "1000";
|
||||
|
||||
syncDepartmentData(sqlSession, baseUrl, coCd);
|
||||
|
||||
sqlSession.commit();
|
||||
result.put("success", true);
|
||||
result.put("message", "부서 정보 동기화가 완료되었습니다.");
|
||||
System.out.println("ERP 부서 정보 동기화 완료");
|
||||
} catch (Exception e) {
|
||||
sqlSession.rollback();
|
||||
result.put("success", false);
|
||||
result.put("message", "부서 정보 동기화 중 오류가 발생했습니다: " + e.getMessage());
|
||||
System.err.println("부서 정보 동기화 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래처 정보만 동기화 (수동 실행)
|
||||
* @return 성공 여부 Map
|
||||
*/
|
||||
public Map<String, Object> syncCustomerDataManual() {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("ERP 거래처 정보 동기화 시작 (수동)");
|
||||
System.out.println("====================================");
|
||||
|
||||
try {
|
||||
String baseUrl = "https://erp.rps-korea.com";
|
||||
String coCd = "1000";
|
||||
|
||||
syncCustomerData(sqlSession, baseUrl, coCd);
|
||||
|
||||
sqlSession.commit();
|
||||
result.put("success", true);
|
||||
result.put("message", "거래처 정보 동기화가 완료되었습니다.");
|
||||
System.out.println("ERP 거래처 정보 동기화 완료");
|
||||
} catch (Exception e) {
|
||||
sqlSession.rollback();
|
||||
result.put("success", false);
|
||||
result.put("message", "거래처 정보 동기화 중 오류가 발생했습니다: " + e.getMessage());
|
||||
System.err.println("거래처 정보 동기화 오류: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP 데이터 동기화 실제 실행 로직
|
||||
*/
|
||||
private void executeSyncErpData() {
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
|
||||
|
||||
try {
|
||||
// API 기본 URL 및 회사코드 설정
|
||||
String baseUrl = "https://erp.rps-korea.com";
|
||||
String coCd = "1000";
|
||||
|
||||
// 1. 거래처 정보 동기화
|
||||
syncCustomerData(sqlSession, baseUrl, coCd);
|
||||
|
||||
// 2. 부서 정보 동기화
|
||||
syncDepartmentData(sqlSession, baseUrl, coCd);
|
||||
|
||||
// 3. 사원 정보 동기화
|
||||
syncEmployeeData(sqlSession, baseUrl, coCd);
|
||||
|
||||
sqlSession.commit();
|
||||
System.out.println("ERP 데이터 동기화 배치 완료");
|
||||
|
||||
} catch (Exception e) {
|
||||
sqlSession.rollback();
|
||||
System.err.println("ERP 데이터 동기화 중 오류 발생: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
sqlSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래처 정보 동기화
|
||||
*/
|
||||
private void syncCustomerData(SqlSession sqlSession, String baseUrl, String coCd) {
|
||||
try {
|
||||
System.out.println("거래처 정보 동기화 시작...");
|
||||
|
||||
CustomerApiClient customerClient = new CustomerApiClient();
|
||||
String jsonResponse = customerClient.getCustomerList(baseUrl, coCd);
|
||||
|
||||
// JSON 파싱 및 DB 저장
|
||||
List<Map<String, Object>> customerList = parseCustomerJson(jsonResponse);
|
||||
|
||||
int processCount = 0;
|
||||
|
||||
// 처음 10건 로그 출력
|
||||
System.out.println("====================================");
|
||||
System.out.println("거래처 데이터 샘플 (최대 10건)");
|
||||
System.out.println("====================================");
|
||||
|
||||
for (Map<String, Object> customer : customerList) {
|
||||
// 처음 10건만 로그 출력
|
||||
if (processCount < 10) {
|
||||
System.out.println("[거래처 " + (processCount + 1) + "]");
|
||||
System.out.println(" - CLIENT_CD: " + customer.get("client_cd"));
|
||||
System.out.println(" - CLIENT_NM: " + customer.get("client_nm"));
|
||||
System.out.println(" - CEO_NM: " + customer.get("ceo_nm"));
|
||||
System.out.println(" - TEL_NO: " + customer.get("tel_no"));
|
||||
System.out.println(" - EMAIL: " + customer.get("email"));
|
||||
System.out.println("---");
|
||||
}
|
||||
|
||||
// UPSERT 실행
|
||||
sqlSession.insert("batch.upsertCustomer", customer);
|
||||
processCount++;
|
||||
}
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("거래처 정보 동기화 완료 - 처리: " + processCount + "건");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("거래처 정보 동기화 실패: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 정보 동기화
|
||||
*/
|
||||
private void syncDepartmentData(SqlSession sqlSession, String baseUrl, String coCd) {
|
||||
try {
|
||||
System.out.println("부서 정보 동기화 시작...");
|
||||
|
||||
DepartmentApiClient deptClient = new DepartmentApiClient();
|
||||
String jsonResponse = deptClient.getDepartmentList(baseUrl, coCd, null);
|
||||
|
||||
// JSON 파싱 및 DB 저장
|
||||
List<Map<String, Object>> deptList = parseDepartmentJson(jsonResponse);
|
||||
|
||||
int processCount = 0;
|
||||
|
||||
// 처음 10건 로그 출력
|
||||
System.out.println("====================================");
|
||||
System.out.println("부서 데이터 샘플 (최대 10건)");
|
||||
System.out.println("====================================");
|
||||
|
||||
for (Map<String, Object> dept : deptList) {
|
||||
// 처음 10건만 로그 출력
|
||||
if (processCount < 10) {
|
||||
System.out.println("[부서 " + (processCount + 1) + "]");
|
||||
System.out.println(" - DEPT_CODE: " + dept.get("dept_code"));
|
||||
System.out.println(" - DEPT_NAME: " + dept.get("dept_name"));
|
||||
System.out.println(" - PARENT_DEPT_CODE: " + dept.get("parent_dept_code"));
|
||||
System.out.println(" - STATUS: " + dept.get("status"));
|
||||
System.out.println("---");
|
||||
}
|
||||
|
||||
// UPSERT 실행
|
||||
sqlSession.insert("batch.upsertDepartment", dept);
|
||||
processCount++;
|
||||
}
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("부서 정보 동기화 완료 - 처리: " + processCount + "건");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("부서 정보 동기화 실패: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 사원 정보 동기화
|
||||
*/
|
||||
private void syncEmployeeData(SqlSession sqlSession, String baseUrl, String coCd) {
|
||||
try {
|
||||
System.out.println("사원 정보 동기화 시작...");
|
||||
|
||||
EmployeeApiClient empClient = new EmployeeApiClient();
|
||||
String jsonResponse = empClient.getEmployeeList(baseUrl, coCd);
|
||||
|
||||
// JSON 파싱 및 DB 저장
|
||||
List<Map<String, Object>> empList = parseEmployeeJson(jsonResponse);
|
||||
|
||||
int processCount = 0;
|
||||
|
||||
// 처음 10건 로그 출력
|
||||
System.out.println("====================================");
|
||||
System.out.println("사원 데이터 샘플 (최대 10건)");
|
||||
System.out.println("====================================");
|
||||
|
||||
for (Map<String, Object> emp : empList) {
|
||||
// 처음 10건만 로그 출력
|
||||
if (processCount < 10) {
|
||||
System.out.println("[사원 " + (processCount + 1) + "]");
|
||||
System.out.println(" - USER_ID: " + emp.get("user_id"));
|
||||
System.out.println(" - USER_NAME: " + emp.get("user_name"));
|
||||
System.out.println(" - USER_NAME_ENG: " + emp.get("user_name_eng"));
|
||||
System.out.println(" - DEPT_CODE: " + emp.get("dept_code"));
|
||||
System.out.println(" - DEPT_NAME: " + emp.get("dept_name"));
|
||||
System.out.println(" - EMAIL: " + emp.get("email"));
|
||||
System.out.println(" - CELL_PHONE: " + emp.get("cell_phone"));
|
||||
System.out.println(" - STATUS: " + emp.get("status"));
|
||||
System.out.println("---");
|
||||
}
|
||||
|
||||
// UPSERT 실행
|
||||
sqlSession.insert("batch.upsertEmployee", emp);
|
||||
processCount++;
|
||||
}
|
||||
|
||||
System.out.println("====================================");
|
||||
System.out.println("사원 정보 동기화 완료 - 처리: " + processCount + "건");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("사원 정보 동기화 실패: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래처 JSON 파싱
|
||||
*/
|
||||
private List<Map<String, Object>> parseCustomerJson(String jsonResponse) {
|
||||
List<Map<String, Object>> customerList = new ArrayList<Map<String, Object>>();
|
||||
|
||||
try {
|
||||
// resultData 배열 찾기
|
||||
int dataStart = jsonResponse.indexOf("\"resultData\":[");
|
||||
if (dataStart == -1) {
|
||||
return customerList;
|
||||
}
|
||||
|
||||
String dataSection = jsonResponse.substring(dataStart + 14);
|
||||
int bracketCount = 0;
|
||||
int startIdx = -1;
|
||||
|
||||
for (int i = 0; i < dataSection.length(); i++) {
|
||||
char c = dataSection.charAt(i);
|
||||
|
||||
if (c == '{') {
|
||||
if (bracketCount == 0) {
|
||||
startIdx = i;
|
||||
}
|
||||
bracketCount++;
|
||||
} else if (c == '}') {
|
||||
bracketCount--;
|
||||
if (bracketCount == 0 && startIdx != -1) {
|
||||
String customerJson = dataSection.substring(startIdx, i + 1);
|
||||
Map<String, Object> customer = parseCustomerObject(customerJson);
|
||||
if (customer != null) {
|
||||
customerList.add(customer);
|
||||
}
|
||||
startIdx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("거래처 JSON 파싱 오류: " + e.getMessage());
|
||||
}
|
||||
|
||||
return customerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래처 객체 파싱 (실제 테이블 컬럼에 맞춤)
|
||||
*/
|
||||
private Map<String, Object> parseCustomerObject(String json) {
|
||||
Map<String, Object> customer = new HashMap<String, Object>();
|
||||
|
||||
// objid는 자동생성
|
||||
customer.put("objid", CommonUtils.createObjId());
|
||||
|
||||
// 기본 정보
|
||||
customer.put("client_cd", extractJsonValue(json, "trCd")); // 거래처코드
|
||||
customer.put("client_nm", extractJsonValue(json, "trNm")); // 거래처명
|
||||
customer.put("tr_nmk", extractJsonValue(json, "trNm")); // 거래처명(한글)
|
||||
customer.put("client_nmk", extractJsonValue(json, "trNm")); // 거래처명(한글)
|
||||
customer.put("attr_nmk", extractJsonValue(json, "attrNm")); // 거래처약칭
|
||||
customer.put("client_type", extractJsonValue(json, "trFg")); // 거래처분류
|
||||
customer.put("bus_reg_no", extractJsonValue(json, "regNb")); // 사업자등록번호
|
||||
customer.put("resident_no", extractJsonValue(json, "pplNb")); // 주민번호
|
||||
customer.put("ceo_nm", extractJsonValue(json, "ceoNm")); // 대표자명
|
||||
customer.put("ceo_nmk", extractJsonValue(json, "ceoNm")); // 대표자명(한글)
|
||||
customer.put("bus_type", extractJsonValue(json, "business")); // 업태
|
||||
customer.put("bus_item", extractJsonValue(json, "jongmok")); // 종목
|
||||
customer.put("post_no", extractJsonValue(json, "zip")); // 우편번호
|
||||
customer.put("addr1", extractJsonValue(json, "divAddr1")); // 주소1
|
||||
customer.put("addr2", extractJsonValue(json, "addr2")); // 주소2
|
||||
customer.put("tel_no", extractJsonValue(json, "tel")); // 전화번호
|
||||
customer.put("fax_no", extractJsonValue(json, "fax")); // 팩스번호
|
||||
customer.put("homepage", extractJsonValue(json, "homepage")); // 홈페이지
|
||||
customer.put("email", extractJsonValue(json, "email")); // 이메일
|
||||
customer.put("liq_rs", extractJsonValue(json, "liqRs")); // 주류코드
|
||||
customer.put("tr_fg", extractJsonValue(json, "trFg")); // 거래처분류
|
||||
customer.put("country_nm", extractJsonValue(json, "nationNm")); // 국가명
|
||||
customer.put("class_cd", extractJsonValue(json, "trgrpCd")); // 거래처분류코드
|
||||
customer.put("class_nm", extractJsonValue(json, "trgrpNm")); // 거래처분류명
|
||||
customer.put("grade_cd", extractJsonValue(json, "trratFg")); // 거래처등급코드
|
||||
customer.put("grade_nm", extractJsonValue(json, "trratNm")); // 거래처등급명
|
||||
customer.put("collect_client_cd", extractJsonValue(json, "clttrCd")); // 수금거래처코드
|
||||
customer.put("collect_client_nm", extractJsonValue(json, "clttrNm")); // 수금거래처명
|
||||
customer.put("region_cd", extractJsonValue(json, "localCd")); // 지역코드
|
||||
customer.put("region_nm", extractJsonValue(json, "localNm")); // 지역명
|
||||
customer.put("trade_start_dt", extractJsonValue(json, "frDt")); // 거래시작일
|
||||
customer.put("trade_end_dt", extractJsonValue(json, "toDt")); // 거래종료일
|
||||
customer.put("use_yn", extractJsonValue(json, "useYn")); // 사용여부
|
||||
customer.put("contract_start_dt", extractJsonValue(json, "interDt")); // 계약시작일
|
||||
customer.put("contract_end_dt", extractJsonValue(json, "dueDt")); // 계약종료일
|
||||
customer.put("trade_type", extractJsonValue(json, "trsoFg")); // 거래형태
|
||||
customer.put("discount_rate", extractJsonValue(json, "interRt")); // 할인율
|
||||
customer.put("contract_amt", extractJsonValue(json, "limitAm")); // 계약금액
|
||||
customer.put("monthly_fee", extractJsonValue(json, "interAm")); // 월용역비
|
||||
customer.put("payment_term", extractJsonValue(json, "payconDc")); // 결제조건
|
||||
customer.put("rcp_tp", extractJsonValue(json, "doudate1Fg")); // 예정일구분
|
||||
customer.put("credit_limit", extractJsonValue(json, "creditAm")); // 여신한도액
|
||||
customer.put("limit_return_day", extractJsonValue(json, "returnDt")); // 한도회귀일
|
||||
|
||||
// 매입 금융기관 정보
|
||||
customer.put("pur_bank_cd", extractJsonValue(json, "jiroCd")); // 매입은행코드
|
||||
customer.put("pur_bank_nm", extractJsonValue(json, "jiroNm")); // 매입은행명
|
||||
customer.put("pur_branch_nm", extractJsonValue(json, "placeNm")); // 매입지점명
|
||||
customer.put("pur_account_no", extractJsonValue(json, "baNb")); // 매입계좌번호
|
||||
customer.put("pur_account_holder", extractJsonValue(json, "depositor")); // 매입예금주
|
||||
customer.put("pur_pay_plan", extractJsonValue(json, "stOutSettlePay")); // 매입지급예정일
|
||||
customer.put("pur_slip_type", extractJsonValue(json, "stOutAcct1Fg")); // 매입전표유형
|
||||
customer.put("pur_tax_type", extractJsonValue(json, "stOutTax1Fg")); // 매입세무구분
|
||||
|
||||
// 매출 금융기관 정보
|
||||
customer.put("sale_bank_cd", extractJsonValue(json, "btrCd")); // 매출은행코드
|
||||
customer.put("sale_bank_nm", extractJsonValue(json, "btrCd")); // 매출은행명
|
||||
customer.put("sale_branch_nm", extractJsonValue(json, "stInDummy2")); // 매출지점명
|
||||
customer.put("sale_account_no", extractJsonValue(json, "stInBaNb")); // 매출계좌번호
|
||||
customer.put("sale_collect_plan", extractJsonValue(json, "stInSettlePay")); // 매출수금예정일
|
||||
customer.put("sale_slip_type", extractJsonValue(json, "stInAcct1Fg")); // 매출전표유형
|
||||
customer.put("sale_tax_type", extractJsonValue(json, "stInTax1Fg")); // 매출세무구분
|
||||
|
||||
// 거래처 담당자 정보
|
||||
customer.put("vendor_dept_nm", extractJsonValue(json, "stempgrpTrchargeDept")); // 거래처부서명
|
||||
customer.put("vendor_position", extractJsonValue(json, "stempgrpTrchargeTitle")); // 거래처직급
|
||||
customer.put("vendor_duty", extractJsonValue(json, "stempgrpTrchargeJop")); // 거래처담당업무
|
||||
customer.put("vendor_manager_nm", extractJsonValue(json, "stempgrpTrchargeEmp")); // 거래처담당자명
|
||||
customer.put("vendor_tel", extractJsonValue(json, "stempgrpTrchargeTel")); // 거래처전화번호
|
||||
customer.put("vendor_ext", extractJsonValue(json, "stempgrpTrchargeExt")); // 거래처내선
|
||||
customer.put("vendor_mobile", extractJsonValue(json, "stempgrpTrchargeHp")); // 거래처휴대폰
|
||||
customer.put("vendor_email", extractJsonValue(json, "stempgrpTrchargeEmail")); // 거래처이메일
|
||||
|
||||
// 관리담당자 정보
|
||||
customer.put("mgr_dept_cd", extractJsonValue(json, "stempDeptCd")); // 관리부서코드
|
||||
customer.put("mgr_dept_nm", extractJsonValue(json, "stempDeptNm")); // 관리부서명
|
||||
customer.put("mgr_position", extractJsonValue(json, "stempTitleDc")); // 관리직급
|
||||
customer.put("mgr_duty", extractJsonValue(json, "stempJobDc")); // 관리담당업무
|
||||
customer.put("mgr_emp_cd", extractJsonValue(json, "stempEmpCd")); // 관리사원코드
|
||||
customer.put("mgr_emp_nm", extractJsonValue(json, "stempEmpNm")); // 관리사원명
|
||||
customer.put("mgr_tel", extractJsonValue(json, "stempTel")); // 관리전화번호
|
||||
customer.put("mgr_ext", extractJsonValue(json, "stempTelDc")); // 관리내선
|
||||
customer.put("mgr_mobile", extractJsonValue(json, "stempHp")); // 관리휴대폰
|
||||
customer.put("mgr_email", extractJsonValue(json, "stempEmail")); // 관리이메일
|
||||
customer.put("mgr_remark", extractJsonValue(json, "stempRmkDc")); // 관리비고
|
||||
|
||||
// 수신처 정보
|
||||
customer.put("rec_remark", extractJsonValue(json, "streceiveRmkDc")); // 수신처비고
|
||||
customer.put("rec_post_no", extractJsonValue(json, "streceiveZip")); // 수신처우편번호
|
||||
customer.put("rec_addr1", extractJsonValue(json, "streceiveAddr1")); // 수신처주소1
|
||||
customer.put("rec_addr2", extractJsonValue(json, "streceiveAddr2")); // 수신처주소2
|
||||
customer.put("rec_tel", extractJsonValue(json, "streceiveTel")); // 수신처전화번호
|
||||
customer.put("rec_fax", extractJsonValue(json, "streceiveFax")); // 수신처팩스
|
||||
|
||||
// 프로젝트 정보
|
||||
customer.put("project_cd", extractJsonValue(json, "pjtCd")); // 프로젝트코드
|
||||
customer.put("project_nm", extractJsonValue(json, "pjtNm")); // 프로젝트명
|
||||
customer.put("pjt_nmk", extractJsonValue(json, "pjtNm")); // 프로젝트명(한글)
|
||||
|
||||
// 기타 정보
|
||||
customer.put("ext_data_cd", extractJsonValue(json, "linkCd")); // 외부데이터코드
|
||||
customer.put("e_tax_yn", extractJsonValue(json, "jeonjaYn")); // 전자세금계산서여부
|
||||
customer.put("unit_report_client", extractJsonValue(json, "reptrCd")); // 단위신고거래처
|
||||
customer.put("sub_bus_no", extractJsonValue(json, "apprNb")); // 종사업장번호
|
||||
customer.put("procurement_yn", extractJsonValue(json, "ppsFg")); // 조달청다수공급자
|
||||
customer.put("use_fg", extractJsonValue(json, "liqFg")); // 용도구분
|
||||
customer.put("for_yn", extractJsonValue(json, "forYn")); // 내외국인여부
|
||||
customer.put("plan_day_type", extractJsonValue(json, "doudate1Fg")); // 예정일구분
|
||||
customer.put("plan_day", extractJsonValue(json, "doudate1Dd")); // 예정일
|
||||
customer.put("purpose_type", extractJsonValue(json, "liqFg")); // 용도구분
|
||||
|
||||
// 등록/수정 정보
|
||||
customer.put("insert_dt", extractJsonValue(json, "insertDt")); // 삽입일자
|
||||
customer.put("modify_dt", extractJsonValue(json, "modifyDt")); // 수정일
|
||||
customer.put("insert_id", "batch_system"); // 등록자
|
||||
customer.put("modify_id", "batch_system"); // 수정자
|
||||
|
||||
return customer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 JSON 파싱
|
||||
*/
|
||||
private List<Map<String, Object>> parseDepartmentJson(String jsonResponse) {
|
||||
List<Map<String, Object>> deptList = new ArrayList<Map<String, Object>>();
|
||||
|
||||
try {
|
||||
int dataStart = jsonResponse.indexOf("\"resultData\":[");
|
||||
if (dataStart == -1) {
|
||||
return deptList;
|
||||
}
|
||||
|
||||
String dataSection = jsonResponse.substring(dataStart + 14);
|
||||
int bracketCount = 0;
|
||||
int startIdx = -1;
|
||||
|
||||
for (int i = 0; i < dataSection.length(); i++) {
|
||||
char c = dataSection.charAt(i);
|
||||
|
||||
if (c == '{') {
|
||||
if (bracketCount == 0) {
|
||||
startIdx = i;
|
||||
}
|
||||
bracketCount++;
|
||||
} else if (c == '}') {
|
||||
bracketCount--;
|
||||
if (bracketCount == 0 && startIdx != -1) {
|
||||
String deptJson = dataSection.substring(startIdx, i + 1);
|
||||
Map<String, Object> dept = parseDepartmentObject(deptJson);
|
||||
if (dept != null) {
|
||||
deptList.add(dept);
|
||||
}
|
||||
startIdx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("부서 JSON 파싱 오류: " + e.getMessage());
|
||||
}
|
||||
|
||||
return deptList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 객체 파싱 (실제 JSON 응답 기준으로 dept_info 테이블 매핑)
|
||||
*/
|
||||
private Map<String, Object> parseDepartmentObject(String json) {
|
||||
Map<String, Object> dept = new HashMap<String, Object>();
|
||||
|
||||
// JSON 필드 → dept_info 테이블 컬럼 매핑
|
||||
dept.put("dept_code", extractJsonValue(json, "deptCd")); // 부서코드 (deptCd)
|
||||
dept.put("parent_dept_code", extractJsonValue(json, "parentDeptCd")); // 상위부서코드 (parentDeptCd)
|
||||
dept.put("dept_name", extractJsonValue(json, "deptNm")); // 부서명 (deptNm)
|
||||
dept.put("status", "active"); // 상태 (기본값 active)
|
||||
dept.put("data_type", "ERP"); // 데이터유형
|
||||
|
||||
return dept;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사원 JSON 파싱
|
||||
*/
|
||||
private List<Map<String, Object>> parseEmployeeJson(String jsonResponse) {
|
||||
List<Map<String, Object>> empList = new ArrayList<Map<String, Object>>();
|
||||
|
||||
try {
|
||||
int dataStart = jsonResponse.indexOf("\"resultData\":[");
|
||||
if (dataStart == -1) {
|
||||
return empList;
|
||||
}
|
||||
|
||||
String dataSection = jsonResponse.substring(dataStart + 14);
|
||||
int bracketCount = 0;
|
||||
int startIdx = -1;
|
||||
|
||||
for (int i = 0; i < dataSection.length(); i++) {
|
||||
char c = dataSection.charAt(i);
|
||||
|
||||
if (c == '{') {
|
||||
if (bracketCount == 0) {
|
||||
startIdx = i;
|
||||
}
|
||||
bracketCount++;
|
||||
} else if (c == '}') {
|
||||
bracketCount--;
|
||||
if (bracketCount == 0 && startIdx != -1) {
|
||||
String empJson = dataSection.substring(startIdx, i + 1);
|
||||
Map<String, Object> emp = parseEmployeeObject(empJson);
|
||||
if (emp != null) {
|
||||
empList.add(emp);
|
||||
}
|
||||
startIdx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("사원 JSON 파싱 오류: " + e.getMessage());
|
||||
}
|
||||
|
||||
return empList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사원 객체 파싱 (실제 JSON 응답 기준으로 user_info 테이블 매핑)
|
||||
*/
|
||||
private Map<String, Object> parseEmployeeObject(String json) {
|
||||
Map<String, Object> emp = new HashMap<String, Object>();
|
||||
|
||||
// JSON 필드 → user_info 테이블 컬럼 매핑
|
||||
emp.put("sabun", extractJsonValue(json, "empCd")); // 사번 (empCd)
|
||||
emp.put("user_id", extractJsonValue(json, "empCd")); // 사용자ID (empCd)
|
||||
emp.put("user_password", "5715e7d798fd421c7100c435e7547e82"); // 기본 비밀번호 (MD5 해시)
|
||||
emp.put("user_name", extractJsonValue(json, "korNm")); // 사용자명 (korNm)
|
||||
emp.put("user_name_eng", extractJsonValue(json, "enlsNm")); // 영문명 (enlsNm)
|
||||
emp.put("dept_code", extractJsonValue(json, "deptCd")); // 부서코드 (deptCd)
|
||||
emp.put("dept_name", extractJsonValue(json, "deptNm")); // 부서명 (deptNm)
|
||||
emp.put("position_code", extractJsonValue(json, "hclsCd")); // 직급코드 (hclsCd)
|
||||
emp.put("position_name", extractJsonValue(json, "hclsNm")); // 직급명 (hclsNm)
|
||||
emp.put("rank", extractJsonValue(json, "hrspNm")); // 직책명 (hrspNm - 사원, 대리 등)
|
||||
emp.put("email", extractJsonValue(json, "emalAdd")); // 이메일 (emalAdd)
|
||||
emp.put("cell_phone", extractJsonValue(json, "emgcTel")); // 휴대폰 (emgcTel)
|
||||
emp.put("user_type", extractJsonValue(json, "enrlFg")); // 사용자유형 (enrlFg - J01:재직)
|
||||
emp.put("(주)RPS", extractJsonValue(json, "enrlNm")); // 사용자유형명 (enrlNm)
|
||||
|
||||
// 재직구분에 따른 상태 설정 (J01:재직=active, 그 외=inactive)
|
||||
String enrlFg = extractJsonValue(json, "enrlFg");
|
||||
emp.put("status", "J01".equals(enrlFg) ? "active" : "inactive"); // 상태
|
||||
|
||||
// 퇴직일자 (rtrDt)
|
||||
emp.put("end_date", extractJsonValue(json, "rtrDt")); // 종료일 (퇴직일)
|
||||
|
||||
emp.put("data_type", "ERP"); // 데이터유형
|
||||
|
||||
return emp;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON에서 특정 필드 값 추출
|
||||
*/
|
||||
private String extractJsonValue(String json, String fieldName) {
|
||||
String searchKey = "\"" + fieldName + "\":";
|
||||
int startIdx = json.indexOf(searchKey);
|
||||
if (startIdx == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
startIdx += searchKey.length();
|
||||
|
||||
// 공백 제거
|
||||
while (startIdx < json.length() && Character.isWhitespace(json.charAt(startIdx))) {
|
||||
startIdx++;
|
||||
}
|
||||
|
||||
if (startIdx >= json.length()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char firstChar = json.charAt(startIdx);
|
||||
|
||||
// 문자열 값인 경우
|
||||
if (firstChar == '"') {
|
||||
int endIdx = json.indexOf('"', startIdx + 1);
|
||||
if (endIdx == -1) return "";
|
||||
return json.substring(startIdx + 1, endIdx);
|
||||
}
|
||||
// 숫자나 null인 경우
|
||||
else {
|
||||
int endIdx = startIdx;
|
||||
while (endIdx < json.length() &&
|
||||
(Character.isDigit(json.charAt(endIdx)) ||
|
||||
json.charAt(endIdx) == '.' ||
|
||||
json.charAt(endIdx) == '-' ||
|
||||
json.charAt(endIdx) == 'n' ||
|
||||
json.charAt(endIdx) == 'u' ||
|
||||
json.charAt(endIdx) == 'l')) {
|
||||
endIdx++;
|
||||
}
|
||||
String value = json.substring(startIdx, endIdx).trim();
|
||||
if (value.startsWith("null")) {
|
||||
return "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user