[Spring Boot] REST API 개발 (MyBatis,HSQLDB)

개요

여기에서는 Spring Boot + MyBatis + HSQLDB를 사용하여 CRUD REST API를 구축하는 방법을 보여준다.


개발환경은 다음과 같다:

● Spring Tool Suite 3 (Version: 3.9.11)

● Spring Boot Version : 2.7.11

● Java : JDK 8


HSQLDB 대신 H2 DB, Apache Derby, SQLite 등의 인메모리 데이터베이스를 사용할 수도 있다.


※ 관련글 목록: http://yellow.kr/lifeView.jsp?s=spring



예제 REST API 설명

만들려는 예제 REST API는 책 관리 시스템으로 다음과 같은 기능을 구현한다:

● 책 정보 리스트

● 책 정보 등록

● 책 정보 조회

● 책 정보 수정

● 책 정보 삭제


예제 Application의 Flow는 다음과 같다. 여기에서는 Spring Boot REST 애플리케이션 작성 부분이다.



REST 개요

Representational State Transfer (REST)는 웹 서비스 아키텍처의 하나로, 클라이언트와 서버 간의 통신을 위한 소프트웨어 디자인 패턴을 말한다. REST는 HTTP 프로토콜을 기반으로하며, 웹 상의 자원(Resource)을 다루기 위한 아키텍처로 설계되었다.

REST는 클라이언트와 서버 간에 자원을 주고받기 위한 인터페이스로, HTTP 요청 메서드(GET, POST, PUT, DELETE 등)를 사용하여 자원에 대한 CRUD(Create, Read, Update, Delete) 작업을 수행한다. 또한, REST는 자원을 고유하게 식별하는 URI(Uniform Resource Identifier)를 사용하여 자원을 식별하고, HTTP 상태 코드를 이용하여 요청 처리 결과를 반환한다.

REST의 장점으로는 ‘stateless’ 특성이 있다. 이것은 서버가 클라이언트의 이전 상태를 기억하지 않으므로, 클라이언트와 서버 간의 상호작용이 간단하고 효율적으로 이루어질 수 있다는 것을 의미한다. 또한, REST는 여러 플랫폼과 언어에서 사용될 수 있으며, 서버와 클라이언트 간에 독립적으로 구현될 수 있기 때문에 시스템의 확장성이 용이하다.

하지만 REST는 설계와 구현의 자유도가 높기 때문에, 일관성 없는 구현이나 URI 디자인 등으로 인한 문제가 발생할 수도 있다. 따라서 RESTful한 아키텍처를 구현하기 위해서는 일관된 URI 디자인, HTTP 요청 메서드 사용, 리소스 모델링 등에 대한 지침을 따르는 것이 중요하다.

REST API에서 JSON은 가장 일반적인 데이터 형식 중 하나이다. 그러나 XML, CSV 등의 다른 형식도 사용될 수 있다. 이러한 형식은 서비스를 개발하는 개발자 또는 API 사용자의 요구 사항에 따라 달라진다. 최근에는 JSON이 대부분의 RESTful API에서 사용되며, JSON의 가볍고 간단한 구조가 이를 가능하게 한다. 또한 JSON을 사용하면 다양한 프로그래밍 언어와 플랫폼 간에 데이터 교환을 쉽게 할 수 있다.



Spring Boot project 생성

● eclips에서 Spring Boot project를 생성한다.

File > New > Project… > Spring Boot > Spring Starter Project

Name, Group, Package에 적당한 내용을 입력하고 [Next] 클릭


● 필요한 Dependency들을 선택한다.

Spring Web, MyBatis, HyperSQL를 선택한다.

[Finish] 클릭


● Project 생성 됨

yellow-rest 라는 이름으로 Project가 생성되었고, YellowRestApplication.java 가 생성되었다.

package com.yellow.rest;

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

@SpringBootApplication
public class YellowRestApplication {

	public static void main(String[] args) {
		SpringApplication.run(YellowRestApplication.class, args);
	}

}


예제 애플리케이션이 완성되면 Project Structure은 다음과 같다.



Maven Dependencies

pom.xml을 보면 다음과 같은 dependency를 확인할 수 있다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.3.0</version>
</dependency>

