개발 기록/도서관 관리 시스템

[Library Management System] 25.10.31 | (구현) 마이페이지 도서 대출 연장 기능 구현, 응답 결과 DTO 필드 수정

dev.jelee 2025. 11. 1. 01:54

 

[ 작업한 내용 ]

# Frontend

1. 도서 대출 연장 유무 및 버튼

- 대출 연장 버튼 UI 틀만 구현

<div>대출연장: <span>0</span>회</div>
<button 
  disabled=""
  className="
    mt-2 px-2 py-1 
    border border-gray-500 
    text-[15px] self-start
    hover:border-teal-600
    hover:bg-teal-600
    hover:text-white
    disabled:border-gray-300
    disabled:text-gray-300"
>연장하기</button>

# Backend

1. 사용자 도서 대출 연장 api 구현

- controller, service, dto, messages.properteis, LoanErrorCode

// controller
@PatchMapping("/loans/{loanId}/extend")
public ResponseEntity<?> extendLoan(
  @PathVariable("loanId") Long loanId,
  @AuthenticationPrincipal User user) {

    // 서비스로직
    UserLoanExtendedResDTO responseDTO = userLoanService.extendLoan(loanId, user.getId());

    // 성공메시지
    String message = messageProvider.getMessage(LoanSuccessCode.LOAN_EXTENDED.getMessage());
  
    // 응답
    return ResponseEntity
              .status(LoanSuccessCode.LOAN_EXTENDED.getHttpStatus())
              .body(ApiResponse.success(
                LoanSuccessCode.LOAN_EXTENDED, 
                message, 
                responseDTO));
}


// service
@Transactional
public UserLoanExtendedResDTO extendLoan(Long loanId, Long userId) {

  // 사용자 조회 및 예외 처리
  User user = userRepository.findById(userId)
    .orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
  
  // loanId로 조회 및 예외처리
  Loan loan = loanRepository.findById(loanId)
      .orElseThrow(() -> new BaseException(LoanErrorCode.LOAN_NOT_FOUND));
  
  // 로그인 사용자와 대출자와 동일한지 확인
  if (user.getId() != loan.getUser().getId()) {
    throw new BaseException(LoanErrorCode.LOAN_USER_NOT_SAME);
  }

  // loan 상태가 대출중인 것만 가능
  // 연체, 반납, 분실 상태는 불가
  if (loan.getStatus() != LoanStatus.LOANED) {
    throw new BaseException(LoanErrorCode.LOAN_CANNOT_EXTEND);
  }

  // loan 대출 연장 여부 체크 및 예외처리
  if (loan.isExtended() != false) {
    throw new BaseException(LoanErrorCode.LOAN_ALREADY_EXTENDED);
  }

  // 대출 연장 및 반납 기간 업데이트
  // 대출 연장은 1회 가능, 7일 추가
  loan.setExtended(true);
  loan.setDueDate(loan.getDueDate().plusDays(7));

  // 반환
  return new UserLoanExtendedResDTO(loan);
}


// dto
@Getter
public class UserLoanExtendedResDTO {
  private Long id;
  private String username;
  private String bookTitle;
  private LocalDateTime loanDate;
  private LocalDateTime dueDate;
  private boolean extended;
  private LoanStatus status;

  public UserLoanExtendedResDTO(Loan loan) {
    this.id = loan.getId();
    this.username = loan.getUser().getUsername();
    this.bookTitle = loan.getBook().getTitle();
    this.loanDate = loan.getLoanDate();
    this.dueDate = loan.getDueDate();
    this.extended = loan.isExtended();
    this.status = loan.getStatus();
  }
}


// messages.properties
error.loan.user.not_same=도서 대출자와 로그인한 사용자가 동일하지 않습니다.


// LoanErrorCode
LOAN_USER_NOT_SAME(HttpStatus.BAD_REQUEST, "LOAN_5010", "error.loan.user.not_same");

2. 도서 대출 전체 조회 시 응답 DTO 필드 수정

- dueDate, extended 추가

@Getter
public class UserLoanListResDTO {
  private Long id;
  private String bookTitle;
  private String author;
  private String publisher;
  private LocalDate publishedDate;
  private String location;
  private LocalDateTime loanDate;
  private LocalDateTime dueDate;
  private LocalDateTime returnDate;
  private String borrower;
  private LoanStatus status;
  private boolean extended;

  public UserLoanListResDTO(Loan loan) {
    this.id = loan.getId();
    this.bookTitle = loan.getBook().getTitle();
    this.author = loan.getBook().getAuthor();
    this.publisher = loan.getBook().getPublisher();
    this.publishedDate = loan.getBook().getPublishedDate();
    this.location = loan.getBook().getLocation();
    this.loanDate = loan.getLoanDate();
    this.dueDate = loan.getDueDate();
    this.returnDate = loan.getReturnDate();
    this.borrower = loan.getUser().getUsername();
    this.status = loan.getStatus();
    this.extended = loan.isExtended();
  }
}