Spring Boot와 JPA를 활용한 도서관 관리 REST API 및 웹 애플리케이션입니다.
| 분류 | 기술 |
|---|---|
| Language | Java 21 |
| Framework | Spring Boot 3.5 |
| ORM | Spring Data JPA / Hibernate |
| Database | H2 (In-Memory) |
| View | Thymeleaf |
| Build | Gradle |
git clone https://github.com/KIHWANGPARK/khLibrary.git
cd khLibrary./gradlew bootRun- 웹 화면: http://localhost:8080
- H2 콘솔: http://localhost:8080/h2-console
- JDBC URL:
jdbc:h2:mem:librarydb - Username:
sa - Password: (없음)
- JDBC URL:
┌─────────────────┐ ┌─────────────────────┐
│ Patron │ │ Loan │
│─────────────────│ │─────────────────────│
│ patron_id (PK) │──────<│ loan_id (PK) │
│ name │ │ patron_id (FK) │
│ email │ │ branch_id (FK) │
│ city │ │ loan_date │
│ street │ │ due_date │
│ zipcode │ │ status │
└─────────────────┘ └──────────┬──────────┘
│
┌──────────▼──────────┐
│ LoanItem │
│─────────────────────│
│ loan_item_id (PK) │
│ loan_id (FK) │
│ book_id (FK) │
│ count │
└──────────┬──────────┘
│
┌─────────────────┐ ┌──────────▼──────────┐
│ Branch │ │ Book │
│─────────────────│ │─────────────────────│
│ branch_id (PK) │ │ book_id (PK) │
│ branch_name │ │ book_type (DTYPE) │
│ status │ │ title │
│ city │ │ isbn │
│ street │ │ price │
│ zipcode │ │ available_copies │
└─────────────────┘ │ author (PRINTED) │
│ publisher (PRINTED) │
│ file_format (EBOOK) │
│ narrator (AUDIO) │
└─────────────────────┘
| Method | URL | 설명 |
|---|---|---|
| GET | /api/patrons | 이용자 전체 조회 |
| GET | /api/patrons/{id} | 이용자 단건 조회 |
| POST | /api/patrons | 이용자 등록 |
| PATCH | /api/patrons/{id} | 이용자 정보 수정 |
POST /api/patrons 요청 예시
{
"name": "박기황",
"email": "park@naver.com",
"city": "서울",
"street": "중앙대로 123",
"zipcode": "12345"
}GET /api/patrons 응답 예시
[
{
"id": 1,
"name": "박기황",
"email": "park@example.com",
"city": "서울",
"street": "중앙대로 123",
"zipcode": "12345"
}
]| Method | URL | 설명 |
|---|---|---|
| GET | /api/books | 도서 전체 조회 |
| GET | /api/books/{id} | 도서 단건 조회 |
| POST | /api/books | 도서 등록 |
| PATCH | /api/books/{id} | 도서 정보 수정 |
POST /api/books 요청 예시
{
"title": "백엔드 단기심화 6기 화이팅",
"isbn": "123-45-678-0100-2",
"price": 19900,
"availableCopies": 5,
"author": "박기황",
"publisher": "KH출판사",
"publishedYear": 2026
}GET /api/books 응답 예시
[
{
"id": 1,
"title": "백엔드 단기심화 6기 화이팅",
"isbn": "123-45-678-0100-2",
"price": 19900,
"availableCopies": 5
}
]| Method | URL | 설명 |
|---|---|---|
| GET | /api/loans | 대여 전체 조회 |
| GET | /api/loans/{id} | 대여 단일 조회 |
| POST | /api/loans | 대여 신청 |
| PATCH | /api/loans/{id}/return | 반납 처리 |
POST /api/loans 요청 예시
{
"patronId": 1,
"bookId": 1,
"count": 1
}GET /api/loans 응답 예시
[
{
"id": 1,
"patronName": "박기황",
"bookTitle": "백엔드 단기심화 6기 화이팅",
"count": 1,
"status": "ACTIVE",
"loanDate": "2025-01-01T10:00:00",
"dueDate": "2025-01-15T10:00:00"
}
]src/main/java/com/example/jpashop/
├── domain/ # 핵심 domain Entity
│ ├── book/ # 도서 상속 구조
│ │ ├── Book.java # 추상 클래스 (SINGLE_TABLE 전략)
│ │ ├── PrintedBook.java # 종이책
│ │ ├── EBook.java # 전자책
│ │ └── AudioBook.java # 오디오북
│ ├── Patron.java # 회원
│ ├── Loan.java # 대여
│ ├── LoanItem.java # 대여 항목
│ ├── Branch.java # 지점
│ └── Genre.java # 장르
├── exception/ # 커스텀 예외
├── repository/ # JPA 리포지토리
├── service/ # 비즈니스 로직
└── web/
├── api/ # REST API 컨트롤러
│ ├── PatronApiController.java
│ ├── BookApiController.java
│ └── LoanApiController.java
└── (MVC 컨트롤러 + Form 객체)
- JPA 연관관계 매핑 : @OneToMany, @ManyToOne, @OneToOne, @ManyToMany
- 단일 테이블 상속 전략 : 도서 타입 관리 (PrintedBook / EBook / AudioBook)
- 도메인 모델 패턴 : 비즈니스 로직을 엔티티에 위치시켜 객체지향 설계 적용
- 변경 감지 (Dirty Checking) : 트랜잭션 내 엔티티 수정 시 별도 저장 없이 자동 반영
- 지연 로딩 (LAZY) : 불필요한 쿼리 방지로 성능 최적화
- REST API + Thymeleaf MVC : 두 가지 방식 동시 지원
- 유효성 검증 : @Valid, @NotEmpty, @Email 애노테이션 활용