'Spring Boot'에 해당되는 글 2건

  1. Spring Boot, MyBatis 연동으로 MySQL 데이터베이스 질의하기 (4)
  2. IntelliJ IDEA에서 Spring Boot 웹 프로젝트 생성하기 (1)

Spring Boot, MyBatis 연동으로 MySQL 데이터베이스 질의하기

먼저 읽어볼만한 글

데이터베이스 연결 및 질의를 위한 의존성 정보 추가

/build.gradle에 아래 내용을 추가한다. MyBatis 라이브러리를 이용하여 MySQL 데이터베이스에 연결하기 위한 의존성 정보이다.

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', version: '1.3.5.RELEASE'
    compile group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '1.1.1'
    compile group: 'org.mybatis', name: 'mybatis-typehandlers-jsr310', version: '1.0.1'
    compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.2'
}
  • mybatis-typehandlers-jsr310 아티팩트는 데이터베이스 컬럼의 날짜/시간 타입을 Java 8부터 추가된 LocalDate, LocalTime, LocalDateTime, Year, Month 클래스로의 자동 맵핑을 지원한다. MyBatis 3.4 버전부터 자동 지원되며 이전 버전은 별도의 typeHandler 등록이 필요하다.

데이터베이스 연결 정보 작성

/src/main/resouces/application.properties에 아래와 같이 연결한 데이터베이스 연결 정보를 작성한다. Profile에 따라 다른 연결 정보를 작성하면 개발, 운영 환경에 따라 연결 데이터베이스를 다르게 설정할 수 있다.

spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_example
spring.datasource.username=root
spring.datasource.password=Q1w2e3r4
spring.datasource.connectionProperties=useSSL=false;useUnicode=yes;characterEncoding=UTF-8;serverTimezone=UTC
spring.datasource.initSQL=SELECT 1

  • DataSourceProperties 클래스에 의해 위에 명시한 데이터베이스 연결 정보를 맵핑한다.


    • spring.datasource.type: 데이터베이스에 연결할 DataSource 클래스명을 명시한다. 여기서는 Tomcat JDBC Connection Pool을 명시했다. 별도로 명시하지 않을 경우 DataSourceBuilder 클래스에 의해 Tomcat JDBC Connection Pool, HikariCP, DBCP 1, DBCP 2 순서대로 유무를 조사하여 자동 등록한다.

    • spring.datasource.driverClassName: 데이터베이스에 연결할 Driver 클래스명을 명시한다. MySQL에 접속하기 위해 Connector/J를 명시했다. 역시 별도로 명시하지 않을 경우 자동 등록한다.


  • Tomcat JDBC Connection Pool을 사용할 경우 PoolConfiguration 클래스에 의해 추가 설정을 적용한다. 위 예제에는 2개의 추가 설정 만을 명시했지만 실제로 레퍼런스 문서에 명시된 모든 설정 값을 명시할 수 있다.


    • spring.datasource.connectionProperties: 데이터베이스 연결시 적용할 파라메터를 명시한다. 데이터베이스 환경마다 다르므로 적절한 파라메터를 입력한다.


    • spring.datasource.initSQL: 새로운 연결을 생성할 때 마다 실행할 SQL 문을 명시한다.


  • DataSourceAutoConfiguration 클래스에 의해 위 맵핑된 데이터베이스 연결 정보로 dataSource(javax.sql.DataSource) 이름의 빈을 생성한다. 위 방법을 사용하지 않고 직접 입맛에 맞게 dataSource 빈을 생성해도 무방하다.


  • MybatisAutoConfiguration 클래스에 의해 위 생성된 dataSource 빈을 자동으로 인지하여 sqlSeesionFactory(org.mybatis.spring), sqlSessionTemplate(org.mybatis.spring) 이름의 빈을 생성한다. 이 것 만으로 애플리케이션에서 MySQL 데이터베이스에 질의하기 위한 준비는 끝났다.

데이터베이스 질의를 수행하는 DAO 클래스 작성

/src/main/com.jsonobject.example/ExampleDAO.java를 아래와 같이 작성한다. 데이터베이스의 현재 시간을 문자열로 반환하는 간단한 기능이다. 아래와 같은 어노테이션 기반의 질의문 작성은 간단하고 직관적이지만 실제로 프로덕션 레벨에서 요구되는 Dynamic SQL을 소화하기에는 한계가 있으므로 XML 방식의 Mapper 사용을 추천한다.

package com.jsonobject.example;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface ExampleDAO {

    @Select("SELECT NOW()")
    String getCurrentDateTime();
}

DAO를 소비하는 비즈니스 로직 작성

아래는 앞서 작성한 DAO 클래스를 이용하여 비즈니스 로직을 작성한 예이다. 기본적인 Java, JDBC를 이용한 질의에 비해 Spring Boot, MyBatis를 이용한 질의는 매우 간단한 것을 확인할 수 있다.

package com.jsonobject.example;

@Service
public class ExampleService {

