[SpringBoot] Rest Api Sample ๋ง๋ค๊ธฐ #1
๊ธฐ์กด์ ๊ธํ๊ฒ ์งํํ ์ฌ๋ด SMS API ์๋น์ค๋ฅผ ๋ง๋ค๊ณ ๋์, ์ ๋ฆฌ๋ ํ ๊ฒธ ์ํ๋ก REST API ์ํ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด๊ธฐ๋ก ํ๋ค.
๊ธฐ๋ณธ์ ์ธ ๋ฒ์ ์ ๋ณด๋ ๋ค์๊ณผ ๊ฐ๋ค.
1. ๊ธฐ๋ณธ ํ๋ก์ ํธ ์ธํ
- JDK11
- Spring Boot 2.7.1
- Gradle 7.4.1 (Project Initialize > VS Code Spring Extension > Create a Gradle Project)
๊ทธ๋ฆฌ๊ณ Build.gradle ์ ์ถ๊ฐํ dependency ๋ ์๋์ ๊ฐ๋ค.
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// dev tool
implementation group: 'org.springframework.boot', name: 'spring-boot-devtools'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.9'
// https://mvnrepository.com/artifact/com.h2database/h2
implementation group: 'com.h2database', name: 'h2', version: '2.1.214'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jdbc
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jdbc', version: '2.7.1'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.7.1'
// https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter
implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '2.2.2'
์ค์ ํ๋ฉด์, ์ถ๊ฐ์ ์ผ๋ก ์๋๋ ํ ์คํธ ํ ๋ ๋ฐ๋ณต๋ฌธ์ ํตํด์ ๋ฐ์ดํฐ ์ํ์ ์์ฑํ์ฌ ํ ์คํธํ๊ณค ํ์๋๋ฐ, ์ค์ ์ด ์ํ์ ๊ธฐ๋ฐ์ผ๋ก ์๋น์ค๋ฅผ ์์ฑํ๊ฒ ๋๋ฉด ์ด์ฐจํผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ API๋ฅผ ๊ตฌ์ฑํด์ผ ํ๋ ๋งํผ ์ํ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ํ๋ฉด ํจ์จ์ ์ผ๋ก ์ ๊ณตํ ์ ์์๊น๋ฅผ ๊ณ ๋ฏผํ์๋๋ฐ, ๊ทธ ๋ ๋ง์นจ ๊ฒ์ํด์ ๋์จ ๊ฒ์ด h2 Database ์๋ค.
์ฌํ๊น์ง๋ "ํ ์คํธ" ๋จ๊ณ๋ ๊ทธ๋ค์ง ๋ง์ด ๊ณ ๋ ค๋ฅผ ํ์ง ์์์๋๋ฐ, ๋ง์ ์ฌ์ฉํด๋ณด๋ ์๊ฐ๋ณด๋ค ๊ด์ฐฎ์๋ค.
Spring Boot์ Auto Configuration์ ํตํ์ฌ ๋ณ๋์ ๋ง์ ์
ํ
์ ํ์ง ์๋๋ผ๋ DB๋ฅผ ์ธํ
ํ์ฌ ํ๋ก์ ํธ๋ฅผ ๋๋ฆด ์ ์์๋ค.
์๋๋ h2 database์ ๋ํด ์ฐพ์ ๋ธ๋ก๊ทธ ๊ธ์ด๋ค.
https://dololak.tistory.com/285
[H2DB] H2 Database๋? H2DB ์ค์น ๋ฐฉ๋ฒ
H2DB H2DB๋ ์๋ฐ ๊ธฐ๋ฐ์ ์คํ์์ค ๊ด๊ณํ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ๊ด๋ฆฌ ์์คํ (RDBMS )์ ๋๋ค. H2DB๋ ์๋ฒ(Server) ๋ชจ๋์ ์๋ฒ ๋๋(Embedded) ๋ชจ๋์ ์ธ๋ฉ๋ชจ๋ฆฌ DB ๊ธฐ๋ฅ์ ์ง์ํฉ๋๋ค. ๋ฌผ๋ก ๋์คํฌ ๊ธฐ๋ฐ ํ ์ด๋ธ์
dololak.tistory.com
์ค์ ์๋น์ค์์๋ MyBatis๋ฅผ ์ฌ์ฉํ๋ ๋งํผ ์ํ ํ๋ก์ ํธ์์๋ ์ฐ๋ํด๋ณด์๋ค.
2. h2 Database + MyBatis ์ฐ๊ณ ์ค์
์ฐ์ build.gradle์ ์๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ค.
build.gradle
// https://mvnrepository.com/artifact/com.h2database/h2
implementation group: 'com.h2database', name: 'h2', version: '2.1.214'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jdbc
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jdbc', version: '2.7.1'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.7.1'
// https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter
implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '2.2.2'
์ค์ ํ์ผ์ ์๋์ ๊ฐ์ด ์ธํ ํ๋ค.
application.yml
spring:
application:
name: REST-API
datasource:
hikari:
# ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ DB๋ฅผ ์ฌ๋ฆฐ๋ค.
jdbc-url: jdbc:h2:mem:h2-test
# ํ์ผ ํํ๋ฅผ ์ฌ์ฉํ๊ณ ์ ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ค.
# jdbc-url: jdbc:h2:file:{๊ฒฝ๋ก}/{ํ์ผ๋ช
}
driver-class-name: org.h2.Driver
username: sa
password:
generate-unique-name: false
maximum-pool-size: 4
h2:
console:
enable: true
path: /h2-console
h2-test๋ผ๋ DB๋ช ์ ๋ง์๋๋ก, username/password๋ ์์ ๊ฐ์ด ์ค์ ํ๋ค. ์๋์ h2 ํญ๋ชฉ์ ๋ธ๋ผ์ฐ์ ๋ก ์ฝ์์ฐฝ์ ์ ๊ทผํ๊ธฐ ์ํ ์ค์ ๊ณผ ๊ฒฝ๋ก์ด๋ค. ์ ์ค์ ๋๋ก๋ผ๋ฉด ์ดํ๋ฆฌ์ผ์ด์ ๊ตฌ๋ ํ, http://localhost:8080/h2-console ๋ก ์ฝ์์ ์ ์์ด ๊ฐ๋ฅํ๋ค(8080ํฌํธ๊ธฐ์ค)
๊ทธ๋ฆฌ๊ณ ๋ ํ ๊ฐ๋จํ test ํด๋์ค๋ฅผ ์์ฑํ์ฌ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ๋ํ์ฌ DB๊ฐ ์ฌ๋ผ์ค๋์ง ํ์ธ ํ ์ ์๋ค.
testRunner.java
package rest.api.sample;
import java.sql.Connection;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class TestRunner implements ApplicationRunner {
@Autowired
DataSource dataSource;
@Override
public void run(ApplicationArguments args) throws Exception {
Connection connection = dataSource.getConnection();
System.out.println("url : " + connection.getMetaData().getURL());
System.out.println("userName : " + connection.getMetaData().getUserName());
}
}
์ด๋ ๊ฒ ๋ก๊ทธ๊ฐ ์ ์์ ์ผ๋ก ์ฐํ๋ค๋ฉด ๋ฌธ์ ์์ด ๊ตฌ๋๋ ๊ฒ์ด๊ณ , ์ฝ์๋ก๋ ํ์ธ์ด ๊ฐ๋ฅํ๋ค.
๋ด๊ฐ ๊ฒช์ ๋ฌธ์ ๋ก๋ Spring Boot ์ Auto Configuration์ด ์ ๋๋ก ๋์ํ์ง ์์์ No Bean for datasouce ์๋ฌ๊ฐ ๋จ๊ธด ํ๋๋ฐ, ์๋ก๊ณ ์นจ๊ณผ ์ฌ๋ก๋ฉ์ ํตํด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค.
์ด์ MyBatis๋ฅผ ์ถ๊ฐํด๋ณด์.
build.gradle์๋ ์๊น ์ถ๊ฐ๋ฅผ ํ์ผ๋, application.yml์ ์๋์ ์ค์ ์ ์ถ๊ฐํ๋ค.
application.yml
mybatis:
# mapperํ์ผ ์์น ์ค์
mapper-locations: mybatis/**/*.xml
# ์นด๋ฉ ์ผ์ด์ค ํ์ฉ
configuration:
map-underscore-to-camel-case: true
# ํ ํจํค์ง๋ช
์ ์ง์ ํ์ง ์๊ธฐ ์ํ ๋ฏธ๋ฆฌ ์ ์ ์ถ๊ฐ
type-aliases-package: rest.api.sample.data
๊ทธ๋ฆฌ๊ณ ๊ฐ ์ค์ ์ ๋ง๊ฒ repository์ interface ํด๋์ค์ mapper๋ฅผ ์ถ๊ฐํ๋ฉด ๋๋ค.
3. Boot Running ์, h2 database์ ์ํ ๋ฐ์ดํฐ ์ถ๊ฐํ๊ธฐ.
๊ธฐ๋ณธ์ ์ผ๋ก h2 database๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด, schema์ ๋ฐ์ดํฐ๋ฅผ ์ดํ๋ฆฌ์ผ์ด์
๊ตฌ๋ ์, ์๋์ผ๋ก ์ฐพ์์ ์คํํด์ค๋ค.
๋ฐ๋ผ์, ํด๋น sql ํ์ผ์ ์์ฑํ์ฌ ์ ์ ํ๊ฒ ๋๋๋ฉด ์ดํ๋ฆฌ์ผ์ด์
๊ตฌ๋ ์, ์์์ ์ฝ์ด์ ์คํ์ ์์ผ์ค๋ค.
๊ฒฝ๋ก๋ resouces ํด๋ ์๋์ด๋ฉฐ, ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
schema.sql
CREATE TABLE IF NOT EXISTS members
(
user_id VARCHAR(50) NOT NULL,
user_name VARCHAR(50) NOT NULL,
user_email VARCHAR(50) NOT NULL,
user_age VARCHAR(50) NOT NULL,
user_address VARCHAR(50) NOT NULL,
user_enter_date VARCHAR(50) NOT NULL,
PRIMARY KEY (user_id)
);
data.sql
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user1','์ ์ 1','user1@user.net','1','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 1๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user2','์ ์ 2','user2@user.net','2','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 2๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user3','์ ์ 3','user3@user.net','3','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 3๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user4','์ ์ 4','user4@user.net','4','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 4๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user5','์ ์ 5','user5@user.net','5','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 5๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user6','์ ์ 6','user6@user.net','6','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 6๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user7','์ ์ 7','user7@user.net','7','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 7๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user8','์ ์ 8','user8@user.net','8','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 8๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user9','์ ์ 9','user9@user.net','9','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 9๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user10','์ ์ 10','user10@user.net','10','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 10๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user11','์ ์ 11','user11@user.net','11','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 11๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user12','์ ์ 12','user12@user.net','12','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 12๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user13','์ ์ 13','user13@user.net','13','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 13๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user14','์ ์ 14','user14@user.net','14','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 14๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user15','์ ์ 15','user15@user.net','15','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 15๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user16','์ ์ 16','user16@user.net','16','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 16๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user17','์ ์ 17','user17@user.net','17','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 17๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user18','์ ์ 18','user18@user.net','18','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 18๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user19','์ ์ 19','user19@user.net','19','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 19๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user20','์ ์ 20','user20@user.net','20','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 20๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user21','์ ์ 21','user20@user.net','21','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 21๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user22','์ ์ 22','user20@user.net','22','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 22๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user23','์ ์ 23','user20@user.net','23','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 23๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user24','์ ์ 24','user20@user.net','24','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 24๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user25','์ ์ 25','user20@user.net','25','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 25๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user26','์ ์ 26','user20@user.net','26','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 26๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user27','์ ์ 27','user20@user.net','27','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 27๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user28','์ ์ 28','user20@user.net','28','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 28๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user29','์ ์ 29','user20@user.net','29','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 29๊ธธ','2022-07-01');
INSERT INTO members (user_id,user_name,user_email,user_age,user_address,user_enter_date) VALUES ('user30','์ ์ 30','user20@user.net','30','์์ธ์ ์ ์ ๊ตฌ ์ ์ ๋ 30๊ธธ','2022-07-01');
์ด๋ ๊ฒ ์์ฑํด ๋๊ณ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ๋์ํจ ๋ค์, http://localhost:8080/h2-console ๋ก ์ ์ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์๋ค.