Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 포함관계
- 컴파일
- 자바 멀티스레딩
- java변수
- JAVA기초
- 반복문
- 메서드
- function
- Java
- 생성자
- 인텔리제이 기초 설정
- multi-threading
- While
- 메서드 오버로딩
- 시스템 환경 변수 편집
- break문
- IntelliJ IDEA
- for문
- Java데이터 타입
- 인텔리제이 한글 깨짐 해결법
- JAVA객체지향
- 집합관계
- OPP개념
- Thread
- 상수
- 연관관계
- 형 변환
- this예약어
- 접근제어지시자
- continue문
Archives
- Today
- Total
최원종의 개발 블로그
도서관 도서관리 프로그램 - 4 본문
만드는 기능
기능 목록:
도서 관리 : 추가, 목록 조회, 제목 검색,
학생 관리 : 등록, 목록 조회, 로그인
대출/반납 : 대출 처리, 반납 처리, 대출 중인 도서 조회
규칙
규칙:
- main 브랜치에 직접 push 금지
- 기능 완성 후 PR 생성 → github -> self-review(팀원리뷰) → main 에 merge
- 커밋 메시지는 영문 소문자 + 한글 설명 병행
- 하나의 커밋 = 하나의 논리적 변경
자주 하는 실수 및 해결법
커밋 메시지 오타 (push 전)
git commit --amend -m "feat: add BookDAO - addBook method"
커밋을 되돌리고 싶을 때 (단 PUSH 전)
git reset HEAD~1 # 마지막 커밋 취소 (변경 내용은 유지)
git reset --hard HEAD~1 # 마지막 커밋 + 변경 내용 모두 취소
swing시안



DAO 패턴 설계