    @Autowired
    private ExampleDAO exampleDAO;

    public String getCurrentDataTime() {

        return exampleDAO.getCurrentDateTime();
    }
}

2개 이상의 데이터베이스 연결을 위한 설정

앞서 설명한 방법은 애플리케이션에서 1개의 데이터베이스에만 연결한다는 전제 하에 Spring Boot, MyBatis에 의해 미리 만들어진 코드에 의해 각 1개의 DataSource, SqlSessionFactory, SqlSessionTemplate 빈을 자동으로 생성하고 사용하는 시나리오였다. 하지만 프로덕션 레벨에서는 2개 이상의 데이터베이스에 연결하는 요구사항이 흔히 발생한다. 이번에는 2개 이상의 데이터베이스 질의를 수용할 수 있는 방법을 설명한다. 연결할 데이터베이스의 이름을 first라고 가정하고 진행하겠다.

/src/main/resources/application.properties 파일을 아래와 같이 작성한다.

spring.first.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.first.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.first.datasource.url=jdbc:mysql://localhost:3306/spring_boot_example
spring.first.datasource.username=root
spring.first.datasource.password=Q1w2e3r4
spring.first.datasource.connectionProperties=useSSL=false;useUnicode=yes;characterEncoding=UTF-8;serverTimezone=UTC
spring.first.datasource.initSQL=SELECT 1
  • first라는 키워드를 부여함으로서 추후 second, third 등 2개 이상의 데이터베이스 연결이 가능하도록 확장성을 부여했다. 단지 예시일 뿐 어떤 이름을 부여해도 무방하다.

/src/main/java/com.jsonobject.example/FirstDataSoureConfig.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
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 javax.sql.DataSource;

@Configuration
public class FirstDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.first.datasource")
    public DataSource firstDataSource() {

        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory firstSqlSessionFactory(DataSource firstDataSource, ApplicationContext applicationContext) throws Exception {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(firstDataSource);
        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mapper/first/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate firstSqlSessionTemplate(SqlSessionFactory firstSqlSessionFactory) throws Exception {

        return new SqlSessionTemplate(firstSqlSessionFactory);
    }
}
  • 앞서 1개의 데이터베이스 만을 구성할 때는 별도의 클래스 작성이 필요 없었지만 2개 이상부터는 위와 같이 DataSource, SqlSessionFactory, SqlSessionTemplate 빈을 별도로 생성하는 작업이 필요하다. 다른 데이터베이스 연결을 위한 작업시 위와 동일한 형태의 클래스를 작성해주면 된다.

/src/main/java/com.jsonobject.example/ExampleDAO.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

@Repository
public class ExampleDAO {

    @Autowired
    @Qualifier("firstSqlSessionTemplate")
    private SqlSession sqlSession;

    public String getCurrentDateTime() {

        return sqlSession.selectOne("com.jsonobject.example.mapper.ExampleMapper.getCurrentDateTime");
    }
}
  • 앞서 생성한 firstSqlSessionTemplate 빈을 맵핑한 것을 확인할 수 있다.

마지막으로 /src/main/resources/mapper/first/ExampleMapper.xml 파일을 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jsonobject.example.mapper.ExampleMapper">
    <select id="getCurrentDateTime" resultType="String">
        SELECT NOW()
    </select>
</mapper>
  • MyBatis의 장기인 강력한 Dynamic SQL 기능을 이용하려면 위와 같이 Mapper라 불리는 XML 문서에 SQL 문을 작성해야 한다. 프로젝트의 통일성을 위해 DAO 클래스의 패키지명과 일치하는 경로에 저장하도록 한다. 예를 들면 아래와 같다.
    • /src/main/java/com/jsonobject/example/dao/UserDAO.java
    • /src/main/resources/com/jsonobject/example/mapper/UserMapper.xml

참고 글


저작자 표시 비영리 동일 조건 변경 허락
신고

IntelliJ IDEA에서 Spring Boot 웹 프로젝트 생성하기

개요

Spring Boot는 최근 Java 진영에서 각광 받고 있는 간결하고 강력한 웹 프레임워크이다. 이름에서 드러나듯이 국내에서 가장 사랑 받는 Spring 프레임워크를 기반으로 한다. 경쟁자로 역시 뒤지지 않는 막강한 기능의 Dropwizard가 존재하지만 그리 친숙하지 않은 JAX-RS를 기반으로 하여 앞으로도 국내에서 많이 쓰이지는 않을 것으로 생각된다.(나는 작년 국내 모 영화 포탈 서비스의 일부를 JAX-RS 기반의 Jersey로 개발하며 상당한 생산성 향상을 경험한 적이 있다. 문제는 후에 담당한 운영 인력이 익숙치 않은 문법에 어려움을 겪었다고 한다.) 최근에는 소속한 회사의 REST API 백엔드 서비스를 Spring Boot로 개발하고 있는데 매번 그 편리함에 감탄하고 있다. 한편, IntelliJ IDEAEclipse를 압도하는 Java 진영 최강의 IDE로 군림하고 있다. IntelliJSpring Boot의 조합은 신세계라고 생각되어 본 글에서 간단히 프로젝트 생성 방법을 소개하고자 한다.

Spring Boot 프로젝트 생성

먼저 Spring Boot 프로젝트를 생성한다. JDK 8, IntelliJ IDEA 15가 이미 설치된 상태라고 가정하고 진행한다.

  • IntelliJ IDEA 실행 → Create New Project 클릭
  • 좌측 메뉴에서 Gradle 클릭 → Project SDK: 1.8 → Additional Libraries and Frameworks: Java 체크 → Next 클릭
  • GroupId: com.jsonobject 입력 → ArtifactId: spring-boot-example 입력 → Version: 0.0.1 입력 → Next 클릭
  • Use auto-import 체크 → Create directories for empty content roots automatically 체크 → Use default gradle wrapper (recommended) 선택 → Gradle JVM: 1.8 선택→ Next 클릭
  • Project name: spring-boot-example 입력 → Project location: D:\Projects\spring-boot-example 입력 → Finish 클릭

build.gradle 작성

프로젝트 생성을 완료하면 /build.gradle 파일이 생성되어 있다. 아래 내용으로 교체하자. 프로젝트 생성을 위한 최소한의 구성으로 실제 엔터프라이즈 급의 프로젝트를 생성하려면 테스트, 배포 태스크 등 훨씬 복잡한 내용이 추가되어야 한다.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: '1.4.0.RELEASE'
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'spring-boot-example'
    version = '0.0.1'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.5'
}
  • Spring Boot(1.3.5)는 기본적으로 Embedded Tomcat(8.0.33)을 컨테이너로 사용한다. 전통적으로 컨테이너 위에서 배포되어 작동하는 방식이 아니라 빌드된 .JAR를 실행하면 내장된 컨테이너를 실행하여 애플리케이션을 작동시킨다. 이런 특징은 번거로운 배포 절차와 컨테이너에 대한 애플리케이션의 종속성을 최소화 시켜준다.

