Skip to content

Commit

Permalink
도서 대출 코드 및 테스트 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
shine-17 committed Nov 22, 2024
1 parent 2111487 commit db57c96
Show file tree
Hide file tree
Showing 15 changed files with 362 additions and 61 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ dependencies {
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'

}

tasks.named('test') {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/study/bookcafe/common/ApiResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.study.bookcafe.common;

import com.google.gson.Gson;

public class ApiResult {
private boolean isSuccess;
private String message;
private Object data;

public ApiResult(boolean isSuccess, String message) {
this.isSuccess = isSuccess;
this.message = message;
}
public ApiResult(boolean isSuccess, Object data, String message) {
this.isSuccess = isSuccess;
this.data = data;
this.message = message;
}

public boolean isSuccess() {
return isSuccess;
}

@Override
public String toString() {
return new Gson().toJson(this);
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/study/bookcafe/dao/BookDAO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.study.bookcafe.dao;

import com.study.bookcafe.dto.BookDTO;
import org.springframework.stereotype.Component;
import java.sql.Date;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

@Component
public class BookDAO {

Map<Long, BookDTO> books = new HashMap<>(){{
put(1L, new BookDTO(9788936433598L, "채식주의자", "한강", "창비", Date.valueOf(LocalDate.of(2007, 10, 30)), 35000));
put(2L, new BookDTO(9788936433598L, "채식주의자", "한강", "창비", Date.valueOf(LocalDate.of(2018, 4, 25)), 13000));
}};

public BookDTO findById(long bookId) {
// 추후 DB 연결 후 재작성
return books.get(bookId);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/study/bookcafe/dao/BorrowDAO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.study.bookcafe.dao;

import com.study.bookcafe.dto.BorrowDTO;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class BorrowDAO {
Map<Long, BorrowDTO> borrows = new HashMap<>(){{
put(1L, new BorrowDTO(1, 1, 9788936433598L));
put(2L, new BorrowDTO(1, 2, 9788936433598L));
put(3L, null);
}};

public BorrowDTO find(long memberId, long bookId, long ISBN) {
// 추후 DB 연결 후 재작성
return borrows.get(memberId);
}

public void save(BorrowDTO borrowDTO) {
// 추후 DB 연결 후 작성
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/study/bookcafe/dao/GeneralMemberDAO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.study.bookcafe.dao;

import com.study.bookcafe.dto.Level;
import com.study.bookcafe.dto.MemberDTO;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

@Component
public class GeneralMemberDAO implements MemberDAO {

Map<Long, MemberDTO> members = new HashMap<>(){{
put(1L, new MemberDTO("슈카", Level.BASIC, 0));
put(2L, new MemberDTO("머스크", Level.WORM, 3));
put(3L, new MemberDTO("트럼프", Level.LIBRARIAN, 5));
}};

@Override
public MemberDTO findById(long memberId) {
// 추후 DB 연결 후 재작성
return members.get(memberId);
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/study/bookcafe/dao/MemberDAO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.study.bookcafe.dao;

import com.study.bookcafe.dto.MemberDTO;

public interface MemberDAO {
MemberDTO findById(long memberId);
}
51 changes: 51 additions & 0 deletions src/main/java/com/study/bookcafe/dto/BookDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.study.bookcafe.dto;

import java.sql.Date;

public class BookDTO {
// 도서 한 권에 대한 정보
private long bookId; // 도서 번호

// 같은 도서가 여러 권일 때, 재고나 대출 권수를 상태로 저장해야할지? or 각 도서를 다른 레코드로 저장해야할지?

// 같은 도서 여러 권을 ISBN으로 묶어 하나의 도서에 대한 정보
private long ISBN; // 국제표준도서번호
private String title; // 도서 명
private String author; // 저자 명
private String publisher; // 출판사
private Date publishDate; // 출판일
private double price; // 도서 가격

private boolean isBorrow = true; // 현재 대출 여부
private int inventory; // 재고
private int borrowed; // 대출 중인 권수
private int reservationCount; // 예약 수

public BookDTO(long ISBN, String title, String author, String publisher, Date publishDate, double price) {
this.ISBN = ISBN;
this.title = title;
this.author = author;
this.publisher = publisher;
this.publishDate = publishDate;
this.price = price;
}

public BookDTO(String title, int inventory, int borrowed, int reservationCount) {
this.title = title;
this.inventory = inventory;
this.borrowed = borrowed;
this.reservationCount = reservationCount;
}

public long getISBN() {
return ISBN;
}

private int getBorrowed() {
return borrowed;
}

public boolean canBorrow() {
return isBorrow;
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/study/bookcafe/dto/BorrowDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.study.bookcafe.dto;

import java.sql.Timestamp;
import java.time.LocalDateTime;

public class BorrowDTO {
private long borrowId; // 대출 ID
private long memberId; // 회원 ID
private long bookId; // 도서 ID
private long ISBN; // 국제표준도서번호

private Timestamp borrowDate; // 대출 날짜
private Timestamp returnDate; // 반납 날짜

public BorrowDTO(long memberId, long bookId, long ISBN) {
this.memberId = memberId;
this.bookId = bookId;
this.ISBN = ISBN;
this.borrowDate = Timestamp.valueOf(LocalDateTime.now());
this.returnDate = Timestamp.valueOf(LocalDateTime.now().plusWeeks(1));
}
}
28 changes: 28 additions & 0 deletions src/main/java/com/study/bookcafe/dto/Level.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.study.bookcafe.dto;

public enum Level {

LIBRARIAN(2, 10,null), // 사서 회원
WORM(1, 5,null), // 책벌레 회원
BASIC(0, 3, WORM); // 일반 회원

private final int value; // 등급 값
private final int maximumBorrowCount; // 등급 별 최대 대출 권수
private final Level next; // 다음 등급

Level(int value, int maximumBorrowCount, Level next) {
this.value = value;
this.maximumBorrowCount = maximumBorrowCount;
this.next = next;
}

/**
* 회원의 대출 가능 권수를 알려준다.
*
* @param borrowCount (현재 회원의 현재대출권수)
* @return 회원의 최대 대출 권수 - 회원의 현재 대출 권수
*/
public boolean isBookBorrowCountLeft(int borrowCount) {
return this.maximumBorrowCount - borrowCount > 0;
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/study/bookcafe/dto/MemberDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.study.bookcafe.dto;

public class MemberDTO {
private long memberId; // 회원 ID
private String memberName; // 회원 이름
Level level; // 회원 등급
int borrowCount; // 현재 대출 권수

public MemberDTO(String memberName, Level level, int borrowCount) {
this.memberName = memberName;
this.level = level;
this.borrowCount = borrowCount;
}

private int getBorrowCount() {
return borrowCount;
}

/**
* 회원이 대출 가능한 상태인지 알려준다.
*
* @return 현재 회원의 대출 가능 권수가 남았는지 여부
*/
public boolean canBorrow() {
return level.isBookBorrowCountLeft(getBorrowCount());
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/study/bookcafe/service/BorrowService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.study.bookcafe.service;

import com.study.bookcafe.common.ApiResult;

public interface BorrowService {
ApiResult borrowBook(long memberId, long bookId);
}
68 changes: 68 additions & 0 deletions src/main/java/com/study/bookcafe/service/BorrowServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.study.bookcafe.service;

import com.study.bookcafe.common.ApiResult;
import com.study.bookcafe.dao.BookDAO;
import com.study.bookcafe.dao.BorrowDAO;
import com.study.bookcafe.dao.MemberDAO;
import com.study.bookcafe.dto.BookDTO;
import com.study.bookcafe.dto.BorrowDTO;
import com.study.bookcafe.dto.MemberDTO;
import org.springframework.stereotype.Component;

@Component
public class BorrowServiceImpl implements BorrowService {

private final MemberDAO memberDAO;
private final BookDAO bookDAO;
private final BorrowDAO borrowDAO;

public BorrowServiceImpl(MemberDAO memberDAO, BookDAO bookDAO, BorrowDAO borrowDAO) {
this.memberDAO = memberDAO;
this.bookDAO = bookDAO;
this.borrowDAO = borrowDAO;
}

/**
* 회원이 도서를 대출한다.
*
* @param memberId 회원 ID
* @param bookId 도서 ID
* @return 도서 대출 결과(성공여부, 데이터, 결과메세지)
*/
@Override
public ApiResult borrowBook(long memberId, long bookId) {

/*
1. 회원이 대출 가능한 상태인지 확인
2. 회원이 대출하려는 도서가 대출 가능한 상태인지 확인
3. 회원이 도서를 대출
4. 회원-도서(도서번호, ISBN) 매핑된 대출 데이터 추가
동시성 이슈
트랜잭션 처리 필요
*/

MemberDTO member = memberDAO.findById(memberId);
if(!member.canBorrow()) {
return new ApiResult(false, "현재 회원님의 대출 가능 권수가 없습니다.");
}

BookDTO book = bookDAO.findById(bookId);
if(!book.canBorrow()) {
return new ApiResult(false, "현재 해당 도서는 모두 대출 중입니다.");
}

BorrowDTO borrowDTO = borrowDAO.find(memberId, bookId, book.getISBN());
if(borrowDTO != null) {
return new ApiResult(false, "이미 해당 도서를 대출 중입니다.");
}

BorrowDTO newBorrowDTO = new BorrowDTO(memberId, bookId, book.getISBN());
borrowDAO.save(newBorrowDTO);

return new ApiResult(true, newBorrowDTO,"해당 도서에 대한 대출이 완료되었습니다.");
}



}
28 changes: 5 additions & 23 deletions src/test/java/com/study/bookcafe/book/BorrowTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.study.bookcafe.book;

import org.assertj.core.api.Assertions;
import com.study.bookcafe.dto.BookDTO;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

Expand All @@ -12,29 +12,11 @@ public class BorrowTest {
@DisplayName("도서가 현재 대출가능한 상태인지 확인한다. (도서의 현재 대출가능수량 확인")
public void checkBookStatusForBorrow() {

Book book1 = new Book("채식주의자", 3, 1, 0);
Book book2 = new Book("흰", 2, 2, 4);
BookDTO book1 = new BookDTO("채식주의자", 3, 1, 0);
BookDTO book2 = new BookDTO("흰", 2, 2, 4);

assertThat(book1.canBorrowed()).isEqualTo(true);
assertThat(book2.canBorrowed()).isEqualTo(false);
assertThat(book1.canBorrow()).isEqualTo(true);
assertThat(book2.canBorrow()).isEqualTo(false);

}
}

class Book {
String title;
int inventory;
int borrowed;
int reservationCount;

public Book(String title, int inventory, int borrowed, int reservationCount) {
this.title = title;
this.inventory = inventory;
this.borrowed = borrowed;
this.reservationCount = reservationCount;
}

public boolean canBorrowed() {
return inventory - borrowed > 0;
}
}
Loading

0 comments on commit db57c96

Please sign in to comment.