지난번 Springboot + gradle 설정(https://basketdeveloper.tistory.com/73)에 이어
Spring boot에서 DB(Mysql) 간단 연동법과 JPA를 사용하는 방법을 정리해봅니다.
01. build.gradle.kt 에 Dependency 추가
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.run.BootRun
plugins {
id("org.springframework.boot") version "2.2.4.RELEASE"
id("io.spring.dependency-management") version "1.0.9.RELEASE"
kotlin("jvm") version "1.3.61"
kotlin("plugin.spring") version "1.3.61"
kotlin("plugin.jpa") version "1.3.61" // <-- 추가됨
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa") // <-- 추가됨
implementation("org.springframework.boot:spring-boot-starter-jdbc") // <-- 추가됨
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("mysql:mysql-connector-java") // <-- 추가됨
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}
tasks.getByName<BootRun>("bootRun") {
main = "com.example.demo.DemoApplicationKt"
}
위 설정은 Spring boot Initializer를 통해 생성한 build.gradle.kt 에서 몇가지 dependency를 추가한 것입니다.
- JPA사용을 위한 Kotlin 플러그인을 추가해줬습니다. (plugin.jpa)
- 그리고 아래 라이브러리를 추가해줍시다.
- org.springframework.boot:spring-boot-starter-data-jpa
- org.springframework.boot:spring-boot-starter-jdbc
- mysql:mysql-connector-java
02. application.properties 수정
server.address=localhost
server.port=8080
spring.datasource.firstdb.jdbc-url=jdbc:mysql://[DB호스트]:[DB포트]/[DB명]
spring.datasource.firstdb.username=사용자명
spring.datasource.firstdb.password=패스워드
spring.datasource.firstdb.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.database=mysql
spring.jpa.show-sql=true
위와 같이 작성해주었습니다.
DB 정보들은 각자 환경에 맞게 변경해야합니다.
firstdb는 임의로 정한것이며 이것도 각자 datasource 이름을 명명하면 됩니다.
03. Config 파일 작성
package com.example.demo.spring
import com.zaxxer.hikari.HikariDataSource
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.transaction.PlatformTransactionManager
import org.springframework.transaction.annotation.EnableTransactionManagement
import javax.persistence.EntityManagerFactory
import javax.sql.DataSource
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
basePackages = ["com.example.demo.api"]
)
class DataSourceConfig {
@Primary
@Bean
@ConfigurationProperties("spring.datasource.firstdb")
fun dataSource(): DataSource {
val dataSource = DataSourceBuilder.create().type(HikariDataSource::class.java).build()
// UTF-8
dataSource.connectionInitSql = "SET NAMES utf8mb4"
return dataSource
}
@Primary
@Bean
fun entityManagerFactory(
builder: EntityManagerFactoryBuilder): LocalContainerEntityManagerFactoryBean {
return builder
.dataSource(this.dataSource())
.packages("com.example.demo.api")
.persistenceUnit("firstdb")
.build()
}
@Primary
@Bean
fun transactionManager(builder: EntityManagerFactoryBuilder): JpaTransactionManager {
return JpaTransactionManager(entityManagerFactory(builder).`object`!!)
}
}
Annotation의 강력한 기능을 이용해 코틀린소스로 설정을 하였습니다.
basePackage나 ConfigurationProperties는 각자에 맞게 수정해주시면 되구유. 간단히 각 함수를 설명하자면...
- dataSource : application.properies에서 DB 연결을 위한 설정값으로 dataSource를 만듭니다. 한글입력처리를 위해서 SET NAMES utf8이 추가됬구요. (위 설정은 여러 DB를 연결할때 설정입니다. 하나만 사용한다면 굳이 dataSource 만들필요없이 springboot 설정파일만 건드려도 됩니다...)
entityManager : JPA는 Entity라는 개념이 있습니다. 그외에도 Context와 Persist 등 생소한것들이 있는데.. 일단 넘어갑니다. (설명하기엔 저도 아직 부족하네요 ㅜㅜ)transactionManager : 트랜잭션을 위한 설정입니다. 해당 글에선 사용하지 않겠지만, 필수적인 개념이죠.
04. 간단히 사용해보기
4-1. 패키지 구성
member라는 패키지를 만들고 domain, repository를 만들어줬습니다. 그리고 MemberController를 생성했습니다.
4-2. Domain 작성
package com.example.demo.api.member.domain
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table
@Entity
@Table(name = "MEMBER")
data class Member(
@Id
@Column(name = "id")
var id: String = "",
@Column(name = "name")
var name: String = "",
@Column(name = "type")
var type: String = "",
@Column(name = "password")
var password: String = "",
@Column(name = "email")
var email: String = ""
)
위와 같이 작성해봤어요.
각자 테이블 구조에 맞게 맞춰주면됩니다.
여기서 주의할점!!
@Table의 name을 위처럼 대문자로 사용하기 위해선 아래와 같은 설정이 application.properties에 추가되야합니다.
...(생략)
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
4-3. Repository 작성
package com.example.demo.api.member.repository
import com.example.demo.api.member.domain.Member
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface MemberRepository : JpaRepository<Member, String>
위와같이 Repository로 작성해줍니다.
JpaRepository로 부터 인터페이스 상속 받았는데요. 요놈은 내부적으로 CrudRepository를 상속받아 구현되 있습니다.
Paging등 더 기능이 강력합니다.
위처럼 interface만 정의해줘도 find, save와 같은 메서드를 사용하여 DB를 조회하고 데이터를 입력할 수 있습니다.
만약 Primary Key가 숫자라면(ex. auto increament와 같은 설정사용시)
interface memberRepository: JpaRepository<Member, Long>과 같이 변경해줘야합니다.
4-4. Controller 작성
package com.example.demo.api.member
import com.example.demo.api.member.domain.Member
import com.example.demo.api.member.repository.MemberRepository
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/members")
class MemberController(
val memberRepository: MemberRepository
) {
@GetMapping()
fun getMembers(): ResponseEntity<*> {
val users = memberRepository.findAll()
return ResponseEntity.ok(users)
}
@PostMapping()
fun setMember(@RequestBody member: Member): ResponseEntity<*> {
val res = memberRepository.save(member)
return ResponseEntity.ok(res)
}
}
간단히 Member 테이블의 모든 row를 가져오는 것과 Member 테이블에 row를 하나 입력하는 Endpoint를 만들어 줬습니다.
@RestController로 작성되었기 때문에 이 예제는 API 서버의 역할을 하는 걸로 가정합니다.
05. 실행
서버를 띄워 확인해봅시다.
정상 작동하네요. 하지만 빈 배열이 응답합니다.
그렇다면 POST로 member를 입력 후, 다시 조회해봅시다.
API 툴을 사용해서 아래와 같은 JSON 데이터를 POST 전송했습니다.
{
"id": "test2",
"name":"rrrrr",
"password":"wfwef",
"type":"2",
"email":"test@eimeeme.com"
}
그리고 다시 조회 API를 호출해보면
정상동작을 확인 할 수 있습니다.
'개발 이야기 > Springboot' 카테고리의 다른 글
[Kotlin] Springboot + Redis 사용법 (0) | 2020.04.26 |
---|---|
[Kotlin] Springboot + Mybatis 사용법 (0) | 2020.03.28 |
[Kotlin] Springboot + Gradle 시작하기 (0) | 2020.02.22 |
Spring_Annotataion이란? (0) | 2018.10.03 |
Spring_@Scheduled 사용하기 (0) | 2018.05.25 |