REST(Representational Safe Transfer)
데이터를 주고 받는 방식의 아키텍처 (디자인 패턴)
HTTP URI를 통한 자원의 명시
- url?category=novel 와 같은 쿼리 스트링 방식이 아니라 url/category/novel 과 같은 방식 사용
- 대문자 사용 지양
- _ 대신 - 사용
- URL 마지막에 / 사용하지 않음
- 행위를 포함하지 않음(insert, update, delete)
- 가급적 명사 사용(동사 사용 지양)
HTTP Method(Get, Post, Put, Delete)로 해당 자원을 제어하는 행위를 표현
- GET - Read(Select) : URL/1
- POST - Create(Insert) : URL
- PUT - Update : URL/1
- DELETE - Delete : URL/1
Restful 서비스(API)
- REST 아키텍처를 준수하는 서비스
- RESTful 서비스에서는 Controller에서 요청 받은 내용을 처리하고 데이터를 가공해서 처리 결과를 "특정 플랫폼"에 적합한 형태의 View로 만들어서 응답하지 않고 데이터만 처리하거나 응답 데이터가 있다면 JSON/XML로 응답한다. (View와는 무관하다)
- 즉, 클라이언트는 규칙에 맞게 작업을 요청하면 되고 서버는 어떤 플랫폼에서 어떻게 사용할 것인지를 신경쓰지 않고 요청 받은 데이터만 처리하고 응답하면 된다.
- 클라이언트는 받은 데이터를 알아서 가공해서 사용한다. 즉, 멀티 플랫폼에서 사용 가능하다.
- 이러한 특성으로, 사용자 플랫폼과 view에 상관하지 않고 요청한 데이터만 응답해주는 오픈 API에서 Restful한 서비스 방식을 많이 사용한다.
- 어플리케이션의 복잡도 증가로 인해 서비스별 독립적 구축과 운영이 필요해지면서 많이 활용되고 있다.
전체 프로젝트 파일 구조

프로젝트 코드

Chap03RestApiApplication
package com.greedy.rest.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Chap03RestApiApplication {
public static void main(String[] args) {
SpringApplication.run(Chap03RestApiApplication.class, args);
}
}
ContextConfiguration
package com.greedy.rest.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.greedy.rest")
public class ContextConfiguration {
}
MyBatisConfiguration
package com.greedy.rest.config;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(basePackages="com.greedy.rest", annotationClass = Mapper.class)
public class MyBatisConfiguration {
}

BookController
package com.greedy.rest.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.RestController;
import com.greedy.rest.model.dto.BookDTO;
import com.greedy.rest.model.service.BookService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
/* @Controller + @ResponseBody
* => 모든 메소드에 @ResponseBody가 적용되므로 메소드별로 명시할 필요가 없음
* => @RestController의 용도는 JSON/XML 등의 형식으로 데이터를 반환하는 것
* */
public class BookController {
private BookService bookService;
@Autowired
public BookController(BookService bookService) {
this.bookService = bookService;
}
// @GetMapping("/book/category/{category}")
// public List<BookDTO> selectBookByCategory(@PathVariable String category){
//
// log.debug("조회 요청 category : {}", category);
//
// return bookService.selectBookByCategory(category);
// }
/* ResponseEntity : 개발자가 직접 결과 데이터와 HTTP 상태 코드를
제어할 수 있는 클래스로
* 결과 데이터가 예외적인 상황에 대해서 세밀한 제어를 할 수 있다.
* */
@GetMapping("/book/category/{category}")
public ResponseEntity<Map<String, Object>>
selectBookByCategory(@PathVariable String category){
log.debug("조회 요청 category : {}", category);
List<BookDTO> bookList = bookService.selectBookByCategory(category);
Map<String, Object> result = new HashMap<>();
result.put("data", bookList);
if(bookList.isEmpty()) {
result.put("data", "no data");
result.put("message", "check your category");
}
return ResponseEntity.ok(result);
}
@PostMapping("/book")
public ResponseEntity<Map<String, String>> insertBook(@RequestBody BookDTO book){
log.debug("입력 요청 book : {}", book);
String message = bookService.insertBook(book)
> 0 ? "book registration success" : "book registration failed";
Map<String, String> result = new HashMap<>();
result.put("message", message);
return ResponseEntity.ok(result);
}
@PutMapping("/book/{id}")
public ResponseEntity<Map<String, String>>
updateBook(@PathVariable int id, @RequestBody BookDTO book){
log.debug("수정 요청 id : {}", id);
log.debug("수정 요청 book : {}", book);
book.setId(id);
String message = bookService.updateBook(book)
> 0 ? "book modification success" : "check your book id";
Map<String, String> result = new HashMap<>();
result.put("message", message);
return ResponseEntity.ok(result);
}
@DeleteMapping("/book/{id}")
public ResponseEntity<Map<String, String>> deleteBook(@PathVariable int id) {
log.debug("삭제 요청 id : {}", id);
String message = bookService.deleteBook(id)
> 0 ? "book deletion success" : "check your book id";
Map<String, String> result = new HashMap<>();
result.put("message", message);
return ResponseEntity.ok(result);
}
/* 도서 아이디 전달 받아 해당 도서 정보 응답하는 기능 구현하기 */
@GetMapping("/book/{id}")
public ResponseEntity<Map<String, Object>> selectBookByid(@PathVariable int id) {
log.debug("조회 요청 id : {}", id);
BookDTO book = bookService.selectBookByid(id);
Map<String, Object> result = new HashMap<>();
result.put("data", book);
if(book == null) {
result.put("data", "no data");
result.put("message", "check your book id");
}
return ResponseEntity.ok(result);
}
}
interface BookMapper
package com.greedy.rest.model.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.greedy.rest.model.dto.BookDTO;
@Mapper
public interface BookMapper {
List<BookDTO> selectBookByCategory(String category);
int insertBook(BookDTO book);
int updateBook(BookDTO book);
int deleteBook(int id);
BookDTO selectBookByid(int id);
}
BookDTO
package com.greedy.rest.model.dto;
import lombok.Data;
@Data
public class BookDTO {
private int id;
private String title;
private String author;
private String publisher;
private String category;
}
interface BookService
package com.greedy.rest.model.service;
import java.util.List;
import com.greedy.rest.model.dto.BookDTO;
public interface BookService {
List<BookDTO> selectBookByCategory(String category);
int insertBook(BookDTO book);
int updateBook(BookDTO book);
int deleteBook(int id);
BookDTO selectBookByid(int id);
}
BookServiceImpl implements BookService
package com.greedy.rest.model.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.greedy.rest.model.dao.BookMapper;
import com.greedy.rest.model.dto.BookDTO;
@Service
@Transactional
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
@Autowired
public BookServiceImpl(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
@Override
public List<BookDTO> selectBookByCategory(String category) {
return bookMapper.selectBookByCategory(category);
}
@Override
public int insertBook(BookDTO book) {
return bookMapper.insertBook(book);
}
@Override
public int updateBook(BookDTO book) {
return bookMapper.updateBook(book);
}
@Override
public int deleteBook(int id) {
return bookMapper.deleteBook(id);
}
@Override
public BookDTO selectBookByid(int id) {
return bookMapper.selectBookByid(id);
}
}