.gitignore 작성

Git으로 소스 코드를 관리할 경우 IntelliJ IDEAGradle이 생성하는 파일까지 관리 대상이 되는 것은 불필요한 일이다. /.gitignore 파일을 아래와 같이 작성하여 필요한 파일만 관리되도록 설정한다.

.gradle
.idea
build
*.iml

Application.java 작성

@SpringBootApplication 어노테이션이 붙는 클래스는 Spring Boot 프로젝트 실행의 시작점이다. /src/main/java/com.jsonobject.example/Application.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}
  • Spring Boot 기반의 웹 애플리케이션은 ApplicationContext 오브젝트를 어디에 저장될까? 바로 ServletContext의 애트리뷰트(Key: org.springframework.web.context.WebApplicationContext.ROOT, Value: AnnotationConfigEmbeddedWebApplicationContext 오브젝트)에 저장한다. 따라서 ServeltContext와 같은 생명주기를 가질 수 있다.

HelloController.java 작성

Spring Boot 프로젝트 개발을 위한 최소한의 준비가 끝났다. @Controller 클래스를 작성해보자. /src/main/java/com.jsonobject.example/HelloController.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/")
    public String hello() {

        return "Hello, Spring Boot!";
    }
}

테스트

/(루트) 경로의 HTTP 요청에 대응하는 컨트롤러 작성까지 끝났다. 이제 테스트를 해보자. 브라우저를 열고 http://localhost:8080/에 접속한다. 화면에 Hello, Spring Boot! 문자열이 출력되었다면 정상적으로 실행된 것이다.

빌드

Spring Boot로 제작한 애플리케이션을 빌드하면 1개의 .jar 파일이 생성된다.

  • Shift 키 2번 연타 -> Gradle 입력 후 Tool Windows: Gradle 선택 -> Tasks -> build -> build 실행
  • /{project_location}/build/libs/{project_name}-{version}.jar 경로에서 빌드되어 생성된 .jar 파일을 확인할 수 있다.

실행

빌드된 .jar 파일은 일반적인 Java 애플리케이션과 완전히 동일한 방법으로 구동된다.

# 일반적인 Java 애플리케이션으로 실행한다.
$ java -jar {project_name}-{version}.jar

# 리눅스 운영체제에서 24시간 백그라운드로 동작하는 데몬으로 실행한다.
$ nohup java -server -jar {project_name}-{version}.jar &

결론

앞으로 Spring Boot 기반의 프로덕션 서비스를 구축하면서 경험하고 깨달은 것을 차근차근 글로 작성해보고자 한다. 작은 첫 시작으로 기본적인 프로젝트 생성 글을 작성하였고 앞으로 계속 새로운 글을 작성할 예정이다.

참고 글

다음 단계로 읽을만한 글

저작자 표시 비영리 동일 조건 변경 허락
신고