SpringBoot + MyBatis + Oracle(with Docker) 초간단실습

JPA를 공부하기 전에 먼저 MyBatis로 서버를 셋팅하는걸 해보고 싶었다. 지난해 학원에서 교육받을때는 실력있는 팀원이 해주셔서 내가 직접 해본 경험이 없었다.

이 실습의 목적은 스프링부트로 만든 서버에서 MyBatis로 오라클에 쿼리를 던져서 조회하는 실습을 해볼 것이다.

DB는 도커(Docker)오라클 컨테이너를 생성해서 이용할 것이며, 커맨드라인에서 SQL PLUS 을 통해 테이블을 생성하고, 데이터를 삽입한다.

서버는 스프링부트(Spring Boot) 로 생성하며, MVC 패턴으로 생성한다.


DB 생성하기

도커 컨테이너 접속해서 SQL PLUS 실행하기

1
2
$ docker start oralce11g
$ docker exec -it oracle11g bash
1
root@a0ddd3dd3495: /# sqlplus

테이블 생성하기

1
2
3
4
5
6
CREATE TABLE members(
id number PRIMARY KEY,
name varchar2(20),
job varchar2(20),
loc varchar2(30)
);

id값에 INSERT할 때 사용하기 위한 SEQUENCE 생성하기

1
2
3
4
5
6
CREATE SEQUENCE id_seq  -- 시퀀스 이름
INCREMENT BY 1 -- 시퀀스 증감 숫자
START WITH 1 -- 시퀀스 시작 숫자
MINVALUE 1 -- 최솟값
MAXVALUE 100 -- 최댓값
NOCYCLE; -- 순환하지 않음

테이블에 값 추가하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INSERT INTO members(id, name, jon, loc)
VALUES (id_seq.nextval, 'Sam', 'Athelete', 'Seoul');

INSERT INTO members(id, name, jon, loc)
VALUES(id_seq.nextval, 'Andy', 'Programmer', 'Kyonggi');

INSERT INTO members(id, name, jon, loc)
VALUES(id_seq.nextval, 'Nani', 'Mechanical Engineer', 'Seoul');

INSERT INTO members(id, name, jon, loc)
VALUES(id_seq.nextval, 'Gil', 'Fashion MD', 'Seoul');

INSERT INTO members(id, name, jon, loc)
VALUES(id_seq.nextval, 'Tom', 'Reporter', 'Seoul');

COMMIT;

Spring Boot 서버 생성하기

프로젝트 생성하기

[Spring Start Project] 로 생성하고, Dependency로 Spring Web, Lombok, MyBatis Framework, Oracle Driver 을 주입한다.

프로젝트의 패키지 구조는 다음과 같다.


application.properties에 Datasource 설정 추가하기

먼저 MyBatis Mapper와 DBMS에 대한 Datasource 설정을 application.properties에서 한다. 본 파일은 /src/main/resources에 위치해있다.

1
2
3
4
5
6
7
8
9
10
11
# Setting for Oracle
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.username=[db-user-name]
spring.datasource.password=[db-user-password]

# VO location
mybatis.type-aliases-package=com.devandy.web.vo

# XML location
mybatis.mapper-locations=classpath:mappers/**/*.xml

VO와 XML 위치를 지정하는 설정을 미리 등록해두었다.


VO 생성하기

데이터를 오브젝트 형태로 담아놓을 VO를 생성한다.

경로 : /src/main/java/com/devandy/web/vo
파일명 : MemberVO.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.devandy.web.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class MemberVO {
@JsonProperty
private int id;

@JsonProperty
private String name;

@JsonProperty
private String job;

@JsonProperty
private String home;
}

Getter/Setter 메서드를 자동으로 생성해주는 Lombok 라이브러리의 @Data 어노테이션을 클래스 위에 작성한다.

그리고 Postman으로 Json 형식으로 데이터를 호출할것이므로 VO 각 필드위에 @JsonProperty 라는 어노테이션도 추가해준다. 이 어노테이션을 붙이지 않으면, API를 호출하는 과정에서 Serializable(직렬화) 에러가 발생한다.


