Book Project
- Create Book : 생성 요청 처리
- Find Book : 조회 요청 처리
- Find Books 전체 조회 요청 처리
API | Method | URL | Request DATA | Response DATA |
Create Book | POST | "/api/book" | { title : "String", authorId : "Long" } |
{ id : "Long" } |
Find Books | GET | "/api/book" | none | [ { id : "Long", title : "String", authodId : "Long" } ] |
Find Book | GET | "/api/book/:id" | none | { id : "Long", title : "String", authodId : "Long" } |
폴더 구조
Package | Class |
controller | BookController |
domain | Book |
dto | BookResponse |
CreateBookRequest | |
repository | BookRepository (interface) |
BookInMemoryRepository | |
service | BookService |
Domain
domain는 모델의 정보 처리의 파일이다.
//domain
package com.example.demo.domain;
public class Book {
//Book 객체는 고유 id, title, autorId를 가지고 있음
private Long id;
private String title;
private Long authorId;
//고유 ID Getter
public Long getId() {
return id;
}
//Title Getter
public String getTitle() {
return title;
}
//AuthorId Getter
public Long getAuthorId() {
return authorId;
}
//생성자 1
public Book(Long id, String title, Long authorId) {
this.id = id;
this.title = title;
this.authorId = authorId;
}
//생성자 2
public Book(String title, Long authorId) {
this.title = title;
this.authorId = authorId;
}
}
Controller
controller는 유저의 요청을 처리해주는 파일이다.
//controller
package com.example.demo.controller;
import com.example.demo.domain.Book;
import com.example.demo.dto.BookResponse;
import com.example.demo.dto.CreateBookRequest;
import com.example.demo.service.BookService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
public class BookController {
private final BookService bookService;
//생성자
public BookController(BookService bookService) {
this.bookService = bookService;
}
//GET : "/api/book"
@GetMapping("/api/book")
public List<BookResponse> findAll(){
//bookService.findAll 값을 BookResponse 객체로 생성
return this.bookService.findAll().stream().map(book -> new BookResponse(book)).collect(Collectors.toList());
}
//GET : "/api/book/:id"
@GetMapping("/api/book/{id}")
//PathVariable를 이용하여 {id} 값을 추출하여 매개 변수로 전달
public BookResponse findById(@PathVariable(name = "id") Long id) {
//ID 값으로 Data를 찾아 book 객체 생성 후 저장
Book book = this.bookService.findById(id);
//BookRespnse에 book을 넣어 생성 후 리턴
return new BookResponse(book);
}
@PostMapping("/api/book")
//@RequestBody를 이용하여, 요청 값 읽기
public Long save(@RequestBody CreateBookRequest request) {
return this.bookService.save(request);
}
}
Repository
인터페이스를 사용하여 만들어준다.
//interface : BookRepository
package com.example.demo.repository;
import java.util.*;
import com.example.demo.domain.Book;
public interface BookRepository {
//Find Books
List<Book> findAll();
//Find Book
Optional<Book> findById(Long id);
//Create Book
Book save(Book book);
}
BookRepository 인터페이스를 상속 받아 저장소를 생성한다.
//BookInMemoryRepository
package com.example.demo.repository;
import com.example.demo.domain.Book;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Repository
public class BookInMemoryRepository implements BookRepository {
//Book 객체를 담은 ArrayList, bookList를 생성
private final List<Book> bookList = new ArrayList<>();
//Book 고유 ID 값 지정 private Long bookNextId = 1L;
private Long bookNextId = 1L;
//Book List 반환 기능
@Override
public List<Book> findAll() {
return this.bookList;
}
//ID 값을 받아 해당 ID의 Book 반환
@Override
public Optional<Book> findById(Long id) {
// stream을 이용하여, filter로 List를 돌리고, 입력 받은 ID와 List의 Book ID가 같으면 선택 후 첫 번째 값 반환
return this.bookList.stream()
.filter(book -> book.getId().equals(id))
.findFirst();
}
//Book 객체를 받아 저장 및 업데이트
@Override
public Book save(Book book) {
//Book 객체인, bookOptional에 입력 받은 book의 ID 값을 이용하여 List에 해당 ID 값 있는 지 여부 저장
Optional<Book> bookOptional = this.findById(book.getId());
//만약에 값이 있다면 => 중복 데이터
if (bookOptional.isPresent()) {
//수정한 book 객체를 가져와서 targetBook에 저장
Book targetBook = bookOptional.get();
//updateInfo 사용하여, 타이틀과 ID 값 변경
targetBook.updateInfo(book.getTitle(), book.getAuthorId());
return targetBook;
}
//savedBook 객체 생성자 이용하여 생성, 고유 ID 값과 타이틀, ID 값을 가짐
Book savedBook = new Book(bookNextId++, book.getTitle(), book.getAuthorId());
//add를 이용하여 bookList에 추가
this.bookList.add(savedBook);
//Return 해줌
return savedBook;
}
}
Service
서비스는 로직이 담긴 곳으로, controller와 연결된다.
//BookService
package com.example.demo.service;
import com.example.demo.domain.Book;
import com.example.demo.dto.CreateBookRequest;
import com.example.demo.repository.BookRepository;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> findAll(){
return this.bookRepository.findAll();
}
public Book findById(Long id) {
return this.bookRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("not exist book id : '" + id + "'"));
}
public Long save(CreateBookRequest request) {
Book book = new Book(request.getTitle(), request.getAuthorId());
Book savedBook = this.bookRepository.save(book);
return savedBook.getId();
}
}
DTO
DTO(Data Transfer Object)는 계층 간 데이터 교환을 하기 위해 사용하는 객체로, 로직을 가지고 있지 않으며, getter, setter만 가지고 있는 클래스다.
요청 받을 때 데이터와 응답을 보낼 때 사용한다.
//Book Response
package com.example.demo.dto;
import com.example.demo.domain.Book;
public class BookResponse {
private Long id;
private String title;
private Long authorId;
public BookResponse(Book book) {
this.id = book.getId();
this.title = book.getTitle();
this.authorId = book.getAuthorId();
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public Long getAuthorId() {
return authorId;
}
}
//CreateBookRequest
package com.example.demo.dto;
import com.example.demo.domain.Book;
public class CreateBookRequest {
private String title;
private Long authorId;
public CreateBookRequest(String title, Long authorId) {
this.title = title;
this.authorId = authorId;
}
public String getTitle() {
return title;
}
public Long getAuthorId() {
return authorId;
}
}
'B.E > Spring' 카테고리의 다른 글
[Spring] Spring Boot 프로젝트 배포 (0) | 2022.08.21 |
---|---|
[Spring] Ioc, DI, 컨테이너 (0) | 2022.08.14 |
[Spring] 좋은 객체 지향 설계의 5가지 원칙 (0) | 2022.08.14 |
[Spring] 객체 지향 프로그래밍이란? (0) | 2022.08.14 |
[SPRING] 01. IntelliJ, Spring Initalizr 셋팅하기 (0) | 2022.04.11 |