시작하기 전에
하기 포스팅은 "스프링부트 시작하기(김인우 저)" 책을 공부하며 적은 포스팅입니다. 이번 포스팅에서는 게시판 구현 전, 의존성 주입 및 데이터베이스 연결을 진행하고자 합니다.
SpringBoot 프로젝트 생성하기
File > New > Other...을 클릭하여 Spring Starter Project 프로젝트를 생성해보겠습니다. 기존에 SpringBoot 프로젝트 생성과 관련해 설명한 글이 있기 때문에 자세히 설명하지 않고 넘어가겠습니다.
위 사진과 같이 의존성 설정이 필요합니다. 각각 검색을 통해 필요한 라이브러리를 선택하면 됩니다. 프로젝트 생성한 후, Gradle이 라이브러리를 받는데 시간이 조금 걸릴 수 있습니다. 기존에 프로젝트 생성 시 체크했던 의존성을 포함하여 게시판 프로젝트에서 사용할 라이브러리를 추가해주었습니다. 각 의존성 이름은 SpringBoot 버전에 따라 다를 수 있으니, 참고하여 체크하면 되겠습니다.
위 의존성 설정에서 볼 수 있듯이 SpringBoot는 기본적인 웹 MVC 뿐 아니라, 대용량 분산서비스를 위한 스프링 클라우드(Spring Cloud), 페이스북이나 링크드인과 같은 SNS 관련 라이브러리, 여러 템플릿 엔진 등 다양한 환경과 요구사항에 맞는 어플리케이션 개발 시, 환경 설정에 유용합니다.
build.gradle 파일을 열어보면, 추가한 의존성이 잘 들어가있는 것을 확인할 수 있습니다.
/* build.gradle */
plugins {
id 'org.springframework.boot' version '2.4.1'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
이때, 의존성이 spring framework가 아닌, spring-boot-starter에 속해있음을 알 수 있습니다. SpringBoot를 사용하기 전에는 웹 어플리케이션에 필요한 라이브러리와 해당 라이브러리에 종속된 라이브러리들을 개발자가 일일이 추가해야 했습니다. 개발자가 일일이 추가하더라도, 각 라이브러리마다 요구하는 추가 라이브러리의 버전이 다르거나 충돌이 나는 경우가 종종 발생합니다.
SpringBoot는 이러한 어려움을 해결하기 위해, 웹 어플리케이션의 기능에 따라 spring-boot-starter 의존성 그룹을 만들어 각각의 그룹에 맞는 의존성이 자동으로 포함되도록 했습니다.
Gradle을 이용한 라이브러리 다운로드하기
spring-boot-starter를 이용하여 어플리케이션을 생성하면, 처음에 선택한 라이브러리들을 자동으로 다운로드합니다. 이때, 라이브러리 다운로드 중 에러가 발생할 수도 있습니다. 또한, 어플리케이션 개발 진행 중 여러 라이브러리를 추가해야 할 경우가 있을 수 있습니다.
이 경우, build.gradle에 라이브러리를 추가하고 Gradle을 이용해서 라이브러리를 다운로드하면 됩니다. 프로젝트 우클릭 후 Gradle > Refresh Gradle Project를 선택하면, build.gradle에 정의된 라이브러리 중 새로 추가되거나 다운로드 중 에러가 발생한 라이브러리를 다운로드하게 됩니다.
데이터베이스 연결하기
웹 어플리케이션에 데이터베이스는 거의 필수적인 요소입니다. 여기서는 데이터베이스를 사용하기 위한 기본 설정을 하겠습니다. 일반적인 프로젝트에서는 개발 서버에 데이터베이스를 설치하고 사용합니다. 만약, 학습용으로 사용할 수 있는 데이터베이스가 있다면 그것을 사용하면 됩니다. 서버가 없다면 로컬 환경에 데이터베이스를 설치하고 진행해야 합니다. MySQL이 설치되어 있다는 가정하에 진행하겠습니다. 로컬 환경에 MySQL 설치하는 포스팅은 따로 남겨두었으니, 필요시 참고하시면 됩니다.
데이터 소스 설정하기
SpringBoot 프로젝트의 경우 DataSource를 처리하기 위해서는 크게 두 가지 방식을 사용합니다.
- application.properties를 이용하여 데이터 소스를 설정합니다.
- @Bean 어노테이션을 이용하여 데이터 소스를 설정합니다.
두 방식 모두 사용할 수 있지만, 개발환경과 운영환경에서 다르게 적용될 수 있는 설정들은 application.properties에 정의하는 것이 좋습니다. 이는 각 환경에 따른 프로퍼티 파일을 만들고 그에 따른 설정을 정의한 후, 어플리케이션이 실행되는 환경에 따라 자동적으로 원하는 설정을 선택하기 위함입니다.
application.properties에 데이터 소스 설정하기
src/main/resources 폴더에 있는 application.properties 파일에 아래 내용을 작성합니다.
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.hikari.username=[ 계정명(예: root) ]
spring.datasource.hikari.password=[ 비밀번호(처음 생성 시 정한 비밀번호) ]
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.jdbc-url
: 연결할 데이터베이스의 주소를 설정합니다. 주소에 유니코드 설정과 UTF-8 문자열 인코딩, 그리고 서버의 타임존 설정을 추가했습니다.spring.datasource.hikari.username, password
: 데이터베이스의 아이디와 비밀번호를 설정합니다.spring.datasource.hikari.connection-test-query
: 데이터베이스와 정상적으로 연결되는지 확인하기 위한 테스트 쿼리 입니다.allowPublicKeyRetrieval=true&useSSL=false
: jdbc-url을 지정하는 구문 제일 뒤에 붙어있는 부분으로, mySQL 8 버전 이상을 사용할 경우 넣어주어야 하는 옵션입니다. 이 옵션을 넣어줌으로써 클라이언트가 서버에서 자동으로 공개키를 요청할 수 있게됩니다. MITM 공격을 방지하기 위해 기본적으로 false로 되어있으므로, 명시적으로 활성화해야 합니다.
DatabaseConfiguration 클래스 만들기
src/main/java/board 패키지 밑에 configuration 패키지를 생성하고 DatabaseConfiguration 클래스를 생성합니다. 해당 클래스에는 아래 코드를 작성하면 됩니다.
board 패키지 밑에 신규 패키지를 생성할 경우, Source folder: board/src/main/java로 뜨게 됩니다. 이때, board 밑에 configuration이 있어야한다고 해서 Source folder를 임의로 변경하면 안됩니다(아래 왼쪽 사진과 같은 에러 발생).
위 stackoverflow를 참고하여 name을 board.configuration으로 정하면, board 패키지 밑에 configuration 패키지가 생성됩니다.
package board.configuration;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfiguration {
@Bean
@ConfigurationProperties(prefix="spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
@Bean
public DataSource dataSource() throws Exception {
DataSource dataSource = new HikariDataSource(hikariConfig());
System.out.println(dataSource.toString());
return dataSource;
}
}
- @PropertySource("classpath:/application.properties"): application.properties를 설정 파일로 사용할 수 있도록 위치를 지정합니다. @PropertySource 어노테이션을 추가하여 다른 설정 파일도 사용할 수 있습니다.
- @ConfigurationProperties(prefix="spring.datasource.hikari"): application.properties에서 설정했던 데이터베이스 관련 정보를 사용하도록 지정합니다. @ConfigurationProperties의 prefix가 spring.datasource.hikari로 지정되어 있으므로, spring.datasource.hikari로 시작하는 설정을 이용해 히카리CP의 설정 파일을 만듭니다.
- DataSource = dataSource = new HikariDataSource(hikariConfig()): 앞서 만든 히카리CP 설정 파일을 이용하여 database와 연결할 datasource를 생성합니다. 여기서는 datasource가 제대로 생성되었는지 확인하기 위해 데이터소스를 출력(System.out.println(dataSource.toString())했습니다.
application.properties 설정 및 DatabaseConfiguration.java 설정 후 springboot 실행한 결과
책에서 예상한 결과는 SELECT 1 쿼리가 실행되는 것입니다. 그런데, 필자의 로그를 보면 "No MyBatis mapper was found in '[board]' package. Please check your configuration.이 있습니다. 예상컨데, mapper 관련 설정이 없어 접근을 하지 못한 것으로 보입니다. 일단 책 내용을 쭉 따라해보며, 이후엔 문제가 없는지 보겠습니다.
myBatis 연동하기
myBatis란, 쿼리 기반 웹 어플리케이션을 개발할 때 가장 많이 사용되는 sql mapper 프레임워크입니다. myBatis를 사용하지 않고 직접 JDBC를 이용할 경우, 개발자가 작성해야 할 코드가 늘어나고 서비스 로직 코드와 쿼리를 분리하기 어렵습니다. 또한, 커넥션 풀의 설정 등을 개발자가 하나하나 신경을 써야하는 문제가 있습니다. 따라서, JDBC를 이용해 직접 개발하기보다는 myBatis와 같은 프레임워크를 사용하는게 일반적입니다.
JDBC를 이용하여 직접 프로그래밍을 한다면?
클래스나 JSP와 같은 코드 안에 SQL을 작성해야 합니다. 즉, SQL의 변경이 일어날 때에 프로그램 자체를 수정해야하는 어려움이 있습니다. 반면, myBatis를 사용하면 SQL을 XML 파일에 작성하여 SQL의 변환이 자유롭고 가독성이 좋습니다.
myBatis 설정하기
앞서 만든 DataBaseConfiguration 클래스를 하기와 같이 수정합니다.
package board.configuration;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
@ConfigurationProperties(prefix="spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
@Bean
public DataSource dataSource() throws Exception {
DataSource dataSource = new HikariDataSource(hikariConfig());
System.out.println(dataSource.toString());
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:/mapper/**/sql-*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
- SqlSessionFactoryBean.sqlSessionFactoryBean = new SqlSessionFactoryBean(): spring-myBatis에서는 SqlSessionFactory를 생성하기 위해서는 SqlSessionFactoryBean을 사용합니다. 만약 spring이 아닌 myBatis를 단독으로 사용할 경우에는 SqlSessionFactoryBuilder를 사용합니다.
- SqlSessionFactoryBean.setDataSource(dataSource): 앞서 만든 datasource로 설정합니다.
- SqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:/mapper/**/sql-*.xml")): myBatis의 mapper 파일 위치를 설정합니다. mapper는 어플리케이션에서 사용할 SQL을 담고 있는 XML 파일을 의미합니다. mapper를 등록할 때에는 mapper 파일을 하나씩 따로 등록할 수도 있지만, 하나의 어플리케이션에는 일반적으로 많은 수의 mapper 파일이 있어 하나하나 등록이 어렵습니다. 그래서, 이렇게 패턴을 정해 xml 파일을 등록합니다.
- classpath: resources 폴더를 의미함
- /mapper/**/: mapper 폴더 밑의 모든 폴더를 의미함. 프로젝트에 따라 mapper 파일이 여러개일 수도 있고, mapper 폴더 밑에 여러 폴더로 나뉘어져있는 경우도 있을 수 있어 이렇게 지정함
- /sql-*.xml: 이름이 sql로 시작하고 확장자가 xml인 모든 파일을 의미함
mapper 폴더 생성하기
src/main/resourcfes 폴더 밑에 mapper 폴더를 생성합니다. mapper 폴더에는 어플리케이션에서 사용할 쿼리를 담고 있는 XML 파일을 저장합니다.
myBatis 연결 확인하기
myBatis 연결이 제대로 되었는지 확인하기 위해 src/test/java 밑의 board 패키지의 BoardApplicationTests.java 코드를 작성해보겠습니다. 해당 패키지는 테스트를 위한 패키지로 JUnit를 이용하여 테스트를 할 수 있게 해줍니다.
BoardApplicationTests.java 파일에는 아래와 같이 작성하면 됩니다(책과 달리 제 Springboot에는 JUnit 5가 설치되어 있어 소스 코드가 조금 다릅니다).
package board;
/* springboot 2.2 부터 junit 5 */
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
class BoardApplicationTests {
@Autowired
private SqlSessionTemplate sqlSession;
@Test
void contextLoads() {
}
@Test
public void testSqlSession() throws Exception{
System.out.println(sqlSession.toString());
}
}
myBatis 설정 후 BoardApplicationTests.java 실행 결과
Test 소스에서 sqlSession을 string 형식으로 출력하기 위해서는 sqlSession이라는 객체를 생성해야 했습니다. 따라서, 해당 출력 부분이 실행 결과 내 빨간 박스에 존재하므로 해당 실습은 성공입니다.
마무리
앞서 datasource만 설정했을 때와 다르게 myBatis 부분에서는 원하는 결과가 생성되긴 했습니다. 다만, SELECT 1은 테스트 쿼리라 생성이 되었어야 할 것 같아 조금 의문이 남지만 일단 진도를 나가보도록 하겠습니다.
'FRAMEWORK > Spring' 카테고리의 다른 글
[SpringBoot] 게시판 구현하기 4 (게시글 등록 기능 생성하기) (0) | 2020.12.21 |
---|---|
[SpringBoot] 게시판 구현하기 3 (게시판 목록 만들기) (2) | 2020.12.21 |
[SpringBoot] 게시판 구현하기 2 (게시판을 만들기 위한 기본 설정) (1) | 2020.12.13 |
[Spring] 스프링 프레임워크 이해하기 (0) | 2020.12.12 |
[SpringBoot] Springboot 프로젝트 만들어보기 (0) | 2020.12.12 |