From 725687bd86dc0619823a74c213406c29cab8ba99 Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 12:26:44 +0900 Subject: [PATCH 01/10] update: application.yml --- src/main/resources/application.yml | 36 +++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a31f193..87fbd3e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,14 +1,10 @@ server: port: 8085 -eureka: - instance: - preferIpAddress: true - client: - registerWithEureka: true - fetchRegistry: true - serviceUrl: - defaultZone: http://${EUREKA_HOSTNAME:localhost}:8761/eureka/ +--- spring: + config: + activate: + on-profile: local application: name: gogo-sp main: @@ -24,5 +20,25 @@ spring: datasource: url: jdbc:mysql://${DB_URL:localhost:3306}/${DB_NAME:gogo-sp}?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true username: ${DB_USER:root} - password: ${DB_PASSWORD:1029384756} - driver-class-name: com.mysql.cj.jdbc.Driver \ No newline at end of file + password: ${DB_PASSWORD:12345} + driver-class-name: com.mysql.cj.jdbc.Driver + + data: + redis: + host: localhost + port: 6379 + +management: + endpoints: + web: + exposure: + include: ["prometheus", "info"] + +eureka: + instance: + preferIpAddress: true + client: + registerWithEureka: true + fetchRegistry: true + serviceUrl: + defaultZone: http://${EUREKA_HOSTNAME:localhost}:8761/eureka/ \ No newline at end of file From 8b01fb1843f25903e833a14db17bb103c8f3ebcc Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 12:27:01 +0900 Subject: [PATCH 02/10] add: isOpening column --- .../gogosp/domain/customer/root/persistence/CustomerInquiry.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt index a5ec739..8c0551c 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt @@ -21,5 +21,8 @@ class CustomerInquiry( @Column(name = "is_reading", nullable = false) val isReading: Boolean, + + @Column(name = "is_opening", nullable = false) + val isOpening: Boolean, ) { } \ No newline at end of file From daf40b71e06931b39745c7ddb6942f597ba37241 Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 12:27:25 +0900 Subject: [PATCH 03/10] add: writeCustomerInquiry API --- .../application/CustomerInquiryProcessor.kt | 26 +++++++++++++++++ .../application/CustomerInquiryService.kt | 7 +++++ .../application/CustomerInquiryServiceImpl.kt | 19 +++++++++++++ .../application/dto/CustomerInquiryDto.kt | 14 ++++++++++ .../presentation/CustomerInquiryController.kt | 28 +++++++++++++++++++ .../gogosp/global/config/SecurityConfig.kt | 4 +++ 6 files changed, 98 insertions(+) create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryProcessor.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryProcessor.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryProcessor.kt new file mode 100644 index 0000000..ba5bd46 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryProcessor.kt @@ -0,0 +1,26 @@ +package gogo.gogosp.domain.customer.root.application + +import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto +import gogo.gogosp.domain.customer.root.persistence.CustomerInquiry +import gogo.gogosp.domain.customer.root.persistence.CustomerInquiryRepository +import gogo.gogosp.global.internal.student.stub.StudentByIdStub +import org.springframework.stereotype.Component + +@Component +class CustomerInquiryProcessor( + private val customerInquiryRepository: CustomerInquiryRepository +) { + + fun saveCustomerInquiry(dto: WriteCustomerInquiryReqDto, student: StudentByIdStub) { + val customerInquiry = CustomerInquiry( + studentId = student.studentId, + title = dto.title, + content = dto.content, + isReading = false, + isOpening = dto.isOpening, + ) + + customerInquiryRepository.save(customerInquiry) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt new file mode 100644 index 0000000..18eebc1 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt @@ -0,0 +1,7 @@ +package gogo.gogosp.domain.customer.root.application + +import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto + +interface CustomerInquiryService { + fun writeInquiry(dto: WriteCustomerInquiryReqDto) +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt new file mode 100644 index 0000000..ee5be42 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt @@ -0,0 +1,19 @@ +package gogo.gogosp.domain.customer.root.application + +import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto +import gogo.gogosp.global.util.UserContextUtil +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class CustomerInquiryServiceImpl( + private val userUtil: UserContextUtil, + private val customerInquiryProcessor: CustomerInquiryProcessor +): CustomerInquiryService { + + @Transactional + override fun writeInquiry(dto: WriteCustomerInquiryReqDto) { + val student = userUtil.getCurrentStudent() + customerInquiryProcessor.saveCustomerInquiry(dto, student) + } +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt new file mode 100644 index 0000000..0471c77 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt @@ -0,0 +1,14 @@ +package gogo.gogosp.domain.customer.root.application.dto + +import jakarta.validation.constraints.Size +import org.jetbrains.annotations.NotNull + +data class WriteCustomerInquiryReqDto( + @NotNull + @Size(min = 1, max = 10) + val title: String, + @NotNull + val content: String, + @NotNull + val isOpening: Boolean, +) diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt new file mode 100644 index 0000000..9436f4d --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt @@ -0,0 +1,28 @@ +package gogo.gogosp.domain.customer.root.presentation + +import gogo.gogosp.domain.customer.root.application.CustomerInquiryService +import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto +import jakarta.validation.Valid +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/sp") +class CustomerInquiryController( + private val customerInquiryService: CustomerInquiryService +) { + + @PostMapping("/customer/inquiry") + fun writeInquiry( + @RequestBody @Valid dto: WriteCustomerInquiryReqDto + ): ResponseEntity { + customerInquiryService.writeInquiry(dto) + return ResponseEntity.status(HttpStatus.CREATED).build() + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt b/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt index 501d6c4..e414b8c 100644 --- a/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt +++ b/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt @@ -4,6 +4,7 @@ package gogo.gogosp.global.config import gogo.gogosp.global.filter.AuthenticationFilter import gogo.gogosp.global.handler.CustomAccessDeniedHandler import gogo.gogosp.global.handler.CustomAuthenticationEntryPointHandler +import gogo.gogosp.global.internal.user.stub.Authority import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.HttpMethod @@ -43,6 +44,9 @@ class SecurityConfig( http.authorizeHttpRequests { httpRequests -> httpRequests.requestMatchers(HttpMethod.GET, "/sp/health").permitAll() + + httpRequests.requestMatchers(HttpMethod.POST, "/sp/customer/inquiry").hasAnyRole(Authority.USER.name, Authority.STAFF.name) + httpRequests.anyRequest().denyAll() } From 65bd022a58062e58bbf671e4035f3ad9734cc8ea Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 17:49:10 +0900 Subject: [PATCH 04/10] update: StageException -> SpException class name update --- src/main/kotlin/gogo/gogosp/global/error/ErrorResponse.kt | 2 +- .../kotlin/gogo/gogosp/global/error/GlobalExceptionHandler.kt | 4 ++-- .../gogosp/global/error/{StageException.kt => SpException.kt} | 2 +- .../gogo/gogosp/global/feign/FeignClientErrorDecoder.kt | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/main/kotlin/gogo/gogosp/global/error/{StageException.kt => SpException.kt} (81%) diff --git a/src/main/kotlin/gogo/gogosp/global/error/ErrorResponse.kt b/src/main/kotlin/gogo/gogosp/global/error/ErrorResponse.kt index 76d0998..a6625f0 100644 --- a/src/main/kotlin/gogo/gogosp/global/error/ErrorResponse.kt +++ b/src/main/kotlin/gogo/gogosp/global/error/ErrorResponse.kt @@ -9,7 +9,7 @@ data class ErrorResponse( val status: Int ) { companion object { - fun of(e: StageException) = + fun of(e: SpException) = ErrorResponse( message = e.message, status = e.status diff --git a/src/main/kotlin/gogo/gogosp/global/error/GlobalExceptionHandler.kt b/src/main/kotlin/gogo/gogosp/global/error/GlobalExceptionHandler.kt index a5a1859..40c84be 100644 --- a/src/main/kotlin/gogo/gogosp/global/error/GlobalExceptionHandler.kt +++ b/src/main/kotlin/gogo/gogosp/global/error/GlobalExceptionHandler.kt @@ -12,8 +12,8 @@ import org.springframework.web.servlet.NoHandlerFoundException @RestControllerAdvice class GlobalExceptionHandler { - @ExceptionHandler(StageException::class) - fun userExceptionHandler(e: StageException): ResponseEntity = + @ExceptionHandler(SpException::class) + fun userExceptionHandler(e: SpException): ResponseEntity = ResponseEntity(ErrorResponse.of(e), HttpStatus.valueOf(e.status)) @ExceptionHandler(BindException::class) diff --git a/src/main/kotlin/gogo/gogosp/global/error/StageException.kt b/src/main/kotlin/gogo/gogosp/global/error/SpException.kt similarity index 81% rename from src/main/kotlin/gogo/gogosp/global/error/StageException.kt rename to src/main/kotlin/gogo/gogosp/global/error/SpException.kt index 3331792..23b31cb 100644 --- a/src/main/kotlin/gogo/gogosp/global/error/StageException.kt +++ b/src/main/kotlin/gogo/gogosp/global/error/SpException.kt @@ -1,6 +1,6 @@ package gogo.gogosp.global.error -open class StageException( +open class SpException( override val message: String, val status: Int ) : RuntimeException(message) diff --git a/src/main/kotlin/gogo/gogosp/global/feign/FeignClientErrorDecoder.kt b/src/main/kotlin/gogo/gogosp/global/feign/FeignClientErrorDecoder.kt index 99206bf..d54f14d 100644 --- a/src/main/kotlin/gogo/gogosp/global/feign/FeignClientErrorDecoder.kt +++ b/src/main/kotlin/gogo/gogosp/global/feign/FeignClientErrorDecoder.kt @@ -3,7 +3,7 @@ package gogo.gogosp.global.feign import feign.FeignException import feign.Response import feign.codec.ErrorDecoder -import gogo.gogosp.global.error.StageException +import gogo.gogosp.global.error.SpException import org.springframework.http.HttpStatus class FeignClientErrorDecoder : ErrorDecoder { @@ -12,7 +12,7 @@ class FeignClientErrorDecoder : ErrorDecoder { response: Response, ): Exception? { if (response.status() >= 400) { - throw StageException("HTTP 통신 오류", HttpStatus.INTERNAL_SERVER_ERROR.value()) + throw SpException("HTTP 통신 오류", HttpStatus.INTERNAL_SERVER_ERROR.value()) } return FeignException.errorStatus(methodKey, response) } From 6e0853cb374db274d9e6ac0ee5f563fa42b0a5c0 Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:00:16 +0900 Subject: [PATCH 05/10] add: QueryDsl setting --- build.gradle.kts | 9 +++++++-- .../gogo/gogosp/global/config/QueryDslConfig.kt | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/gogo/gogosp/global/config/QueryDslConfig.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5acafa7..29f36ea 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ plugins { - kotlin("jvm") version "1.9.25" - kotlin("plugin.spring") version "1.9.25" + kotlin("jvm") version "2.1.0" + kotlin("plugin.spring") version "2.1.0" id("org.springframework.boot") version "3.4.1" id("io.spring.dependency-management") version "1.1.7" kotlin("plugin.jpa") version "1.9.25" + kotlin("kapt") version "1.9.20" } group = "gogo" @@ -37,6 +38,10 @@ dependencies { testImplementation("org.springframework.kafka:spring-kafka-test") testImplementation("org.springframework.security:spring-security-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta") + kapt("com.querydsl:querydsl-apt:5.0.0:jakarta") + kapt("jakarta.annotation:jakarta.annotation-api") + kapt("jakarta.persistence:jakarta.persistence-api") } dependencyManagement { diff --git a/src/main/kotlin/gogo/gogosp/global/config/QueryDslConfig.kt b/src/main/kotlin/gogo/gogosp/global/config/QueryDslConfig.kt new file mode 100644 index 0000000..5a6c092 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/global/config/QueryDslConfig.kt @@ -0,0 +1,16 @@ +package gogo.gogosp.global.config + +import com.querydsl.jpa.impl.JPAQueryFactory +import jakarta.persistence.EntityManager +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class QueryDslConfig( + private val entityManager: EntityManager +) { + + @Bean + fun jpaQueryFactory() = JPAQueryFactory(entityManager) + +} \ No newline at end of file From 7bd80aa6da5da4635a28f905d415109ee2a2a41f Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:01:08 +0900 Subject: [PATCH 06/10] delete: unique constraints --- .../gogosp/domain/customer/root/persistence/CustomerInquiry.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt index 8c0551c..bb1ba4c 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiry.kt @@ -10,7 +10,7 @@ class CustomerInquiry( @Column(name = "customer_inquiry_id", nullable = false) val customerInquiryId: Long = 0, - @Column(name = "student_id", nullable = false, unique = true) + @Column(name = "student_id", nullable = false) val studentId: Long, @Column(name = "title", nullable = false) From 1d3a2220a098edf8f23f03d77bd04b13be69c23f Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:01:40 +0900 Subject: [PATCH 07/10] add: student bundle api server to server config --- .../gogosp/global/feign/client/StudentClient.kt | 6 ++++++ .../global/internal/student/api/StudentApi.kt | 2 ++ .../global/internal/student/api/StudentApiImpl.kt | 5 +++++ .../global/internal/student/stub/StudentStub.kt | 14 ++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/main/kotlin/gogo/gogosp/global/feign/client/StudentClient.kt b/src/main/kotlin/gogo/gogosp/global/feign/client/StudentClient.kt index 4f51ca9..3640638 100644 --- a/src/main/kotlin/gogo/gogosp/global/feign/client/StudentClient.kt +++ b/src/main/kotlin/gogo/gogosp/global/feign/client/StudentClient.kt @@ -1,6 +1,7 @@ package gogo.gogosp.global.feign.client import gogo.gogosp.global.internal.student.stub.StudentByIdStub +import gogo.gogosp.global.internal.student.stub.StudentByIdsStub import org.springframework.cloud.openfeign.FeignClient import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam @@ -11,4 +12,9 @@ interface StudentClient { fun queryStudentByUserId( @RequestParam("userId") userId: Long ): StudentByIdStub + + @GetMapping("/user/student/bundle") + fun queryStudentsByStudentIds( + @RequestParam("studentIds") studentIds: List + ): StudentByIdsStub } diff --git a/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApi.kt b/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApi.kt index c88b4ac..904847b 100644 --- a/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApi.kt +++ b/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApi.kt @@ -1,7 +1,9 @@ package gogo.gogosp.global.internal.student.api import gogo.gogosp.global.internal.student.stub.StudentByIdStub +import gogo.gogosp.global.internal.student.stub.StudentByIdsStub interface StudentApi { fun queryByUserId(userId: Long): StudentByIdStub + fun queryStudentsByStudentIds(studentIds: List): StudentByIdsStub } \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApiImpl.kt b/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApiImpl.kt index 9bf3101..8397405 100644 --- a/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApiImpl.kt +++ b/src/main/kotlin/gogo/gogosp/global/internal/student/api/StudentApiImpl.kt @@ -2,6 +2,7 @@ package gogo.gogosp.global.internal.student.api import gogo.gogosp.global.feign.client.StudentClient import gogo.gogosp.global.internal.student.stub.StudentByIdStub +import gogo.gogosp.global.internal.student.stub.StudentByIdsStub import org.springframework.stereotype.Component @Component @@ -11,4 +12,8 @@ class StudentApiImpl( override fun queryByUserId(userId: Long): StudentByIdStub { return studentClient.queryStudentByUserId(userId) } + + override fun queryStudentsByStudentIds(studentIds: List): StudentByIdsStub { + return studentClient.queryStudentsByStudentIds(studentIds) + } } diff --git a/src/main/kotlin/gogo/gogosp/global/internal/student/stub/StudentStub.kt b/src/main/kotlin/gogo/gogosp/global/internal/student/stub/StudentStub.kt index 4d39f42..0318065 100644 --- a/src/main/kotlin/gogo/gogosp/global/internal/student/stub/StudentStub.kt +++ b/src/main/kotlin/gogo/gogosp/global/internal/student/stub/StudentStub.kt @@ -16,3 +16,17 @@ data class StudentByIdStub( val isActiveProfanityFilter: Boolean, val createdAt: LocalDateTime ) + +data class StudentByIdsStub( + val students: List +) + +data class StudentByIdsStubDto( + val studentId: Long, + val schoolId: Long, + val sex: Sex, + val name: String, + val deviceToken: String?, + val classNumber: Int, + val studentNumber: Int, +) From 347087eeec24161910d609cfcf0f4016828b8aed Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:05:40 +0900 Subject: [PATCH 08/10] add: getInquiryList API --- .../application/CustomerInquiryService.kt | 2 ++ .../application/CustomerInquiryServiceImpl.kt | 11 +++++++- .../application/CustomerInquiryValidator.kt | 15 +++++++++++ .../application/dto/CustomerInquiryDto.kt | 27 +++++++++++++++++++ .../persistence/CustomerInquiryRepository.kt | 2 +- .../presentation/CustomerInquiryController.kt | 15 ++++++++--- .../gogosp/global/config/SecurityConfig.kt | 1 + 7 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryValidator.kt diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt index 18eebc1..c8d7fd6 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryService.kt @@ -1,7 +1,9 @@ package gogo.gogosp.domain.customer.root.application +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto interface CustomerInquiryService { fun writeInquiry(dto: WriteCustomerInquiryReqDto) + fun getInquiryList(page: Int, size: Int): GetCustomerInquiryListResDto } \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt index ee5be42..a2e01ca 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryServiceImpl.kt @@ -1,5 +1,6 @@ package gogo.gogosp.domain.customer.root.application +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto import gogo.gogosp.global.util.UserContextUtil import org.springframework.stereotype.Service @@ -8,7 +9,9 @@ import org.springframework.transaction.annotation.Transactional @Service class CustomerInquiryServiceImpl( private val userUtil: UserContextUtil, - private val customerInquiryProcessor: CustomerInquiryProcessor + private val customerInquiryProcessor: CustomerInquiryProcessor, + private val customerInquiryReader: CustomerInquiryReader, + private val customerInquiryValidator: CustomerInquiryValidator ): CustomerInquiryService { @Transactional @@ -16,4 +19,10 @@ class CustomerInquiryServiceImpl( val student = userUtil.getCurrentStudent() customerInquiryProcessor.saveCustomerInquiry(dto, student) } + + @Transactional(readOnly = true) + override fun getInquiryList(page: Int, size: Int): GetCustomerInquiryListResDto { + customerInquiryValidator.validPageAndSize(page, size) + return customerInquiryReader.readCustomerInquiryPage(page, size) + } } \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryValidator.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryValidator.kt new file mode 100644 index 0000000..d347e22 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryValidator.kt @@ -0,0 +1,15 @@ +package gogo.gogosp.domain.customer.root.application + +import gogo.gogosp.global.error.SpException +import org.springframework.http.HttpStatus +import org.springframework.stereotype.Component + +@Component +class CustomerInquiryValidator { + + fun validPageAndSize(page: Int, size: Int) { + if (page < 0 || size < 0) { + throw SpException("page와 size는 음수일 수 없습니다.", HttpStatus.BAD_REQUEST.value()) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt index 0471c77..cfac206 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/dto/CustomerInquiryDto.kt @@ -1,6 +1,7 @@ package gogo.gogosp.domain.customer.root.application.dto import jakarta.validation.constraints.Size +import org.aspectj.weaver.IntMap import org.jetbrains.annotations.NotNull data class WriteCustomerInquiryReqDto( @@ -12,3 +13,29 @@ data class WriteCustomerInquiryReqDto( @NotNull val isOpening: Boolean, ) + +data class GetCustomerInquiryListResDto( + val info: PagingDto, + val inquiries: List +) + +data class CustomerInquiryDto( + val customerInquiryId: Long, + val title: String, + val content: String, + val isReading: Boolean, + val isOpening: Boolean, + val authorDto: AuthorDto +) + +data class PagingDto( + val page: Int, + val size: Int +) + +data class AuthorDto( + val studentId: Long, + val name: String, + val classNumber: Int, + val studentNumber: Int, +) diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryRepository.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryRepository.kt index 6c8b77a..c5ea73b 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryRepository.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryRepository.kt @@ -2,5 +2,5 @@ package gogo.gogosp.domain.customer.root.persistence import org.springframework.data.jpa.repository.JpaRepository -interface CustomerInquiryRepository: JpaRepository { +interface CustomerInquiryRepository: JpaRepository, CustomerInquiryCustomRepository { } \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt index 9436f4d..25b2fbf 100644 --- a/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/presentation/CustomerInquiryController.kt @@ -1,14 +1,12 @@ package gogo.gogosp.domain.customer.root.presentation import gogo.gogosp.domain.customer.root.application.CustomerInquiryService +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto import gogo.gogosp.domain.customer.root.application.dto.WriteCustomerInquiryReqDto import jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/sp") @@ -24,5 +22,14 @@ class CustomerInquiryController( return ResponseEntity.status(HttpStatus.CREATED).build() } + @GetMapping("/customer") + fun getInquiryList( + @RequestParam(required = false, defaultValue = "0") page: Int, + @RequestParam(required = false, defaultValue = "20") size: Int, + ): ResponseEntity { + val response = customerInquiryService.getInquiryList(page, size) + return ResponseEntity.ok(response) + } + } \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt b/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt index e414b8c..9f5fc00 100644 --- a/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt +++ b/src/main/kotlin/gogo/gogosp/global/config/SecurityConfig.kt @@ -46,6 +46,7 @@ class SecurityConfig( httpRequests.requestMatchers(HttpMethod.GET, "/sp/health").permitAll() httpRequests.requestMatchers(HttpMethod.POST, "/sp/customer/inquiry").hasAnyRole(Authority.USER.name, Authority.STAFF.name) + httpRequests.requestMatchers(HttpMethod.GET, "/sp/customer").hasAnyRole(Authority.USER.name, Authority.STAFF.name) httpRequests.anyRequest().denyAll() } From c6de34d805d9e404bcc1415a792562ebb244b6fd Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:05:57 +0900 Subject: [PATCH 09/10] add: readCustomerInquiryPage method --- .../root/application/CustomerInquiryReader.kt | 18 ++++++ .../CustomerInquiryCustomRepository.kt | 8 +++ .../CustomerInquiryCustomRepositoryImpl.kt | 63 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryReader.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepository.kt create mode 100644 src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepositoryImpl.kt diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryReader.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryReader.kt new file mode 100644 index 0000000..c0e5446 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/application/CustomerInquiryReader.kt @@ -0,0 +1,18 @@ +package gogo.gogosp.domain.customer.root.application + +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto +import gogo.gogosp.domain.customer.root.persistence.CustomerInquiryRepository +import org.springframework.data.domain.PageRequest + +import org.springframework.stereotype.Component +@Component +class CustomerInquiryReader( + private val customerInquiryRepository: CustomerInquiryRepository +) { + + fun readCustomerInquiryPage(page: Int, size: Int): GetCustomerInquiryListResDto { + val pageRequest = PageRequest.of(page, size) + return customerInquiryRepository.queryCustomerInquiry(pageRequest, size) + } +} + diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepository.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepository.kt new file mode 100644 index 0000000..6b8ad3d --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepository.kt @@ -0,0 +1,8 @@ +package gogo.gogosp.domain.customer.root.persistence + +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto +import org.springframework.data.domain.Pageable + +interface CustomerInquiryCustomRepository { + fun queryCustomerInquiry(pageable: Pageable, size: Int): GetCustomerInquiryListResDto +} \ No newline at end of file diff --git a/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepositoryImpl.kt b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepositoryImpl.kt new file mode 100644 index 0000000..60982a9 --- /dev/null +++ b/src/main/kotlin/gogo/gogosp/domain/customer/root/persistence/CustomerInquiryCustomRepositoryImpl.kt @@ -0,0 +1,63 @@ +package gogo.gogosp.domain.customer.root.persistence + +import com.querydsl.jpa.impl.JPAQueryFactory +import gogo.gogosp.domain.customer.root.application.dto.AuthorDto +import gogo.gogosp.domain.customer.root.application.dto.CustomerInquiryDto +import gogo.gogosp.domain.customer.root.application.dto.GetCustomerInquiryListResDto +import gogo.gogosp.domain.customer.root.application.dto.PagingDto +import gogo.gogosp.domain.customer.root.persistence.QCustomerInquiry.customerInquiry +import gogo.gogosp.global.internal.student.api.StudentApi +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Repository + +@Repository +class CustomerInquiryCustomRepositoryImpl( + private val queryFactory: JPAQueryFactory, + private val studentApi: StudentApi +): CustomerInquiryCustomRepository { + + override fun queryCustomerInquiry(pageable: Pageable, size: Int): GetCustomerInquiryListResDto { + val customerInquiryList = queryFactory + .selectFrom(customerInquiry) + .orderBy( + customerInquiry.customerInquiryId.desc() + ) + .offset(pageable.offset) + .limit(pageable.pageSize.toLong()) + .fetch() + + val studentIds = customerInquiryList.map {it.studentId}.toSet().toList() + + val students = studentApi.queryStudentsByStudentIds(studentIds).students + + val customerInquiryDto = customerInquiryList.map { customerInquiry -> + val student = students.find { it.studentId == customerInquiry.studentId }!! + + CustomerInquiryDto( + customerInquiryId = customerInquiry.customerInquiryId, + title = customerInquiry.title, + content = customerInquiry.content, + isReading = customerInquiry.isReading, + isOpening = customerInquiry.isOpening, + authorDto = AuthorDto( + studentId = student.studentId, + name = student.name, + classNumber = student.classNumber, + studentNumber = student.studentNumber + ) + ) + } + + val totalElement = customerInquiryList.size + + val totalPage = if (totalElement % size == 0) { + totalElement / size + } else { + totalElement / size + 1 + } + + val pagingDto = PagingDto(totalPage, totalElement) + + return GetCustomerInquiryListResDto(pagingDto, customerInquiryDto) + } +} \ No newline at end of file From f0f302c78da9d0b3887e8b1c8b9803689dba52bc Mon Sep 17 00:00:00 2001 From: Umjiseung <127853946+Umjiseung@users.noreply.github.com> Date: Thu, 10 Apr 2025 20:08:01 +0900 Subject: [PATCH 10/10] fix: inverse serialization problem --- .../kotlin/gogo/gogosp/global/internal/user/stub/Sex.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/gogo/gogosp/global/internal/user/stub/Sex.kt b/src/main/kotlin/gogo/gogosp/global/internal/user/stub/Sex.kt index 6e84c31..0308be9 100644 --- a/src/main/kotlin/gogo/gogosp/global/internal/user/stub/Sex.kt +++ b/src/main/kotlin/gogo/gogosp/global/internal/user/stub/Sex.kt @@ -1,5 +1,10 @@ package gogo.gogosp.global.internal.user.stub +import com.fasterxml.jackson.annotation.JsonProperty + enum class Sex { - MALE, FEMALE + @JsonProperty("MALE") + MALE, + @JsonProperty("FEMALE") + FEMALE } \ No newline at end of file