Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

학급 open api batch로 가져오기 #40

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dependencies {
runtimeOnly("com.mysql:mysql-connector-j")

// mongodb
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
// implementation("org.springframework.boot:spring-boot-starter-data-mongodb")

// security
implementation("org.springframework.boot:spring-boot-starter-security")
Expand Down Expand Up @@ -85,6 +85,7 @@ dependencies {

// webclient
implementation("org.springframework.boot:spring-boot-starter-webflux")

//JSON
implementation("org.json:json:20231013")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.asap.asapbackend.batch.classroom

import com.asap.asapbackend.domain.classroom.domain.model.Classroom
import com.asap.asapbackend.domain.school.domain.model.School

interface ClassroomInfoProvider {
fun retrieveClassroomInfo(batchSize: Int, startIndex: Int): ClassroomDataContainer

data class ClassroomDataContainer(
val classroomInfo: List<ClassroomInfo>,
val hasNext: Boolean
)

data class ClassroomInfo(
val school: School,
val grade: Int,
val classNumber: String
) {
fun toClassroom(): Classroom {
return Classroom(
school = school,
grade = grade,
className = classNumber
)
}
}
}

fun List<ClassroomInfoProvider.ClassroomInfo>.toClassrooms(): List<Classroom> {
return this.map { it.toClassroom() }
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package com.asap.asapbackend.batch.classroom

import com.asap.asapbackend.domain.classroom.domain.service.ClassroomAppender
import com.asap.asapbackend.global.util.TransactionUtils
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.stereotype.Component

@RestController
@Component
class ClassroomScheduler(
private val classroomService: ClassroomService
private val classroomInfoProvider: ClassroomInfoProvider,
private val classroomAppender: ClassroomAppender
) {
@Scheduled(cron = "0 0 4 1 3 ?") // 매년 3월 1일 04:00:00에 실행
@GetMapping("/addClassroom")
fun addClassroom(){
classroomService.addClassroom()
@Scheduled(cron = "0 5 4 1 3 ?") // 매년 3월 1일 04:05:00에 실행
fun addClassroom() {
val batchSize = 100
var startIndex = 0
do {
val classroomDataContainer = classroomInfoProvider.retrieveClassroomInfo(batchSize, startIndex)

startIndex += batchSize

TransactionUtils.writable {
classroomAppender.addClassroom(classroomDataContainer.classroomInfo.toClassrooms())
}
} while (classroomDataContainer.hasNext)
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.asap.asapbackend.batch.school

import com.asap.asapbackend.client.openapi.school.dto.SchoolInfo
import com.asap.asapbackend.domain.school.domain.model.School

interface SchoolInfoProvider {
Expand All @@ -16,8 +15,8 @@ interface SchoolInfoProvider {
val eduOfficeCode: String, //ATPT_OFCDC_SC_CODE
val schoolCode: String, //SD_SCHUL_CODE
val school: String, //SCHUL_NM
val address:String //ORG_RDNMA
){
val address: String //ORG_RDNMA
) {
fun toSchool(): School {
return School(
eduOfficeCode = eduOfficeCode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,18 @@ package com.asap.asapbackend.batch.school

import com.asap.asapbackend.domain.school.domain.service.SchoolAppender
import com.asap.asapbackend.global.util.TransactionUtils
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component

private val logger = KotlinLogging.logger {}

@Component
class SchoolScheduler(
private val schoolInfoProvider: SchoolInfoProvider,
private val schoolAppender: SchoolAppender
) {
@Scheduled(cron = "0 0 4 1 3 ?") // 매년 3월 1일 04:00:00에 실행
// @Scheduled(fixedRate = 500000) // 500초마다 실행
fun addSchool() {
val batchSize = 100
var startIndex = 1
logger.info { "start scheduler" }
do {
val schoolDataContainer = schoolInfoProvider.retrieveSchoolInfo(batchSize, startIndex)

Expand All @@ -27,6 +22,6 @@ class SchoolScheduler(
TransactionUtils.writable {
schoolAppender.appendUniqueSchool(schoolDataContainer.schoolInfo.toSchools())
}
}while (schoolDataContainer.hasNext)
} while (schoolDataContainer.hasNext)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.asap.asapbackend.client.openapi.classroom

import com.asap.asapbackend.batch.classroom.ClassroomInfoProvider
import com.asap.asapbackend.client.openapi.classroom.dto.ClassroomOpenApiResponse
import com.asap.asapbackend.domain.school.domain.repository.SchoolRepository
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.util.UriBuilder
import java.time.Year

@Component
class ClassroomOpenApiClient(
private val schoolRepository: SchoolRepository
) : ClassroomInfoProvider {
override fun retrieveClassroomInfo(batchSize: Int, startIndex: Int): ClassroomInfoProvider.ClassroomDataContainer {
var endIndex = startIndex + batchSize
val hasNext = schoolRepository.count() > endIndex
if (!hasNext) {
endIndex = schoolRepository.count().toInt()
}
val schools = schoolRepository.findAll().subList(startIndex, endIndex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findall()보다는 page나 커서기반으로 조회하자
모든 데이터를 다 조회하면 성능이 매우 안좋을것같아

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

page로 가져오면 다음 데이터가 있는지 hasNext 프로퍼티가 있어서 위에 hasNext 구하기 위한 쿼리는 없애자

Copy link
Member Author

@sominyun sominyun May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿굿 이런 리뷰 조타
page 단위로 조회하는걸로 수정완
커서랑 페이징 중에 페이징이 메모리 적게 쓴다길래 페이징으로 해봤는데 별로면 말해줘~

val classroomInfoList: MutableList<ClassroomInfoProvider.ClassroomInfo> = mutableListOf()
schools.forEach { school ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 forEach보다는 map을 사용해서 바로 List<ClassroomInfoProvider.ClassroomInfo>로 바꾸는거는 어때

val apiUrl = "https://open.neis.go.kr/hub/classInfo"
val classroomInfoResult = WebClient.create(apiUrl).get()
.uri { uriBuilder: UriBuilder ->
uriBuilder
.queryParam("KEY", "32e897d4054342b19fd68dfb1b9ba621")
.queryParam("ATPT_OFCDC_SC_CODE", school.eduOfficeCode)
.queryParam("SD_SCHUL_CODE", school.schoolCode)
.queryParam("AY", Year.now())
.queryParam("Type", "json")
.build()
}
.retrieve()
.bodyToMono(String::class.java)
.map {
jacksonObjectMapper().readValue(it, ClassroomOpenApiResponse::class.java)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 spring objectmapper 사용하자

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바꿨어~

}
.block()
classroomInfoResult?.classInfo?.forEach { classInfo ->
classInfo.row?.let { rows ->
classroomInfoList.addAll(rows.map { it.toClassroomInfo(school) })
}
}
}
return ClassroomInfoProvider.ClassroomDataContainer(
classroomInfo = classroomInfoList,
hasNext = hasNext
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.asap.asapbackend.client.openapi.classroom.dto

import com.asap.asapbackend.batch.classroom.ClassroomInfoProvider
import com.asap.asapbackend.domain.school.domain.model.School

data class ClassroomOpenApiResponse(
val classInfo: List<ClassInfo>?,
val RESULT: Result?
)

data class ClassInfo(
val head: List<Head>?,
val row: List<Row>?
)

data class Head(
val list_total_count: Int?,
val RESULT: Result?
)

data class Result(
val CODE: String,
val MESSAGE: String
)

data class Row(
val ATPT_OFCDC_SC_CODE: String?,
val ATPT_OFCDC_SC_NM: String?,
val SD_SCHUL_CODE: String?,
val SCHUL_NM: String?,
val AY: String?,
val GRADE: Int,
val DGHT_CRSE_SC_NM: String?,
val SCHUL_CRSE_SC_NM: String?,
val ORD_SC_NM: String?,
val DDDEP_NM: String?,
val CLASS_NM: String,
val LOAD_DTM: String?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용 안하는 필드는 제거하는거 어떄

) {
fun toClassroomInfo(school: School): ClassroomInfoProvider.ClassroomInfo {
return ClassroomInfoProvider.ClassroomInfo(
school,
GRADE,
CLASS_NM
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient

@Component
class SchoolOpenApiClient : SchoolInfoProvider{
override fun retrieveSchoolInfo(batchSize: Int, startIndex: Int): SchoolInfoProvider.SchoolDataContainer{
class SchoolOpenApiClient : SchoolInfoProvider {
override fun retrieveSchoolInfo(batchSize: Int, startIndex: Int): SchoolInfoProvider.SchoolDataContainer {
val endIndex = startIndex + batchSize
val apiUrl = "http://openapi.seoul.go.kr:8088/4b78477274736f6d36386d505a614b/json/neisSchoolInfoJS/$startIndex/$endIndex"
val schoolInfoResult = WebClient.create(apiUrl).get()
.retrieve()
.bodyToMono(SchoolOpenApiResponse::class.java)
.block()
val neisSchoolInfoJS = schoolInfoResult?.neisSchoolInfoJS
val hasNext = (schoolInfoResult?.neisSchoolInfoJS?.list_total_count ?: 0) > endIndex
val hasNext = (neisSchoolInfoJS?.list_total_count ?: 0) > endIndex
return SchoolInfoProvider.SchoolDataContainer(
schoolInfo = neisSchoolInfoJS?.row?.map { it.toSchoolInfo() } ?: emptyList(),
hasNext = hasNext
Expand Down
Loading
Loading