도서 관리자 기능 추가

Kim taegwan·2026년 4월 8일

도서 관리자 프로그램에서 기능을 추가해보자

현재 문제점

도서 추가, 학생 등록, 학생 목록 확인을 아무나 할 수 있습니다.
실제 도서관이라면 관리자만 할 수 있어야 합니다.

→ 이번 단원에서 관리자 계정을 추가하고
권한에 따라 기능을 제한합니다.

인가(Authorization) : 인증 된 사용자가 특정 자원에 접근하고자 할 때 접근 할 자격이 되는지 증명하는 것

인가처리를 해보자.

AdminDAO

sql문을 실행하는 dao를 만들자

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; // 인증 실패
    }


}

받아온 어드민 아이디와 비밀번호를 적어서 쿼리문을 조회하여 Admin DTo에 값을 넣는 모습이다.
rs.next 처음에는 행앞에 있다가 실행되면 첫번재 행으로 이동하여 값이 있는지 확인한다.
값이 있으면 바로 true 반환한다.
지금 반환값이 리스트가 아니고 객체이기 때문에 객체 하나만 반환하는 모습 객체를 여러개 반환할려면 List 쓰고 while(rs.next)를 하면 된다. 지금은 관리자 아이디와 패스워드에 맞는 행이 하나밖에 없어서
이렇게 쓰는 모습이다. 단일 객체 반환방식은 if를 쓰는 모습이다.


ibraryService

그다음은 라이브러리 서비스기능을 추가한다.

    // 관리자 인증 서비스 기능 추가
  public Admin authenticateAdmin(String adminId, String password) throws SQLException {
      if (adminId == null || adminId.trim().isEmpty()) {
          throw new SQLException("관리자 ID를 입력하세요");
      }
      if (password == null || password.trim().isEmpty()) {
          throw new SQLException("관리자 password를 입력하세요");
      }
      return adminDAO.authenticateAdmin(adminId, password);
  }

id와 비밀번호가 null값이 아니고 똑바로 적었다면 adminDAo의 메서드 authenticateAdmin()를 실행해서 admin객체를 반환하는 모습이다.


LibraryView

    // 관리자 인증(로그인) 처리
  public void adminLogin() throws SQLException {
      if (currentStudentId != null || currentAdminId != null) {
          System.out.println("이미 로그인 중입니다. 먼저 로그아웃해주세요");
          return;
      }

      System.out.print("관리자 ID : ");
      String adminId = scanner.nextLine().trim();
      if (adminId.trim().isEmpty()) {
          System.out.println("관리자 ID를 입력해주세요");
          return;
      }

      System.out.print("관리자 PW : ");
      String password = scanner.nextLine().trim();
      if (password.trim().isEmpty()) {
          System.out.println("관리자 password를 입력해주세요");
          return;
      }

      Admin admin = service.authenticateAdmin(adminId, password);
      if (admin == null) {
          System.out.println("관리자 ID 또는 비밀번호가 틀렸습니다");
      } else {
          currentAdminId = admin.getId();
          currentAdminName = admin.getName();
          System.out.println(currentAdminName + " 관리자님, 환영합니다!");
      }
  }

처음에 currentStudentId와 currentAdminId에 값이 있는지 확인하여 로그인을 하였는지 확인부터 한다. 그다음 아이디와 비밀번호를 입력하여 authenticateAdmin메서드를 실행하여
그 아이디와 비밀번호에 맞는 어드민 번호와 이름을 들고와서 currentStudentId와 currentAdminId에 값을 다시 넣는다.


이제 추가한 기능에 맞게 관리자 계정을 추가하고 권한에 따라 기능이 제한됐는지
한번 실행해 보자.

LibraryView

  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 currentAdminId = 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(currentAdminId == null) {
                            System.out.println("관리자만 도서를 추가할 수 있습니다");
                            break;
                        }
                        addBook();
                        break;
                    case 2:
                        listBooks();
                        break;
                    case 3:
                        searchBooks();
                        break;
                    case 4:
                        if(currentAdminId == null) {
                            System.out.println("관리자만 학생을 등록할 수 있습니다");
                            break;
                        }
                        addStudent();
                        break;
                    case 5:
                        if (currentAdminId == 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:
                        adminLogin(); // 관리자 로그인
                        break;
                    default:
                        System.out.println("1~11 사이의 숫자를 입력하세요.");
                }
            } catch (SQLException e) {
                // DB 오류는 사용자에게 친절하게 표시
                System.out.println("오류: " + e.getMessage());
            }
        }
    }

    private void printMenu() {
        System.out.println("\n=== 도서관리 시스템 ===");


        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 && currentAdminId == null) {
            System.out.println("현재 로그인 상태가 아닙니다.");
        } else {
            String name = currentStudentId != null ? currentStudentName : currentAdminName;
            currentStudentId = null;
            currentStudentName = null;
            currentAdminId = 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 || currentAdminId != null) {
            System.out.println("이미 로그인 중입니다. 먼저 로그아웃해주세요");
            return;
        }

        System.out.print("관리자 ID : ");
        String adminId = scanner.nextLine().trim();
        if (adminId.trim().isEmpty()) {
            System.out.println("관리자 ID를 입력해주세요");
            return;
        }

        System.out.print("관리자 PW : ");
        String password = scanner.nextLine().trim();
        if (password.trim().isEmpty()) {
            System.out.println("관리자 password를 입력해주세요");
            return;
        }

        Admin admin = service.authenticateAdmin(adminId, password);
        if (admin == null) {
            System.out.println("관리자 ID 또는 비밀번호가 틀렸습니다");
        } else {
            currentAdminId = admin.getId();
            currentAdminName = admin.getName();
            System.out.println(currentAdminName + " 관리자님, 환영합니다!");
        }
    }

}

start() 메서드 부터 보면 관리자 아이디에 로그인이 됐는지 아닌지 부터 확인하는 모습이다.
try {switch (choice) {
case 1:
if(currentAdminId == null) {
System.out.println("관리자만 도서를 추가할 수 있습니다");
break;
}

마지막 adminlogin() 메서드로 관리자 아이디 로그인 기능도 추가한 모습이다.
이렇게 관리자 인가처리가 잘 되었다.

0개의 댓글