From f45e07c8793622ef709521a153c3cb45ed7682f9 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 2 Jan 2024 06:05:59 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BF=A0=ED=8F=B0=20=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 + .../can/coupon/CanCouponController.kt | 19 ++++++++ .../can/coupon/CanCouponRepository.kt | 17 +++++++ .../sodalive/can/coupon/CanCouponService.kt | 46 +++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 38cc7a9..e34510a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -59,6 +59,8 @@ dependencies { // firebase admin sdk implementation("com.google.firebase:firebase-admin:9.2.0") + implementation("org.apache.poi:poi-ooxml:5.2.3") + developmentOnly("org.springframework.boot:spring-boot-devtools") runtimeOnly("com.h2database:h2") runtimeOnly("com.mysql:mysql-connector-j") diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt index cfd7b79..219996f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt @@ -4,6 +4,9 @@ import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.member.Member import org.springframework.data.domain.Pageable +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping @@ -55,4 +58,20 @@ class CanCouponController(private val service: CanCouponService) { ) ) } + + @GetMapping("/number-list/download") + @PreAuthorize("hasRole('ADMIN')") + fun downloadCouponNumberList( + @RequestParam couponId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + val fileName = "쿠폰번호리스트.xlsx" + val response = service.downloadCouponNumberList(couponId) + ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attatchment;filename=$fileName") + .contentType(MediaType.parseMediaType("application/vnd.ms-excel")) + .body(response) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponRepository.kt index 2c28256..9c3653c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponRepository.kt @@ -12,6 +12,8 @@ interface CanCouponQueryRepository { fun getCouponList(offset: Long, limit: Long): List fun getCouponNumberTotalCount(couponId: Long): Int fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List + + fun getAllCouponNumberList(couponId: Long): List } class CanCouponQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponQueryRepository { @@ -57,4 +59,19 @@ class CanCouponQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : .limit(limit) .fetch() } + + override fun getAllCouponNumberList(couponId: Long): List { + return queryFactory + .select( + QGetCouponNumberListItemResponse( + canCouponNumber.id, + canCouponNumber.couponNumber, + canCouponNumber.member.isNotNull + ) + ) + .from(canCouponNumber) + .where(canCouponNumber.canCoupon.id.eq(couponId)) + .orderBy(canCouponNumber.id.asc()) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt index 5e219b7..9524e17 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt @@ -3,8 +3,13 @@ package kr.co.vividnext.sodalive.can.coupon import com.fasterxml.jackson.databind.ObjectMapper import kr.co.vividnext.sodalive.aws.sqs.SqsEvent import kr.co.vividnext.sodalive.aws.sqs.SqsEventType +import kr.co.vividnext.sodalive.common.SodaException +import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.IOException import java.time.format.DateTimeFormatter @Service @@ -48,4 +53,45 @@ class CanCouponService( val items = repository.getCouponNumberList(couponId = couponId, offset = offset, limit = limit) return GetCouponNumberListResponse(totalCount, items) } + + fun downloadCouponNumberList(couponId: Long): ByteArrayInputStream { + val header = listOf("순번", "쿠폰번호", "사용여부") + val byteArrayOutputStream = ByteArrayOutputStream() + val couponNumberList = repository.getAllCouponNumberList(couponId) + + val workbook = XSSFWorkbook() + try { + val sheet = workbook.createSheet() + val row = sheet.createRow(0) + header.forEachIndexed { index, string -> + val cell = row.createCell(index) + cell.setCellValue(string) + } + + couponNumberList.forEachIndexed { index, item -> + val couponNumberRow = sheet.createRow(index + 1) + couponNumberRow.createCell(0).setCellValue(item.couponNumberId.toString()) + couponNumberRow.createCell(1).setCellValue(insertHyphens(item.couponNumber)) + couponNumberRow.createCell(2).setCellValue( + if (item.isUsed) { + "O" + } else { + "X" + } + ) + } + + workbook.write(byteArrayOutputStream) + return ByteArrayInputStream(byteArrayOutputStream.toByteArray()) + } catch (e: IOException) { + throw SodaException("다운로드를 하지 못했습니다.\n다시 시도해 주세요.") + } finally { + workbook.close() + byteArrayOutputStream.close() + } + } + + private fun insertHyphens(input: String): String { + return input.chunked(4).joinToString("-") + } }