Update: 외부연동 API 로직 변경
This commit is contained in:
parent
fbf1d9d6e0
commit
116e3eb351
@ -33,7 +33,6 @@ import java.util.*;
|
|||||||
public class ExternalIntegrationInteractor implements ExternalIntegrationUseCase {
|
public class ExternalIntegrationInteractor implements ExternalIntegrationUseCase {
|
||||||
|
|
||||||
private final ExternalPlatformPort externalPlatformPort;
|
private final ExternalPlatformPort externalPlatformPort;
|
||||||
private final EventPort eventPort;
|
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
|||||||
@ -96,6 +96,13 @@ public interface ExternalPlatformPort {
|
|||||||
* @return 연동 해제 성공 여부
|
* @return 연동 해제 성공 여부
|
||||||
*/
|
*/
|
||||||
boolean disconnectPlatform(Long storeId, String platform);
|
boolean disconnectPlatform(Long storeId, String platform);
|
||||||
|
/**
|
||||||
|
* 연동된 플랫폼 목록 조회
|
||||||
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @return 연동된 플랫폼 목록
|
||||||
|
*/
|
||||||
|
List<String> getConnectedPlatforms(Long storeId);
|
||||||
|
|
||||||
public List<Map<String, Object>> getTempReviews(Long storeId, String platform);
|
public List<Map<String, Object>> getTempReviews(Long storeId, String platform);
|
||||||
}
|
}
|
||||||
@ -18,8 +18,8 @@ import java.time.Duration;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 외부 플랫폼 어댑터 클래스
|
* 외부 플랫폼 연동 어댑터
|
||||||
* External Platform Port를 구현하여 외부 API 연동 기능을 제공
|
* 각 플랫폼별 API 호출 및 Redis 저장을 담당
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -30,42 +30,40 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort {
|
|||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@Value("${external-api.naver.client-id:}")
|
@Value("${external.kakao.crawler.url:http://localhost:9001}")
|
||||||
private String naverClientId;
|
private String kakaoCrawlerUrl;
|
||||||
|
|
||||||
@Value("${external-api.naver.client-secret:}")
|
@Value("${external.naver.crawler.url:http://localhost:9002}")
|
||||||
private String naverClientSecret;
|
private String naverCrawlerUrl;
|
||||||
|
|
||||||
@Value("${external-api.kakao.api-key:}")
|
@Value("${external.google.crawler.url:http://localhost:9003}")
|
||||||
private String kakaoApiKey;
|
private String googleCrawlerUrl;
|
||||||
|
|
||||||
@Value("${external-api.google.api-key:}")
|
@Value("${external.hiorder.api.url:http://localhost:8080}")
|
||||||
private String googleApiKey;
|
private String hiorderApiUrl;
|
||||||
|
|
||||||
@Value("${external-api.hiorder.api-key:}")
|
// ===== 리뷰 동기화 메서드들 =====
|
||||||
private String hiorderApiKey;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int syncNaverReviews(Long storeId, String externalStoreId) {
|
public int syncNaverReviews(Long storeId, String externalStoreId) {
|
||||||
log.info("네이버 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
log.info("네이버 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 네이버 API 호출 (Mock)
|
// 네이버 크롤링 서비스 호출
|
||||||
|
String url = String.format("%s/api/naver/reviews?storeId=%s", naverCrawlerUrl, externalStoreId);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.set("X-Naver-Client-Id", naverClientId);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
headers.set("X-Naver-Client-Secret", naverClientSecret);
|
|
||||||
|
|
||||||
// 실제 API 호출 로직
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
// ResponseEntity<Map> response = restTemplate.exchange(...);
|
ResponseEntity<String> response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, entity, String.class);
|
||||||
|
|
||||||
// Mock 응답
|
return processNaverResponse(storeId, "NAVER", response.getBody());
|
||||||
int syncedCount = 15; // Mock 데이터
|
|
||||||
|
|
||||||
log.info("네이버 리뷰 동기화 완료: storeId={}, syncedCount={}", storeId, syncedCount);
|
|
||||||
return syncedCount;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("네이버 리뷰 동기화 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("네이버 리뷰 동기화 실패: storeId={}, externalStoreId={}, error={}",
|
||||||
|
storeId, externalStoreId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, "NAVER", "FAILED", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,50 +73,45 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort {
|
|||||||
log.info("카카오 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
log.info("카카오 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 기존 API 호출 로직 그대로 유지 ⭐
|
// 카카오 크롤링 서비스 호출
|
||||||
String url = "http://kakao-review-api.20.249.191.180.nip.io/analyze";
|
String url = String.format("%s/api/kakao/reviews?storeId=%s", kakaoCrawlerUrl, externalStoreId);
|
||||||
|
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
|
||||||
requestBody.put("store_id", storeId);
|
|
||||||
requestBody.put("days_limit", 360);
|
|
||||||
requestBody.put("max_time", 300);
|
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, entity, String.class);
|
||||||
|
|
||||||
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
|
return processKakaoResponse(storeId, "KAKAO", response.getBody());
|
||||||
|
|
||||||
int syncedCount = parseAndStoreToRedis(storeId, "KAKAO", response.getBody());
|
|
||||||
|
|
||||||
return syncedCount;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("카카오 리뷰 동기화 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("카카오 리뷰 동기화 실패: storeId={}, externalStoreId={}, error={}",
|
||||||
|
storeId, externalStoreId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, "KAKAO", "FAILED", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int syncGoogleReviews(Long storeId, String externalStoreId) {
|
public int syncGoogleReviews(Long storeId, String externalStoreId) {
|
||||||
log.info("구글 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
log.info("구글 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 구글 Places API 호출 (Mock)
|
// 구글 크롤링 서비스 호출
|
||||||
String url = "https://maps.googleapis.com/maps/api/place/details/json?place_id=" +
|
String url = String.format("%s/api/google/reviews?storeId=%s", googleCrawlerUrl, externalStoreId);
|
||||||
externalStoreId + "&fields=reviews&key=" + googleApiKey;
|
|
||||||
|
|
||||||
// Mock 응답
|
HttpHeaders headers = new HttpHeaders();
|
||||||
int syncedCount = 20;
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
log.info("구글 리뷰 동기화 완료: storeId={}, syncedCount={}", storeId, syncedCount);
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
return syncedCount;
|
ResponseEntity<String> response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, entity, String.class);
|
||||||
|
|
||||||
|
return processGoogleResponse(storeId, "GOOGLE", response.getBody());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("구글 리뷰 동기화 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("구글 리뷰 동기화 실패: storeId={}, externalStoreId={}, error={}",
|
||||||
|
storeId, externalStoreId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, "GOOGLE", "FAILED", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,263 +121,248 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort {
|
|||||||
log.info("하이오더 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
log.info("하이오더 리뷰 동기화 시작: storeId={}, externalStoreId={}", storeId, externalStoreId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 하이오더 API 호출 (Mock)
|
// 하이오더 API 호출
|
||||||
|
String url = String.format("%s/api/reviews?storeId=%s", hiorderApiUrl, externalStoreId);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.set("Authorization", "Bearer " + hiorderApiKey);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// Mock 응답
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
int syncedCount = 8;
|
ResponseEntity<String> response = restTemplate.exchange(url, org.springframework.http.HttpMethod.GET, entity, String.class);
|
||||||
|
|
||||||
log.info("하이오더 리뷰 동기화 완료: storeId={}, syncedCount={}", storeId, syncedCount);
|
return processHiorderResponse(storeId, "HIORDER", response.getBody());
|
||||||
return syncedCount;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("하이오더 리뷰 동기화 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("하이오더 리뷰 동기화 실패: storeId={}, externalStoreId={}, error={}",
|
||||||
|
storeId, externalStoreId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, "HIORDER", "FAILED", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 계정 연동 메서드들 =====
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean connectNaverAccount(Long storeId, String username, String password) {
|
public boolean connectNaverAccount(Long storeId, String username, String password) {
|
||||||
log.info("네이버 계정 연동 시작: storeId={}, username={}", storeId, username);
|
log.info("네이버 계정 연동: storeId={}", storeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 네이버 계정 인증 로직 (Mock)
|
if (validateCredentials(username, password)) {
|
||||||
// 실제로는 OAuth2 플로우나 ID/PW 인증
|
saveConnectionInfo(storeId, "NAVER", username);
|
||||||
|
return true;
|
||||||
// Mock 성공
|
|
||||||
boolean connected = true;
|
|
||||||
|
|
||||||
if (connected) {
|
|
||||||
// 연동 정보 저장
|
|
||||||
saveExternalConnection(storeId, "NAVER", username);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
log.info("네이버 계정 연동 완료: storeId={}, connected={}", storeId, connected);
|
|
||||||
return connected;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("네이버 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("네이버 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean connectKakaoAccount(Long storeId, String username, String password) {
|
public boolean connectKakaoAccount(Long storeId, String username, String password) {
|
||||||
log.info("카카오 계정 연동 시작: storeId={}, username={}", storeId, username);
|
log.info("카카오 계정 연동: storeId={}", storeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 카카오 계정 인증 로직 (Mock)
|
if (validateCredentials(username, password)) {
|
||||||
boolean connected = true;
|
saveConnectionInfo(storeId, "KAKAO", username);
|
||||||
|
return true;
|
||||||
if (connected) {
|
|
||||||
saveExternalConnection(storeId, "KAKAO", username);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
log.info("카카오 계정 연동 완료: storeId={}, connected={}", storeId, connected);
|
|
||||||
return connected;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("카카오 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("카카오 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean connectGoogleAccount(Long storeId, String username, String password) {
|
public boolean connectGoogleAccount(Long storeId, String username, String password) {
|
||||||
log.info("구글 계정 연동 시작: storeId={}, username={}", storeId, username);
|
log.info("구글 계정 연동: storeId={}", storeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 구글 계정 인증 로직 (Mock)
|
if (validateCredentials(username, password)) {
|
||||||
boolean connected = true;
|
saveConnectionInfo(storeId, "GOOGLE", username);
|
||||||
|
return true;
|
||||||
if (connected) {
|
|
||||||
saveExternalConnection(storeId, "GOOGLE", username);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
log.info("구글 계정 연동 완료: storeId={}, connected={}", storeId, connected);
|
|
||||||
return connected;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("구글 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("구글 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean connectHiorderAccount(Long storeId, String username, String password) {
|
public boolean connectHiorderAccount(Long storeId, String username, String password) {
|
||||||
log.info("하이오더 계정 연동 시작: storeId={}, username={}", storeId, username);
|
log.info("하이오더 계정 연동: storeId={}", storeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 하이오더 계정 인증 로직 (Mock)
|
if (validateCredentials(username, password)) {
|
||||||
boolean connected = true;
|
saveConnectionInfo(storeId, "HIORDER", username);
|
||||||
|
return true;
|
||||||
if (connected) {
|
|
||||||
saveExternalConnection(storeId, "HIORDER", username);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
log.info("하이오더 계정 연동 완료: storeId={}, connected={}", storeId, connected);
|
|
||||||
return connected;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("하이오더 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage(), e);
|
log.error("하이오더 계정 연동 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean disconnectPlatform(Long storeId, String platform) {
|
public boolean disconnectPlatform(Long storeId, String platform) {
|
||||||
log.info("외부 플랫폼 연동 해제 시작: storeId={}, platform={}", storeId, platform);
|
log.info("플랫폼 연동 해제: storeId={}, platform={}", storeId, platform);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 플랫폼별 연동 해제 로직
|
String connectionKey = String.format("external:connection:%d:%s", storeId, platform);
|
||||||
boolean disconnected = false;
|
redisTemplate.delete(connectionKey);
|
||||||
|
|
||||||
switch (platform.toUpperCase()) {
|
log.info("플랫폼 연동 해제 완료: storeId={}, platform={}", storeId, platform);
|
||||||
case "NAVER":
|
return true;
|
||||||
disconnected = disconnectNaverAccount(storeId);
|
|
||||||
break;
|
|
||||||
case "KAKAO":
|
|
||||||
disconnected = disconnectKakaoAccount(storeId);
|
|
||||||
break;
|
|
||||||
case "GOOGLE":
|
|
||||||
disconnected = disconnectGoogleAccount(storeId);
|
|
||||||
break;
|
|
||||||
case "HIORDER":
|
|
||||||
disconnected = disconnectHiorderAccount(storeId);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log.warn("지원하지 않는 플랫폼: {}", platform);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disconnected) {
|
|
||||||
removeExternalConnection(storeId, platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("외부 플랫폼 연동 해제 완료: storeId={}, platform={}, disconnected={}",
|
|
||||||
storeId, platform, disconnected);
|
|
||||||
return disconnected;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("외부 플랫폼 연동 해제 실패: storeId={}, platform={}, error={}",
|
log.error("플랫폼 연동 해제 실패: storeId={}, platform={}, error={}",
|
||||||
storeId, platform, e.getMessage(), e);
|
storeId, platform, e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 네이버 계정 연동 해제
|
public List<String> getConnectedPlatforms(Long storeId) {
|
||||||
*/
|
log.info("연동된 플랫폼 조회: storeId={}", storeId);
|
||||||
private boolean disconnectNaverAccount(Long storeId) {
|
|
||||||
// 네이버 연동 해제 로직 (Mock)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 카카오 계정 연동 해제
|
|
||||||
*/
|
|
||||||
private boolean disconnectKakaoAccount(Long storeId) {
|
|
||||||
// 카카오 연동 해제 로직 (Mock)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 구글 계정 연동 해제
|
|
||||||
*/
|
|
||||||
private boolean disconnectGoogleAccount(Long storeId) {
|
|
||||||
// 구글 연동 해제 로직 (Mock)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 하이오더 계정 연동 해제
|
|
||||||
*/
|
|
||||||
private boolean disconnectHiorderAccount(Long storeId) {
|
|
||||||
// 하이오더 연동 해제 로직 (Mock)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 외부 연동 정보 저장 Redis 활용
|
|
||||||
*/
|
|
||||||
private void saveExternalConnection(Long storeId, String platform, String username) {
|
|
||||||
try {
|
try {
|
||||||
String connectionKey = String.format("external:connection:%d:%s", storeId, platform);
|
List<String> connectedPlatforms = new ArrayList<>();
|
||||||
|
|
||||||
Map<String, Object> connectionData = new HashMap<>();
|
String pattern = String.format("external:connection:%d:*", storeId);
|
||||||
connectionData.put("storeId", storeId);
|
Set<String> keys = redisTemplate.keys(pattern);
|
||||||
connectionData.put("platform", platform);
|
|
||||||
connectionData.put("username", username);
|
|
||||||
connectionData.put("connectedAt", System.currentTimeMillis());
|
|
||||||
connectionData.put("isActive", true);
|
|
||||||
|
|
||||||
redisTemplate.opsForValue().set(connectionKey, connectionData, Duration.ofDays(30));
|
if (keys != null) {
|
||||||
|
for (String key : keys) {
|
||||||
|
String platform = key.substring(key.lastIndexOf(':') + 1);
|
||||||
|
connectedPlatforms.add(platform.toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.info("외부 연동 정보 Redis 저장 완료: storeId={}, platform={}, username={}",
|
return connectedPlatforms;
|
||||||
storeId, platform, username);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("외부 연동 정보 저장 실패: storeId={}, platform={}, error={}",
|
log.error("연동된 플랫폼 조회 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
storeId, platform, e.getMessage());
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 외부 연동 정보 제거
|
public List<Map<String, Object>> getTempReviews(Long storeId, String platform) {
|
||||||
*/
|
try {
|
||||||
private void removeExternalConnection(Long storeId, String platform) {
|
String pattern = String.format("external:reviews:pending:%d:%s:*", storeId, platform);
|
||||||
// 실제로는 ExternalPlatformEntity에서 연동 정보 제거
|
Set<String> keys = redisTemplate.keys(pattern);
|
||||||
log.info("외부 연동 정보 제거: storeId={}, platform={}", storeId, platform);
|
|
||||||
|
if (keys != null && !keys.isEmpty()) {
|
||||||
|
String latestKey = keys.stream()
|
||||||
|
.max(Comparator.comparing(key -> {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(key.substring(key.lastIndexOf(':') + 1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (latestKey != null) {
|
||||||
|
Map<String, Object> cacheData = (Map<String, Object>) redisTemplate.opsForValue().get(latestKey);
|
||||||
|
if (cacheData != null && cacheData.containsKey("reviews")) {
|
||||||
|
return (List<Map<String, Object>>) cacheData.get("reviews");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis에서 임시 리뷰 데이터 조회 실패: storeId={}, platform={}", storeId, platform);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ===== Private Helper Methods =====
|
||||||
* 카카오 응답 파싱 및 Redis 저장 (새로 추가)
|
|
||||||
*/
|
private int processNaverResponse(Long storeId, String platform, String responseBody) {
|
||||||
private int parseAndStoreToRedis(Long storeId, String platform, String responseBody) {
|
|
||||||
try {
|
try {
|
||||||
log.info("카카오 API 응답: {}", responseBody);
|
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||||
|
log.warn("네이버 응답이 비어있음: storeId={}", storeId);
|
||||||
// JSON 파싱
|
|
||||||
JsonNode rootNode = objectMapper.readTree(responseBody);
|
|
||||||
JsonNode reviewsNode = rootNode.get("reviews");
|
|
||||||
|
|
||||||
if (reviewsNode == null || !reviewsNode.isArray()) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 리뷰 데이터 변환
|
JsonNode root = objectMapper.readTree(responseBody);
|
||||||
|
|
||||||
List<Map<String, Object>> parsedReviews = new ArrayList<>();
|
List<Map<String, Object>> parsedReviews = new ArrayList<>();
|
||||||
for (JsonNode reviewNode : reviewsNode) {
|
|
||||||
Map<String, Object> review = new HashMap<>();
|
// 네이버 크롤링 응답 처리
|
||||||
review.put("reviewId", reviewNode.get("review_id").asText());
|
if (root.has("success") && root.get("success").asBoolean() && root.has("data")) {
|
||||||
review.put("content", reviewNode.get("content").asText());
|
JsonNode data = root.get("data");
|
||||||
review.put("rating", reviewNode.get("rating").asInt());
|
if (data.has("reviews")) {
|
||||||
review.put("authorName", reviewNode.get("author_name").asText());
|
JsonNode reviews = data.get("reviews");
|
||||||
review.put("reviewDate", reviewNode.get("review_date").asText());
|
for (JsonNode reviewNode : reviews) {
|
||||||
review.put("platform", platform);
|
Map<String, Object> review = new HashMap<>();
|
||||||
parsedReviews.add(review);
|
review.put("reviewId", reviewNode.path("reviewId").asText());
|
||||||
|
review.put("rating", reviewNode.path("rating").asDouble(0.0));
|
||||||
|
review.put("content", reviewNode.path("content").asText());
|
||||||
|
review.put("reviewerName", reviewNode.path("reviewerName").asText());
|
||||||
|
review.put("createdAt", reviewNode.path("createdAt").asText());
|
||||||
|
review.put("platform", platform);
|
||||||
|
parsedReviews.add(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parsedReviews.isEmpty()) {
|
if (!parsedReviews.isEmpty()) {
|
||||||
// Redis에 저장 (TTL: 24시간)
|
saveToRedis(storeId, platform, parsedReviews);
|
||||||
String redisKey = String.format("external:reviews:pending:%d:%s:%d",
|
|
||||||
storeId, platform, System.currentTimeMillis());
|
|
||||||
|
|
||||||
Map<String, Object> cacheData = new HashMap<>();
|
|
||||||
cacheData.put("storeId", storeId);
|
|
||||||
cacheData.put("platform", platform);
|
|
||||||
cacheData.put("reviews", parsedReviews);
|
|
||||||
cacheData.put("status", "PENDING");
|
|
||||||
cacheData.put("createdAt", System.currentTimeMillis());
|
|
||||||
cacheData.put("retryCount", 0);
|
|
||||||
|
|
||||||
redisTemplate.opsForValue().set(redisKey, cacheData, Duration.ofHours(24));
|
|
||||||
|
|
||||||
log.info("Redis에 리뷰 데이터 저장 완료: key={}, count={}", redisKey, parsedReviews.size());
|
|
||||||
|
|
||||||
// 동기화 상태 업데이트
|
|
||||||
updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size());
|
updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size());
|
||||||
|
|
||||||
|
log.info("Redis에 리뷰 데이터 저장 완료: key={}, count={}",
|
||||||
|
String.format("external:reviews:pending:%d:%s:%d", storeId, platform, System.currentTimeMillis()),
|
||||||
|
parsedReviews.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedReviews.size();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("네이버 응답 파싱 및 Redis 저장 실패: {}", e.getMessage());
|
||||||
|
updateSyncStatus(storeId, platform, "FAILED", 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int processKakaoResponse(Long storeId, String platform, String responseBody) {
|
||||||
|
try {
|
||||||
|
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||||
|
log.warn("카카오 응답이 비어있음: storeId={}", storeId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode root = objectMapper.readTree(responseBody);
|
||||||
|
|
||||||
|
List<Map<String, Object>> parsedReviews = new ArrayList<>();
|
||||||
|
|
||||||
|
// 카카오 크롤링 응답 처리
|
||||||
|
if (root.has("success") && root.get("success").asBoolean() && root.has("data")) {
|
||||||
|
JsonNode data = root.get("data");
|
||||||
|
if (data.has("reviews")) {
|
||||||
|
JsonNode reviews = data.get("reviews");
|
||||||
|
for (JsonNode reviewNode : reviews) {
|
||||||
|
Map<String, Object> review = new HashMap<>();
|
||||||
|
review.put("reviewId", reviewNode.path("reviewId").asText());
|
||||||
|
review.put("rating", reviewNode.path("rating").asDouble(0.0));
|
||||||
|
review.put("content", reviewNode.path("content").asText());
|
||||||
|
review.put("reviewerName", reviewNode.path("reviewerName").asText());
|
||||||
|
review.put("createdAt", reviewNode.path("createdAt").asText());
|
||||||
|
review.put("platform", platform);
|
||||||
|
parsedReviews.add(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedReviews.isEmpty()) {
|
||||||
|
saveToRedis(storeId, platform, parsedReviews);
|
||||||
|
updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size());
|
||||||
|
|
||||||
|
log.info("Redis에 리뷰 데이터 저장 완료: key={}, count={}",
|
||||||
|
String.format("external:reviews:pending:%d:%s:%d", storeId, platform, System.currentTimeMillis()),
|
||||||
|
parsedReviews.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedReviews.size();
|
return parsedReviews.size();
|
||||||
@ -396,6 +374,117 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int processGoogleResponse(Long storeId, String platform, String responseBody) {
|
||||||
|
try {
|
||||||
|
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||||
|
log.warn("구글 응답이 비어있음: storeId={}", storeId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode root = objectMapper.readTree(responseBody);
|
||||||
|
|
||||||
|
List<Map<String, Object>> parsedReviews = new ArrayList<>();
|
||||||
|
|
||||||
|
// 구글 크롤링 응답 처리
|
||||||
|
if (root.has("success") && root.get("success").asBoolean() && root.has("data")) {
|
||||||
|
JsonNode data = root.get("data");
|
||||||
|
if (data.has("reviews")) {
|
||||||
|
JsonNode reviews = data.get("reviews");
|
||||||
|
for (JsonNode reviewNode : reviews) {
|
||||||
|
Map<String, Object> review = new HashMap<>();
|
||||||
|
review.put("reviewId", reviewNode.path("reviewId").asText());
|
||||||
|
review.put("rating", reviewNode.path("rating").asDouble(0.0));
|
||||||
|
review.put("content", reviewNode.path("content").asText());
|
||||||
|
review.put("reviewerName", reviewNode.path("reviewerName").asText());
|
||||||
|
review.put("createdAt", reviewNode.path("createdAt").asText());
|
||||||
|
review.put("platform", platform);
|
||||||
|
parsedReviews.add(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedReviews.isEmpty()) {
|
||||||
|
saveToRedis(storeId, platform, parsedReviews);
|
||||||
|
updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedReviews.size();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("구글 응답 파싱 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, platform, "FAILED", 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int processHiorderResponse(Long storeId, String platform, String responseBody) {
|
||||||
|
try {
|
||||||
|
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||||
|
log.warn("하이오더 응답이 비어있음: storeId={}", storeId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode root = objectMapper.readTree(responseBody);
|
||||||
|
|
||||||
|
List<Map<String, Object>> parsedReviews = new ArrayList<>();
|
||||||
|
|
||||||
|
// 하이오더 API 응답 처리
|
||||||
|
if (root.has("success") && root.get("success").asBoolean() && root.has("data")) {
|
||||||
|
JsonNode data = root.get("data");
|
||||||
|
for (JsonNode reviewNode : data) {
|
||||||
|
Map<String, Object> review = new HashMap<>();
|
||||||
|
review.put("reviewId", reviewNode.path("reviewId").asText());
|
||||||
|
review.put("rating", reviewNode.path("rating").asDouble(0.0));
|
||||||
|
review.put("content", reviewNode.path("comment").asText());
|
||||||
|
review.put("reviewerName", reviewNode.path("customerName").asText());
|
||||||
|
review.put("createdAt", reviewNode.path("reviewDate").asText());
|
||||||
|
review.put("platform", platform);
|
||||||
|
parsedReviews.add(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedReviews.isEmpty()) {
|
||||||
|
saveToRedis(storeId, platform, parsedReviews);
|
||||||
|
updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedReviews.size();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("하이오더 응답 파싱 실패: storeId={}, error={}", storeId, e.getMessage());
|
||||||
|
updateSyncStatus(storeId, platform, "FAILED", 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateCredentials(String username, String password) {
|
||||||
|
return username != null && !username.trim().isEmpty() &&
|
||||||
|
password != null && !password.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveToRedis(Long storeId, String platform, List<Map<String, Object>> reviews) {
|
||||||
|
try {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
String redisKey = String.format("external:reviews:pending:%d:%s:%d", storeId, platform, timestamp);
|
||||||
|
|
||||||
|
Map<String, Object> cacheData = new HashMap<>();
|
||||||
|
cacheData.put("storeId", storeId);
|
||||||
|
cacheData.put("platform", platform);
|
||||||
|
cacheData.put("reviews", reviews);
|
||||||
|
cacheData.put("timestamp", timestamp);
|
||||||
|
cacheData.put("status", "PENDING");
|
||||||
|
cacheData.put("retryCount", 0);
|
||||||
|
|
||||||
|
redisTemplate.opsForValue().set(redisKey, cacheData, Duration.ofDays(1));
|
||||||
|
|
||||||
|
log.info("Redis에 리뷰 데이터 저장 완료: key={}, count={}", redisKey, reviews.size());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis 저장 실패: storeId={}, platform={}, error={}",
|
||||||
|
storeId, platform, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 동기화 상태 Redis에 저장
|
* 동기화 상태 Redis에 저장
|
||||||
*/
|
*/
|
||||||
@ -417,35 +506,24 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void saveConnectionInfo(Long storeId, String platform, String username) {
|
||||||
public List<Map<String, Object>> getTempReviews(Long storeId, String platform) {
|
|
||||||
try {
|
try {
|
||||||
// Redis에서 최신 pending 데이터 조회
|
String connectionKey = String.format("external:connection:%d:%s", storeId, platform);
|
||||||
String pattern = String.format("external:reviews:pending:%d:%s:*", storeId, platform);
|
|
||||||
Set<String> keys = redisTemplate.keys(pattern);
|
|
||||||
|
|
||||||
if (keys != null && !keys.isEmpty()) {
|
Map<String, Object> connectionData = new HashMap<>();
|
||||||
// 가장 최신 키 선택 (타임스탬프 기준)
|
connectionData.put("storeId", storeId);
|
||||||
String latestKey = keys.stream()
|
connectionData.put("platform", platform);
|
||||||
.max(Comparator.comparing(key -> Long.parseLong(key.substring(key.lastIndexOf(':') + 1))))
|
connectionData.put("username", username);
|
||||||
.orElse(null);
|
connectionData.put("connectedAt", System.currentTimeMillis());
|
||||||
|
connectionData.put("status", "CONNECTED");
|
||||||
|
|
||||||
if (latestKey != null) {
|
redisTemplate.opsForValue().set(connectionKey, connectionData, Duration.ofDays(30));
|
||||||
Map<String, Object> cacheData = (Map<String, Object>) redisTemplate.opsForValue().get(latestKey);
|
|
||||||
if (cacheData != null) {
|
|
||||||
return (List<Map<String, Object>>) cacheData.get("reviews");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>();
|
log.info("연동 정보 저장 완료: storeId={}, platform={}", storeId, platform);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Redis에서 임시 리뷰 데이터 조회 실패: storeId={}, platform={}", storeId, platform);
|
log.error("연동 정보 저장 실패: storeId={}, platform={}, error={}",
|
||||||
return new ArrayList<>();
|
storeId, platform, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user