요구 사항
DAY 1 : 설정 및 설계
-활동 :
-GitHub 리포지토리 생성, 브랜치 전약 수립(main , dev, feature/*)
-MySQL 데이터베이스 및 테이블 생성.
역할 분담 : DTO와 DAO 초기 설계.
성과물 : 리포지토리, DB 스키마 , ERD 다이어그램
Day 2. DAO 및 DTO 구현
활동
- Book , Student , Borrow DTO 작성 (Lombok 사용)
-DAO 클래스 구현 (bookDAO, StudentDAO, BorrowDAO)
-기본 CRUD 기능 테스트
성과물 : DTO, DAO 코드, Git 커밋
Day 3 : Service 및 View 구현
활동
-LibraryService 에서 비즈니스 로직 구현
-LibraryView 로 콘솔 UI 구현
-기능 통합 및 버그 수정
-성과물 : 완성된 Service , View, 통합코드
DAY 4 : 테스트 및 마무리
-활동 :
- 최종 테스트 및 디버깅
- UI 개선 , 코드 리뷰
- Git main 브랜치로 병합
- 성과물 : 완성된 프로젝트, 최종 커밋
패키지 구조 설정 하기
src/main/java
├── util
│ └── DatabaseUtil.java
├── dto
│ ├── Book.java
│ ├── Student.java
│ ├── Borrow.java
├── dao
│ ├── BookDAO.java
│ ├── StudentDAO.java
│ ├── BorrowDAO.java
├── service
│ └── LibraryService.java
├── view
│ └── LibraryView.java
└── Main.java
-DTO : 데이터 전송 객체, DB 테이블과 매핑(@Getter, @Setter, @Builder 등 사용)
-DAO : 데이터베이스 접근 로직, CRUD 작업 처리.
-Service : 비즈니스 로직, DAQ 호출
View : 콘솔 UI, 사용자 입력/출력 처리.
Main : 프로그램 진입점.
1. 테이블 설계
-- 데이터 베이스 생성
create database library;
use library;
-- 1. 도서 테이블 만들기 (books)
create table books(
id int auto_increment primary key,
title varchar(255) not null,
publisher varchar(255),
publication_year int,
isbn varchar(13),
available boolean default true
);
-- 2. 학생 테이블 만들기 (students)
create table students(
id int auto_increment primary key,
name varchar(100) not null,
student_id varchar(20) not null unique
);
-- 3. 중간 테이블 (borrows)
create table borrows(
id int auto_increment primaru key,
student_id int,
book_id int,
borrow_date date not null,
return_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); -- 김민서가 '소프트웨어 공학' 대출
2. 모델링 하기 DTO 설계
package dto;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@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;
}
package dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Borrow {
private int id;
private int bookId;
private int studentId;
private LocalDate borrowDate;
private LocalDate returnDate;
}
package dto;
import lombok.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private int id;
private String name;
private String studentId;
}
3. DBUtil 클래스 만들어 보기
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 데이터 베이스 연결을 관리하는 유틸리티 클래스
*/
public class DatabaseUtil {
// "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=Asia/Seoul";
private static final String DB_URL = "jdbc:mysql://localhost:3306/library?serverTimeZone=Asia/Seoul";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "asd1234";
// 데이터 베이스 연결 객체a를 반환 하는 함수
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
}
}
-데이터베이스 연결 코드는 URL, 사용자 이름, 비밀번호 등을 포함하며, 여러 곳에서 반복적으로 사용됩니다. DatabaseUtil 클래스를 만들면 이 코드를 한 곳에서 중앙 집중적으로 관리할 수 있어 중복을 줄이고 유지보수를
쉽게 만듭니다.
- 모든 데이터베이스 연결이 동일한 설정(예 : DB_URL, DB_USER, DB_PASSWORD)을 사용하도록 보장합니다.
설정이 변경될 경우, 한 곳만 수정하면 되므로 오류 가능성이 줄어듭니다.
- 다른 클래스나 모듈에서 데이터베이스 연결이 필요한 때,DatabaseUtil.getCommection()을 호출하기만 하면 간단히
연결을 얻을 수 있습니다. 이는 코드의 재사용성을 높이고 개발 효율성을 향상시킵니다.
- 추가 개선 가능성에 용이 하다.
4. DAO 클래스 구현해보기
- bookDAO 만들어 보기
package dao;
import dto.Book;
import util.DatabaseUtil;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 도서 관련 데이터베이스 작업을 처리하는 DAO 클래스
*/
public class BookDAO {
// 새 도서를 데이터 베이스에 추가
public void addBook(Book book) throws SQLException {
String sql = "INSERT INTO books (title, author, publisher, publication_year, 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());
pstmt.executeUpdate();
}
}
// 모든 도서 모록을 조회 기능 추가
public List<Book> getAllBooks() throws SQLException {
List<Book> bookList = new ArrayList<>();
String sql = "SELECT * FROM books ";
try(Connection conn = DatabaseUtil.getConnection();
Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String title = rs.getString("title");
String author = rs.getString("author");
String publisher = rs.getString("publisher");
int publicationYear = rs.getInt("publication_year");
String isbn = rs.getString("isbn");
boolean available = rs.getBoolean("available");
Book book = new Book(id, title, author, publisher, publicationYear, isbn, available);
bookList.add(book);
}
}
return bookList;
}
// 책 제목으로 도서를 검색 기능
public List<Book> searchBooksTitle(String searchTitle) 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, "%" + searchTitle + "%");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String title = rs.getString("title");
String author = rs.getString("author");
String publisher = rs.getString("publisher");
int publicationYear = rs.getInt("publication_year");
String isbn = rs.getString("isbn");
boolean available = rs.getBoolean("available");
Book book = new Book(id, title, author, publisher, publicationYear, isbn, available);
bookList.add(book);
}
}
return bookList;
}
// TODO - 테스트 코드 삭제 예정
// 테스트 코드 작성
public static void main(String[] args) {
// 전체 조회 테스트
BookDAO bookDAO = new BookDAO();
try {
// bookDAO.getAllBooks();
ArrayList<Book> selectedBookList =
(ArrayList) bookDAO.searchBooksTitle("입문");
for (int i = 0; i < selectedBookList.size(); i++) {
System.out.println(selectedBookList.get(i));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 수정, 삭제
}
StydentDAO
package dao;
import dto.Student;
import 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 {
// 1. 쿼리문 만들기 및 테스트 (DB에서)
String sql = "INSERT INTO students (name, student_id) values (?, ?) ";
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 ";
try(Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Student studentDto = new Student();
studentDto.setId(rs.getInt("id"));
studentDto.setName(rs.getString("name"));
studentDto.setStudentId(rs.getString("student_id"));
studentList.add(studentDto);
}
}
return studentList;
}
// 학생 student_id로 학생 인증(로그인 용) 기능 만들기
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);
ResultSet rs = pstmt.executeQuery();
if(rs.next()) {
Student studentDTO = new Student();
studentDTO.setId(rs.getInt("id"));
studentDTO.setName(rs.getString("name"));
studentDTO.setStudentId( rs.getString("student_id"));
return studentDTO;
}
}
return null;
}
}
package dao;
import util.DatabaseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class BorrowDAO {
// 도서 대출을 처리 기능
public void borrowBook(int bookId, int studentPk) throws SQLException {
// 대출 가능 여부 --- SELECT(books)
// 대출 하다면 --> INSERT(borrows)
// 대출이 실행 되었다면 --> UPDATE (books-> available)
String checkSql = "select available from books where id = ? ";
try(Connection conn = DatabaseUtil.getConnection();
PreparedStatement checkPstmt = conn.prepareStatement(checkSql)) {
checkPstmt.setInt(1, bookId);
ResultSet rs1 = checkPstmt.executeQuery();
if(rs1.next() && rs1.getBoolean("available")) {
// insert, update
String insertSql = "insert into borrows (student_id, booK_id, borrow_date) \n" +
"values (?, ?, CURRENT_DATE) ";
String updateSql = "update books set available = FALSE where id = ? ";
try(PreparedStatement borrowStmt = conn.prepareStatement(insertSql);
PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
borrowStmt.setInt(1, studentPk);
borrowStmt.setInt(2, bookId);
System.out.println("--------------------------------------");
updateStmt.setInt(1, bookId);
borrowStmt.executeUpdate();
updateStmt.executeUpdate();
}
} else {
throw new SQLException("도서가 대출 불가능 합니다");
}
}
}
// 메인 함수
public static void main(String[] args) {
// 대출 실행 테스트
BorrowDAO borrowDAO = new BorrowDAO();
try {
borrowDAO.borrowBook(1, 3);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} // end of main
}
5. 서비스 클래스 구현해보기
뷰 클래스 구현해보기
package service;
import dao.BookDAO;
import dao.BorrowDAO;
import dao.StudentDAO;
import dto.Book;
import dto.Borrow;
import dto.Student;
import java.sql.SQLException;
import java.util.List;
/**
* 비즈니스 로직을 처리하는 서비스 클래스
*/
public class LibraryService {
private final BookDAO bookDAO = new BookDAO();
private final StudentDAO studentDAO = new StudentDAO();
private final BorrowDAO borrowDAO = new BorrowDAO();
// 책을 추가하는 서비스
public void addBook(Book book) throws SQLException {
// 입력 값 유효성 검사
if(book.getTitle() == null || book.getAuthor() == null
|| book.getTitle().trim().isEmpty() || book.getAuthor().trim().isEmpty() ) {
throw new SQLException("도서 제목과 저자는 필수 입력 항목입니다.");
}
// 유효성 검사 통과후 BookDAO 에게 일을 협력 요청 한다.
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.searchBooksTitle(title);
}
// 학생을 추가하는 서비스
public void addStudent(Student student) throws SQLException {
// 유효성 검사 ... 생략 (직접 구현 해보기)
studentDAO.addStudent(student);
}
// 전체 학생 목록을 조회 하는 서비스
public List<Student> getAllStudents() throws SQLException {
return studentDAO.getAllStudents();
}
// 도서를 대출하는 서비스
public void borrowBook(int bookId, int studentId) throws SQLException {
// 유효성 검사(벨리테이션 처리)
if(bookId <= 0 || studentId <= 0) {
throw new SQLException("유효한 도서 ID와 학생 ID를 입력해주세요");
}
// borrowDAO 객체에게 협력 요청하고
// borrows 테이블에 insert 처리에 책임은 BorrowDAO 객체가 가진다
borrowDAO.borrowBook(bookId, studentId);
}
// 현재 대출중인 도서 목록을 보여주는 서비스
public List<Borrow> getBorrowedBooks() throws SQLException {
return borrowDAO.getBorrowedBooks();
}
// 도서 대출을 반납하는 서비스
public void returnBook(int bookId, int studentId) throws SQLException {
if(bookId <= 0 || studentId <= 0) {
throw new SQLException("유효한 도서 ID와 학생 ID를 입력해주세요");
}
borrowDAO.returnBook(bookId, studentId);
}
// 학생 ID로 학생 인증하는 서비스
// [공백공백공백]
public Student authenticateStudent(String studentId) throws SQLException {
if(studentId == null || studentId.trim().isEmpty()) {
throw new SQLException("학번을 입력해주세요");
}
return studentDAO.authenticateStudent(studentId);
}
}
뷰 클래스 구현해보기
package view;
import dto.Student;
import service.LibraryService;
import javax.swing.*;
import java.sql.SQLException;
import java.util.Scanner;
/**
* 사용자 인터페이스를 처리하는 뷰 클래스
*/
public class LibraryView {
private final LibraryService service = new LibraryService();
private final Scanner scanner = new Scanner(System.in);
private Integer currentStudentId = null;
private String currentStudentName = null;
// principal - 접근 주체
// private Student principalUser = null;
public void start() {
while (true) {
System.out.println("===도서관리 시스템===");
if(currentStudentId == null) {
System.out.println("현재 로그아웃 상태 입니다");
} else {
System.out.println("현재 로그인 유저 : " + currentStudentName);
}
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.print("선택 : ");
int choice;
try {
choice = scanner.nextInt();
scanner.nextLine(); // 버퍼비우기
} catch (Exception e) {
System.out.println("사용자야 정수값을 입력해주겠니?");
scanner.nextLine();
continue;
}
switch (choice) {
case 1:
System.out.println("도서추가");
break;
case 2:
System.out.println("22");
break;
case 3:
System.out.println("3");
break;
case 4:
System.out.println("4");
break;
case 5:
System.out.println("5");
break;
case 6:
System.out.println("6");
break;
case 7:
System.out.println("7");
break;
case 8:
System.out.println("8");
break;
case 9:
System.out.println("9");
break;
case 10:
System.out.println("10");
break;
case 11:
System.out.println("시스템 종료");
scanner.close(); // 자원 해제
return;
default:
System.out.println("잘못된 입력 입니다");
}
} // end of while
} // end of start
// 로그인 기능 만들어 보기
private void login() throws SQLException {
if(currentStudentId != null) {
System.out.println("이미 로그인된 상태입니다");
return;
}
System.out.print("학번 : ");
String studentId = scanner.nextLine().trim();
if(studentId.isEmpty()) {
System.out.println("학번을 입력해주세요");
return;
}
// 1. 학번을 입력 받았다면 -> 실제 학번이 맞는지 확인
// 1.1 (데이터 접근해서 해당하는 학번(비밀번호) 맞는지 조회
// 이 메서드에 결과는 두가지 (객체 존재, null)
Student studentDTO = service.authenticateStudent(studentId);
if(studentDTO == null) {
System.out.println("존재하지 않는 학번입니다");
} else {
currentStudentId = studentDTO.getId();
currentStudentName = studentDTO.getName();
System.out.println("로그인 성공 : " + currentStudentName);
}
}
// 로그 아웃 기능 만들어 보기
private void logout() {
if(currentStudentId == null) {
System.out.println("이미 로그인 상태가 아닙니다.");
} else {
currentStudentId = null;
currentStudentName = null;
System.out.println("로그아웃 완료");
}
}
}
'DB의 접근기술' 카테고리의 다른 글
(JAVA) 성능 최적화(HikariCP)와 커넥션 풀이란? - 7 (1) | 2025.05.27 |
---|---|
(JAVA) Gradle, Maven, 저장소란 뭘까? (1) | 2025.05.26 |
(JAVA) JDBE 프로젝트 만들어 보기(학생) -5 (0) | 2025.05.26 |
(JAVA DB) JDBC CRUD 연습 - 2 (0) | 2025.05.19 |
(JDBC) JDBC 구성 요소(아키텍처) - 2 (0) | 2025.05.14 |