728x90
320x100
[개발목표]
- 책 단건 조회시, 하단에 대여했던 내역을 확인 가능하게끔 구현
- 책 단건 조회시, 책 이미지도 보여지게끔 구현
[구현화면]
책 정보

- 책 단건조회 시, 하단에 대여 기록을 확인할 수 있도록 구현.
[구현하기]
bookMapper.xml
<!-- 책 대여 기록 조회 -->
<select id="findRentalHistoryByBookId" resultType="seulgi.bookRentalSystem.domain.book.BookRental">
SELECT
ROW_NUMBER() OVER (ORDER BY RENTAL_DATE DESC) AS row_num,
BOOK_RENTAL_ID,
(SELECT MEMBER_NAME FROM MEMBER_TB WHERE MEMBER_ID = BOOK_RENTAL_ID) AS BOOK_RENTAL_NAME,
RENTAL_DATE,
RETURN_DATE
FROM BOOK_RENTAL
WHERE BOOK_ID = #{bookId}
ORDER BY RENTAL_DATE DESC;
</select>
bookMapper.java
package seulgi.bookRentalSystem.domain.book;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface BookMapper {
//생략
//책 대여 기록 조회
List<BookRental> findRentalHistoryByBookId(@Param("bookId") String bookId);
//생략
}
bookServiceImpl.java
package seulgi.bookRentalSystem.domain.book;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class BookServiceImpl implements BookService {
private final BookMapper bookMapper;
//생략
//책 대여 기록 조회
@Override
public List<BookRental> findRentalHistoryByBookId(String bookId) {
return bookMapper.findRentalHistoryByBookId(bookId);
}
//생략
}
BookController.java
package seulgi.bookRentalSystem.web.book;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import seulgi.bookRentalSystem.domain.book.*;
import seulgi.bookRentalSystem.domain.member.Member;
import seulgi.bookRentalSystem.domain.member.MemberServiceImpl;
import seulgi.bookRentalSystem.domain.member.UpdateForm;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Controller
@RequiredArgsConstructor
@Transactional
@RequestMapping("/book")
public class BookController {
private final BookServiceImpl bookService;
/**
* 책 단건 조회
* @param bookId
* @param model
* @param request
* @return
*/
@GetMapping("/{bookId}")
public String book(@PathVariable String bookId, Model model
,HttpServletRequest request){
String loginId = (String) request.getSession().getAttribute("loginId");
String rentalId = bookService.findRentalIdByBookId(bookId);
Book book = bookService.findByBookId(bookId);
book.setAuthorName(book.getAuthorName());
book.setBookRentalId(rentalId);
// 📌 대여 이력 추가
List<BookRental> rentalHistory = bookService.findRentalHistoryByBookId(bookId);
model.addAttribute("loginId", loginId);
model.addAttribute("book", book);
model.addAttribute("rentalHistory", rentalHistory); // 📌 대여 기록 모델 추가
return "book/book";
}
}
book.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{common/layout}"
layout:fragment="content">
<head>
<title>책 정보</title>
<script th:src="@{/js/book/book.js}"></script>
</head>
<body>
<div class="container" style="max-width: 800px">
<div class="py-5 text-center">
<h2>책 정보</h2>
</div>
//생략
<!-- 책 썸네일 -->
<div class="mb-3 d-flex justify-content-center">
<img id="bookImage" th:if="${book.thumbnailImg != null and book.thumbnailImg != ''}"
th:src="${book.thumbnailImg}" alt="책 이미지"
style="width: 200px; height: auto; border-radius: 10px;">
</div>
//생략
<div style="margin-top: 80px;">
<hr class="my-4">
<!-- 대여 기록 있을 때 -->
<h3>대여 기록</h3>
<table class="table" th:if="${not #lists.isEmpty(rentalHistory)}">
<thead>
<tr>
<th>No</th>
<th>대여한 사람 ID</th>
<th>대여 시간</th>
<th>반납 시간</th>
</tr>
</thead>
<tbody>
<tr th:each="rental, stat : ${rentalHistory}">
<td th:text="${stat.count}">1</td>
<td th:text="${rental.bookRentalName}">사용자</td>
<td th:text="${rental.rentalDate}">2025-02-19 14:00</td>
<td th:text="${rental.returnDate != null ? rental.returnDate : '대여 중'}">대여 중</td>
</tr>
</tbody>
</table>
<!-- 대여 기록 없을 때 -->
<p class="text-center text-muted" th:if="${#lists.isEmpty(rentalHistory)}">대여 기록이 없습니다.</p>
</div>
</div>
</body>
</html>
- 대여 기록이 없을 땐 대여기록이 없습니다 라고 띄움.
book.js
document.addEventListener('DOMContentLoaded', function (){
//생략
// 책 이미지 표시 여부 설정
const bookImage = document.getElementById("bookImage");
// 이미지 URL이 잘못된 경우 숨김
if (!bookImage.src || bookImage.src.includes("/book/BOOK")) {
bookImage.style.display = "none";
} else {
bookImage.style.display = "block";
}
})
- 저장된 책 이미지 경로가 없을 땐 빈 화면, 보일 때만 이미지 보이게끔 구현.
728x90
320x100
'💻 뚝딱뚝딱 > 팀내도서대여시스템(OBRS)' 카테고리의 다른 글
[개발일지#017] 로그인 인터셉터(Interceptor) 적용하기 (0) | 2025.02.20 |
---|---|
[개발일지#016] 검색 기능 구현하기 (0) | 2025.02.20 |
[개발일지#014] 도서 API 적용하기 (Feat. 카카오 도서 API) (0) | 2025.02.20 |
[개발일지#013] 데이터베이스 컬럼추가 및 화면 수정 (0) | 2024.06.27 |
[개발일지#012] AWS(아마존 웹 서비스) 회원가입 하기 (0) | 2024.06.04 |
뚜루리님의
글이 좋았다면 응원을 보내주세요!
이 글이 도움이 됐다면, 응원 댓글을 써보세요. 블로거에게 지급되는 응원금은 새로운 창작의 큰 힘이 됩니다.
응원 댓글은 만 14세 이상 카카오계정 이용자라면 누구나 편하게 작성, 결제할 수 있습니다.
글 본문, 댓글 목록 등을 통해 응원한 팬과 응원 댓글, 응원금을 강조해 보여줍니다.
응원금은 앱에서는 인앱결제, 웹에서는 카카오페이 및 신용카드로 결제할 수 있습니다.