BookMapper.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.greedy.rest.model.dao.BookMapper">
<resultMap id="bookResultMap" type="com.greedy.rest.model.dto.BookDTO">
<id property="id" column="BOOK_ID"/>
<result property="title" column="BOOK_TITLE"/>
<result property="author" column="BOOK_AUTHOR"/>
<result property="publisher" column="BOOK_PUBLISHER"/>
<result property="category" column="BOOK_CATEGORY"/>
</resultMap>
<select id="selectBookByCategory" resultMap="bookResultMap">
SELECT
BOOK_ID
, BOOK_TITLE
, BOOK_AUTHOR
, BOOK_PUBLISHER
, BOOK_CATEGORY
FROM TBL_BOOK
WHERE BOOK_CATEGORY = #{ category }
</select>
<insert id="insertBook">
INSERT
INTO TBL_BOOK
(
BOOK_ID
, BOOK_TITLE
, BOOK_AUTHOR
, BOOK_PUBLISHER
, BOOK_CATEGORY
)
VALUES
(
SEQ_BOOK_ID.NEXTVAL
, #{ title }
, #{ author }
, #{ publisher }
, #{ category }
)
</insert>
<update id="updateBook">
UPDATE
TBL_BOOK
SET BOOK_TITLE = #{ title }
, BOOK_AUTHOR = #{ author }
, BOOK_PUBLISHER = #{ publisher }
, BOOK_CATEGORY = #{ category }
WHERE BOOK_ID = #{ id }
</update>
<delete id="deleteBook">
DELETE
FROM TBL_BOOK
WHERE BOOK_ID = #{ id }
</delete>
<select id="selectBookByid" resultMap="bookResultMap">
SELECT
BOOK_ID
, BOOK_TITLE
, BOOK_AUTHOR
, BOOK_PUBLISHER
, BOOK_CATEGORY
FROM TBL_BOOK
WHERE BOOK_ID = #{id}
</select>
</mapper>
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>rest api</title>
</head>
<body>
<h1>REST API</h1>
</body>
</html>
application.yml
# server port config
server:
port: 8001
# datasource config
spring:
datasource:
driver-class-name: oracle.jdbc.driver.OracleDriver
url : jdbc:oracle:thin:@localhost:1521:xe
username :
password :
# mybatis config
mybatis:
mapper-locations: mappers/**/*.xml
# logging level
logging:
level:
'[com.greedy.rest]': debug
'Programming > Spring Framework' 카테고리의 다른 글
| Spring-Boot-Crud (2) : Thymeleaf (0) | 2022.05.09 |
|---|---|
| Spring-Boot-Crud (1) (0) | 2022.05.09 |
| Spring Security (2) (0) | 2022.04.25 |
| Spring Security (1) (0) | 2022.04.25 |
| Spring Boot 초기 설정 (0) | 2022.04.20 |















































































































































