kopring으로 프로젝트를 생성하면 된다.
나의 경우 Spring intializer에서 다음과 같이 프로젝트를 생성했다. restdocs를 추가했었으나 오류가 나더라... 어차피 지금 당장 쓸건 아니니 우선 제외시켜놨다.
아 그리고 참고로 vscode의 경우 kotlin + gradle을 지원하지 않고 있다... 언젠가 해줄지 모르지만 아직 해주지 않으니 intellij를 써야한다.
@RestController
@RequestMapping("/v1")
class HelloController {
@GetMapping("/hello")
fun hello(): String{
return "hello"
}
}
컨트롤러를 테스트용으로 만들어보았다.
결과 값이 잘 나온다.
그럼 객체로 반환은 어떻게 하는지 궁금해졌다. 객체로 반환시켜보자.
class MemberDto (
val name: String,
val email: String,
val phone: String? =null,
)
먼저 MemberDto
를 먼저 생성했다. data class로 만들어도 된다.
@RestController
@RequestMapping("/v1")
class HelloController {
@GetMapping("/hello")
fun hello(): String{
return "hello"
}
@GetMapping("/user")
fun user(): ResponseEntity<Any> {
val user = MemberDto("juno", "juno@mail.com")
return ResponseEntity.ok(user)
}
}
controller의 경우 다음과 같이 작성해주면 된다. Any의 경우 반환할 class를 직접 지정해주는게 더 좋을거 같긴하다만 귀찮아서 Any로 써봤다.
Java에서 해봤다면 kotlin 문법만 알면 금방 적을할 수 있었다.
spring:
h2:
console:
enabled: true
settings:
web-allow-others: true
path: /h2-console
jpa:
hibernate:
ddl-auto: create
show-sql: true
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb
username: sa
password:
JPA와 H2를 사용하여 DB를 생성해주고 enabled 해준다. 서버를 실행해서 확인해보자!
이 화면이 나오면 잘 설정된 것이다.
@Entity
@Table(name = "MEMBER")
class MemberEntity (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long,
var name: String,
val email: String,
val phone: String? =null,
){
fun changeName(name: String){
this.name = name
}
}
@Repository
interface MemberRepository : JpaRepository<MemberEntity, Long>{
fun findByName(name: String): Optional<MemberEntity>
}
interface MemberService {
fun findMember(name: String): Optional<MemberEntity>
}
@Service
class MemberServiceImpl(
private val memberRepository: MemberRepository,
) : MemberService{
override fun findMember(name: String): Optional<MemberEntity> {
return memberRepository.findByName(name)
}
}
이제 테스트 코드를 통해 확인해보자
@SpringBootTest
class MemberServiceImplTest(
@Autowired val memberService: MemberService,
@Autowired val memberRepository: MemberRepository,
){
@Test
@DisplayName("member 조회에 성공한다.")
@Transactional
fun memberFind(){
//given
val member = MemberEntity("juno", "juno@mail.com", "01012341234")
memberRepository.save(member)
//when
val findMember = memberService.findMember("juno").get()
//then
assertEquals(findMember.name, member.name)
}
}
테스트 결과를 보면 insert문과 select 문이 정상적으로 실행되었고 테스트도 정상 실행된것을 확인할 수 있었다.
interface MemberService {
...
fun save(memberDto: MemberDto)
}
@Service
class MemberServiceImpl(
...
@Transactional
override fun save(memberDto: MemberDto) {
memberRepository.save(MemberEntity(memberDto.name, memberDto.email, memberDto.phone))
}
}
데이터를 넣어야하므로 save를 추가해주었다.
@RestController
@RequestMapping("/v1/member")
class MemberController (
private val memberService: MemberService,
){
@GetMapping("/{name}")
fun getMember(@PathVariable(value = "name") name: String): ResponseEntity<MemberEntity> {
return ResponseEntity.ok(memberService.findMember(name).get())
}
@PostMapping("")
fun insertMember(@RequestBody memberDto: MemberDto): ResponseEntity<Any> {
memberService.save(memberDto)
return ResponseEntity.status(HttpStatus.CREATED).body("회원가입 완료")
}
}
다음과 같이 두개의 매핑을 추가해주었고 실행해보자.
다음과 같이 정상 실행되었고
insert 문도 이쁘게 날아갔다.
또한 우리가 phone은 null을 허용해두었기에 다음과 같이 작성하지 않아도 잘 된다.
우리가 이전에 만들었던 find도 정상적으로 실행되며
select 문도 이쁘게 날아간다.