diff --git a/.gitignore b/.gitignore index 9de0e37..e17772e 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,9 @@ nb-configuration.xml ## Miscellaneous ############################## *.log + +############################## +## Production +############################## +src/main/resources/application-prod-db.yml +src/main/resources/application-jwt.yml diff --git a/build.gradle b/build.gradle index 18efdfa..4416840 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ repositories { } dependencies { + implementation 'com.opencsv:opencsv:5.5.2' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' @@ -38,6 +39,7 @@ dependencies { runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6' + implementation 'com.mysql:mysql-connector-j:9.1.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' @@ -48,4 +50,4 @@ dependencies { tasks.named('test') { useJUnitPlatform() -} +} \ No newline at end of file diff --git a/scripts/deploy.sh b/scripts/deploy.sh index cc6a3f2..8e195ce 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -6,7 +6,7 @@ APP_NAME=gamsa cd $REPOSITORY echo "> 현재 구동 중인 애플리케이션 pid 확인" -CURRENT_PID=$(pgrep -f ${APP_NAME}-*.jar) +CURRENT_PID=$(lsof -i :8080 -t) echo "> 현재 구동 중인 애플리케이션 pid: $CURRENT_PID" if [ -z "$CURRENT_PID" ]; then @@ -18,7 +18,7 @@ else fi echo "> 새 애플리케이션 배포" -JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1) +JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | head -n 1) echo "> JAR Name: $JAR_NAME" @@ -26,4 +26,7 @@ echo "> $JAR_NAME에 실행권한 추가" chmod +x $JAR_NAME echo "> $JAR_NAME 실행" -nohup java -jar $REPOSITORY/$JAR_NAME --spring.profiles.active=prod 2>&1 & \ No newline at end of file +nohup java -jar \ + -Dspring.config.location=/home/ubuntu/prod/application-prod-db.yml,/home/ubuntu/prod/application-jwt.yml \ + -Dspring.profiles.active=prod \ + $REPOSITORY/$JAR_NAME 2>&1 & \ No newline at end of file diff --git a/src/main/java/com/gamsa/Application.java b/src/main/java/com/gamsa/Application.java index 1ac8a46..a5a8742 100644 --- a/src/main/java/com/gamsa/Application.java +++ b/src/main/java/com/gamsa/Application.java @@ -4,14 +4,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableScheduling; @ConfigurationPropertiesScan @EnableJpaAuditing +@EnableScheduling @SpringBootApplication public class Application { - public static void main(String[] args) { SpringApplication.run(Application.class, args); } - } diff --git a/src/main/java/com/gamsa/activity/domain/District.java b/src/main/java/com/gamsa/activity/domain/District.java index 9379f12..d8982fb 100644 --- a/src/main/java/com/gamsa/activity/domain/District.java +++ b/src/main/java/com/gamsa/activity/domain/District.java @@ -3,6 +3,8 @@ import lombok.Builder; import lombok.Getter; +import java.math.BigDecimal; + @Getter @Builder public class District { @@ -11,5 +13,7 @@ public class District { private int sidoCode; private String sidoName; private String gunguName; + private BigDecimal latitude; + private BigDecimal longitude; private boolean sido; } diff --git a/src/main/java/com/gamsa/activity/dto/ActivityApiResponse.java b/src/main/java/com/gamsa/activity/dto/ActivityApiResponse.java new file mode 100644 index 0000000..0d86386 --- /dev/null +++ b/src/main/java/com/gamsa/activity/dto/ActivityApiResponse.java @@ -0,0 +1,62 @@ +package com.gamsa.activity.dto; + +import com.gamsa.activity.constant.Category; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; + +@Getter +@Builder +@RequiredArgsConstructor +public class ActivityApiResponse { + + private final Long actId; + private final String actTitle; + private final String actLocation; + private final String description; + private final LocalDateTime noticeStartDate; + private final LocalDateTime noticeEndDate; + private final LocalDateTime actStartDate; + private final LocalDateTime actEndDate; + private final int actStartTime; + private final int actEndTime; + private final int recruitTotalNum; + private final boolean adultPossible; + private final boolean teenPossible; + private final boolean groupPossible; + private final int actWeek; + private final String actManager; + private final String actPhone; + private final String url; + private final Category category; + private final String instituteName; + private final Integer sidoGunguCode; + + public ActivitySaveRequest toSaveRequest(long instituteId) { + return ActivitySaveRequest.builder() + .actId(actId) + .actTitle(actTitle) + .actLocation(actLocation) + .description(description) + .noticeStartDate(noticeStartDate) + .noticeEndDate(noticeEndDate) + .actStartDate(actStartDate) + .actEndDate(actEndDate) + .actStartTime(actStartTime) + .actEndTime(actEndTime) + .recruitTotalNum(recruitTotalNum) + .adultPossible(adultPossible) + .teenPossible(teenPossible) + .groupPossible(groupPossible) + .actWeek(actWeek) + .actManager(actManager) + .actPhone(actPhone) + .url(url) + .category(category) + .instituteId(instituteId) + .sidoGunguCode(sidoGunguCode) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gamsa/activity/dto/DistrictSaveRequest.java b/src/main/java/com/gamsa/activity/dto/DistrictSaveRequest.java index 6217fdd..d85f732 100644 --- a/src/main/java/com/gamsa/activity/dto/DistrictSaveRequest.java +++ b/src/main/java/com/gamsa/activity/dto/DistrictSaveRequest.java @@ -1,28 +1,35 @@ package com.gamsa.activity.dto; import com.gamsa.activity.domain.District; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.math.BigDecimal; + @Getter @Builder -@RequiredArgsConstructor +@AllArgsConstructor public class DistrictSaveRequest { private final int sidoGunguCode; private final int sidoCode; private final String sidoName; private final String gunguName; + private BigDecimal latitude; + private BigDecimal longitude; private final boolean sido; public District toModel() { return District.builder() - .sidoGunguCode(sidoGunguCode) - .sidoCode(sidoCode) - .sidoName(sidoName) - .gunguName(gunguName) - .sido(sido) - .build(); + .sidoGunguCode(sidoGunguCode) + .sidoCode(sidoCode) + .sidoName(sidoName) + .gunguName(gunguName) + .latitude(latitude) + .longitude(longitude) + .sido(sido) + .build(); } } diff --git a/src/main/java/com/gamsa/activity/dto/InstituteApiResponse.java b/src/main/java/com/gamsa/activity/dto/InstituteApiResponse.java new file mode 100644 index 0000000..72a5179 --- /dev/null +++ b/src/main/java/com/gamsa/activity/dto/InstituteApiResponse.java @@ -0,0 +1,35 @@ +package com.gamsa.activity.dto; + +import com.gamsa.activity.domain.District; +import com.gamsa.activity.domain.Institute; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.math.BigDecimal; +import java.util.Map; + +@Getter +@Builder +@AllArgsConstructor +public class InstituteApiResponse { + + private String name; + private String location; + private int sidoCode; + private int sidoGunguCode; + private String phone; + + public InstituteSaveRequest toSaveRequest(Map coordinates) { + return InstituteSaveRequest.builder() + .name(name) + .location(location) + .sidoCode(sidoCode) + .sidoGunguCode(sidoGunguCode) + .longitude(coordinates.get("longitude")) + .latitude(coordinates.get("latitude")) + .phone(phone) + .build(); + } +} diff --git a/src/main/java/com/gamsa/activity/dto/InstituteSaveRequest.java b/src/main/java/com/gamsa/activity/dto/InstituteSaveRequest.java index 630cc48..8577dae 100644 --- a/src/main/java/com/gamsa/activity/dto/InstituteSaveRequest.java +++ b/src/main/java/com/gamsa/activity/dto/InstituteSaveRequest.java @@ -5,6 +5,7 @@ import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter @Builder diff --git a/src/main/java/com/gamsa/activity/entity/DistrictJpaEntity.java b/src/main/java/com/gamsa/activity/entity/DistrictJpaEntity.java index d66c64e..8d72266 100644 --- a/src/main/java/com/gamsa/activity/entity/DistrictJpaEntity.java +++ b/src/main/java/com/gamsa/activity/entity/DistrictJpaEntity.java @@ -6,11 +6,9 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; + +import java.math.BigDecimal; @Getter @Builder @@ -27,6 +25,12 @@ public class DistrictJpaEntity extends BaseEntity { @Column(name = "sido_code", nullable = false) private int sidoCode; + @Column(name = "latitude") + private BigDecimal latitude; + + @Column(name = "longitude") + private BigDecimal longitude; + @Column(name = "sido_name", length = 15, nullable = false) private String sidoName; @@ -38,21 +42,21 @@ public class DistrictJpaEntity extends BaseEntity { public static DistrictJpaEntity from(District district) { return DistrictJpaEntity.builder() - .sidoGunguCode(district.getSidoGunguCode()) - .sidoCode(district.getSidoCode()) - .sidoName(district.getSidoName()) - .gunguName(district.getGunguName()) - .sido(district.isSido()) - .build(); + .sidoGunguCode(district.getSidoGunguCode()) + .sidoCode(district.getSidoCode()) + .sidoName(district.getSidoName()) + .gunguName(district.getGunguName()) + .sido(district.isSido()) + .build(); } public District toModel() { return District.builder() - .sidoGunguCode(getSidoGunguCode()) - .sidoCode(getSidoCode()) - .sidoName(getSidoName()) - .gunguName(getGunguName()) - .sido(isSido()) - .build(); + .sidoGunguCode(getSidoGunguCode()) + .sidoCode(getSidoCode()) + .sidoName(getSidoName()) + .gunguName(getGunguName()) + .sido(isSido()) + .build(); } } diff --git a/src/main/java/com/gamsa/activity/service/DistrictService.java b/src/main/java/com/gamsa/activity/service/DistrictService.java index bcc853e..11ce1f3 100644 --- a/src/main/java/com/gamsa/activity/service/DistrictService.java +++ b/src/main/java/com/gamsa/activity/service/DistrictService.java @@ -1,11 +1,15 @@ package com.gamsa.activity.service; import com.gamsa.activity.constant.ActivityErrorCode; +import com.gamsa.activity.domain.District; import com.gamsa.activity.dto.DistrictFindAllResponse; import com.gamsa.activity.dto.DistrictSaveRequest; import com.gamsa.activity.exception.ActivityException; import com.gamsa.activity.repository.DistrictRepository; -import java.util.List; + +import java.math.BigDecimal; +import java.util.*; + import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -44,4 +48,13 @@ public List findAllGungu() { .map(DistrictFindAllResponse::from) .toList(); } + + public Map findCoordinates(int gunguCode) { + District find = districtRepository.findBySidoGunguCode(gunguCode) + .orElseThrow(NoSuchElementException::new); + Map coordinates = new HashMap<>(); + coordinates.put("longitude", find.getLongitude()); + coordinates.put("latitude", find.getLatitude()); + return coordinates; + } } diff --git a/src/main/java/com/gamsa/activity/service/InstituteService.java b/src/main/java/com/gamsa/activity/service/InstituteService.java index 7849c43..e0f1779 100644 --- a/src/main/java/com/gamsa/activity/service/InstituteService.java +++ b/src/main/java/com/gamsa/activity/service/InstituteService.java @@ -27,4 +27,8 @@ public void save(InstituteSaveRequest saveRequest) { instituteRepository.save(saveRequest.toModel(district)); } + + public Long findByName(String name) { + return instituteRepository.findByName(name).orElseThrow(() -> new ActivityException(ActivityErrorCode.INSTITUTE_NOT_EXISTS)).getInstituteId(); + } } diff --git a/src/main/java/com/gamsa/dataupdate/DataUpdateErrorCode.java b/src/main/java/com/gamsa/dataupdate/DataUpdateErrorCode.java new file mode 100644 index 0000000..f24851f --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/DataUpdateErrorCode.java @@ -0,0 +1,25 @@ +package com.gamsa.dataupdate; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum DataUpdateErrorCode { + // 1365 API 오류 + OPENAPI_NOT_RESPOND(504, "Open API가 응답하지 않습니다."), + OPENAPI_ERROR(504, "Open API의 반환 값을 처리할 수 없습니다."), + + + // 카카오 API 오류 + KAKAOLOCALAPI_NOT_RESPOND(504, "카카오 API가 정상적으로 응답하지 않습니다."), + KAKAOLOCALAPT_ERROR(504, "카카오 API의 반환 값을 처리할 수 없습니다."), + + // 내부 처리 오류 + INVALID_CSV(500, "주어진 CSV 파일을 처리할 수 없습니다"), + INVALID_FILE_SOURCE(500, "주어진 파일 경로가 올바르지 않습니다."); + + + private final int ststus; + private final String msg; +} diff --git a/src/main/java/com/gamsa/dataupdate/DataUpdateException.java b/src/main/java/com/gamsa/dataupdate/DataUpdateException.java new file mode 100644 index 0000000..a1ee8cd --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/DataUpdateException.java @@ -0,0 +1,10 @@ +package com.gamsa.dataupdate; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class DataUpdateException extends RuntimeException { + private final DataUpdateErrorCode errorCode; +} diff --git a/src/main/java/com/gamsa/dataupdate/DataUpdateScheduler.java b/src/main/java/com/gamsa/dataupdate/DataUpdateScheduler.java new file mode 100644 index 0000000..2ae1229 --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/DataUpdateScheduler.java @@ -0,0 +1,26 @@ +package com.gamsa.dataupdate; + +import com.gamsa.dataupdate.service.ActivityDataUpdateService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; + +@Component +@RequiredArgsConstructor +public class DataUpdateScheduler { + private final ActivityDataUpdateService activityDataUpdateService; + + @Value("${spring.openapi.days}") + private int days; + + @Scheduled(cron = "0 1 0 * * *") + public void runActivityDataUpdate() { + LocalDate today = LocalDate.now(); + LocalDate endDate = today.plusDays(days); + + activityDataUpdateService.update(today, endDate); + } +} diff --git a/src/main/java/com/gamsa/dataupdate/service/ActivityDataUpdateService.java b/src/main/java/com/gamsa/dataupdate/service/ActivityDataUpdateService.java new file mode 100644 index 0000000..27568d8 --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/service/ActivityDataUpdateService.java @@ -0,0 +1,48 @@ +package com.gamsa.dataupdate.service; + +import com.gamsa.activity.dto.ActivitySaveRequest; +import com.gamsa.activity.dto.InstituteSaveRequest; +import com.gamsa.activity.service.ActivityService; +import com.gamsa.activity.service.DistrictService; +import com.gamsa.activity.service.InstituteService; +import com.gamsa.dataupdate.utils.ActivityDataUtils; +import com.gamsa.dataupdate.utils.KakaoLocalUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.List; + +@RequiredArgsConstructor +@Service +public class ActivityDataUpdateService { + private final ActivityService activityService; + private final ActivityDataUtils activityDataUtils; + private final KakaoLocalUtils kakaoLocalUtils; + + DistrictService districtService; + InstituteService instituteService; + + public void update(LocalDate startDate, LocalDate endDate) { + List programList = activityDataUtils.getVolunteerParticipationList(startDate, endDate); + + List saveRequests = programList.stream() + .map(activityDataUtils::getInstituteApiResponse) + .map(instituteApiResponse -> { + return instituteApiResponse.toSaveRequest(kakaoLocalUtils.getCoordinateByAddress(instituteApiResponse.getLocation()) + .orElse(districtService.findCoordinates(instituteApiResponse.getSidoGunguCode()))); + }) + .toList(); + + saveRequests.forEach(instituteService::save); + + List activitySaveRequests = programList.stream() + .map(activityDataUtils::getVolunteerDetail) + .map(activityApiResponse -> { + return activityApiResponse.toSaveRequest(instituteService.findByName(activityApiResponse.getInstituteName())); + }) + .toList(); + + activitySaveRequests.forEach(activityService::save); + } +} \ No newline at end of file diff --git a/src/main/java/com/gamsa/dataupdate/service/DistrictDataUpdateService.java b/src/main/java/com/gamsa/dataupdate/service/DistrictDataUpdateService.java new file mode 100644 index 0000000..f0b6261 --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/service/DistrictDataUpdateService.java @@ -0,0 +1,70 @@ +package com.gamsa.dataupdate.service; + +import com.gamsa.activity.dto.DistrictSaveRequest; +import com.gamsa.activity.service.DistrictService; +import com.gamsa.dataupdate.DataUpdateErrorCode; +import com.gamsa.dataupdate.DataUpdateException; +import com.opencsv.CSVReader; +import com.opencsv.exceptions.CsvValidationException; +import jakarta.annotation.PostConstruct; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigDecimal; + +@Service +@Component +@RequiredArgsConstructor +public class DistrictDataUpdateService { + private final DistrictService districtService; + + @Value("{data.csvpath}") + private String csvPath; + + @PostConstruct + public void DistrictInit() { + if (!isDataChanged()) loadDataFromCSV(csvPath); + } + + private boolean isDataChanged() { + // 나중에 file 변경에 따른 로직으로 수정 + return (districtService.findAllGungu().isEmpty()) + && (districtService.findAllSido().isEmpty()); + } + + @Transactional + public void loadDataFromCSV(String csvPath) { + try { + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(csvPath).getFile()); + FileReader fileReader = new FileReader(file); + CSVReader csvReader = new CSVReader(fileReader); + + csvReader.readNext(); + String[] nextRecord; + while ((nextRecord = csvReader.readNext()) != null) { + DistrictSaveRequest districtSaveRequest = DistrictSaveRequest.builder() + .sidoGunguCode(Integer.getInteger(nextRecord[0])) + .sidoCode(Integer.getInteger(nextRecord[1])) + .sidoName(nextRecord[2]) + .gunguName(nextRecord[3]) + .latitude(new BigDecimal(nextRecord[4])) + .longitude(new BigDecimal(nextRecord[5])) + .sido(Boolean.parseBoolean(nextRecord[6])) + .build(); + + districtService.save(districtSaveRequest); + } + } catch (IOException e) { + throw new DataUpdateException(DataUpdateErrorCode.INVALID_FILE_SOURCE); + } catch (CsvValidationException e) { + throw new DataUpdateException(DataUpdateErrorCode.INVALID_CSV); + } + } +} diff --git a/src/main/java/com/gamsa/dataupdate/utils/ActivityDataUtils.java b/src/main/java/com/gamsa/dataupdate/utils/ActivityDataUtils.java new file mode 100644 index 0000000..8ff1018 --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/utils/ActivityDataUtils.java @@ -0,0 +1,205 @@ +package com.gamsa.dataupdate.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gamsa.activity.constant.Category; +import com.gamsa.activity.dto.ActivityApiResponse; +import com.gamsa.activity.dto.InstituteApiResponse; +import com.gamsa.dataupdate.DataUpdateErrorCode; +import com.gamsa.dataupdate.DataUpdateException; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class ActivityDataUtils { + @Value(value = "${openapi.key}") + private String openapiKey; + + @Value(value = "${openapi.url}") + private String openapiUrl; + + @Value(value = "${openapi.volurl}") + private String volUrl; + + private final RestTemplate restTemplate = new RestTemplate(); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + + public List getVolunteerParticipationList(LocalDate startDate, LocalDate endDate) { + + String url = openapiUrl + "/getVltrPeriodSrvcList"; + + List volunteerList = new ArrayList<>(); + + int numOfItem = 20; + int pageNo = 1; + + while (numOfItem != 0) { + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url) + .queryParam("ServiceKey", openapiKey) + .queryParam("progrmBgnde", startDate.format(formatter)) + .queryParam("progrmEndde", endDate.format(formatter)) + .queryParam("numOfRows", 20) + .queryParam("pageNo", pageNo); + + ResponseEntity response = restTemplate.getForEntity(uriBuilder.toUriString(), String.class); + + if (response.getStatusCode().is2xxSuccessful()) { + try { + String jsonContent = response.getBody(); + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(jsonContent); + + JsonNode itemsNode = rootNode.path("response").path("body").path("items"); + + numOfItem = itemsNode.size(); + + for (JsonNode item : itemsNode) { + String programNo = item.path("progrmRegistNo").asText(); + volunteerList.add(programNo); + } + + pageNo++; + + } catch (Exception e) { + System.out.println(e.getMessage()); + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_ERROR); + } + } else { + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_NOT_RESPOND); + } + } + + return volunteerList; + } + + public InstituteApiResponse getInstituteApiResponse(String programNo) { + String url = openapiUrl + "/getVltrPartcptnItem"; + + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url) + .queryParam("ServiceKey", openapiKey) + .queryParam("progrmRegistNo", programNo); + + ResponseEntity response = restTemplate.getForEntity(uriBuilder.toUriString(), String.class); + + if (response.getStatusCode().is2xxSuccessful()) { + try { + String jsonContent = response.getBody(); + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(jsonContent); + + JsonNode item = rootNode.path("response").path("body").path("items").path("item"); + + System.out.println(item); + InstituteApiResponse instituteApiResponse = InstituteApiResponse.builder() + .name(item.path("mnnstNm").asText()) + .location(item.path("postAdres").asText()) + .sidoCode(item.path("sidoCd").asInt()) + .sidoGunguCode(item.path("gugunCd").asInt()) + .phone(item.path("telno").asText()) + .build(); + + return instituteApiResponse; + + } catch (Exception e) { + System.out.println(e.getMessage()); + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_ERROR); + } + } else { + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_NOT_RESPOND); + } + } + + public ActivityApiResponse getVolunteerDetail(String programNo) { + String url = openapiUrl + "/getVltrPartcptnItem"; + + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url) + .queryParam("ServiceKey", openapiKey) + .queryParam("progrmRegistNo", programNo); + + ResponseEntity response = restTemplate.getForEntity(uriBuilder.toUriString(), String.class); + + if (response.getStatusCode().is2xxSuccessful()) { + try { + String jsonContent = response.getBody(); + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(jsonContent); + + JsonNode item = rootNode.path("response").path("body").path("items").path("item"); + + ActivityApiResponse activityApiResponse = ActivityApiResponse.builder() + .actId((long) item.path("progrmRegistNo").asInt()) + .actTitle(item.path("progrmSj").asText()) + .actLocation(item.path("actPlace").asText()) + .description(item.path("progrmCn").asText()) + .noticeStartDate(LocalDate.parse(String.valueOf(item.path("noticeBgnde").asInt()), formatter).atStartOfDay()) + .noticeEndDate(LocalDate.parse(String.valueOf(item.path("noticeEndde").asInt()), formatter).atStartOfDay()) + .actStartDate(LocalDate.parse(String.valueOf(item.path("progrmBgnde").asInt()), formatter).atStartOfDay()) + .actEndDate(LocalDate.parse(String.valueOf(item.path("progrmBgnde").asInt()), formatter).atStartOfDay()) + .actStartTime(item.path("actBeginTm").asInt()) + .actEndTime(item.path("actEndTm").asInt()) + .recruitTotalNum(item.path("rcritNmpr").asInt()) + .adultPossible(item.path("adultPosblAt").asText() == "Y" ? true : false) + .teenPossible(item.path("yngbgsPosblAt").asText() == "Y" ? true : false) + .groupPossible(item.path("grpPosblAt").asText() == "Y" ? true : false) + .actWeek(item.path("actWkdy").asInt()) + .actManager(item.path("nanmmbyNmAdmn").asText()) + .actPhone(item.path("telno").asText()) + .url(volUrl + item.path("progrmRegistNo").asText()) + .instituteName(item.path("mnnstNm").asText()) + .category(getCategory(item.path("srvcClCode").asText())) + .sidoGunguCode(item.path("gugunCd").asInt()) + + .build(); + + return activityApiResponse; + + } catch (Exception e) { + System.out.println(e.getMessage()); + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_ERROR); + } + } else { + System.out.println("Error: " + response.getStatusCode()); + throw new DataUpdateException(DataUpdateErrorCode.OPENAPI_NOT_RESPOND); + } + } + + private Category getCategory(String text) { + if ((text.contains("생활편의지원")) + || text.contains("주거환경") + || text.contains("농어촌 봉사")) { + return Category.LIFE_SUPPORT_AND_HOUSING_IMPROVEMENT; + } else if ((text.contains("교육")) + || text.contains("멘토링")) { + return Category.EDUCATION_AND_MENTORING; + } else if (text.contains("행정보조")) { + return Category.ADMINISTRATIVE_AND_OFFICE_SUPPORT; + } else if ((text.contains("문화행사")) + || text.contains("환경보호") + || text.contains("국제협력") + || text.contains("안전.예방")) { + return Category.CULTURE_ENVIRONMENT_AND_INTERNATIONAL_COOPERATION; + } else if ((text.contains("보건의료")) + || text.contains("공익.인권")) { + return Category.HEALTHCARE_AND_PUBLIC_WELFARE; + } else if ((text.contains("상담")) + || text.contains("자원봉사교육")) { + return Category.COUNSELING_AND_VOLUNTEER_TRAINING; + } else { + return Category.OTHER_ACTIVITIES; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gamsa/dataupdate/utils/KakaoLocalUtils.java b/src/main/java/com/gamsa/dataupdate/utils/KakaoLocalUtils.java new file mode 100644 index 0000000..ca42e83 --- /dev/null +++ b/src/main/java/com/gamsa/dataupdate/utils/KakaoLocalUtils.java @@ -0,0 +1,59 @@ +package com.gamsa.dataupdate.utils; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Component +public class KakaoLocalUtils { + + @Value("${kakao.localkey}") + private String kakaoKey; + + private final RestTemplate restTemplate = new RestTemplate(); + + public Optional> getCoordinateByAddress(String address) { + // 요청 URL 생성 + String url = "https://dapi.kakao.com/v2/local/search/address.json?query=" + address; + // 헤더 설정 + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "KakaoAK " + kakaoKey); + + // HTTP 요청 + HttpEntity entity = new HttpEntity<>(headers); + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.GET, entity, Map.class); + + // 응답 처리 + if (response.getStatusCode().is2xxSuccessful()) { + Map result = response.getBody(); + if (result != null && result.containsKey("documents")) { + // 첫 번째 결과의 x, y 좌표 반환 + var documents = (List>) result.get("documents"); + if (!documents.isEmpty()) { + Map firstDoc = documents.getFirst(); + BigDecimal x = new BigDecimal(firstDoc.get("x").toString()); + BigDecimal y = new BigDecimal(firstDoc.get("y").toString()); + + Map coordinates = new HashMap<>(); + coordinates.put("longitude", x); + coordinates.put("latitude", y); + return Optional.of(coordinates); + } + } + } + + System.out.println("API 요청 실패: " + response.getStatusCode()); + return Optional.empty(); + } +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index e69de29..6f7cd83 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,10 @@ +spring: + config: + import: + - application-jwt.yml + - application-prod-db.yml + +logging: + level: + org: + hibernate: info diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e75c3d5..e2c4134 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -6,3 +6,14 @@ spring: kakao: user-info-url: https://kapi.kakao.com/v2/user/me + localkey: + +data: + csvpath: "district_and_coordinate_kr.csv" + +openapi: + key: + url: "http://openapi.1365.go.kr/openapi/service/rest/VolunteerPartcptnService/" + volurl: "https://www.1365.go.kr/vols/1572247904127/partcptn/timeCptn.do?type=show&progrmRegistNo=" + days: 7 + diff --git a/src/main/resources/district_and_coordinate_kr.csv b/src/main/resources/district_and_coordinate_kr.csv new file mode 100644 index 0000000..e00fee1 --- /dev/null +++ b/src/main/resources/district_and_coordinate_kr.csv @@ -0,0 +1,441 @@ +sidoGunguCode,sidoCode,sidoName,gunguName,latitude,longitude,sido +3000000,6110000,서울특별시,종로구,37.59491732,126.9773213,FALSE +3410000,6270000,대구광역시,중구,37.56014356,126.9959681,FALSE +3650000,6300000,대전광역시,중구,37.56014356,126.9959681,FALSE +3250000,6260000,부산광역시,중구,37.56014356,126.9959681,FALSE +3010000,6110000,서울특별시,중구,37.56014356,126.9959681,FALSE +3690000,6310000,울산광역시,중구,37.56014356,126.9959681,FALSE +3490000,6280000,인천광역시,중구,37.56014356,126.9959681,FALSE +3410000,6270000,대구광역시,중구,35.10547776,129.0315402,FALSE +3650000,6300000,대전광역시,중구,35.10547776,129.0315402,FALSE +3250000,6260000,부산광역시,중구,35.10547776,129.0315402,FALSE +3010000,6110000,서울특별시,중구,35.10547776,129.0315402,FALSE +3690000,6310000,울산광역시,중구,35.10547776,129.0315402,FALSE +3490000,6280000,인천광역시,중구,35.10547776,129.0315402,FALSE +3410000,6270000,대구광역시,중구,35.86653529,128.5936058,FALSE +3650000,6300000,대전광역시,중구,35.86653529,128.5936058,FALSE +3250000,6260000,부산광역시,중구,35.86653529,128.5936058,FALSE +3010000,6110000,서울특별시,중구,35.86653529,128.5936058,FALSE +3690000,6310000,울산광역시,중구,35.86653529,128.5936058,FALSE +3490000,6280000,인천광역시,중구,35.86653529,128.5936058,FALSE +3410000,6270000,대구광역시,중구,37.46753391,126.4805605,FALSE +3650000,6300000,대전광역시,중구,37.46753391,126.4805605,FALSE +3250000,6260000,부산광역시,중구,37.46753391,126.4805605,FALSE +3010000,6110000,서울특별시,중구,37.46753391,126.4805605,FALSE +3690000,6310000,울산광역시,중구,37.46753391,126.4805605,FALSE +3490000,6280000,인천광역시,중구,37.46753391,126.4805605,FALSE +3410000,6270000,대구광역시,중구,36.28086015,127.4110573,FALSE +3650000,6300000,대전광역시,중구,36.28086015,127.4110573,FALSE +3250000,6260000,부산광역시,중구,36.28086015,127.4110573,FALSE +3010000,6110000,서울특별시,중구,36.28086015,127.4110573,FALSE +3690000,6310000,울산광역시,중구,36.28086015,127.4110573,FALSE +3490000,6280000,인천광역시,중구,36.28086015,127.4110573,FALSE +3410000,6270000,대구광역시,중구,35.57104934,129.3082429,FALSE +3650000,6300000,대전광역시,중구,35.57104934,129.3082429,FALSE +3250000,6260000,부산광역시,중구,35.57104934,129.3082429,FALSE +3010000,6110000,서울특별시,중구,35.57104934,129.3082429,FALSE +3690000,6310000,울산광역시,중구,35.57104934,129.3082429,FALSE +3490000,6280000,인천광역시,중구,35.57104934,129.3082429,FALSE +3020000,6110000,서울특별시,용산구,37.53138497,126.979907,FALSE +3030000,6110000,서울특별시,성동구,37.55102969,127.0410585,FALSE +3040000,6110000,서울특별시,광진구,37.54670608,127.0857435,FALSE +3050000,6110000,서울특별시,동대문구,37.58195655,127.0548481,FALSE +3060000,6110000,서울특별시,중랑구,37.59780259,127.0928803,FALSE +3070000,6110000,서울특별시,성북구,37.6057019,127.0175795,FALSE +3080000,6110000,서울특별시,강북구,37.64347391,127.011189,FALSE +3090000,6110000,서울특별시,도봉구,37.66910208,127.0323688,FALSE +3100000,6110000,서울특별시,노원구,37.65251105,127.0750347,FALSE +3110000,6110000,서울특별시,은평구,37.61921128,126.9270229,FALSE +3120000,6110000,서울특별시,서대문구,37.57778531,126.9390631,FALSE +3130000,6110000,서울특별시,마포구,37.55931349,126.90827,FALSE +3140000,6110000,서울특별시,양천구,37.52478941,126.8554777,FALSE +3360000,6260000,부산광역시,강서구,37.56123543,126.822807,FALSE +3150000,6110000,서울특별시,강서구,37.56123543,126.822807,FALSE +3360000,6260000,부산광역시,강서구,35.13834787,128.8924006,FALSE +3150000,6110000,서울특별시,강서구,35.13834787,128.8924006,FALSE +3160000,6110000,서울특별시,구로구,37.49440543,126.8563006,FALSE +3170000,6110000,서울특별시,금천구,37.46056756,126.9008202,FALSE +3180000,6110000,서울특별시,영등포구,37.52230829,126.9101695,FALSE +3190000,6110000,서울특별시,동작구,37.49887688,126.9516415,FALSE +3200000,6110000,서울특별시,관악구,37.46737569,126.9453372,FALSE +3210000,6110000,서울특별시,서초구,37.47329547,127.0312203,FALSE +3220000,6110000,서울특별시,강남구,37.49664389,127.0629852,FALSE +3230000,6110000,서울특별시,송파구,37.50561924,127.115295,FALSE +3240000,6110000,서울특별시,강동구,37.55045024,127.1470118,FALSE +3600000,6290000,광주광역시,서구,35.10383663,129.0149537,FALSE +3430000,6270000,대구광역시,서구,35.10383663,129.0149537,FALSE +3660000,6300000,대전광역시,서구,35.10383663,129.0149537,FALSE +3260000,6260000,부산광역시,서구,35.10383663,129.0149537,FALSE +3560000,6280000,인천광역시,서구,35.10383663,129.0149537,FALSE +3600000,6290000,광주광역시,서구,35.87500167,128.5496976,FALSE +3430000,6270000,대구광역시,서구,35.87500167,128.5496976,FALSE +3660000,6300000,대전광역시,서구,35.87500167,128.5496976,FALSE +3260000,6260000,부산광역시,서구,35.87500167,128.5496976,FALSE +3560000,6280000,인천광역시,서구,35.87500167,128.5496976,FALSE +3600000,6290000,광주광역시,서구,37.55780443,126.6563778,FALSE +3430000,6270000,대구광역시,서구,37.55780443,126.6563778,FALSE +3660000,6300000,대전광역시,서구,37.55780443,126.6563778,FALSE +3260000,6260000,부산광역시,서구,37.55780443,126.6563778,FALSE +3560000,6280000,인천광역시,서구,37.55780443,126.6563778,FALSE +3600000,6290000,광주광역시,서구,35.13569311,126.8507191,FALSE +3430000,6270000,대구광역시,서구,35.13569311,126.8507191,FALSE +3660000,6300000,대전광역시,서구,35.13569311,126.8507191,FALSE +3260000,6260000,부산광역시,서구,35.13569311,126.8507191,FALSE +3560000,6280000,인천광역시,서구,35.13569311,126.8507191,FALSE +3600000,6290000,광주광역시,서구,36.28023963,127.3451041,FALSE +3430000,6270000,대구광역시,서구,36.28023963,127.3451041,FALSE +3660000,6300000,대전광역시,서구,36.28023963,127.3451041,FALSE +3260000,6260000,부산광역시,서구,36.28023963,127.3451041,FALSE +3560000,6280000,인천광역시,서구,36.28023963,127.3451041,FALSE +3590000,6290000,광주광역시,동구,35.12918632,129.0445856,FALSE +3420000,6270000,대구광역시,동구,35.12918632,129.0445856,FALSE +3640000,6300000,대전광역시,동구,35.12918632,129.0445856,FALSE +3270000,6260000,부산광역시,동구,35.12918632,129.0445856,FALSE +3710000,6310000,울산광역시,동구,35.12918632,129.0445856,FALSE +3500000,6280000,인천광역시,동구,35.12918632,129.0445856,FALSE +3590000,6290000,광주광역시,동구,35.93442633,128.6856599,FALSE +3420000,6270000,대구광역시,동구,35.93442633,128.6856599,FALSE +3640000,6300000,대전광역시,동구,35.93442633,128.6856599,FALSE +3270000,6260000,부산광역시,동구,35.93442633,128.6856599,FALSE +3710000,6310000,울산광역시,동구,35.93442633,128.6856599,FALSE +3500000,6280000,인천광역시,동구,35.93442633,128.6856599,FALSE +3590000,6290000,광주광역시,동구,37.48298658,126.6397466,FALSE +3420000,6270000,대구광역시,동구,37.48298658,126.6397466,FALSE +3640000,6300000,대전광역시,동구,37.48298658,126.6397466,FALSE +3270000,6260000,부산광역시,동구,37.48298658,126.6397466,FALSE +3710000,6310000,울산광역시,동구,37.48298658,126.6397466,FALSE +3500000,6280000,인천광역시,동구,37.48298658,126.6397466,FALSE +3590000,6290000,광주광역시,동구,35.11738023,126.9494643,FALSE +3420000,6270000,대구광역시,동구,35.11738023,126.9494643,FALSE +3640000,6300000,대전광역시,동구,35.11738023,126.9494643,FALSE +3270000,6260000,부산광역시,동구,35.11738023,126.9494643,FALSE +3710000,6310000,울산광역시,동구,35.11738023,126.9494643,FALSE +3500000,6280000,인천광역시,동구,35.11738023,126.9494643,FALSE +3590000,6290000,광주광역시,동구,36.32392023,127.4750374,FALSE +3420000,6270000,대구광역시,동구,36.32392023,127.4750374,FALSE +3640000,6300000,대전광역시,동구,36.32392023,127.4750374,FALSE +3270000,6260000,부산광역시,동구,36.32392023,127.4750374,FALSE +3710000,6310000,울산광역시,동구,36.32392023,127.4750374,FALSE +3500000,6280000,인천광역시,동구,36.32392023,127.4750374,FALSE +3590000,6290000,광주광역시,동구,35.52557365,129.4260655,FALSE +3420000,6270000,대구광역시,동구,35.52557365,129.4260655,FALSE +3640000,6300000,대전광역시,동구,35.52557365,129.4260655,FALSE +3270000,6260000,부산광역시,동구,35.52557365,129.4260655,FALSE +3710000,6310000,울산광역시,동구,35.52557365,129.4260655,FALSE +3500000,6280000,인천광역시,동구,35.52557365,129.4260655,FALSE +3280000,6260000,부산광역시,영도구,35.07868795,129.0648096,FALSE +3290000,6260000,부산광역시,부산진구,35.16524411,129.0430603,FALSE +3300000,6260000,부산광역시,동래구,35.20621244,129.0792201,FALSE +3610000,6290000,광주광역시,남구,35.12613679,129.0940064,FALSE +3440000,6270000,대구광역시,남구,35.12613679,129.0940064,FALSE +3310000,6260000,부산광역시,남구,35.12613679,129.0940064,FALSE +3700000,6310000,울산광역시,남구,35.12613679,129.0940064,FALSE +3510000,6280000,인천광역시,남구,35.12613679,129.0940064,FALSE +3610000,6290000,광주광역시,남구,35.83517716,128.5853296,FALSE +3440000,6270000,대구광역시,남구,35.83517716,128.5853296,FALSE +3310000,6260000,부산광역시,남구,35.83517716,128.5853296,FALSE +3700000,6310000,울산광역시,남구,35.83517716,128.5853296,FALSE +3510000,6280000,인천광역시,남구,35.83517716,128.5853296,FALSE +3610000,6290000,광주광역시,남구,37.45259578,126.6646585,FALSE +3440000,6270000,대구광역시,남구,37.45259578,126.6646585,FALSE +3310000,6260000,부산광역시,남구,37.45259578,126.6646585,FALSE +3700000,6310000,울산광역시,남구,37.45259578,126.6646585,FALSE +3510000,6280000,인천광역시,미추홀구,37.45259578,126.6646585,FALSE +3610000,6290000,광주광역시,남구,35.09405825,126.8567181,FALSE +3440000,6270000,대구광역시,남구,35.09405825,126.8567181,FALSE +3310000,6260000,부산광역시,남구,35.09405825,126.8567181,FALSE +3700000,6310000,울산광역시,남구,35.09405825,126.8567181,FALSE +3510000,6280000,인천광역시,남구,35.09405825,126.8567181,FALSE +3610000,6290000,광주광역시,남구,35.51604996,129.3282023,FALSE +3440000,6270000,대구광역시,남구,35.51604996,129.3282023,FALSE +3310000,6260000,부산광역시,남구,35.51604996,129.3282023,FALSE +3700000,6310000,울산광역시,남구,35.51604996,129.3282023,FALSE +3510000,6280000,인천광역시,남구,35.51604996,129.3282023,FALSE +3620000,6290000,광주광역시,북구,35.22922961,129.0234398,FALSE +3450000,6270000,대구광역시,북구,35.22922961,129.0234398,FALSE +3320000,6260000,부산광역시,북구,35.22922961,129.0234398,FALSE +3720000,6310000,울산광역시,북구,35.22922961,129.0234398,FALSE +3620000,6290000,광주광역시,북구,35.92892237,128.5772044,FALSE +3450000,6270000,대구광역시,북구,35.92892237,128.5772044,FALSE +3320000,6260000,부산광역시,북구,35.92892237,128.5772044,FALSE +3720000,6310000,울산광역시,북구,35.92892237,128.5772044,FALSE +3620000,6290000,광주광역시,북구,35.19324611,126.9254865,FALSE +3450000,6270000,대구광역시,북구,35.19324611,126.9254865,FALSE +3320000,6260000,부산광역시,북구,35.19324611,126.9254865,FALSE +3720000,6310000,울산광역시,북구,35.19324611,126.9254865,FALSE +3620000,6290000,광주광역시,북구,35.61005392,129.3798105,FALSE +3450000,6270000,대구광역시,북구,35.61005392,129.3798105,FALSE +3320000,6260000,부산광역시,북구,35.61005392,129.3798105,FALSE +3720000,6310000,울산광역시,북구,35.61005392,129.3798105,FALSE +3330000,6260000,부산광역시,해운대구,35.19385339,129.1535934,FALSE +3340000,6260000,부산광역시,사하구,35.0893484,128.974349,FALSE +3350000,6260000,부산광역시,금정구,35.25889074,129.0915307,FALSE +3370000,6260000,부산광역시,연제구,35.18241798,129.0829353,FALSE +3380000,6260000,부산광역시,수영구,35.16133146,129.1111627,FALSE +3390000,6260000,부산광역시,사상구,35.15803037,128.9865922,FALSE +3400000,6260000,부산광역시,기장군,35.29801166,129.200956,FALSE +3460000,6270000,대구광역시,수성구,35.83384886,128.6612744,FALSE +3470000,6270000,대구광역시,달서구,35.8274831,128.5292121,FALSE +3480000,6270000,대구광역시,달성군,35.75957305,128.4982981,FALSE +3520000,6280000,인천광역시,연수구,37.39856402,126.6473033,FALSE +3530000,6280000,인천광역시,남동구,37.43134886,126.726461,FALSE +3540000,6280000,인천광역시,부평구,37.49665874,126.7212094,FALSE +3550000,6280000,인천광역시,계양구,37.55729696,126.7346999,FALSE +3570000,6280000,인천광역시,강화군,37.71244395,126.4020881,FALSE +3580000,6280000,인천광역시,옹진군,37.54401126,125.6360222,FALSE +3630000,6290000,광주광역시,광산구,35.16503502,126.7528952,FALSE +3670000,6300000,대전광역시,유성구,36.37679049,127.3332564,FALSE +3680000,6300000,대전광역시,대덕구,36.41217868,127.4401518,FALSE +3730000,6310000,울산광역시,울주군,35.54661673,129.1869255,FALSE +3750000,3740000,경기도,수원시 장안구,37.31396569,127.0034517,FALSE +3760000,3740000,경기도,수원시 권선구,37.26053016,126.9797438,FALSE +3770000,3740000,경기도,수원시 팔달구,37.27746363,127.0162387,FALSE +5610000,3740000,경기도,수원시 영통구,37.27499039,127.0566989,FALSE +3790000,3780000,경기도,성남시 수정구,37.43516624,127.1041452,FALSE +3800000,3780000,경기도,성남시 중원구,37.43343323,127.1639099,FALSE +3810000,3780000,경기도,성남시 분당구,37.37930157,127.106064,FALSE +3820000,6410000,경기도,의정부시,37.73619211,127.0684231,FALSE +3830000,6410000,경기도,안양시,37.40413345,126.9113856,FALSE +3840000,3830000,경기도,안양시 만안구,37.40413345,126.9113856,FALSE +3850000,3830000,경기도,안양시 동안구,37.40039183,126.9555027,FALSE +3860000,6410000,경기도,부천시,37.50425833,126.7887109,FALSE +3900000,6410000,경기도,광명시,37.44515907,126.8647013,FALSE +3910000,6410000,경기도,평택시,37.01183071,126.9877007,FALSE +3920000,6410000,경기도,동두천시,37.91653761,127.0779127,FALSE +5550000,3930000,경기도,안산시 상록구,37.31600383,126.870815,FALSE +5560000,3930000,경기도,안산시 단원구,37.28192491,126.6940412,FALSE +3960000,3940000,경기도,고양시 일산구,37.67986514,126.7975582,FALSE +3950000,3940000,경기도,고양시 덕양구,37.65580987,126.8786321,FALSE +3960100,3940000,경기도,고양시 일산동구,37.67986514,126.7975582,FALSE +4100100,3940000,경기도,고양시 일산서구,37.68020512,126.7279835,FALSE +3970000,6410000,경기도,과천시,37.43384529,127.0026795,FALSE +3980000,6410000,경기도,구리시,37.59922149,127.1312299,FALSE +3990000,6410000,경기도,남양주시,37.66252981,127.2436606,FALSE +4000000,6410000,경기도,오산시,37.16329068,127.0513297,FALSE +4010000,6410000,경기도,시흥시,37.38939741,126.7883928,FALSE +4020000,6410000,경기도,군포시,37.34348269,126.9211347,FALSE +4030000,6410000,경기도,의왕시,37.36238774,126.9896255,FALSE +4040000,6410000,경기도,하남시,37.52281418,127.2059438,FALSE +4050000,6410000,경기도,용인시,37.2033319,127.2529331,FALSE +5620000,4050000,경기도,용인시 처인구,37.2033319,127.2529331,FALSE +5630000,4050000,경기도,용인시 기흥구,37.26742665,127.1213215,FALSE +5640000,4050000,경기도,용인시 수지구,37.33344743,127.0715511,FALSE +4060000,6410000,경기도,파주시,37.85619198,126.8107502,FALSE +4070000,6410000,경기도,이천시,37.20977588,127.4810141,FALSE +4080000,6410000,경기도,안성시,37.03502705,127.3027223,FALSE +4090000,6410000,경기도,김포시,37.68177237,126.6264306,FALSE +5530000,6410000,경기도,화성시,37.16523661,126.8748585,FALSE +5540000,6410000,경기도,광주시,37.40309074,127.301176,FALSE +5590000,6410000,경기도,양주시,37.80865756,127.0011349,FALSE +5600000,6410000,경기도,포천시,37.96977801,127.2503373,FALSE +5700000,6410000,경기도,여주시,37.30245842,127.6157373,FALSE +4140000,6410000,경기도,연천군,38.09272995,127.0244564,FALSE +4160000,6410000,경기도,가평군,37.81843317,127.4501921,FALSE +4170000,6410000,경기도,양평군,37.51805585,127.5792645,FALSE +4181000,6530000,강원특별자치도,춘천시,37.88979679,127.7398684,FALSE +4191000,6530000,강원특별자치도,원주시,37.30822288,127.9295253,FALSE +4201000,6530000,강원특별자치도,강릉시,37.70910197,128.8323789,FALSE +4211000,6530000,강원특별자치도,동해시,37.5066814,129.0555688,FALSE +4221000,6530000,강원특별자치도,태백시,37.17231241,128.9800726,FALSE +4231000,6530000,강원특별자치도,속초시,38.17603138,128.519541,FALSE +4241000,6530000,강원특별자치도,삼척시,37.27748089,129.12171,FALSE +4251000,6530000,강원특별자치도,홍천군,37.74504907,128.0742609,FALSE +4261000,6530000,강원특별자치도,횡성군,37.50914207,128.0770674,FALSE +4271000,6530000,강원특별자치도,영월군,37.20411361,128.500296,FALSE +4281000,6530000,강원특별자치도,평창군,37.55683921,128.48259,FALSE +4291000,6530000,강원특별자치도,정선군,37.37868629,128.7390632,FALSE +4301000,6530000,강원특별자치도,철원군,38.23908523,127.3989244,FALSE +4311000,6530000,강원특별자치도,화천군,38.13842628,127.6851657,FALSE +4321000,6530000,강원특별자치도,양구군,38.17560879,128.0002064,FALSE +4331000,6530000,강원특별자치도,인제군,38.06460026,128.2647272,FALSE +4341000,6530000,강원특별자치도,고성군,38.36275363,128.4111555,FALSE +5420000,6480000,경상남도,고성군,38.36275363,128.4111555,FALSE +4341000,6530000,강원특별자치도,고성군,35.01630447,128.2906632,FALSE +5420000,6480000,경상남도,고성군,35.01630447,128.2906632,FALSE +4351000,6530000,강원특별자치도,양양군,38.00448634,128.5950086,FALSE +5720000,6430000,충청북도,청주시 상당구,36.59211242,127.5848802,FALSE +4370000,4360000,충청북도,청주시 상당구,36.59211242,127.5848802,FALSE +5725000,6430000,충청북도,청주시 서원구,36.54726305,127.4384007,FALSE +5730000,6430000,충청북도,청주시 흥덕구,36.64696076,127.3692749,FALSE +4380000,4360000,충청북도,청주시 흥덕구,36.64696076,127.3692749,FALSE +5735000,6430000,충청북도,청주시 청원구,36.72057891,127.4913176,FALSE +4390000,6430000,충청북도,충주시,37.01519694,127.8956623,FALSE +4400000,6430000,충청북도,제천시,37.05991183,128.1409593,FALSE +4420000,6430000,충청북도,보은군,36.48994959,127.7293357,FALSE +4430000,6430000,충청북도,옥천군,36.32045611,127.6565589,FALSE +4440000,6430000,충청북도,영동군,36.15965896,127.8142281,FALSE +5570000,6430000,충청북도,증평군,36.78647301,127.6046181,FALSE +4450000,6430000,충청북도,진천군,36.87099952,127.4404636,FALSE +4460000,6430000,충청북도,괴산군,36.76965903,127.8295881,FALSE +4470000,6430000,충청북도,음성군,36.97622261,127.6142068,FALSE +4480000,6430000,충청북도,단양군,36.99445276,128.3878416,FALSE +4490000,6440000,충청남도,천안시,36.76411722,127.2208946,FALSE +5650000,4490000,충청남도,천안시 동남구,36.76411722,127.2208946,FALSE +5660000,4490000,충청남도,천안시 서북구,36.89271067,127.1618094,FALSE +4500000,6440000,충청남도,공주시,36.47981976,127.0752191,FALSE +4510000,6440000,충청남도,보령시,36.34024523,126.594247,FALSE +4520000,6440000,충청남도,아산시,36.80731633,126.9800756,FALSE +4530000,6440000,충청남도,서산시,36.78399346,126.4636016,FALSE +4540000,6440000,충청남도,논산시,36.19088691,127.1577164,FALSE +5580000,6440000,충청남도,계룡시,36.2915937,127.2344266,FALSE +5680000,6440000,충청남도,당진시,36.90325778,126.6527445,FALSE +4550000,6440000,충청남도,금산군,36.11900081,127.4783119,FALSE +4570000,6440000,충청남도,부여군,36.2463839,126.8569676,FALSE +4580000,6440000,충청남도,서천군,36.10517212,126.7079805,FALSE +4590000,6440000,충청남도,청양군,36.43058296,126.8531131,FALSE +4600000,6440000,충청남도,홍성군,36.57009431,126.6258536,FALSE +4610000,6440000,충청남도,예산군,36.67062867,126.7843109,FALSE +4620000,6440000,충청남도,태안군,36.7036613,126.2809571,FALSE +4641000,6540000,전북특별자치도,전주시,35.79209428,127.1195036,FALSE +4651000,4641000,전북특별자치도,전주시 완산구,35.79209428,127.1195036,FALSE +4661000,4641000,전북특별자치도,전주시 덕진구,35.85870118,127.1129157,FALSE +4671000,6540000,전북특별자치도,군산시,35.95043894,126.7260152,FALSE +4681000,6540000,전북특별자치도,익산시,36.02310555,126.9895102,FALSE +4691000,6540000,전북특별자치도,정읍시,35.60262466,126.9058575,FALSE +4701000,6540000,전북특별자치도,남원시,35.4225448,127.4418897,FALSE +4711000,6540000,전북특별자치도,김제시,35.80671644,126.8948857,FALSE +4721000,6540000,전북특별자치도,완주군,35.91861444,127.2151146,FALSE +4731000,6540000,전북특별자치도,진안군,35.82880745,127.4300354,FALSE +4741000,6540000,전북특별자치도,무주군,35.93936736,127.7129531,FALSE +4751000,6540000,전북특별자치도,장수군,35.65746098,127.5442641,FALSE +4761000,6540000,전북특별자치도,임실군,35.59820204,127.2366472,FALSE +4771000,6540000,전북특별자치도,순창군,35.4336343,127.090087,FALSE +4781000,6540000,전북특별자치도,고창군,35.44816757,126.6160462,FALSE +4791000,6540000,전북특별자치도,부안군,35.6779229,126.6443774,FALSE +4800000,6460000,전라남도,목포시,34.80376416,126.3918353,FALSE +4810000,6460000,전라남도,여수시,34.69617175,127.6532031,FALSE +4820000,6460000,전라남도,순천시,34.99474506,127.3891627,FALSE +4830000,6460000,전라남도,나주시,34.9885894,126.7204103,FALSE +4840000,6460000,전라남도,광양시,35.0219785,127.6550735,FALSE +4850000,6460000,전라남도,담양군,35.2914951,126.9952909,FALSE +4860000,6460000,전라남도,곡성군,35.21661355,127.2635825,FALSE +4870000,6460000,전라남도,구례군,35.23676622,127.5031193,FALSE +4880000,6460000,전라남도,고흥군,34.59848495,127.3146205,FALSE +4890000,6460000,전라남도,보성군,34.8143749,127.1621214,FALSE +4900000,6460000,전라남도,화순군,35.00818573,127.0334335,FALSE +4910000,6460000,전라남도,장흥군,34.67653701,126.9215323,FALSE +4920000,6460000,전라남도,강진군,34.62046495,126.7721517,FALSE +4930000,6460000,전라남도,해남군,34.5458247,126.5217898,FALSE +4940000,6460000,전라남도,영암군,34.79956672,126.6306945,FALSE +4950000,6460000,전라남도,무안군,34.95320449,126.4259079,FALSE +4960000,6460000,전라남도,함평군,35.11267054,126.5356041,FALSE +4970000,6460000,전라남도,영광군,35.27848603,126.4531293,FALSE +4980000,6460000,전라남도,장성군,35.32956437,126.7684949,FALSE +4990000,6460000,전라남도,완도군,34.29557933,126.7768069,FALSE +5000000,6460000,전라남도,진도군,34.43939638,126.2150578,FALSE +5010000,6460000,전라남도,신안군,34.81240654,126.048907,FALSE +5030000,5020000,경상북도,포항시 남구,35.95813526,129.4376545,FALSE +5040000,5020000,경상북도,포항시 북구,36.16507327,129.234009,FALSE +5050000,6470000,경상북도,경주시,35.8266428,129.2359296,FALSE +5060000,6470000,경상북도,김천시,36.06042386,128.0777075,FALSE +5070000,6470000,경상북도,안동시,36.58024221,128.7800427,FALSE +5080000,6470000,경상북도,구미시,36.20730964,128.3555555,FALSE +5090000,6470000,경상북도,영주시,36.8704754,128.5976826,FALSE +5100000,6470000,경상북도,영천시,36.01577844,128.942624,FALSE +5110000,6470000,경상북도,상주시,36.42950234,128.067007,FALSE +5120000,6470000,경상북도,문경시,36.69079151,128.1486082,FALSE +5130000,6470000,경상북도,경산시,35.83406007,128.8090552,FALSE +5140000,6470000,경상북도,군위군,36.17011208,128.6482246,FALSE +5141000,6270000,대구광역시,군위군,36.17011208,128.6482246,FALSE +5150000,6470000,경상북도,의성군,36.36204451,128.6150673,FALSE +5160000,6470000,경상북도,청송군,36.35697643,129.0573852,FALSE +5170000,6470000,경상북도,영양군,36.69638883,129.1450305,FALSE +5180000,6470000,경상북도,영덕군,36.48238769,129.3173762,FALSE +5190000,6470000,경상북도,청도군,35.67297478,128.786527,FALSE +5200000,6470000,경상북도,고령군,35.73719712,128.3067337,FALSE +5210000,6470000,경상북도,성주군,35.90722342,128.2333931,FALSE +5220000,6470000,경상북도,칠곡군,36.01551131,128.4625838,FALSE +5230000,6470000,경상북도,예천군,36.65384527,128.422384,FALSE +5240000,6470000,경상북도,봉화군,36.93414016,128.9129004,FALSE +5250000,6470000,경상북도,울진군,36.90391313,129.3123186,FALSE +5260000,6470000,경상북도,울릉군,37.50194192,130.864243,FALSE +5670123,5670000,경상남도,창원시 의창구,35.30894896,128.6495884,FALSE +5670140,5670000,경상남도,창원시 성산구,35.19618568,128.6721044,FALSE +5670156,5670000,경상남도,창원시 마산합포구,35.13545806,128.4852558,FALSE +5670184,5670000,경상남도,창원시 마산회원구,35.23222659,128.5364332,FALSE +5670206,5670000,경상남도,창원시 진해구,35.12994945,128.7363008,FALSE +5310000,6480000,경상남도,진주시,35.20515765,128.1298011,FALSE +5330000,6480000,경상남도,통영시,34.82932843,128.3740775,FALSE +5340000,6480000,경상남도,사천시,35.04970341,128.0376963,FALSE +5350000,6480000,경상남도,김해시,35.27215642,128.8452158,FALSE +5360000,6480000,경상남도,밀양시,35.4984997,128.7896015,FALSE +5370000,6480000,경상남도,거제시,34.8704352,128.6231395,FALSE +5380000,6480000,경상남도,양산시,35.40188821,129.0410414,FALSE +5390000,6480000,경상남도,의령군,35.39243102,128.2770578,FALSE +5400000,6480000,경상남도,함안군,35.29100281,128.4308769,FALSE +5410000,6480000,경상남도,창녕군,35.50822773,128.4930519,FALSE +5430000,6480000,경상남도,남해군,34.81829098,127.9411405,FALSE +5440000,6480000,경상남도,하동군,35.13830463,127.779049,FALSE +5450000,6480000,경상남도,산청군,35.36859736,127.8843379,FALSE +5460000,6480000,경상남도,함양군,35.55160171,127.7220411,FALSE +5470000,6480000,경상남도,거창군,35.73255219,127.9041696,FALSE +5480000,6480000,경상남도,합천군,35.57657745,128.1415437,FALSE +5490000,6490000,제주도,제주시,33.44220188,126.5292476,FALSE +6510000,6500000,제주특별자치도,제주시,33.44220188,126.5292476,FALSE +5500000,6490000,제주도,서귀포시,33.32504027,126.5810857,FALSE +6520000,6500000,제주특별자치도,서귀포시,33.32504027,126.5810857,FALSE +6530000,6530000,강원특별자치도,강원특별자치도,37.71904264,128.3008969,TRUE +6410000,6410000,경기도,경기도,37.53434923,127.1810501,TRUE +6480000,6480000,경상남도,경상남도,35.32449891,128.2611748,TRUE +6470000,6470000,경상북도,경상북도,36.34862579,128.748716,TRUE +6290000,6290000,광주광역시,광주광역시,35.15572822,126.8354348,TRUE +6270000,6270000,대구광역시,대구광역시,35.8298146,128.5653587,TRUE +6300000,6300000,대전광역시,대전광역시,36.3397636,127.3940388,TRUE +6260000,6260000,부산광역시,부산광역시,35.21033858,129.0691138,TRUE +6110000,6110000,서울특별시,서울특별시,37.55191813,126.9918238,TRUE +5690000,5690000,세종특별자치시,세종특별자치시,36.56072897,127.258722,TRUE +6310000,6310000,울산광역시,울산광역시,35.55422196,129.237579,TRUE +6280000,6280000,인천광역시,인천광역시,37.58457102,126.3755151,TRUE +6460000,6460000,전라남도,전라남도,34.87817002,126.9052332,TRUE +6540000,6540000,전북특별자치도,전북특별자치도,35.71581062,127.1427384,TRUE +6490000,6490000,제주도,제주도,33.38699923,126.5538395,TRUE +6500000,6500000,제주특별자치도,제주특별자치도,33.38699923,126.5538395,TRUE +6440000,6440000,충청남도,충청남도,36.52940199,126.8497393,TRUE +6430000,6430000,충청북도,충청북도,36.73877678,127.8313457,TRUE +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +5710000,6430000,충청북도,청주시,,, +6430140,6430000,충청북도,증평출장소,,, +4410000,6430000,충청북도,청원군,,, diff --git a/src/test/java/com/gamsa/dataupdate/ActivityDataUtilsTest.java b/src/test/java/com/gamsa/dataupdate/ActivityDataUtilsTest.java new file mode 100644 index 0000000..fcf92b7 --- /dev/null +++ b/src/test/java/com/gamsa/dataupdate/ActivityDataUtilsTest.java @@ -0,0 +1,55 @@ +package com.gamsa.dataupdate; + +import com.gamsa.activity.constant.Category; +import com.gamsa.dataupdate.utils.ActivityDataUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +public class ActivityDataUtilsTest { + + @Autowired + private ActivityDataUtils activityDataUtils; + + @Test + void 기간별_활동_리스트_조회() { + //given + LocalDate today = LocalDate.now(); + LocalDate endDate = today.plusDays(7); + + //when + var list = activityDataUtils.getVolunteerParticipationList(today, endDate); + + //then + assertThat(list.size()).isNotZero(); + } + + @Test + void 기관_상세_조회() { + //given + String programNo = "3168803"; + + //when + var result = activityDataUtils.getInstituteApiResponse(programNo); + + //then + assertThat(result.getName()).isEqualTo("음성효심주간보호센터"); + } + + @Test + void 활동_상세_조회() { + //given + String programNo = "3168803"; + + //when + var result = activityDataUtils.getVolunteerDetail(programNo); + + //then + assertThat(result.getCategory()).isEqualTo(Category.CULTURE_ENVIRONMENT_AND_INTERNATIONAL_COOPERATION); + } +} diff --git a/src/test/java/com/gamsa/dataupdate/DataUpdateSchedulerTest.java b/src/test/java/com/gamsa/dataupdate/DataUpdateSchedulerTest.java new file mode 100644 index 0000000..b7d25b4 --- /dev/null +++ b/src/test/java/com/gamsa/dataupdate/DataUpdateSchedulerTest.java @@ -0,0 +1,43 @@ +package com.gamsa.dataupdate; + +import com.gamsa.dataupdate.service.ActivityDataUpdateService; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; + +@SpringBootTest +public class DataUpdateSchedulerTest { + + @Autowired + private DataUpdateScheduler dataUpdateScheduler; + + @MockBean + private ActivityDataUpdateService activityDataUpdateService; + + @Test + public void 업데이트_메서드_동작() { + //given + int days = 7; + + //when + dataUpdateScheduler.runActivityDataUpdate(); + + //then + ArgumentCaptor captor = ArgumentCaptor.forClass(LocalDate.class); + verify(activityDataUpdateService).update(captor.capture(), captor.capture()); + + LocalDate today = LocalDate.now(); + LocalDate expectedEndDate = today.plusDays(days); + + assertThat(captor.getAllValues()) + .hasSize(2) + .containsExactly(today, expectedEndDate); + } +} \ No newline at end of file diff --git a/src/test/java/com/gamsa/dataupdate/KakaoLocalUtilsTest.java b/src/test/java/com/gamsa/dataupdate/KakaoLocalUtilsTest.java new file mode 100644 index 0000000..46ced13 --- /dev/null +++ b/src/test/java/com/gamsa/dataupdate/KakaoLocalUtilsTest.java @@ -0,0 +1,28 @@ +package com.gamsa.dataupdate; + +import com.gamsa.dataupdate.utils.KakaoLocalUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +public class KakaoLocalUtilsTest { + + @Autowired + private KakaoLocalUtils kakaoLocalUtils; + + @Test + void 주소_검색_테스트() { + //given + String address = "경기 광주시 중앙로175번길 14 송정문화센터 2층"; + + //when + var result = kakaoLocalUtils.getCoordinateByAddress(address).orElseThrow(); + + //then + System.out.println(result); + assertThat(result).isNotNull(); + } +}