DAO 생성하기

DB에 쿼리를 던지는 MyBatis Mapper 클래스를 생성하는 단계이다. DAO 안에 실제 쿼리까지 포함시킬수 있으나 인터페이스와 Mapper를 분리했다.

경로 : src/main/java/com/devandy/web/dao
파일명 : MemberDAO.class

1
2
3
4
5
6
7
8
9
10
package com.devandy.web.dao;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.devandy.web.vo.MemberVO;

@Mapper
public interface MemberDAO {
public List<MemberVO> selectAllMembers();
}

Mapper 작성하기 (Oracle 쿼리)

DAO를 구현하는 xml이다. 실제로 던지는 쿼리를 작성한다.

경로 : /src/main/resources/mappers/member
파일명 : SelectSQL.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?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.devandy.web.dao.MemberDAO">
<select id="selectAllMembers"
resultType="MemberVO">
SELECT ID, NAME, JOB, LOC
FROM MEMBERS
</select>
</mapper>

Mapper 태그안의 namespace 를 통해 MyBatis가 맵핑할 이 쿼리가 어떤 DAO에서 호출될 것인지 명시한다.

Mapper 태그 내부에는 쿼리의 타입으로 SELECT 인지, INSERT 인지를 명시하고, id는 DAO에서 해당 쿼리를 implement하는 메서드명을 작성해준다. resultType 은 DAO 메서드를 통해 반환받을 타입을 작성한다.

위의 쿼리를 단순히 MEMBERS라는 테이블을 조회하는 쿼리이므로, 반환받을 데이터는 VO 객체에 해당한다. 따라서 resultType 으로 VO 명을 작성한다.

정리하면, 위의 쿼리는 MemberDAO.classselectAllMembers() 를 구현하는 쿼리이며, 쿼리의 결과로 VO를 반환받는 객체이다.


Service 생성하기

Service 클래스는 MVC 패턴에서 Controller에의해 호출되며, 앞서 생성한 DAO를 호출하는 클래스이다.

경로 : src/main/java/com/devandy/web/service
파일명 : MemberService.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.devandy.web.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.devandy.web.dao.MemberDAO;
import com.devandy.web.vo.MemberVO;

@Service
public class MemberService {

@Autowired
MemberDAO memberDao;

public List<MemberVO> selectAllMembers() {
return memberDao.selectAllMembers();
}
}

Controller 생성하기

드디어 API를 호출하는 컨트롤러를 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.devandy.web.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.devandy.web.service.MemberService;
import com.devandy.web.vo.MemberVO;

@Controller
public class APIcontroller {

@Autowired
MemberService memberService;

@GetMapping("/members")
public @ResponseBody List<MemberVO> selectListMembers() {
List<MemberVO> allMembers = memberService.selectAllMembers();
return allMembers;
}
}

/members라는 API를 호출하는 selectListMembers()라는 메서드를 생성했다. 웹페이지를 반환하는게 아니라 Json 형식으로 데이터를 반환받을 것이므로 메서드의 리턴타입은 @ResponseBody 로 한다.

그리고 제네릭타입으로 MemberVO 를 갖는 List를 생성해서 List에 memberServiceselectAllMembers() 호출 결과를 담는다.

메서드의 리턴타입으로 이 List를 받으면, Postman을 통해 Json으로 데이터를 받을 수 있을 것이다.


Postman으로 API 호출하기

Postman은 API를 테스트할 수 있는 애플리케이션이다. Postman을 사용하면, 파라미터(param)나 인증(Authorization), Header 등을 변경해서 간편하게 API를 호출하는 테스트를 해볼수 있다.

GET 메서드로 http://localhost:8080/members 로 API를 호출해보니 오라클에서 작성한 테이블의 데이터가 정상적으로 JSON형식으로 반환받는 것을 확인할 수 있다.

이번엔 SQL Plus로 생성해놓은 테이블을 스프링부트로 생성한 웹 서버에 API를 요청해서 반환하는 것만 실습해보았다. 다음 포스팅에선 CRUD를 구현하는 실습을 해보겠다.