<dependency>
	<groupId>org.hsqldb</groupId>
	<artifactId>hsqldb</artifactId>
	<scope>runtime</scope>
</dependency>



application.properties 설정

server.port=8081
mybatis.mapper-locations=classpath:/com/yellow/rest/*.xml

– Spring Boot의 기본 port는 8080이다. 다른 포트를 사용하려면 application.properties 에 설정해야 한다. 테스트를 위해 예제 Spring Boot REST 애플리케이션은 port 8081 에서 API를 서비스하고, 다른 글에서 소개할 REST API를 호출하는 Client는 port 8080를 사용할 예정이다.


– 예제 REST 애플리케이션은 MyBatis를 사용한다. 따라서 Book.xml 으로 존재하는 Mapper XML 파일의 위치를 application.properties에 설정한다.



HSQLDB 데이터베이스 초기화

일반적으로 Spring Boot에서 데이터 초기화를 위해 데이터베이스 DDL 및 DML을 실행하려면 schema.sql 또는 data.sql 파일을 사용한다.

schema.sql 파일은 데이터베이스 스키마를 생성하고 수정하는 데 사용된다. 이 파일은 스프링 부트 애플리케이션을 시작할 때 한 번 실행된다.

data.sql 파일은 데이터베이스 초기 데이터를 삽입하는 데 사용된다. 이 파일은 schema.sql이 실행된 후 실행된다.


보통 src/main/resources 폴더 내에 schema.sql 또는 data.sql 파일을 만들어놓으면 스프링 부트가 자동으로 이 파일들을 읽어서 데이터베이스 초기화 작업을 수행한다. 만약 다른 폴더에 위치한 파일을 사용하려면 application.properties에 파일 경로를 지정할 수 있다.


● schema.sql

DROP TABLE book IF EXISTS;

CREATE TABLE book (
  book_id VARCHAR(4),
  title VARCHAR(40),
  author VARCHAR(40),
  publisher VARCHAR(40),
  release_date VARCHAR(8),
  isbn VARCHAR(13),
  PRIMARY KEY(book_id)
);


● data.sql

INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1001','장기20세기','조반니 아리기','그린비','20140520','9788976827821');
INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1002','신의 지문','그레이엄 핸콕','까치','20170120','9788972916307');
INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1003','신화의 이미지','조지프 캠벨','살림출판사','20060220','9788952204776');
INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1004','블랙아테나 1','마틴 버낼','소나무','20060110','9788971395479');
INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1005','판다의 엄지','스티븐 제이 굴드','사이언스북스','20160520','9788983717788');
INSERT INTO book(book_id,title,author,publisher,release_date,isbn) VALUES('1006','이기적 유전자','리처드 도킨스','을유문화사','20181020','9788932473901');



Model, Repository, Service

● Book.java

package com.yellow.rest;

public class Book {
	
	private String bookId;
	private String title;
	private String author;
	private String publisher;
	private String releaseDate;
	private String isbn;
	
	public Book() {}
	
	public Book(String bookId, String title, String author, String publisher, String releaseDate, String isbn) {
		this.setBookId(bookId);
		this.setTitle(title);
		this.setAuthor(author);
		this.setPublisher(publisher);
		this.setReleaseDate(releaseDate);
		this.setIsbn(isbn);
	}
	
	public String getBookId() {
		return bookId;
	}
	public void setBookId(String bookId) {
		this.bookId = bookId;
	}
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	
	public String getPublisher() {
		return publisher;
	}
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getReleaseDate() {
		return releaseDate;
	}
	public void setReleaseDate(String releaseDate) {
		this.releaseDate = releaseDate;
	}

	public String getIsbn() {
		return isbn;
	}
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	
	@Override
	public String toString() {
		return "bookId:" + bookId + ",title:" + title + ",author:" + author 
				+ ",publisher:" + publisher + ",releaseDate:" + releaseDate + ",isbn:" + isbn;
	}
}


● Book.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.yellow.rest.BookRepository">
	<select id="findAll" resultType="com.yellow.rest.Book">
	SELECT book_id AS bookId, title, author, publisher, release_date AS releaseDate, isbn FROM book ORDER BY book_id
	</select>
	<select id="findById" resultType="com.yellow.rest.Book">
	SELECT book_id AS bookId, title, author, publisher, release_date AS releaseDate, isbn FROM book 
	WHERE book_id = #{bookId}
	</select>
	<insert id="save" parameterType="com.yellow.rest.Book">
	INSERT INTO book(book_id, title, author, publisher, release_date, isbn)
		VALUES(#{bookId},#{title},#{author},#{publisher},#{releaseDate},#{isbn})
	</insert>
	<update id="update" parameterType="com.yellow.rest.Book">
	UPDATE book SET title=#{title}, author=#{author}, publisher=#{publisher}, release_date=#{releaseDate}, isbn=#{isbn} 
	WHERE book_id = #{bookId}
	</update>
	<delete id="delete">
	DELETE FROM book 
	WHERE book_id = #{bookId}
	</delete>
</mapper>


● BookRepository.java

package com.yellow.rest;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BookRepository {
	
	public List<Book> findAll();
	public Book findById(String bookId);
	public void save(Book book);
	public void update(Book book);
	public void delete(String bookId);

}


● BookService.java

package com.yellow.rest;

import java.util.List;

import org.springframework.stereotype.Service;

@Service
public class BookService {
	
	private final BookRepository bookRepository;
	public BookService(BookRepository bookRepository) {
		this.bookRepository = bookRepository;
	}
	
	public List<Book> getAllBooks() {
		return bookRepository.findAll();
	}
	
	public Book getBookById(String bookId) {
		return bookRepository.findById(bookId);
	}
	
	public void saveBook(Book book) {
		bookRepository.save(book);
	}
	
	public void updateBook(Book book) {
		bookRepository.update(book);
	}
	
	public void deleteBook(String bookId) {
		bookRepository.delete(bookId);
	}

}



Contoller

● BookController.java

package com.yellow.rest;

import java.util.List;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin
@RequestMapping("/api/books")
public class BookController {
	
	private BookService bookService;
	
	public BookController(BookService bookService) {
		this.bookService = bookService;
	}
	
	@GetMapping("")
	public List<Book> getAllBooks(Model model) {	
		return bookService.getAllBooks();
	}
	
	@GetMapping("/{id}")
	public Book getBookById(@PathVariable("id") String id) {
		return bookService.getBookById(id);
	}
	
	@PostMapping("")
	public void saveBook(@RequestBody Book book) {
		bookService.saveBook(book);
	}
	
	@PutMapping("/{id}")
	public void updateBook(@PathVariable("id") String id, @RequestBody Book book) {
		book.setBookId(id);
		bookService.updateBook(book);
	}
	
	@DeleteMapping("/{id}")
	public void deleteBook(@PathVariable("id") String id) {
		bookService.deleteBook(id);
	}

}

@RestController는 Spring MVC 프레임워크에서 컨트롤러 클래스를 작성할 때 사용하는 어노테이션 중 하나이다. @RestController 어노테이션을 사용하면 클래스 내의 모든 메소드가 HTTP 응답으로 데이터를 직접 반환할 수 있다. 이때 반환되는 데이터 형식은 기본적으로 JSON이다. 따라서 @RestController를 사용하면 JSON 데이터 형식을 사용하는 것이 일반적이다. 그러나 다른 데이터 형식도 사용할 수 있으며, 이는 개발자가 응답으로 반환할 데이터의 형식을 선택할 수 있기 때문이다. 예를 들어, @RestController에서 문자열, XML, CSV 등의 형식을 반환할 수도 있다.

@CrossOrigin은 REST API 리소스에 대한 CORS(cross-origin 리소스 공유) 활성화를 위해 사용한다.



Application 실행

Project를 선택한 후, Run AS > Spring Boot App 를 하면 내장 Tomcat 서버에 배포된다. 브라우저에서 다음의 URL을 실행한다.​​

● http://localhost:8081/api/books


● http://localhost:8081/api/books/1002


HTTP GET 은 JSON의 형태로 정상적으로 출력되는 것을 확인할 수 있다.


[Spring Boot] REST API 개발 (MyBatis,HSQLDB)
Tagged on:                 

2 thoughts on “[Spring Boot] REST API 개발 (MyBatis,HSQLDB)

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.