Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.kotlinweb.board.controller
import com.example.kotlinweb.board.model.Post
import com.example.kotlinweb.board.service.BoardService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
class BoardController(private val boardService: BoardService) {

@GetMapping(value = ["/board"])
fun findAllPosts(): ResponseEntity<Any> {;
return ResponseEntity(boardService.findPosts(), HttpStatus.OK);
}

@PostMapping(value = ["/board"])
fun savePost(@RequestBody post: Post): ResponseEntity<Any> {
return ResponseEntity(boardService.savePost(post), HttpStatus.CREATED);
}

@PutMapping(value = ["/board/{id}"])
fun updatePost(@RequestBody post: Post, @PathVariable id: String): ResponseEntity<Any> {
return ResponseEntity(boardService.updatePost(post), HttpStatus.OK);
}

@DeleteMapping(value = ["/board"])
fun deletePost(@RequestBody post: Post): ResponseEntity<Any> {
Copy link
Member

@kkw01234 kkw01234 Aug 23, 2020

Choose a reason for hiding this comment

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

근데 delete는 body지원 안하지 않나요? (잘 모름..)

return ResponseEntity(boardService.deletePost(post), HttpStatus.OK);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example.kotlinweb.board.model

class AbstractDatabase(
Copy link
Member

Choose a reason for hiding this comment

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

JPA를 안쓰기 위해 별도의 싱글톤을 사용하신거군요 멋진 아이디어네요


) {
companion object {
var posts: MutableList<Any> = mutableListOf()
Copy link
Member

@kkw01234 kkw01234 Aug 23, 2020

Choose a reason for hiding this comment

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

posts를 바꿀 경우가 있나요? var로 선언이 되어있길래..
그리고 Any를 쓴 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

val로 바꾸는게 맞는것 같네요.
모든 타입 다 가능하게끔 하려고 Any선언 했는데. 나름의 추상화...
해당 클래스 파일도 제네릭으로 하는게 맞았던거 같네요


fun create(obj: Any?) {
obj?.let {
posts.add(obj)
}
}

fun delete(obj: Any?) {
obj?.let {
obj as Post
posts.removeAt(obj.id.toInt() - 1)
}
}

fun read(): MutableList<Any> {
return posts;
}
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/com/example/kotlinweb/board/model/Post.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.kotlinweb.board.model

import java.time.LocalDateTime

class Post(
val id: Long, val title: String, val writer: String, val text: String
) {
val createDate: LocalDateTime = LocalDateTime.now()
var updateDate: LocalDateTime = LocalDateTime.now()
Copy link
Member

Choose a reason for hiding this comment

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

createDate, updateDate도 생성자에 넣는거 가능합니다!

코틀린에서는 default값 주입 가능해요
class Post(
val id: Long,
val title: String,
val writer: String,
val text: String,
val createDate: LocalDateTime = LocalDateTime.now()
var updateDate: LocalDateTime = LocalDateTime.now()
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.kotlinweb.board.repository

import com.example.kotlinweb.board.model.AbstractDatabase
import com.example.kotlinweb.board.model.Post
import org.springframework.stereotype.Repository

@Repository
class PostCrudRepository : PostRepository<Post> {

override fun <Post> save(post: Post) {
AbstractDatabase.create(post);
}

override fun find(): MutableList<Any> {
Copy link
Member

Choose a reason for hiding this comment

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

여기도 Any가 있네요..

return AbstractDatabase.read()
}

override fun findById(postId: Long): Post {
return find().map { any -> any as Post }.first { post -> post.id == postId }
}

override fun <Post> delete(post: Post) {
return AbstractDatabase.delete(post)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.kotlinweb.board.repository

interface PostRepository<T> {
fun <T> save(t: T)
fun find(): Any
fun findById(t: Long): Any
fun <T> delete(t: T)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.kotlinweb.board.service

import com.example.kotlinweb.board.model.Post

interface BoardService {
fun savePost(post: Post)
fun findPosts(): Any
fun updatePost(post: Post)
fun deletePost(post: Post)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.kotlinweb.board.service

import com.example.kotlinweb.board.model.Post
import com.example.kotlinweb.board.repository.PostRepository
import org.springframework.stereotype.Service

@Service
class BoardServiceImpl(private val postRepository: PostRepository<Post>) : BoardService {

override fun savePost(post: Post) {
postRepository.save(post)
}

override fun findPosts(): Any {
return postRepository.find()
}

override fun updatePost(post: Post) {
var foundPost: Post = postRepository.findById(post.id) as Post
foundPost?.let {
postRepository.delete(post)
Copy link
Member

Choose a reason for hiding this comment

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

delete(it)이 더 올바른 표현처럼 보여요

Copy link
Author

Choose a reason for hiding this comment

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

급하게 하고, 올리다보니 실수..

postRepository.save(post)
}
}

override fun deletePost(post: Post) {
var foundPost: Post = postRepository.findById(post.id) as Post
foundPost?.let {
postRepository.delete(post)
Copy link
Member

@kkw01234 kkw01234 Aug 23, 2020

Choose a reason for hiding this comment

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

let을 null check만 하는 것은 좋지 않은걸로 알고있는데 제가 잘 알고있는지는... (https://tourspace.tistory.com/208)

Copy link
Member

@minkukjo minkukjo Aug 24, 2020

Choose a reason for hiding this comment

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

foundPost가 nullable 타입이 아니라서 safety call을 할 필요는 없을 것 같습니다.
mark가 의도하신 바가 JPA query method를 사용해서 못찾은 경우에 null check를 하려는 의도셨다면 Post -> Post? 타입으로 바꾸는게 좋을 것 같아요.
다니엘이 올려주신 예제가 아주 좋네요. 저도 널체크는 명시적으로 if( A == null )로 하는게 좀 더 직관적인 것 같습니다. 이건 개인차 인것 같아요~

Copy link
Author

Choose a reason for hiding this comment

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

if로 하는게 맞을 것 같아요! 저도 급하게 하다보니 ?를.. 생략해버렸네요

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ResponseBody

@Controller
class HealthController{
class HealthController {

@get:ResponseBody
@get:GetMapping(value = ["/health_check.html"])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.kotlinweb.board.service

import com.example.kotlinweb.board.model.AbstractDatabase
import com.example.kotlinweb.board.model.Post
import com.example.kotlinweb.board.repository.PostCrudRepository
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
Copy link
Member

Choose a reason for hiding this comment

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

SpringBootTest에 포함되어있어서 JUnit 5에서는 생략해도됩니다~

@SpringBootTest
internal class BoardServiceImplTest(
@Autowired val repository: PostCrudRepository
) {

@Test
fun savePostTest() {
val post: Post = Post(1L, "Test Title", "KDH", "memo")
val boardService: BoardService = BoardServiceImpl(repository)
boardService.savePost(post)
verify(AbstractDatabase, times(1)).create(Any())
}

@Test
fun readPostsTest() {
val post1: Post = Post(1L, "Test Title", "KDH", "memo1")
val post2: Post = Post(2L, "Test Title2", "KDH2", "memo2")
val boardService: BoardService = BoardServiceImpl(repository)
boardService.savePost(post1)
boardService.savePost(post2)
var posts: MutableList<Any> = AbstractDatabase.read()
val savedPost1: Post = posts[0] as Post
val savedPost2: Post = posts[1] as Post
assertAll(
"posts",
{ Assertions.assertEquals(post1.title, savedPost1.title) },
{ Assertions.assertEquals(post2.writer, savedPost2.writer) }
)
}
}