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

[Library Management System] 25.09.10 (43일)

dev.jelee 2025. 9. 10. 13:27

[ 작업한 내용 ]

< 도서 반납 처리 기능 >

PATCH /api/v1/admin/loans/{loanId}/return

 

1. messages.properties

- 도서 반납 처리 관련 메시지 정의.

// 성공메시지
success.loan.returned=도서가 성공적으로 반납되었습니다.

// 에러메시지
error.loan.already_returned=해당 도서는 이미 반납되었습니다.

2. LoanSuccessCode

- 도서 반납 처리 관련 성공 코드 정의.

LOAN_RETURNED_SUCCESS(HttpStatus.OK, "LOAN_201", "success.loan.returned");

3. LoanErrorCode

- 도서 반납 처리 관련 에러 코드 정의.

LOAN_ALREADY_RETURNED(HttpStatus.BAD_REQUEST, "LOAN_401", "error.loan.already_returned");

4. AdminLoanReturnResDTO

- 도서 반납 처리 응답 DTO

- id, username, booktitle, returnDate, status 필드

- Loan 엔티티를 파라미터로 받는 AdminLoanReturnResDTO 생성자함수 정의.

@Getter
public class AdminLoanReturnResDTO {
  private Long id;
  private String username;
  private String bookTitle;
  private LocalDateTime returnDate;
  private LoanStatus status;

  public AdminLoanReturnResDTO(Loan loan) {
    this.id = loan.getId();
    this.username = loan.getUser().getUsername();
    this.bookTitle = loan.getBook().getTitle();
    this.returnDate = loan.getReturnDate();
    this.status = loan.getStatus();
  }
}

5. AdminLoanController

- PATCH /api/v1/admin/loans/{loanId}/return 형식의 요청을 처리한다.

- loanId는 @PathVariable를 통해 전달받는다.

- 요청 받은 데이터를 Service로 전달하여 데이터 처리 후 결과를 AdminLoanReturnResDTO 형태로 반환받는다.

- 클라이언트 측으로 성공메시지와 응답받은 DTO를 ApiResponse.success()로 감싸서 응답 본문으로 전달한다.

@PatchMapping("/{loanId}/return")
public ResponseEntity<?> returnLoan(@PathVariable("loanId") Long loanId) {

// 서비스로직
AdminLoanReturnResDTO responseDTO = adminLoanService.returnLoan(loanId);

// 성공메시지
String message = messageProvider.getMessage(LoanSuccessCode.LOAN_RETURNED_SUCCESS.getMessage());

return ResponseEntity
          .status(LoanSuccessCode.LOAN_RETURNED_SUCCESS.getHttpStatus())
          .body(ApiResponse.success(
            LoanSuccessCode.LOAN_RETURNED_SUCCESS, 
            message, 
            responseDTO));
}

6. AdminLoanService

- 전달받은 loanId로 loanRepository의 .findById() 메서드를 통해 해당 대출 내역을 조회하여 Loan 엔티티 형태로 저장한다. 만약에 해당 대출 내역이 없으면 LoanErrorCode.LOAN_NOT_FOUND 예외를 던진다.

- 가져온 Loan의 status가 RETURNED(반남됨) 상태인지 체크한다. 이미 반납된 상태라면 이미 반납된 상태라는 예외를 던진다.

- 아직 반납이 안된 상태라면 반납 날짜와 상태를 RETURNED로 변경해준다.

- 최종적으로 변경된 loan을 AdminLoanReturnResDTO 형태로 만들어 Controller로 반환한다.

@Transactional
public AdminLoanReturnResDTO returnLoan(Long loanId) {

	// Loan 엔티티 조회 + 예외 처리
	Loan loan = loanRepository.findById(loanId)
    	.orElseThrow(() -> new BaseException(LoanErrorCode.LOAN_NOT_FOUND));

	// Book 엔티티 조회
	Book book = bookRepository.findById(loan.getBook().getId())
    	.orElseThrow(() -> new BaseException(BookErrorCode.BOOK_NOT_FOUND));

	// loan 상태 체크 (반납이 된 상태인지)
    if (loan.getStatus() == LoanStatus.RETURNED) {
      throw new BaseException(LoanErrorCode.LOAN_ALREADY_RETURNED);
    }

    // 대출 내역 반납 시간과 상태 변경
    loan.setReturnDate(LocalDateTime.now());
    loan.setStatus(LoanStatus.RETURNED);

    // 도서 상태와 수정 시간 변경
    book.setStatus(BookStatus.AVAILABLE);
    book.setUpdatedAt(LocalDateTime.now());

    // 변경된 loan 반환
    return new AdminLoanReturnResDTO(loan);
}

<사용자 인증 정보 기능 리팩토링>

1. UserInfoResDTO

- UserInfoResponseDTO에서 UserInfoResDTO로 명칭 변경

- User 엔티티를 파라미터로 받는 생성자 함수 정의.

public UserInfoResDTO(User user) {
	this.username = user.getUsername();
	this.email = user.getEmail();
	this.joinDate = user.getJoinDate();
	this.lastLoginDate = user.getLastLoginDate();
}

2. UserController

- 비즈니스 로직을 Controller 단계에서 처리하였기 때문에 Service와 역할 구분을 명확하게 하기 위해 코드 리팩토링

- GET 방식으로 Authentication을 파라미터로 받는다.

- Service로 인증 객체를 전달하고 결과를 UserInfoResDTO타입으로 저장한다.

- 클라이언트 측으로 성공 메시지와 응답 DTO를 ApiResponse.success()로 감싸여 응답 바디로 반환한다.

@GetMapping()
public ResponseEntity<?> getMyInfo(Authentication authentication) {

	// 서비스 로직
	UserInfoResDTO responseDTO = userService.getMyInfo(authentication);

	// 성공메시지
	String message = messageProvider.getMessage(AuthSuccessCode.AUTH_USER_VERIFIED.getMessage());

	// 반환
	return ResponseEntity
                .status(AuthSuccessCode.AUTH_USER_VERIFIED.getHttpStatus())
                .body(ApiResponse.success(
                    AuthSuccessCode.AUTH_USER_VERIFIED, 
                    message, 
                    responseDTO));
}

3. UserService

- Controller로 전달받은 Authentication으로 User 객체를 생성한다.

- User 객체에 데이터가 있는지 유효성 체크를 한다. 없으면 예외 던지기.

- 데이터가 있으면 User를 기반으로 UserInfoResDTO 형태로 만들어 Controller로 반환한다.

@Transactional
public UserInfoResDTO getMyInfo(Authentication authentication) {

    // User 인증 객체
    User user = (User) authentication.getPrincipal();

    // User에 인증 정보 체크
    if (user == null) {
      throw new BaseException(AuthErrorCode.AUTH_UNAUTHORIZED);
    }

    // 반환
    return new UserInfoResDTO(user);
}

commit.
도서 반납 성공(좌), 반납 이미 된 경우(우)