코틀린 시작 기록(3)
웹 프로그래밍/Kotlin

코틀린 시작 기록(3)

728x90
반응형

과거 해커톤 때 팀원들 교육용으로 만들었던 투표 API를 코프링으로 옮겨보려한다.

https://github.com/Aiden-Kwak/NextJsDemo

 

GitHub - Aiden-Kwak/NextJsDemo: 팀원 교육용으로 제작

팀원 교육용으로 제작. Contribute to Aiden-Kwak/NextJsDemo development by creating an account on GitHub.

github.com

 

 

원하는 응답

GET /api/get-vote
{"id":1,"bidenCount":0,"trumpCount":0}

POST /api/post-vote with {"vote": "Biden"}
{"id":1,"bidenCount":1,"trumpCount":0}

POST /api/post-vote with {"vote": "Trump"}
{"id":1,"bidenCount":1,"trumpCount":1}

 

1. 구조

구조

대충 이렇다. 더 그럴듯한 구조를 발견하지 못하면 당분간 이렇게 작성할 듯하다.

controller, dto, model, repository, service 구조를 가져가려한다.

 

- controller: 

클라이언트 요청을 제일 먼저 받는 곳. 요쳥을 service에 전달하고 응답을 반환한다.

 

- service:

비즈니스 로직을 여기 모아둔다. 여기선 투표수 증가처리. controller가 요청한 작업을 여기서 수행. DRF로 따지면 view에 가까움

 

- repository:

JPA써서 데이터베이스와 직접 통신. Vote 데이터를 조회,저장,삭제

* JPA(Java Persistence API)는 자바 진영에서 ORM 기술표준으로 쓰는 인터페이스 모아둔거

 

- model

- dto

 

2. model/Vote.kt

package com.example.vote.model
// 얘가 JPA에서 제공하는 클래스랑 어노테이션 가져옴. @Entity, @Id, @GeneratedValue등
import jakarta.persistence.*

@Entity // 이 클래스가 JPA 엔티티임을 표시
data class Vote(
    @Id // id를 pk로 지정. DRF랑 다르게 직접 지정필요한듯
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    var bidenCount: Int = 0,
    var trumpCount: Int = 0
)

 

@GeneratedValue(strategy = GenerationType.IDENTITY) 이거는 JPA가 엔티티의 PK 생성방식을 지정함. GenerationType.IDENTITY에 의해서 데이터 삽입시 디비가 자동으로 고유값을 할당한다.

 

3. controller/VoteController.kt

package com.example.vote.controller

import com.example.vote.dto.VoteRequest
import com.example.vote.model.Vote
import com.example.vote.service.VoteService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api")
class VoteController(
    private val voteService: VoteService
) {

    @GetMapping("/get-vote")
    fun getVote(): ResponseEntity<Vote> {
        val vote = voteService.getVote()
        return ResponseEntity.ok(vote)
    }

    @PostMapping("/post-vote")
    fun postVote(@RequestBody request: VoteRequest): ResponseEntity<Any> {
        return try {
            val updatedVote = voteService.postVote(request)
            ResponseEntity.status(HttpStatus.CREATED).body(updatedVote)
        } catch (e: IllegalArgumentException) {
            ResponseEntity.badRequest().body(mapOf("error" to e.message))
        }
    }
}

 

- 모든 엔드포인트를 /api로

- private val voteService: VoteService 통해서 VoteService 주입 받음

 

4. repository/VoteRepository.kt

package com.example.vote.repository

import com.example.vote.model.Vote
import org.springframework.data.jpa.repository.JpaRepository

interface VoteRepository : JpaRepository<Vote, Long>

JpaRepository를 상속받아 Vote 엔티티에 대해 Long 타입 ID 사용하는 기본 CRUD 메서드 사용할 수 있다.

save(), findById(), findAll(), delete() 같은거 사용 가능.

 

5. service/VoteService.kt

package com.example.vote.service

import com.example.vote.dto.VoteRequest
import com.example.vote.model.Vote
import com.example.vote.repository.VoteRepository
import org.springframework.stereotype.Service

@Service
class VoteService(
    private val voteRepository: VoteRepository
) {

    fun getVote(): Vote {
        return voteRepository.findAll().firstOrNull() ?: voteRepository.save(Vote())
    }

    fun postVote(request: VoteRequest): Vote {
        val vote = voteRepository.findAll().firstOrNull() ?: voteRepository.save(Vote())

        when (request.vote) {
            "Biden" -> vote.bidenCount += 1
            "Trump" -> vote.trumpCount += 1
            else -> throw IllegalArgumentException("Invalid vote option")
        }

        return voteRepository.save(vote)
    }
}

> getVote:

- findAll() : 데이터베이스에서 모든 투표기록 가져와

- firstOrNull(): 하나라도 있으면 첫번째 투표기록 사용하고 없으면 널반환

- ?:voteRepository.save(Vote()) : 널이면 다 0인 Vote 객체 생성하고, 저장한후 반환

 

> postVote: 투표수 업데이트하고 업데이트 반환

728x90
반응형

'웹 프로그래밍 > Kotlin' 카테고리의 다른 글

Intellij에서 실행안되는 문제  (0) 2025.04.18
코틀린 시작 기록(2)  (0) 2025.04.07
코틀린 시작 기록 (1)  (1) 2025.04.06