역할 나누는 이유
하나의 클래스에 모든 코드를 넣으면:
DB 연결 코드 + 비즈니스 로직 + 화면 출력이 뒤섞임
한 곳을 고치면 다른 곳이 망가질 위험
코드를 읽기가 매우 어려워짐
역할을 분리하면:
DTO : 데이터를 담는 그릇 (Lombok 으로 간결하게)
DAO : DB 와 직접 대화 (SQL 실행)
Service : 비즈니스 규칙 처리 (대출 가능 여부 확인 등)
View : 사용자 입출력 처리
각 층이 자신의 역할만 담당 → 수정/테스트/읽기가 쉬워짐
패키지 구조
src/main/java
com.tenco.library
├── util
│ └── DatabaseUtil.java ← DB 연결 담당
├── dto
│ ├── Book.java ← 도서 데이터 그릇
│ ├── Student.java ← 학생 데이터 그릇
│ └── Borrow.java ← 대출 기록 데이터 그릇
├── dao
│ ├── BookDAO.java ← 도서 SQL 실행
│ ├── StudentDAO.java ← 학생 SQL 실행
│ └── BorrowDAO.java ← 대출/반납 SQL 실행
├── service
│ └── LibraryService.java ← 비즈니스 로직
├── view
│ └── LibraryView.java ← 사용자 화면
└── Main.java ← 프로그램 시작점
MySQL
CREATE DATABASE IF NOT EXISTS library;
USE library;
-- 도서 테이블
CREATE TABLE IF NOT EXISTS books (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
author VARCHAR(255) NOT NULL,
publisher VARCHAR(255),
publication_year INT,
isbn VARCHAR(13),
available BOOLEAN DEFAULT TRUE
);
-- 학생 테이블
CREATE TABLE IF NOT EXISTS students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
student_id VARCHAR(20) NOT NULL UNIQUE
);
-- 대출 테이블
CREATE TABLE IF NOT EXISTS borrows (
id INT PRIMARY KEY AUTO_INCREMENT,
book_id INT,
student_id INT,
borrow_date DATE NOT NULL,
return_date DATE,
FOREIGN KEY (book_id) REFERENCES books(id),
FOREIGN KEY (student_id) REFERENCES students(id)
);
-- 샘플 데이터
INSERT INTO books (title, author, publisher, publication_year, isbn, available) VALUES
('자바 프로그래밍 입문', '김영훈', '한빛미디어', 2023, '9788968481234', TRUE),
('데이터베이스 기초', '이수진', '길벗', 2022, '9788968485678', TRUE),
('알고리즘 문제 해결', '박민수', '인사이트', 2021, '9788968489012', FALSE),
('웹 개발 입문', '최지영', '한빛아카데미', 2024, '9788968483456', TRUE),
('소프트웨어 공학', '정현우', '생능출판사', 2020, '9788970507890', FALSE);
INSERT INTO students (name, student_id) VALUES
('홍길동', '20230001'),
('김민서', '20230002'),
('이준호', '20230003');
INSERT INTO borrows (book_id, student_id, borrow_date, return_date) VALUES
(3, 1, '2025-05-01', NULL), -- 홍길동 → 알고리즘 문제 해결 대출 중
(5, 2, '2025-05-03', NULL); -- 김민서 → 소프트웨어 공학 대출 중
실습 코드
util/DatabaseUtil.java
package com.tenco.library.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseUtil {
private static final String URL = "jdbc:mysql://localhost:3306/library?serverTimezone=Asia/Seoul";
private static final String DB_USER = System.getenv("DB_USER");
private static final String PASSWORD = System.getenv("DB_PASSWORD");
// 새로운 DB 연결 객체를 반환 합니다.
public static Connection getConnection() throws SQLException {
// 재미삼아 효과 만들어 보기 ...
// Thread thread =new Thread(() ->{
// System.out.print("Connecting to database");
// for (int i = 0; i < 5; i++) {
// System.out.print(".");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// }
// });
// thread.start();
// try {
// thread.join();
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
Connection connection = DriverManager.getConnection(URL, DB_USER, PASSWORD);
System.out.println();
// System.out.println(connection.getMetaData().getDatabaseProductName());
// System.out.println(connection.getMetaData().getDatabaseProductVersion());
return connection;
}
// 수정
//TODO - 삭제예정
//테스트 코드 작성
public static void main(String[] args) {
try {
DatabaseUtil.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
DTO 설계
Admin
package com.tenco.library.dto;
import lombok.*;
//관리자 데이터를 담는 DTO 클래스
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = "passowrd") // toString 출력시 비밀번호 제외
public class Admin {
private int id;
private String adminId;
private String password;
private String name;
}
Book
package com.tenco.library.dto;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class Book {
private int id;
private String title;
private String author;
private String publisher;
private int publicationYear;
private String isbn;
private boolean available;
}
Borrow
package com.tenco.library.dto;
import lombok.*;
import java.time.LocalDate;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class Borrow {
private int id;
private int bookId;
private int studentId;
private LocalDate borrowDate;
private LocalDate returnDate;
}
Student
package com.tenco.library.dto;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class Student {
private int id;
private String name;
private String studentId;
@Builder
public Student(String name, String studentId){
this.name = name;
this.studentId = studentId;
}
}
DAO 설계
AdminDAO
package com.tenco.library.dao;
import com.tenco.library.dto.Admin;
import com.tenco.library.util.DatabaseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AdminDAO {
//관리자 인증(admin_id + password 조회)
public Admin authenticateAdmin(String adminId, String password) throws SQLException {
String sql = """
SELECT * FROM admins WHERE admin_id = ? AND password = ?
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, adminId);
pstmt.setString(2, password);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return Admin.builder()
.id(rs.getInt("id"))
.adminId(rs.getString("admin_id"))
.name(rs.getString("name"))
.build();
//tip 인증 후에는 일반적으로 비밀번호를 리턴하지 않는다
}
}
}
return null; // 인증 실패시 null 반환
}
}
BookDAO
package com.tenco.library.dao;
import com.tenco.library.dto.Book;
import com.tenco.library.util.DatabaseUtil;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.ListResourceBundle;
public class BookDAO {
public BookDAO() {
}
//도서추가
public void addBook(Book book) throws SQLException {
String sql = """
INSERT INTO books(title,author,publisher,publisher,getPublicationYear,isbn)
values(?, ?, ?, ?, ?)
""";
try (Connection conn = DatabaseUtil.getConnection()) {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, book.getTitle());
pstmt.setString(2, book.getAuthor());
pstmt.setString(3, book.getPublisher());
pstmt.setInt(4, book.getPublicationYear());
pstmt.setString(5, book.getIsbn());
}
}
//도서 전체 조회
public List<Book> getAllBooks() throws SQLException {
List<Book> bookList = new ArrayList<>();
String sql = """
select * from books order by id
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
bookList.add(mapToBook(rs));
}
}
return bookList;
}
// 제목으로 도서 검색
public List<Book> searchBooksByTitle(String title) throws SQLException {
List<Book> bookList = new ArrayList<>();
String sql = """
select * from books where title like ?
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "%" + title + "%");
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
bookList.add(mapToBook(rs));
}
}
}
return bookList;
}
private Book mapToBook(ResultSet rs) throws SQLException {
return Book.builder()
.id(rs.getInt("id"))
.title(rs.getString("title"))
.author(rs.getString("author"))
.publisher(rs.getString("publisher"))
.publicationYear(rs.getInt("publication_year"))
.isbn(rs.getString("isbn"))
.available(rs.getBoolean("available"))
.build();
}
}
BorrowDAO
package com.tenco.library.dao;
import com.tenco.library.dto.Borrow;
import com.tenco.library.util.DatabaseUtil;
import java.sql.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
// 대출/반납 관련 SQL 을 실행하는 DAO
public class BorrowDAO {
// 도서 대출 처리
// 대출 가능 여부 확인 --> borrow 테이블에 기록 --- 북 테이블 으로 변경
// try-with-resource 블록 문법 - 블록인 끝나는 순간 무조건 자원을 먼저 닫아 버림
// 이게 트랜잭션 처리할 때는 값을 확인해서 commit 또는 rollback 해야 하기 때문에 사용하면 안됨
// 즉, 직접 close() 처리 해야 함 - 트랜잭션 처리를 위해서.
/**
*
* @param bookId
* @param studentId : 학번이 아니라 student 테이블에 PK 값 이다. int 형
* @throws SQLException
*/
public void borrowBook(int bookId, int studentId) throws SQLException {
Connection conn = null;
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false); // 트랜잭션 시작 ......
// 1. 대출 가능 여부 확인
String checkSql = """
SELECT available FROM books WHERE id = ?
""";
try (PreparedStatement checkPstmt = conn.prepareStatement(checkSql)) {
checkPstmt.setInt(1, bookId);
try (ResultSet rs = checkPstmt.executeQuery()) {
if (rs.next() == false) {
throw new SQLException("존재하지 않는 도서입니다 : " + bookId);
}
if (rs.getBoolean("available") == false) {
throw new SQLException("현재 대출 중인 도서입니다. 반납 후 이용 가능");
}
}
} // end of checkPstmt
// 대출 가능한 한 상태 --> 대출 테이블에 학번,책 번호를 기록 해야 함.
// 2. 대출 기록 추가
String borrowSql = """
INSERT INTO borrows (book_id, student_id, borrow_date) values (? , ? , ?)
""";
try (PreparedStatement borrowPstmt = conn.prepareStatement(borrowSql)) {
borrowPstmt.setInt(1, bookId);
borrowPstmt.setInt(2, studentId);
// LocalDate --> Date 타입으로 변환 함.
borrowPstmt.setDate(3, Date.valueOf(LocalDate.now()));
borrowPstmt.executeUpdate();
} // end of borrowPstmt
// 3. 도서 상태 변경(대출 불가)
String updateSql = """
UPDATE books SET available = FALSE WHERE id = ?
""";
try (PreparedStatement updatePstmt = conn.prepareStatement(updateSql)) {
updatePstmt.setInt(1, bookId);
updatePstmt.executeUpdate();
} // end of updatePstmt
// 1, 2, 3 모두 성공 -> 커밋
conn.commit();
} catch (SQLException e) {
if (conn != null) {
conn.rollback(); // 하나라도 실패하면 전체 롤백
}
System.out.println("오류 발생 " + e.getMessage());
} finally {
if (conn != null) {
// 혹시 중간에 오류가 나서 처리가 안된다면 롤백 처리 함.
// conn.rollback(); -- 성공하더라도 무존 롤백 하게 됨... 그럼 반영 안됨.
conn.setAutoCommit(true); // autocommit 복구
conn.close();
}
}
}
//현재 대출 중인 도서 목록 조회 추가건 borrowdto사용
public List<Borrow> getBorrowList() throws SQLException {
List<Borrow> borrowJoinList = new ArrayList<>();
String blSql = """
SELECT
br.id,
b.id AS 책아이디,
b.title AS 책이름,
s.id AS 학생아이디,
s.name AS 대출한학생이름,
br.borrow_date AS 대출날짜
FROM borrows br
INNER JOIN students s ON br.student_id = s.id
INNER JOIN books b ON br.book_id = b.id
WHERE b.available = 'false' ORDER BY borrow_date
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(blSql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Borrow joinBorrow = Borrow.builder()
.id(rs.getInt("id"))
.bookId(rs.getInt("책아이디"))
.studentId(rs.getInt("학생아이디"))
//.borrowDate()
//.returnDate()
.build();
}
}
return getBorrowList();
}
// 현재 대출 중인 도서 목록 조회
public List<Borrow> getBorrowedBooks() throws SQLException {
List<Borrow> borrowList = new ArrayList<>();
String sql = """
SELECT * FROM borrows WHERE return_date IS NULL ORDER BY borrow_date
""";
// String sql = """
// SELECT *
// FROM borrows br
// INNER JOIN students s ON br.student_id = s.id
// INNER JOIN books b ON br.book_id = b.id
// WHERE b.available = 'false' ORDER BY borrow_date
// """;
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Borrow borrow = Borrow.builder()
.id(rs.getInt("id"))
.bookId(rs.getInt("book_id"))
.studentId(rs.getInt("student_id"))
// rs.getDate() --> toLocalDate() --> LocalDate 변환 됨.
.borrowDate(
rs.getDate("borrow_date") != null
? rs.getDate("borrow_date").toLocalDate()
: null
)
.build();
borrowList.add(borrow);
}
}
return borrowList;
}
// 도서 반납 처리
// 대출 기록 확인 --> return_date 업데이트 --> Book 도서 상태 업데이트
// 트랜 잭션 처리
/**
* @param bookId
* @param studentId : student 테이블 pk
*/
public void returnBook(int bookId, int studentId) throws SQLException {
Connection conn = null; // 트랜 잭션 시작
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false); // 트랜잭션 시작
// 1.대출 기록 확인 - 대출 테이블에 ID 값을 찾을 수 있다
String checkSql = """
SELECT id FROM borrows
WHERE book_id = ?
AND student_id = ?
AND return_date IS NULL
""";
int borrowId;
try (PreparedStatement checkPstmt = conn.prepareStatement(checkSql)) {
checkPstmt.setInt(1, bookId);
checkPstmt.setInt(2, studentId);
try (ResultSet rs = checkPstmt.executeQuery()) {
if (rs.next() == false) {
throw new SQLException("해당 대출 기록이 없거나 이미 반납 되었습니다");
}
// 대출 테이블에 해당하는 PK 추출
borrowId = rs.getInt("id");
}
} // end of checkPstmt
// 2. 반납일 기록
String updateBorrowSql = """
UPDATE borrows SET return_date = ? WHERE id = ?
""";
try (PreparedStatement updateBorrowPstmt = conn.prepareStatement(updateBorrowSql)) {
updateBorrowPstmt.setDate(1, Date.valueOf(LocalDate.now()));
updateBorrowPstmt.setInt(2, borrowId);
updateBorrowPstmt.executeUpdate();
}
// 3. 도서 상태 변경 (대출 가능)
String updateBookSql = """
UPDATE books SET available = TRUE WHERE id = ?
""";
try (PreparedStatement updateBookPstmt = conn.prepareStatement(updateBookSql)) {
updateBookPstmt.setInt(1, bookId);
updateBookPstmt.executeUpdate();
}
// 모두 성공 --> commit 처리
conn.commit();
} catch (SQLException e) {
if (conn != null) {
conn.rollback();
}
System.out.println("오류 발생 : " + e.getMessage());
} finally {
if (conn != null) {
conn.setAutoCommit(true);
conn.close();
}
}
// 1. 대출 기록 확인 - 대출 테이블에 ID 값을 찾을 수 있다
// 2. 반납일 기록
// 3. 도서 상태 변경
// 트랜 잭션 종료 (commit, rollback)
}
}
StudentDAO
package com.tenco.library.dao;
import com.tenco.library.dto.Student;
import com.tenco.library.util.DatabaseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class StudentDAO {
// 학생 등록
public void addStudent(Student student) throws SQLException {
String sql = """
INSERT INTO students(name, student_id) VALUES (? , ?)
""";
//url, user, pw ... ...
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, student.getName());
pstmt.setString(2, student.getStudentId());
pstmt.executeUpdate();
}
}
//전체 학생 조회
public List<Student> getAllStudents() throws SQLException {
List<Student> studentList = new ArrayList<>();
String sql = """
SELECT * FROM students ORDER BY id
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
// Student student = new Student();
// student.setId(rs.getInt("id"));
// student.setName(rs.getString("name"));
// student.setStudentId(rs.getString("student_id"));
//studentList.add(student);
studentList.add(mapToStudent(rs));
}
}
return studentList;
}
// 학번으로 학생 조회 - 로그인
public Student authenticateStudent(String studentId) throws SQLException {
String sql = """
SELECT * FROM students WHERE student_id = ?
""";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, studentId);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
// Student student = new Student();
// student.setId(rs.getInt("id"));
// student.setName(rs.getString("name"));
// student.setStudentId(rs.getString("student_id"));
return mapToStudent(rs);
}
}
}
return null;
}
// // 학생 이름 학번수정하기
// public Student modifyStudentInfo(int id, String name, String studentId) throws SQLException {
// Connection conn = null; // 트랜 잭션 시작
// try {
// conn = DatabaseUtil.getConnection();
// conn.setAutoCommit(false);
//
// //1. 학생 이름 학번 입력후 학생 있는지 찾기
// String infoSql = """
// SELECT id
// FROM students
// WHERE id = ?
// """;
// int studentInfo;
// try (PreparedStatement infoPstmt = conn.prepareStatement(infoSql)) {
// infoPstmt.setInt(1, id);
//
// try (ResultSet rs = infoPstmt.executeQuery()) {
// if (rs.next() == false) {
// throw new SQLException("등록 되지 않은 학생입니다");
// }
// studentInfo =rs.getInt("id");
// }
// }
// //2. 해당 학생 이름 수정하기
//
// String modifyStudentNameSql = """
// UPDATE student SET name = ? WHERE id = ?
// """;
//
// try (PreparedStatement modfiyPstmt = conn.prepareStatement(modifyStudentNameSql)) {
// modfiyPstmt.setString(1, name);
// modfiyPstmt.executeUpdate();
// }
//
//
// // 3. 해당 학생 학번 수정하기
// String modifyStudentIdSql = """
// UPDATE student SET student_id = ? WHERE id = ?
// """;
//
// try (PreparedStatement modfiyPstmt = conn.prepareStatement(modifyStudentIdSql)) {
// modfiyPstmt.setString(1, studentId);
// modfiyPstmt.executeUpdate();
// }
// conn.commit();
//
// } catch (SQLException e) {
// if (conn != null) {
// conn.rollback();
// }
// System.out.println("오류 발생 : " + e.getMessage());
// } finally {
// if (conn != null) {
// conn.setAutoCommit(true);
// conn.close();
// }
// }
// }
//ResultSet -> Student 변환 메서드
private Student mapToStudent(ResultSet rs) throws SQLException {
return Student.builder()
.id(rs.getInt("id"))
.name(rs.getString("name"))
.studentId(rs.getString("student_id"))
.build();
}
}
service 파일
LibraryService코드
package com.tenco.library.service;
import com.tenco.library.dao.AdminDAO;
import com.tenco.library.dao.BookDAO;
import com.tenco.library.dao.BorrowDAO;
import com.tenco.library.dao.StudentDAO;
import com.tenco.library.dto.Admin;
import com.tenco.library.dto.Book;
import com.tenco.library.dto.Borrow;
import com.tenco.library.dto.Student;
import java.sql.SQLException;
import java.util.List;
// 비즈니스 로직을 처리하는 서비스 클래스
// VIEW 계층 (화면) -> Service계층 -->Data 계층
// 뷰 계층에서는 DAO를 직접 호출하지 말고 항상 Service를 통해서 접근한다
public class LibraryService {
private final BookDAO bookDAO = new BookDAO();
private final StudentDAO studentDAO = new StudentDAO();
private final BorrowDAO borrowDAO = new BorrowDAO();
private final AdminDAO adminDAO = new AdminDAO();
// 도서 추가 기능(제목, 저자 필수 검증)
public void addBook(Book book) throws SQLException {
// 1. 유효성검사
if (book.getTitle() == null || book.getTitle().trim().isEmpty()) {
throw new SQLException("도서 제목은 필수 입력 항목입니다.");
}
if (book.getAuthor() == null || book.getAuthor().trim().isEmpty()) {
throw new SQLException("도서 저자는 필수 입력 항목입니다.");
}
bookDAO.addBook(book);
}
// 전체 도서 목록조회(대출 여부 상관없이 다 출력)
public List<Book> getAllBooks() throws SQLException {
return bookDAO.getAllBooks();
}
//책 제목으로 검색 하는 기능
public List<Book> searchBooksByTitle(String title) throws SQLException {
if (title == null || title.trim().isEmpty()) {
throw new SQLException("검색어를 입력해주세요");
}
return bookDAO.searchBooksByTitle(title);
}
//학생 등록 기능(이름, 학번 필수 검증)
public void addStudent(Student student) throws SQLException {
if (student.getName() == null || student.getName().trim().isEmpty()) {
throw new SQLException("학생 이름은 필수 항목입니다");
}
if (student.getStudentId() == null || student.getStudentId().trim().isEmpty()) {
throw new SQLException("학생의 학번은 필수 항목입니다");
}
studentDAO.addStudent(student);
}
// 전체 학생 목록 조회
public List<Student> getAllStudents() throws SQLException {
return studentDAO.getAllStudents();
}
//학번이 유효한지 조회(로그인)
/**
*
* @param studentId: - String(PK 아님)
* @return
*/
public Student authenticateStudent(String studentId) throws SQLException {
if (studentId == null || studentId.trim().isEmpty()) {
throw new SQLException("학번을 입력해주세요");
}
return studentDAO.authenticateStudent(studentId);
}
//도서 대출 요청 기능
/**
*
* @param bookId
* @param studentId : 학번이 아니라 PK값
* @throws SQLException
*/
public void borrowBook(int bookId, int studentId) throws SQLException {
if (bookId <= 0 || studentId <= 0) {
throw new SQLException("유효한 도서 ID와 학생ID를 입력해주세요.");
}
borrowDAO.borrowBook(bookId, studentId);
}
// 도서 반납 처리
/**
*
* @param bookId
* @param studentId : PK (학번아님)
* @throws SQLException
*/
public void returnBook(int bookId, int studentId) throws SQLException {
if (bookId <= 0 || studentId <= 0) {
throw new SQLException("유효한 도서 ID와 학생ID를 입력해주세요.");
}
borrowDAO.returnBook(bookId, studentId);
}
// 도서 조회 기능a
public List<Borrow> getBorrowedBooks() throws SQLException {
return borrowDAO.getBorrowedBooks();
}
// Todo 관리자 기능 추가 예정
//관리자 인증 서비스 기능 추가
public Admin authenticateAdmin(String adminId, String password) throws SQLException {
if (adminId == null || adminId.trim().isEmpty()) {
System.out.println("관리자 ID를 입력하세요");
}
if (password == null || password.trim().isEmpty()) {
System.out.println("관리자 password를 입력하세요");
}
return adminDAO.authenticateAdmin(adminId, password);
}
}//end of class LibraryService
view파일
LibrraryView
package com.tenco.library.view;
import com.tenco.library.dto.Admin;
import com.tenco.library.dto.Book;
import com.tenco.library.dto.Borrow;
import com.tenco.library.dto.Student;
import com.tenco.library.service.LibraryService;
import java.sql.SQLException;
import java.util.List;
import java.util.Scanner;
// 사용자 입출력을 처리하는 View 클래스
public class LibraryView {
private final LibraryService service = new LibraryService();
private final Scanner scanner = new Scanner(System.in);
private Integer currentStudentId = null; // 로그인 중인 학생의 DB id
private String currentStudentName = null; // 로그인 중인 학생 이름
private Integer correntAdminId = null; //관리자 DB id (PK)
private String currentAdminName = null; // 관리자 이름
// 프로그램 메인 루프
public void start() {
System.out.println("=== 도서관리 시스템 시작 ===");
while (true) {
printMenu();
int choice = readInt("선택: ");
try {
switch (choice) {
case 1:
// 관리자 인가 처리 필요함
if (correntAdminId == null) {
System.out.println("관리자만 도서를 추가할 수 있습니다");
break;
}
addBook();
break;
case 2:
listBooks();
break;
case 3:
searchBooks();
break;
case 4:
if (correntAdminId == null) {
System.out.println("관리자만 학생을 등록할 수 있습니다");
break;
}
addStudent();
break;
case 5:
if (correntAdminId == null) {
System.out.println("관리자만 학생정보를 조회할 수 있습니다");
break;
}
listStudents();
break;
case 6:
borrowBook();
break;
case 7:
listBorrowedBooks();
break;
case 8:
returnBook();
break;
case 9:
login();
break;
case 10:
logout();
break;
case 11:
System.out.println("프로그램을 종료합니다.");
scanner.close();
return;
case 12:
System.out.println("관리자 로그인");
adminLogin();
break;
default:
System.out.println("1~11 사이의 숫자를 입력하세요.");
}
} catch (SQLException e) {
// DB 오류는 사용자에게 친절하게 표시
System.out.println("오류: " + e.getMessage());
}
}
}
private void printMenu() {
System.out.println("\n=== 도서관리 시스템 ===");
if (currentStudentId == null && correntAdminId == null) {
System.out.println("[ 로그아웃 상태 ]");
}
if (currentStudentId != null) {
System.out.println("[ 로그인: " + currentStudentName + " ]");
}
if (correntAdminId != null) {
System.out.println("[ 로그인: " + currentAdminName + " ]");
}
System.out.println("──────────────────────");
System.out.println("1. 도서 추가");
System.out.println("2. 도서 목록");
System.out.println("3. 도서 검색");
System.out.println("4. 학생 등록");
System.out.println("5. 학생 목록");
System.out.println("6. 도서 대출");
System.out.println("7. 대출 중인 도서");
System.out.println("8. 도서 반납");
System.out.println("9. 로그인");
System.out.println("10. 로그아웃");
System.out.println("11. 종료");
System.out.println("12. 관리자 로그인");
}
//책 추가
private void addBook() throws SQLException {
System.out.print("제목 : ");
String title = scanner.nextLine().trim();
if (title.isEmpty()) {
System.out.println("제목은 필수입니다.");
return;
}
System.out.print("저자 : ");
String author = scanner.nextLine().trim();
if (author.isEmpty()) {
System.out.println("저자는 필수입니다.");
return;
}
System.out.print("출판사 : ");
String publisher = scanner.nextLine().trim();
int year = readInt("출판년도: ");
if (year < 1 || year > java.time.LocalDate.now().getYear()) {
System.out.println("유효한 출판년도를 입력하세요.");
return;
}
System.out.print("ISBN : ");
String isbn = scanner.nextLine().trim();
Book book = Book.builder()
.title(title)
.author(author)
.publisher(publisher.isEmpty() ? null : publisher)
.publicationYear(year)
.isbn(isbn.isEmpty() ? null : isbn)
.available(true)
.build();
service.addBook(book);
System.out.println("'" + title + "' 도서가 추가되었습니다.");
}
//책 리스트
private void listBooks() throws SQLException {
List<Book> books = service.getAllBooks();
System.out.println("\n=== 도서 목록 ===");
if (books.isEmpty()) {
System.out.println("등록된 도서가 없습니다.");
} else {
System.out.println("─────────────────────────────────────────────────────");
for (Book b : books) {
System.out.printf("ID: %2d | %-30s | %-15s | %s%n",
b.getId(),
b.getTitle(),
b.getAuthor(),
b.isAvailable() ? "대출 가능" : "대출 중");
}
}
}
//책 검색
private void searchBooks() throws SQLException {
System.out.print("검색 제목: ");
String title = scanner.nextLine().trim();
if (title.isEmpty()) {
System.out.println("검색어를 입력해주세요.");
return;
}
List<Book> books = service.searchBooksByTitle(title);
System.out.println("\n=== 검색 결과 ===");
if (books.isEmpty()) {
System.out.println("검색 결과가 없습니다.");
} else {
for (Book b : books) {
System.out.printf("ID: %2d | %-30s | %-15s | %s%n",
b.getId(), b.getTitle(), b.getAuthor(),
b.isAvailable() ? "대출 가능" : "대출 중");
}
}
}
//학생 추가
private void addStudent() throws SQLException {
System.out.print("이름: ");
String name = scanner.nextLine().trim();
if (name.isEmpty()) {
System.out.println("이름은 필수입니다.");
return;
}
System.out.print("학번: ");
String studentId = scanner.nextLine().trim();
if (studentId.isEmpty()) {
System.out.println("학번은 필수입니다.");
return;
}
service.addStudent(Student.builder().name(name).studentId(studentId).build());
System.out.println(name + " 학생이 등록되었습니다.");
}
//학생 리스트
private void listStudents() throws SQLException {
List<Student> students = service.getAllStudents();
System.out.println("\n=== 학생 목록 ===");
if (students.isEmpty()) {
System.out.println("등록된 학생이 없습니다.");
} else {
for (Student s : students) {
System.out.printf("ID: %2d | %-10s | 학번: %s%n",
s.getId(), s.getName(), s.getStudentId());
}
}
}
//책 대여
private void borrowBook() throws SQLException {
if (currentStudentId == null) {
System.out.println("먼저 로그인해주세요. (메뉴 9번)");
return;
}
int bookId = readInt("대출할 도서 ID: ");
if (bookId <= 0) {
System.out.println("유효한 도서 ID 를 입력하세요.");
return;
}
service.borrowBook(bookId, currentStudentId);
System.out.println("대출이 완료되었습니다.");
}
//대여한 책 리스트
private void listBorrowedBooks() throws SQLException {
List<Borrow> borrows = service.getBorrowedBooks();
System.out.println("\n=== 대출 중인 도서 ===");
if (borrows.isEmpty()) {
System.out.println("현재 대출 중인 도서가 없습니다.");
} else {
for (Borrow borrow : borrows) {
System.out.printf("대출ID: %2d | 도서ID: %2d | 학생ID: %2d | 대출일: %s%n",
borrow.getId(), borrow.getBookId(),
borrow.getStudentId(), borrow.getBorrowDate());
}
}
}
// 책반납
private void returnBook() throws SQLException {
if (currentStudentId == null) {
System.out.println("먼저 로그인해주세요. (메뉴 9번)");
return;
}
int bookId = readInt("반납할 도서 ID: ");
if (bookId <= 0) {
System.out.println("유효한 도서 ID 를 입력하세요.");
return;
}
service.returnBook(bookId, currentStudentId);
System.out.println("반납이 완료되었습니다.");
}
//로그인
private void login() throws SQLException {
if (currentStudentId != null) {
System.out.println("이미 로그인 중입니다. (" + currentStudentName + ")");
return;
}
System.out.print("학번: ");
String studentId = scanner.nextLine().trim();
if (studentId.isEmpty()) {
System.out.println("학번을 입력해주세요.");
return;
}
Student student = service.authenticateStudent(studentId);
if (student == null) {
System.out.println("존재하지 않는 학번입니다.");
} else {
currentStudentId = student.getId();
currentStudentName = student.getName();
System.out.println(currentStudentName + " 님, 환영합니다!");
}
}
//로그아웃
private void logout() {
if (currentStudentId == null && correntAdminId == null) {
System.out.println("현재 로그인 상태가 아닙니다.");
} else {
String name = currentStudentId != null ? currentStudentName : currentAdminName;
currentStudentId = null;
currentStudentName = null;
correntAdminId = null;
currentAdminName = null;
System.out.println(name + " 님이 로그아웃되었습니다.");
}
}
// 숫자 입력을 안전하게 처리 (잘못된 입력 시 재요청)
private int readInt(String prompt) {
while (true) {
System.out.print(prompt);
try {
return Integer.parseInt(scanner.nextLine().trim());
} catch (NumberFormatException e) {
System.out.println("숫자를 입력해주세요.");
}
}
}
//관리자 인증(로그인) 처리
public void adminLogin() throws SQLException {
//누구도 로그인 하지 않았을 때, 학생이 로그인 했을 때
//이미 관리자가 로그인 했을 때
if (currentStudentId != null || correntAdminId != null) {
System.out.println("이미 로그인 중입니다. 먼저 로그아웃 해주세요");
return;
}
System.out.printf("관리자 아이디 : ");
String adminId = scanner.nextLine().trim();
if (adminId.trim().isEmpty()) {
System.out.println("관리자 아이디를 입력해주세요");
return;
}
System.out.printf("관리자 PW : ");
String password = scanner.nextLine().trim();
if (password.trim().isEmpty()) {
System.out.println("관리자 PW를 입력해주세요");
return;
}
Admin admin = service.authenticateAdmin(adminId, password);
if (admin == null) {
System.out.println("관리자 ID 또는 PW가 틀렸습니다");
} else {
correntAdminId = admin.getId();
currentAdminName = admin.getName();
System.out.println(currentAdminName + "관리자님, 환영합니다");
}
}
}
Main
package com.tenco.library;
import com.tenco.library.view.LibraryView;
import com.tenco.library.view.LibraryView2;
public class Main {
//프로그램 시작 점
public static void main(String[] args) {
LibraryView libraryView = new LibraryView();
libraryView.start();
}
}
'Java > JAVA 유용한 클래스' 카테고리의 다른 글
| JDBC 데이터 기본 조작 (CRUD) - 3 (0) | 2026.04.14 |
|---|---|
| JDBC 구성 요소 (아키텍처) - 2 (0) | 2026.04.14 |
| JDBC(Java Database Connectivity) (1) | 2026.04.10 |
| HTTP Client 연습 - 5 (0) | 2026.04.01 |
| 공공데이터 API 실습 - HTTP - 4 (0) | 2026.04.01 |






