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()));
}
'프로젝트 > 도서관리 프로젝트' 카테고리의 다른 글
도서관리 프로젝트[11] 배포 - AWS접속, EC2 리눅스 명령어, 배포프로그램 설치 (0) | 2023.06.30 |
---|---|
도서관리 프로젝트[10] git, github, AWS, EC2, 배포 (0) | 2023.06.28 |
도서관리 프로젝트[8] 책 대출 기능 만들기 (0) | 2023.06.25 |
도서관리 프로젝트[7] 책 생성 API개발하기 (0) | 2023.06.25 |
도서관리 프로젝트[5] IoC 제어의 역전, 인터페이스(interface), @Primary (0) | 2023.06.22 |
댓글