본문 바로가기
프로젝트/도서관리 프로젝트

도서관리 프로젝트[9] 책 반납 기능 만들기

by CodeMango 2023. 6. 25.

API스펙 확인하기

 

이미 테이블 도메인은 존재하므로, 테이블은 추가하지 않아도 됩니다.

그런데, 한가지 고민해볼점이 있습니다.

 

이런 경우에는 새로 만드는게 더 좋습니다.

왜냐하면 반납 기능만 수정해야할 때가 온다면 새로운 DTO객체를 수정하는게 더 낫기 때문입니다!

따라서 BookReturnRequest를 따로 만듭니다.

 

1.BookReturnRequest

package com.group.libraryapp.dto.book.request;

public class BookReturnRequest {

    private String userName;
    private String bookName;

    public String getUserName() {
        return userName;
    }

    public String getBookName() {
        return bookName;
    }
}

 

2.BookController에     @PutMapping("/book/return") 추가

    @PutMapping("/book/return")
    public void returnBook(@RequestBody BookReturnRequest request){
        bookService.returnBook(Request);
    }

 

3. BookService에 returnBook 추가

        @Transactional
                public void returnBook(BookReturnRequest request){
            User user = userRepository.findByName(request.getUserName())
                    .orElseThrow(IllegalArgumentException::new);

            //UserLoanHistory  객체의 isReturn값이 true로 바뀜
            UserLoanHistory history = userLoanHistoryRepository.findByUserIdAndBookName(user.getId(), request.getBookName())
                    .orElseThrow(IllegalArgumentException::new);
            history.doReturn();
             userLoanHistoryRepository.save(history); //트랜잭션의 영속성 컨텍스트때문에 이 save코드 안 써도됨

이제 반납처리를 위해서는 UserLoanHistory에 있는 isReturn을 true로 바꿔야 합니다.

 

4. UserLoanHistory에 doReturn()함수 추가

package com.group.libraryapp.domain.user.loanhistory;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class UserLoanHistory {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;
    private long userId;
    private String bookName;
    private boolean isReturn; //0이면 false, 1이면 true로 생각!


    protected UserLoanHistory() {

    }
    public UserLoanHistory(Long id, String bookName) {
        this.id = id;
        this.bookName = bookName;
        this.isReturn = false;
    }

    public void doReturn() {
        this.isReturn = true;
    }
}

 

 

 

 

데이터의 영속성을 위해 DB에 저장하는 것이 필수입니다!

 

 

 


한 객체를 바꿀 때 다른 객체에 영향을 미치지 않게 하는 객체지향적 설계가 가장 좋은 설계입니다.

따라서 지금 코드를 조금 더 객체지향적으로 만들 수 없을까 하는 고민을 하게 됩니다.

현재는 User와 UserLoanHistory은 다 분리되어 있는 객체입니다.

라는 고민을 할 수 있습니다.

 

 

 

 

같은 도메인에, 같은 관심사에 속해있는 User와 UserLoanHistory를 같이 처리하게 해보겠습니다.

이렇게 하기 위해 선행조건은 user와 UserLoanHistory가 서로 알아야 합니다!

 

1. UserLoanHistory에 userId대신 User객체 추가하기

package com.group.libraryapp.domain.user.loanhistory;

import com.group.libraryapp.domain.user.User;

import javax.persistence.*;

@Entity
public class UserLoanHistory {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;

    //user_loan_history 테이블에 User가 없기 때문에 빨간줄 뜸
    //따라서 ManToOne(n:1)이라는 어노테이션을 붙여줌(내가 다수, 상대방이 한개)
    //대출기록은 여러개, 대출기록 소유하는 사용자는 한명
    @ManyToOne
    private User user;
//    private long userId;
    private String bookName;
    private boolean isReturn; //0이면 false, 1이면 true로 생각!


    protected UserLoanHistory() {

    }
    public UserLoanHistory(Long id, String bookName) {
        this.id = id;
        this.bookName = bookName;
        this.isReturn = false;
    }

    public void doReturn() {
        this.isReturn = true;
    }
}

 

@ManyToOne(n:1)

 

 

2. User

반대로 User에는 UserLoanHistory 객체를 추가하고 OneTwoMany어노테이션을 추가합니다. 

package com.group.libraryapp.domain.user;

import com.group.libraryapp.domain.user.loanhistory.UserLoanHistory;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;
    @Column(nullable = false, length = 20, name = "name") // name varchar(20)
    private String name;
    private Integer age;

    // OneToMany = 1:n관계 = ManyTwoOne의 반대

-- ----------------------------------------------------------------------------------


    @OneToMany(mappedBy = "user")
    private List<UserLoanHistory> userLoanHistoryList = new ArrayList<>();


-- ----------------------------------------------------------------------------------
    protected User() {} //매개변수가 없는 기본생성자

    public User(String name, Integer age) {
        //이름값이 null이거나 비어있을 때는 예외를 던져서 user자체가 생성이 안되고, 저장도 안됨.
        if (name == null || name.isBlank()){
            throw new IllegalArgumentException(String.format("잘못된 name(%s)이 들어왔습니다", name));
        }

        this.name = name;
        this.age = age;
    }

    //getter
    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    //변경되는 이름이 들어옴
    public void updateName(String name){
        this.name = name;
    }

}

// %s: 문자열 포맷팅에서 사용되는 형식지정자 - > 잘못된 name(John)이 들어왔습니다
// (%d는 정수, %f는 부동소수점 숫자를 대체)

 

연관관계의 주인

엔티티 객체는 테이블을 매핑하는 것인데, user_id가 id를 가리키고 있으므로 주도권은 user_loan_history에 있습니다.

따라서 연관관계의 주인은 user_loan_history입니다.

연관관계의 주인이 아닌 쪽에 mappedBy 옵션을 달아주어야 합니다.

 

 

3. UserLoanHIstory : id를 user로 변경하기

package com.group.libraryapp.domain.user.loanhistory;

import com.group.libraryapp.domain.user.User;

import javax.persistence.*;

@Entity
public class UserLoanHistory {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;

    //user_loan_history 테이블에 User가 없기 때문에 빨간줄 뜸
    //따라서 ManToOne(n:1)이라는 어노테이션을 붙여줌(내가 다수, 상대방이 한개)
    //대출기록은 여러개, 대출기록 소유하는 사용자는 한명
    @ManyToOne //(n:1)
    private User user;
//    private long userId;
    private String bookName;
    private boolean isReturn; //0이면 false, 1이면 true로 생각!


    protected UserLoanHistory() {

    }
    public UserLoanHistory(User user, String bookName) {
        this.user = user;
        this.bookName = bookName;
        this.isReturn = false;
    }

    public void doReturn() {
        this.isReturn = true;
    }
}

 

4. BookService도 user로 변경하기

        //5. 유저 정보와 책 정보를 기반으로 UserLoanHistory를 저장
        userLoanHistoryRepository.save(new UserLoanHistory(user, book.getName()));
        }

댓글