신경 써야 할 부분
- 데이터를 정상적으로 받아왔는지 여부 : JSON의 Header에 ReturnValue에 Success or Failed가 뜸
- 받아온 데이터가 중복값인지 여부 : 기존의 arff 데이터셋에 Index값이 날짜정보로써 고유값의 역할을 하게끔 작성
- 중복이 아닌 데이터라면 기존의 arff 데이터셋에 업데이트
- 스케줄링을 통해 작업을 자동화
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DataResponse {
private int data;
private String drwNoDate;
private String returnValue;
public int getFormattedDrawDate() {
return Integer.parseInt(drwNoDate.replace("-", ""));
}
}
@JsonIgnoreProperties(ignoreUnknown = true) -> DataResponse 객체를 매핑할 때, JSON에 정의되지 않은 필드를 무시
@Service
public class DataUpdateService {
private static final String API_URL = ${API_URL};
private static final String LATEST_DRAW_NO_FILE = "latestDrawNo.txt";
// 파일 경로를 반환(resources폴더에 저장되도록)
private String getResourceFilePath() throws IOException {
Path path = Paths.get("src/main/resources/" + LATEST_DRAW_NO_FILE);
File file = new File(path.toString());
if (!file.exists()) {
if (file.createNewFile()) {
System.out.println("Created new file: " + file.getAbsolutePath());
} else {
throw new IOException("Failed to create file: " + file.getAbsolutePath());
}
}
return file.getAbsolutePath();
}
// 가장 최근에 처리된 회차 번호를 반환
public int getLatestDrawNo() throws IOException {
String filePath = getResourceFilePath();
File file = new File(filePath);
if (!file.exists()) {
FileWriter writer = new FileWriter(file);
writer.write("1");
writer.close();
return 1;
}
BufferedReader reader = new BufferedReader(new FileReader(file));
String latestDrawNoStr = reader.readLine();
reader.close();
if (latestDrawNoStr == null || latestDrawNoStr.isEmpty()) {
return 1;
}
return Integer.parseInt(latestDrawNoStr);
}
// 회차 번호를 파일에 저장
public void saveLatestDrawNo(int drawNo) throws IOException {
String filePath = getResourceFilePath();
try (FileWriter writer = new FileWriter(filePath)) {
writer.write(Integer.toString(drawNo));
writer.flush(); // 즉시 데이터를 파일에 씁니다.
System.out.println("Saved latest draw number: " + drawNo);
}
}
// API를 통해 데이터를 가져오는 메소드
public DataResponse getDataInfoByDrawNumber(int drawNo) {
RestTemplate restTemplate = new RestTemplate();
String url = API_URL + drawNo;
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
String responseBody = response.getBody();
if (responseBody != null && responseBody.startsWith("{")) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(responseBody, DataResponse.class);
} else {
System.out.println("Unexpected response format: " + responseBody);
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
// 데이터를 ARFF 파일에 저장하는 메서드
// 초안에서는 단순히 데이터를 업데이트하는 로직만 있었지만, API 통신과 파일 업데이트가 함께 이루어지도록 통합
public void updateArffFileFromStartDraw(DataUpdateService dataUpdateService) throws Exception {
int latestDrawNo = dataUpdateService.getLatestDrawNo();
while (true) {
DataResponse dataResponse = dataUpdateService.getDataInfoByDrawNumber(latestDrawNo);
if (dataResponse == null || !"success".equals(dataResponse.getReturnValue())) {
System.out.println("No more data to fetch. Stopping at draw number: " + latestDrawNo);
break;
}
boolean updated = updateArffFile(dataResponse);
dataUpdateService.saveLatestDrawNo(latestDrawNo);
if (updated) {
System.out.println("Updated draw number: " + latestDrawNo);
}
latestDrawNo++;
}
}
// ARFF 파일을 업데이트하는 메서드
// 초안에서는 중복 확인만 했지만, 중복이 아닌 경우 데이터를 추가하는 로직을 통합
public boolean updateArffFile(DataResponse dataResponse) throws Exception {
if (!"success".equals(dataResponse.getReturnValue())) {
System.out.println("Lotto API request was not successful.");
return false;
}
DataSource source = new DataSource(ARFF_FILE_PATH);
Instances data = source.getDataSet();
Attribute drawDateAttribute = data.attribute("drwNoDate");
if (drawDateAttribute == null) {
throw new IllegalArgumentException("Attribute 'drwNoDate' not found in ARFF file.");
}
boolean isDuplicate = false;
int formattedDrawDate = dataResponse.getFormattedDrawDate();
for (Instance instance : data) {
if ((int) instance.value(drawDateAttribute) == formattedDrawDate) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
double[] instanceValues = new double[data.numAttributes()];
instanceValues[0] = dataResponse.getData();
instanceValues[2] = formattedDrawDate;
Instance newInstance = new DenseInstance(1.0, instanceValues);
data.add(newInstance);
ArffSaver saver = new ArffSaver();
saver.setInstances(data);
saver.setFile(new File("src/main/resources/" + ARFF_FILE_PATH));
saver.writeBatch();
System.out.println("ARFF file updated with draw date: " + dataResponse.getDrwNoDate());
return true;
} else {
System.out.println("Duplicate draw date detected: " + dataResponse.getDrwNoDate());
return false;
}
}
@Scheduled(cron = "0 0 2 ? * SUN")
public void updateDataArff() throws Exception {
int latestDrawNo = dataUpdateService.getLatestDrawNo();
while (true) {
DataResponse latestDataInfo = dataUpdateService.getDataInfoByDrawNumber(latestDrawNo);
if (latestDataInfo == null || !"success".equals(latestDataInfo.getReturnValue())) {
System.out.println("No more data to fetch. Stopping at draw number: " + latestDrawNo);
dataUpdateService.saveLatestDrawNo(latestDrawNo - 1);
break;
}
boolean updated = wekaService.updateArffFile(latestDataInfo);
dataUpdateService.saveLatestDrawNo(latestDrawNo);
if (updated) {
System.out.println("Updated draw number: " + latestDrawNo);
}
latestDrawNo++;
}
}