1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện

97 0 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Hệ thống quản lý thư viện
Tác giả Nhóm 01
Người hướng dẫn ThS Bùi Hữu Đông
Trường học Trường Đại học Ngân hàng TP.HCM
Chuyên ngành Hệ thống thông tin
Thể loại Bài tập nhóm
Năm xuất bản 2025
Thành phố Thành phố Hồ Chí Minh
Định dạng
Số trang 97
Dung lượng 2,51 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Cấu trúc

  • 1. Tổng quan về Lập trình hướng đối tượng (10)
    • 1.1. Khái niệm Lập trình hướng đối tượng (10)
      • 1.1.1. Class (Lớp) trong OOP (10)
      • 1.1.2. Object (đối tượng) trong OOP (10)
    • 1.2. Các tính chất của Lập trình hướng đối tượng (10)
  • 2. Mô hình cơ sở dữ liệu (11)
    • 2.1. Sơ đồ ERD (11)
    • 2.2. Mô tả các bảng (11)
      • 2.2.1. Bảng TacGia (11)
      • 2.2.2. Bảng Sach (11)
      • 2.2.3. Bảng DocGia (12)
      • 2.2.4. Bảng ChiTietSachTacGia (12)
      • 2.2.5. Bảng PhieuMuon (12)
      • 2.2.6. Trigger CapNhatTrangThaiSachMuon &CapNhatTrangThaiSachTra (13)
      • 2.2.7. View Sach_TacGia (13)
  • 3. Các lớp trong Java (13)
    • 3.1. Các thực thể chính (13)
      • 3.1.1. TacGia (13)
        • 3.1.1.1. Code (13)
        • 3.1.1.2. Mô tả (15)
        • 3.1.1.3. Chức năng (15)
        • 3.1.1.4. Cách thức hoạt động (15)
      • 3.1.2. Sach (15)
        • 3.1.2.1. Code (15)
        • 3.1.2.2. Mô tả (18)
        • 3.1.2.3. Chức năng (18)
        • 3.1.2.4. Cách thức hoạt động (19)
      • 3.1.3. PhieuMuon (19)
        • 3.1.3.1. Code (19)
        • 3.1.3.2. Mô tả (22)
        • 3.1.3.3. Chức năng (22)
        • 3.1.3.4. Cách thức hoạt động (22)
      • 3.1.4. DocGia (23)
        • 3.1.4.1. Code (23)
        • 3.1.4.2. Mô tả (24)
        • 3.1.4.3. Chức năng (24)
        • 3.1.4.4. Cách thức hoạt động (24)
    • 3.2. Lớp DAO và Lớp Implement (25)
      • 3.2.1. Lớp DAO (25)
      • 3.2.2. Implement (28)
    • 3.3. Các lớp quản lý (48)
      • 3.3.1. QuanLyTacGia (48)
        • 3.3.1.1. Code (48)
        • 3.3.1.2. Mô tả (51)
        • 3.3.1.3. Chức năng (51)
        • 3.3.1.4. Cách thức hoạt động (51)
      • 3.3.2. QuanLySach (52)
        • 3.3.2.1. Code (52)
        • 3.3.2.2. Mô tả (60)
        • 3.3.2.3. Chức năng (60)
        • 3.3.2.4. Cách thức hoạt động (60)
      • 3.3.3. QuanLyMuonSach (61)
        • 3.3.3.1. Code (61)
        • 3.3.3.2. Mô tả (63)
        • 3.3.3.3. Chức năng (63)
        • 3.3.3.4. Cách thức hoạt động (64)
    • 3.4. Lớp Main (65)
      • 3.4.1. Code (65)
      • 3.4.2. Mô tả (80)
      • 3.4.3. Chức năng (80)
      • 3.4.4. Cách thức hoạt động (81)
    • 3.5. DBConnection (81)
      • 3.5.1. Code (81)
      • 3.5.2. Mô tả (85)
      • 3.5.3. Chức năng (85)
      • 3.5.4. Cách thức hoạt động (86)
  • 4. Kết quả chạy chương trình (87)
    • 4.1. Quản lý Tác giả (87)
      • 4.1.1. Thêm thông tin tác giả (87)
      • 4.1.2. Sửa thông tin tác giả (87)
      • 4.1.3. Xóa danh sách thông tin tác giả (88)
      • 4.1.4. Xem danh sách thông tin tác giả (88)
      • 4.1.5. Tìm kiếm thông tin tác giả (89)
    • 4.2. Quản lý Sách (89)
      • 4.2.1. Thêm thông tin sách (89)
      • 4.2.2. Sửa thông tin sách (90)
      • 4.2.3. Xóa thông tin sách (90)
      • 4.2.4. Xem danh sách thông tin sách (91)
      • 4.2.5. Tìm kiếm thông tin sách (91)
    • 4.3. Quản lý Mượn/Trả sách (92)
      • 4.3.1. Mượn sách (92)
      • 4.3.2. Trả sách (92)
        • 4.3.2.1. CSDL trong SQL trước khi trả sách (92)
        • 4.3.2.2. Màn hình hiển thị (93)
        • 4.3.2.3. CSDL trong SQL sau khi trả sách (đã cập nhật ngày trả và đổi trạng thái sách về "Sẵn sàng") (93)
    • 4.4. Chức năng nâng cao & thống kê (94)
      • 4.4.1. Tìm kiếm sách theo tên tác giả (94)
      • 4.4.2. Sắp xếp sách theo Tên sách (alphabet) (94)
      • 4.4.3. Liệt kê danh sách các sách đang được cho mượn (95)

Nội dung

Chức năng của hệ thống không chỉ dừng lại ở các nghiệp vụ cơ bản như thêm, sửa, xóa, tìm kiếm mà còn mở rộng với các tính năng nâng cao như: quản lý mối quan hệ nhiều-nhiều giữa sách và

Tổng quan về Lập trình hướng đối tượng

Khái niệm Lập trình hướng đối tượng

- Lập trình hướng đối tượng (Object Oriented Programming , viết tắt: OOP) là một kỹ thuật lập trình cho phép lập trình viên tạo ra các đối tượng trong code trừu tượng hóa các đối tượng thực tế trong cuộc sống

- Trong OOP sẽ gồm có 2 thành phần chính: Class và Object:

- Class (lớp) trong OOP là các template hay cấu trúc để phục vụ cho việc xây dựng nên các Object (đối tượng) Trong đó sẽ bao gồm một tập hợp các Attribute và Methods để định nghĩa các đặc tính và hành vi cho các Object

+ Attributes (thuộc tính): những thông ti, đặc điểm của đối tượng

+ Methods: (phương thức): những thao tác, hành động mà đối tượng đó có thể thực hiện

1.1.2 Object (đối tượng) trong OOP

- Object (đối tượng) trong OOP là một instance của Class, có thể hiểu là một hiện thực hay ví dụ cụ thể của một Class Vì thế Object khi khởi tạo sẽ mang đầy đủ thông tin cụ thể mà Class đã định nghĩa.

Các tính chất của Lập trình hướng đối tượng

- Lập trình hướng đối tượng có 4 tính chất cơ bản

+ Tính đóng gói: là một kỹ thuật lập trình nền tảng được sử dụng để gom nhóm các attributes và methods cần thiết vào một Object

+ Tính trừu tượng: là một kỹ thuật lập trình dùng để đơn giản hoá cấu trúc của chương trình, tập trung vào những phần quan trọng và có ý nghĩa Những phần phức tạp sẽ được loại bỏ hay ẩn giấu đi (hiding)

+ Tính kế thừa: là một cơ chế xây dựng class mới dựa trên các class đã có Các class kế thừa sẽ bao gồm toàn bộ các attributes và methods từ base class (lớp cơ sở) hay parent class (lớp cha)

+ Tính đa hình trong lập trình hướng đối tượng OOP cho phép một Object có thể có nhiều hình dạng và hành vi khác nhau Nói cách khác đây là một hành động có

2 thể được thực hiện bằng nhiều cách khác nhau Đây lại là một tính chất có thể nói là chứa đựng hầu hết sức mạnh của lập trình hướng đối tượng.

Mô hình cơ sở dữ liệu

Sơ đồ ERD

Mô tả các bảng

- Lưu trữ thông tin về tác giả của các cuốn sách

 MaTacGia (INT, PRIMARY KEY, IDENTITY): Mã định danh duy nhất cho mỗi tác giả, tự tăng

 TenTacGia (NVARCHAR(100), NOT NULL): Họ và tên của tác giả

 QuocTich (NVARCHAR(100)): Quốc tịch của tác giả

- Ý nghĩa: Phân tách dữ liệu tác giả giúp quản lý được các cuốn sách có thể thuộc nhiều tác giả khác nhau (nhiều – nhiều)

- Lưu trữ thông tin về các cuốn sách có trong thư viện

 MaSach (INT, PRIMARY KEY, IDENTITY): Mã định danh duy nhất cho mỗi cuốn sách, tự tăng

 TenSach (NVARCHAR(150), NOT NULL): Tên sách

 NamXuatBan (INT): Năm xuất bản

 NhaXuatBan (NVARCHAR(100)): Tên nhà xuất bản

 TrangThai (NVARCHAR(50)): Trạng thái sách, có giá trị 'Sẵn sàng' hoặc 'Đã cho mượn'

- Ý nghĩa: Đây là bảng quản lý toàn bộ thông tin cơ bản của sách Trạng thái sách được cập nhật tự động qua trigger sau khi mượn/trả

- Lưu thông tin của các độc giả đăng ký mượn sách

 MaDocGia (NVARCHAR(10), PRIMARY KEY): Mã độc giả (được định dạng dạng chuỗi như ‘R001’, ‘R002’ )

 TenDocGia (NVARCHAR(100)): Họ và tên của độc giả

- Ý nghĩa: Bảng này giúp thư viện lưu trữ và tra cứu thông tin người đọc đã từng mượn sách

- Là bảng trung gian quản lý quan hệ nhiều – nhiều giữa Sách và Tác giả

 MaSach (INT, FOREIGN KEY): Mã sách

 MaTacGia (INT, FOREIGN KEY): Mã tác giả

- Ý nghĩa: Một cuốn sách có thể có nhiều tác giả và ngược lại – bảng này đảm nhiệm việc liên kết giữa hai bảng chính Sach và TacGia

- Lưu thông tin chi tiết các lượt mượn sách của độc giả

 MaPhieu (INT, PRIMARY KEY, IDENTITY): Mã phiếu mượn

 MaDocGia (NVARCHAR(10), FOREIGN KEY): Mã độc giả mượn sách

 MaSach (INT, FOREIGN KEY): Mã sách được mượn

 NgayMuon (DATE): Ngày mượn sách

 NgayTra (DATE, NULL): Ngày trả sách (có thể để trống nếu chưa trả)

- Ý nghĩa: Bảng này ghi nhận mọi hoạt động mượn sách của độc giả, giúp theo dõi lịch sử và trạng thái mượn

 CapNhatTrangThaiSachMuon: Sau khi thêm phiếu mượn mới, trạng thái của sách sẽ tự động cập nhật thành “Đã cho mượn”

 CapNhatTrangThaiSachTra: Khi cập nhật ngày trả của phiếu mượn, nếu sách được trả thì trạng thái cập nhật về “Sẵn sàng”

- Ý nghĩa: Tự động hóa xử lý trạng thái sách, giúp giảm lỗi thủ công

- Là một lượt xem dữ liệu (VIEW) kết hợp giữa các bảng Sach, ChiTietSachTacGia và TacGia để hiển thị danh sách sách kèm tên tác giả tương ứng.

Các lớp trong Java

Các thực thể chính

15 package com.hub.oop; public class TacGia { private int idTacGia; private String tenTacGia; private String quocTich;

// Constructor public TacGia(int idTacGia, String tenTacGia, String quocTich) { this.idTacGia = idTacGia; this.tenTacGia = tenTacGia; this.quocTich = quocTich;

// Getter và Setter public int getIdTacGia() { return idTacGia;

} public void setIdTacGia(int idTacGia) { this.idTacGia = idTacGia;

} public void setMaTacGia(int maTacGia) { this.idTacGia = maTacGia;

} public String getTenTacGia() { return tenTacGia;

} public void setTenTacGia(String tenTacGia) { this.tenTacGia = tenTacGia;

} public void setTen(String ten) { this.tenTacGia = ten;

} public String getQuocTich() { return quocTich;

57 public void setQuocTich(String quocTich) { this.quocTich = quocTich;

@Override public String toString() { return "TacGia [idTacGia=" + idTacGia + ", tenTacGia=" + tenTacGia + ", quocTich=" + quocTich + "]";

Lớp TacGia đại diện cho đối tượng tác giả trong hệ thống quản lý thư viện Mỗi đối tượng tác giả bao gồm các thuộc tính: mã số tác giả (idTacGia), tên tác giả (tenTacGia) và quốc tịch (quocTich) Lớp này đóng vai trò là một thực thể dữ liệu (entity) dùng để lưu trữ và quản lý thông tin tác giả, đồng thời hỗ trợ thao tác trong các chức năng thêm, sửa, xóa, hoặc hiển thị sách theo tác giả

- Lưu trữ thông tin cơ bản về tác giả

- Hỗ trợ truy xuất và chỉnh sửa thông tin của tác giả

- Dữ liệu tác giả được biểu diễn qua các thuộc tính maTacGia, tenTacGia, và moTa

- Khởi tạo bằng constructor có tham số để truyền đầy đủ thông tin khi tạo đối tượng

- Cung cấp phương thức getter và setter để truy cập và cập nhật dữ liệu

- Ghi đè phương thức toString() để hiển thị thông tin tác giả dạng chuỗi, phục vụ khi in danh sách hoặc xem chi tiết

3 package com.hub.oop; import java.util.ArrayList;

35 import java.util.List; public class Sach { private int maSach; private String tenSach; private int namXuatBan; private String nhaXuatBan; private String trangThai; public Sach(int maSach, String tenSach, int namXuatBan, String nhaXuatBan, String trangThai) { this.maSach = maSach; this.tenSach = tenSach; this.namXuatBan = namXuatBan; this.nhaXuatBan = nhaXuatBan; this.trangThai = trangThai;

} public int getMaSach() { return maSach;

} public void setMaSach(int maSach) { this.maSach = maSach;

} public String getTenSach() { return tenSach;

} public void setTenSach(String tenSach) { this.tenSach = tenSach;

} public int getNamXuatBan() { return namXuatBan;

67 public void setNamXuatBan(int namXuatBan) { this.namXuatBan = namXuatBan;

} public String getNhaXuatBan() { return nhaXuatBan;

} public void setNhaXuatBan(String nhaXuatBan) { this.nhaXuatBan = nhaXuatBan;

} public String getTrangThai() { return trangThai;

} public void setTrangThai(String trangThai) { this.trangThai = trangThai;

@Override public String toString() { return "Sach [maSach=" + maSach + ", tenSach=" + tenSach + ", namXuatBan=" + namXuatBan + ", nhaXuatBan="

+ nhaXuatBan + ", trangThai=" + trangThai + ", danhSachTacGia=" + danhSachTacGia + "]";

} public List getDanhSachTacGia() { return danhSachTacGia;

} public void setDanhSachTacGia(List danhSachTacGia) { this.danhSachTacGia = danhSachTacGia;

} private List danhSachTacGia = new ArrayList(); public void setTacGias(List tacGias) {

} public List getTacGias() { return danhSachTacGia;

} private int soLanMuon; public int getSoLanMuon() { return soLanMuon;

} public void setSoLanMuon(int soLanMuon) { this.soLanMuon = soLanMuon;

Lớp Sach đại diện cho thông tin của một cuốn sách trong hệ thống quản lý thư viện Mỗi đối tượng sách bao gồm các thuộc tính như mã sách (maSach), tên sách (tenSach), năm xuất bản (namXuatBan), nhà xuất bản (nhaXuatBan), trạng thái mượn trả (trangThai), danh sách tác giả (danhSachTacGia) và số lần sách đã được mượn (soLanMuon) Đây là một lớp thực thể quan trọng, gắn liền với các thao tác như thêm, sửa, hiển thị và thống kê sách trong hệ thống

Lớp Sach có chức năng lưu trữ và quản lý thông tin chi tiết của từng cuốn sách trong hệ thống thư viện Cụ thể, lớp này đảm nhận việc:

- Đại diện cho một cuốn sách với đầy đủ thuộc tính: mã sách, tên sách, năm xuất bản, nhà xuất bản, trạng thái mượn và danh sách tác giả

- Cung cấp các phương thức để truy xuất và cập nhật thông tin sách (thông qua các phương thức getter và setter)

- Hỗ trợ liên kết nhiều tác giả cho một cuốn sách thông qua danh sách TacGia, giúp biểu diễn mối quan hệ 1-n giữa sách và tác giả

- Ghi nhận số lần sách đã được mượn để phục vụ cho các chức năng thống kê trong hệ thống

- Hỗ trợ hiển thị thông tin sách rõ ràng, đầy đủ thông qua phương thức toString(), giúp dễ dàng in ra danh sách hoặc kiểm tra dữ liệu trong quá trình vận hành chương trình

Lớp Sach hoạt động dựa trên các thuộc tính và phương thức đã khai báo Khi khởi tạo một đối tượng sách bằng constructor Sach(int maSach, String tenSach, int namXuatBan, String nhaXuatBan, String trangThai), hệ thống sẽ gán các giá trị đầu vào cho các thuộc tính tương ứng như mã sách, tên sách, năm xuất bản, nhà xuất bản và trạng thái Mỗi thuộc tính đều có phương thức getter và setter tương ứng, cho phép truy xuất và cập nhật dữ liệu linh hoạt

Thuộc tính danhSachTacGia được khai báo dưới dạng List nhằm lưu trữ nhiều tác giả cho một cuốn sách Khi cần gán hoặc truy xuất danh sách tác giả, ta sử dụng các phương thức setDanhSachTacGia(), getDanhSachTacGia(), setTacGias() và getTacGias() Trong đó, setTacGias() và getTacGias() được đặt tên bổ sung để tăng tính tương thích với các đoạn mã khác trong hệ thống

Ngoài ra, thuộc tính soLanMuon được sử dụng để thống kê số lần sách được mượn Mỗi lần sách được mượn thành công, phương thức setSoLanMuon() sẽ được gọi để tăng giá trị này Điều này hỗ trợ cho các chức năng thống kê và báo cáo sách được mượn nhiều Phương thức toString() được ghi đè (@Override) để trả về chuỗi mô tả chi tiết của đối tượng Sach, bao gồm toàn bộ thông tin sách và danh sách tác giả Khi in danh sách sách ra màn hình hoặc ghi log, phương thức này giúp hiển thị thông tin một cách rõ ràng và dễ đọc

33 import java.util.Date; public class PhieuMuon { private int maPhieu; private String maDocGia; private int maSach; private Date ngayMuon; private Date ngayTra;

// Constructor with 4 parameters (without ngayTra) public PhieuMuon(int maPhieu, String maDocGia, int maSach, Date ngayMuon) { this.maPhieu = maPhieu; this.maDocGia = maDocGia; this.maSach = maSach; this.ngayMuon = ngayMuon;

// Constructor with all parameters public PhieuMuon(int maPhieu, String maDocGia, int maSach, Date ngayMuon, Date ngayTra) { this(maPhieu, maDocGia, maSach, ngayMuon); this.ngayTra = ngayTra;

// Getters and setters public int getMaPhieu() { return maPhieu;

} public void setMaPhieu(int maPhieu) {

} public String getMaDocGia() { return maDocGia;

} public void setMaDocGia(String maDocGia) { this.maDocGia = maDocGia;

} public int getMaSach() { return maSach;

} public void setMaSach(int maSach) { this.maSach = maSach;

} public Date getNgayMuon() { return ngayMuon;

} public void setNgayMuon(Date ngayMuon) { this.ngayMuon = ngayMuon;

} public Date getNgayTra() { return ngayTra;

} public void setNgayTra(Date ngayTra) {

@Override public String toString() { return "PhieuMuon [maPhieu=" + maPhieu + ", maDocGia=" + maDocGia + ", maSach=" + maSach + ", ngayMuon=" + ngayMuon +

Lớp PhieuMuon đại diện cho một phiếu mượn sách trong hệ thống quản lý thư viện Mỗi đối tượng PhieuMuon chứa thông tin về cuốn sách được mượn, độc giả mượn sách, ngày mượn và ngày trả Lớp này đóng vai trò là cầu nối giữa sách và độc giả, đồng thời hỗ trợ quản lý quá trình mượn – trả sách một cách chính xác và có tổ chức

Lớp PhieuMuon có chức năng lưu trữ thông tin liên quan đến việc mượn sách, bao gồm:

- Ghi nhận ai đã mượn cuốn sách nào và vào thời điểm nào

- Theo dõi ngày mượn và ngày trả để hỗ trợ kiểm tra thời hạn mượn và xử lý trả sách

- Làm cơ sở để xây dựng các chức năng quản lý mượn – trả sách, thống kê, báo cáo hoạt động mượn sách trong hệ thống

Lớp PhieuMuon bao gồm bốn thuộc tính chính: sach (đối tượng lớp Sach), docGia (đối tượng lớp DocGia), ngayMuon (kiểu LocalDate) và ngayTra (cũng là LocalDate) Khi một đối tượng PhieuMuon được khởi tạo thông qua constructor PhieuMuon(Sach sach, DocGia docGia), hệ thống sẽ gán sách và độc giả tương ứng cho phiếu, đồng thời tự động gán ngày mượn là ngày hiện tại bằng lệnh this.ngayMuon = LocalDate.now()

Phương thức getNgayMuon() trả về ngày mượn, còn setNgayTra(LocalDate ngayTra) cho phép cập nhật ngày trả khi độc giả hoàn tất việc trả sách Trong quá trình xử

14 lý, thông tin sách và độc giả cũng có thể được truy xuất hoặc cập nhật thông qua các getter và setter tương ứng (getSach(), setSach(Sach sach), getDocGia(), setDocGia(DocGia docGia))

Ngoài ra, lớp có phương thức toString() được ghi đè để trả về chuỗi mô tả đầy đủ thông tin về phiếu mượn, bao gồm tên sách, tên độc giả, ngày mượn và ngày trả Phương thức này rất hữu ích khi cần hiển thị danh sách phiếu mượn ra màn hình hoặc in báo cáo

23 package com.hub.oop; public class DocGia { private String maDocGia; private String tenDocGia; public DocGia(String maDocGia, String tenDocGia) { super(); this.maDocGia = maDocGia; this.tenDocGia = tenDocGia;

} public String getMaDocGia() { return maDocGia;

} public void setMaDocGia(String maDocGia) { this.maDocGia = maDocGia;

} public String getTenDocGia() { return tenDocGia;

} public void setTenDocGia(String tenDocGia) { this.tenDocGia = tenDocGia;

27 public String toString() { return "DocGia [maDocGia=" + maDocGia + ", tenDocGia=" + tenDocGia + "]"; }

Lớp DocGia đại diện cho thông tin của một độc giả trong hệ thống quản lý thư viện Mỗi đối tượng DocGia bao gồm các thuộc tính cơ bản như mã độc giả (maDocGia), tên độc giả (tenDocGia) và email (email) Đây là lớp thực thể quan trọng dùng để quản lý danh sách người dùng của thư viện và liên kết với các phiếu mượn

Lớp DocGia có chức năng lưu trữ và quản lý thông tin cá nhân của từng độc giả, cụ thể là:

- Đại diện cho đối tượng người dùng trong hệ thống thư viện

- Hỗ trợ việc tạo lập và truy vết các phiếu mượn tương ứng với từng độc giả

- Cung cấp thông tin liên hệ (email) để phục vụ các chức năng nâng cao như gửi thông báo, nhắc hạn trả sách,

- Làm cơ sở để thống kê, tra cứu hoặc lọc danh sách mượn theo từng người dùng

Lớp DocGia khai báo ba thuộc tính chính: maDocGia, tenDocGia và email Khi một đối tượng độc giả được khởi tạo thông qua constructor DocGia(String maDocGia, String tenDocGia, String email), hệ thống sẽ gán các thông tin tương ứng cho từng thuộc tính, từ đó tạo nên hồ sơ độc giả đầy đủ

Trong quá trình hoạt động, các phương thức getter và setter cho phép truy xuất hoặc cập nhật các thông tin độc giả Cụ thể, getMaDocGia() và setMaDocGia(String maDocGia) được dùng để quản lý mã định danh độc giả – thường là duy nhất trong hệ thống getTenDocGia() và setTenDocGia(String tenDocGia) hỗ trợ thao tác với tên người dùng getEmail() và setEmail(String email) dùng để quản lý và cập nhật thông tin liên hệ

Lớp DAO và Lớp Implement

28 package dao; import java.util.List; import model.PhieuMuon; import model.Sach; import model.TacGia; public interface DAO {

TacGia getTacGiaById(int idTacGia); boolean addTacGia(TacGia tacGia); boolean updateTacGia(TacGia tacGia); boolean deleteTacGia(int idTacGia);

// (các phương thức hiện có)

// Tìm kiếm tác giả theo tên

List searchTacGia(String keyword);

Sach getSachById(int maSach); boolean addSach(Sach sach); boolean updateSach(Sach sach); boolean deleteSach(int maSach);

// Phiếu Mượn boolean muonSach(String maDocGia, int maSach); boolean traSach(int maPhieuMuon);

// Các chức năng nâng cao

List findSachByTenTacGia(String tenTacGia);

List getPhieuMuonQuaHan(int soNgayQuaHan);

- DAO (Data Access Object) là một giao diện (Interface) trừu tượng hóa các thao tác với cơ sở dữ liệu cần thực hiện trên:

+ Các chức năng nâng cao

- Nó đóng vai trò như cầu nối giữa logic nghiệp vụ và hệ quản trị cơ sở dữ liệu (SQL Server)

- Các phương thức khai báo trong DAO sẽ được triển khai chi tiết ở lớp Implement

- Đóng vai trò như định nghĩa các chức năng mà lớp thực thi phải tuân theo.trong Cơ sở dữ liệu

- Tách biệt phần định nghĩa và phần triển khai, giúp dễ mở rộng, bảo trì

- Quản lý tác giả bao gồm các chức năng:

+ Lấy danh sách tất cả tác giả trong hệ thống

+ Truy xuất thông tin của một tác giả theo mã ID

+ Thêm một tác giả mới vào cơ sở dữ liệu

+ Cập nhật thông tin của một tác giả đã có

+ Xóa một tác giả nếu không còn liên kết với sách nào

- Quản lý sách bao gồm các chức năng:

+ Lấy toàn bộ danh sách sách có trong thư viện

+ Truy xuất thông tin của một cuốn sách theo mã sách

+ Thêm một cuốn sách mới vào hệ thống

+ Cập nhật thông tin của một cuốn sách

+ Xóa một cuốn sách khỏi hệ thống cùng với các dữ liệu liên quan

- Quản lý phiếu mượn bao gồm các chức năng:

+ Ghi nhận việc mượn sách của độc giả

+ Cập nhật thông tin trả sách và đổi trạng thái sách về "Sẵn sàng"

+ Lấy toàn bộ danh sách các phiếu mượn trong hệ thống

- Quản lý các chức năng nâng cao bao gồm các chức năng:

+ Tìm kiếm sách theo tên tác giả

+ Trả về danh sách sách đã được sắp xếp theo tên

+ Lấy danh sách các cuốn sách đang được mượn

+ Lấy danh sách phiếu mượn bị quá hạn dựa theo số ngày quy định

+ Trả về 5 cuốn sách có số lần mượn nhiều nhất

- Các lớp khác chỉ cần gọi tới DAO để thao tác dữ liệu mà không cần quan tâm chi tiết xử lý bên trong

- Khi lớp Implement thực thi DAO, hệ thống đảm bảo rằng tất cả chức năng được triển khai đúng theo cam kết

24 package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Date; import java.util.List; import model.PhieuMuon; import model.Sach; import model.TacGia; import util.DBConnection; public class Implement implements DAO { private DBConnection db = new DBConnection();

// ===== TÁC GIẢ ====@Override public List getAllTacGia() {

List list = new ArrayList();

String sql = "SELECT * FROM TacGia"; try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

TacGia tg = new TacGia(rs.getInt("ID_TacGia"), rs.getString("TenTacGia"), rs.getString("QuocTich")); tg.setIdTacGia(rs.getInt("ID_TacGia")); tg.setTen(rs.getString("TenTacGia")); tg.setQuocTich(rs.getString("QuocTich")); list.add(tg);

System out println("Lỗi khi lấy danh sách tác giả: " + e.getMessage());

@Override public TacGia getTacGiaById(int idTacGia) {

String sql = "SELECT * FROM TacGia WHERE ID_TacGia = ?"; try (ResultSet rs = db.executeQuery(sql, idTacGia)) { if (rs != null && rs.next()) { tg = new TacGia(rs.getInt("ID_TacGia"), rs.getString("TenTacGia"), rs.getString("QuocTich"));

System out println("Lỗi khi tìm tác giả theo ID: " + e.getMessage());

List list = new ArrayList();

String sql = "SELECT * FROM Sach WHERE TrangThai = N'Đã cho mượn'"; // Thêm N phía trước chuỗi try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

Sach s = new Sach(rs.getInt("MaSach"), rs.getString("TenSach"), rs.getInt("NamXuatBan"), rs.getString("NhaXuatBan"), rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi lấy sách đang mượn: " + e.getMessage());

@Override public List getPhieuMuonQuaHan(int soNgayQuaHan) {

List list = new ArrayList();

String sql = "SELECT * FROM PhieuMuon WHERE NgayTra IS NULL AND DATEDIFF(day, NgayMuon, GETDATE()) > ?"; try (ResultSet rs = db.executeQuery(sql, soNgayQuaHan)) { while (rs != null && rs.next()) { java.sql.Date sqlDate = rs.getDate("NgayMuon");

Date ngayMuon = new Date(sqlDate.getTime()); // Chuyển từ java.sql.Date sang java.util.Date

PhieuMuon pm = new PhieuMuon(rs.getInt("MaPhieu"), rs.getString("MaDocGia"), rs.getInt("MaSach"),

120 ngayMuon // Sử dụng java.util.Date

System out println("Lỗi khi lấy phiếu mượn quá hạn: " + e.getMessage());

@Override public List getTop5SachMuonNhieuNhat() {

List list = new ArrayList();

String sql = "SELECT TOP 5 s.MaSach, s.TenSach, COUNT(pm.MaSach) AS SoLanMuon "

+ "FROM PhieuMuon pm JOIN Sach s ON pm.MaSach = s.MaSach "

+ "GROUP BY s.MaSach, s.TenSach ORDER BY SoLanMuon DESC"; try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

Sach s = new Sach(rs.getInt("MaSach"), rs.getString("TenSach"), 0, // Năm xuất bản

// Quan trọng: Gán số lần mượn từ kết quả SQL s.setSoLanMuon(rs.getInt("SoLanMuon")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi lấy top 5 sách mượn nhiều nhất: " + e.getMessage());

} public void updateSachStatus(int maSach, String trangThai) {

String sql = "UPDATE Sach SET TrangThai = ? WHERE MaSach = ?"; db.executeUpdate(sql, trangThai, maSach);

@Override public boolean addTacGia(TacGia tacGia) {

String sql = "INSERT INTO TacGia (TenTacGia, QuocTich) VALUES (?, ?)"; int result = db.executeUpdate(sql, tacGia.getTenTacGia(), tacGia.getQuocTich()); if (result > 0) {

System out println("Thêm tác giả thành công."); return true;

System out println("Thêm tác giả thất bại."); return false;

@Override public boolean updateTacGia(TacGia tacGia) {

String sql = "UPDATE TacGia SET TenTacGia = ?, QuocTich = ? WHERE ID_TacGia = ?"; int result = db.executeUpdate(sql, tacGia.getTenTacGia(), tacGia.getQuocTich(), tacGia.getIdTacGia()); if (result > 0) {

System out println("Cập nhật tác giả thành công."); return true;

System out println("Cập nhật tác giả thất bại."); return false;

@Override public boolean deleteTacGia(int idTacGia) {

String checkSql = "SELECT COUNT(*) AS soSach FROM ChiTietSachTacGia WHERE ID_TacGia = ?"; try (ResultSet rs = db.executeQuery(checkSql, idTacGia)) { if (rs != null && rs.next() && rs.getInt("soSach") > 0) {

System out println("Không thể xóa tác giả vì còn sách liên quan."); return false;

System out println("Lỗi khi kiểm tra xóa tác giả: " + e.getMessage()); return false;

String sql = "DELETE FROM TacGia WHERE ID_TacGia = ?"; int result = db.executeUpdate(sql, idTacGia); if (result > 0) {

System out println("Xóa tác giả thành công."); return true;

System out println("Xóa tác giả thất bại."); return false;

@Override public List searchTacGia(String keyword) {

List list = new ArrayList();

String sql = "SELECT * FROM TacGia WHERE TenTacGia LIKE ?"; try (ResultSet rs = db.executeQuery(sql, "%" + keyword + "%")) { while (rs != null && rs.next()) {

TacGia tg = new TacGia(rs.getInt("ID_TacGia"), rs.getString("TenTacGia"), rs.getString("QuocTich")); list.add(tg);

System out println("Lỗi khi tìm kiếm tác giả: " + e.getMessage());

// ===== SÁCH ====@Override public List getAllSach() {

List list = new ArrayList();

String sql = "SELECT * FROM Sach"; try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

Sach s = new Sach(0, sql, 0, sql, sql); s.setMaSach(rs.getInt("MaSach")); s.setTenSach(rs.getString("TenSach")); s.setTrangThai(rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi lấy danh sách sách: " + e.getMessage());

@Override public Sach getSachById(int maSach) {

String sql = "SELECT * FROM Sach WHERE MaSach = ?"; try (ResultSet rs = db.executeQuery(sql, maSach)) { if (rs != null && rs.next()) { s = new Sach(maSach, sql, maSach, sql, sql); s.setMaSach(rs.getInt("MaSach")); s.setTenSach(rs.getString("TenSach")); s.setTrangThai(rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(maSach));

System out println("Lỗi khi tìm sách theo mã: " + e.getMessage());

@Override public boolean addSach(Sach sach) {

String sqlSach = "INSERT INTO Sach (TenSach, NamXuatBan, NhaXuatBan, TrangThai) VALUES (?, ?, ?, ?)"; try (Connection conn = db.openConnection()) { conn.setAutoCommit(false); try (PreparedStatement pstmt = conn.prepareStatement(sqlSach, Statement RETURN_GENERATED_KEYS )) { pstmt.setString(1, sach.getTenSach()); pstmt.setInt(2, sach.getNamXuatBan());

280 pstmt.setString(3, sach.getNhaXuatBan()); pstmt.setString(4, sach.getTrangThai()); int affectedRows = pstmt.executeUpdate(); if (affectedRows == 0) {

System out println("Thêm sách thất bại."); conn.rollback(); return false;

ResultSet generatedKeys = pstmt.getGeneratedKeys(); int maSach = -1; if (generatedKeys.next()) { maSach = generatedKeys.getInt(1);

System out println("Không lấy được mã sách sau khi thêm."); conn.rollback(); return false;

// Thêm tác giả vào bảng ChiTietSachTacGia

String sqlSachTacGia = "INSERT INTO ChiTietSachTacGia (MaSach, ID_TacGia) VALUES (?, ?)"; try (PreparedStatement pstmtSTG = conn.prepareStatement(sqlSachTacGia)) { for (TacGia tg : sach.getTacGias()) { pstmtSTG.setInt(1, maSach); pstmtSTG.setInt(2, tg.getIdTacGia()); // Sửa từ getTenTacGia() sang getIdTacGia() pstmtSTG.addBatch();

System out println("Thêm sách thành công."); return true;

System out println("Lỗi thêm sách, rollback: " + e.getMessage()); conn.rollback(); return false;

System out println("Lỗi kết nối khi thêm sách: " + e.getMessage()); return false;

@Override public boolean updateSach(Sach sach) {

String sqlUpdateSach = "UPDATE Sach SET TenSach = ?, NamXuatBan = ?, NhaXuatBan = ?, TrangThai = ? WHERE MaSach = ?";

String deleteSTG = "DELETE FROM ChiTietSachTacGia WHERE MaSach = ?"; String insertSTG = "INSERT INTO ChiTietSachTacGia (MaSach, ID_TacGia) VALUES (?, ?)"; try (Connection conn = db.openConnection()) { conn.setAutoCommit(false);

// Cập nhật thông tin sách try (PreparedStatement pstmt = conn.prepareStatement(sqlUpdateSach)) { pstmt.setString(1, sach.getTenSach());

344 pstmt.setInt(2, sach.getNamXuatBan()); pstmt.setString(3, sach.getNhaXuatBan()); pstmt.setString(4, sach.getTrangThai()); pstmt.setInt(5, sach.getMaSach()); int result = pstmt.executeUpdate(); if (result == 0) {

System out println("Cập nhật sách thất bại."); conn.rollback(); return false;

// Xóa các tác giả cũ try (PreparedStatement pstmt = conn.prepareStatement(deleteSTG)) { pstmt.setInt(1, sach.getMaSach()); pstmt.executeUpdate();

// Thêm các tác giả mới try (PreparedStatement pstmt = conn.prepareStatement(insertSTG)) { for (TacGia tg : sach.getTacGias()) { pstmt.setInt(1, sach.getMaSach()); pstmt.setInt(2, tg.getIdTacGia()); pstmt.addBatch();

System out println("Cập nhật sách thành công."); return true;

System out println("Lỗi khi cập nhật sách: " + e.getMessage()); return false;

@Override public boolean deleteSach(int maSach) { try (Connection conn = db.openConnection()) { conn.setAutoCommit(false);

String deleteSTG = "DELETE FROM ChiTietSachTacGia WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(deleteSTG)) { pstmt.setInt(1, maSach); pstmt.executeUpdate();

String deletePM = "DELETE FROM PhieuMuon WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(deletePM)) { pstmt.setInt(1, maSach); pstmt.executeUpdate();

String deleteSach = "DELETE FROM Sach WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(deleteSach)) { pstmt.setInt(1, maSach); int result = pstmt.executeUpdate(); if (result == 0) {

System out println("Xóa sách thất bại."); conn.rollback(); return false;

System out println("Xóa sách thành công."); return true;

System out println("Lỗi khi xóa sách: " + e.getMessage()); return false;

} private List getTacGiaByMaSach(int maSach) {

List list = new ArrayList();

String sql = "SELECT tg.ID_TacGia, tg.TenTacGia, tg.QuocTich FROM TacGia tg "

+ "INNER JOIN ChiTietSachTacGia stg ON tg.ID_TacGia = stg.ID_TacGia WHERE stg.MaSach = ?"; try (ResultSet rs = db.executeQuery(sql, maSach)) { while (rs != null && rs.next()) {

TacGia tg = new TacGia(rs.getInt("ID_TacGia"), rs.getString("TenTacGia"), rs.getString("QuocTich")); list.add(tg);

System out println("Lỗi khi lấy tác giả theo mã sách: " + e.getMessage());

@Override public List findSachByTen(String keyword) {

List list = new ArrayList();

String sql = "SELECT * FROM Sach WHERE TenSach LIKE ?"; try (ResultSet rs = db.executeQuery(sql, "%" + keyword + "%")) { while (rs != null && rs.next()) {

Sach s = new Sach(rs.getInt("MaSach"), rs.getString("TenSach"), rs.getInt("NamXuatBan"), rs.getString("NhaXuatBan"), rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi tìm sách theo tên: " + e.getMessage());

// ===== PHIẾU MƯỢN ====@Override public boolean muonSach(String maDocGia, int maSach) { try (Connection conn = db.openConnection()) { conn.setAutoCommit(false);

// Kiểm tra xem mã độc giả có tồn tại không

String checkDocGia = "SELECT COUNT(*) FROM DocGia WHERE MaDocGia

= ?"; try (PreparedStatement pstmt = conn.prepareStatement(checkDocGia)) { pstmt.setString(1, maDocGia);

ResultSet rs = pstmt.executeQuery(); if (rs.next() && rs.getInt(1) == 0) {

System out println("Mã độc giả không tồn tại!"); return false;

String checkStatus = "SELECT TrangThai FROM Sach WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(checkStatus)) { pstmt.setInt(1, maSach);

ResultSet rs = pstmt.executeQuery(); if (!rs.next() || !"Sẵn sàng".equals(rs.getString("TrangThai"))) {

System out println("Sách hiện không sẵn sàng để mượn."); return false;

String insertPM = "INSERT INTO PhieuMuon (MaDocGia, MaSach, NgayMuon) VALUES (?, ?, GETDATE())"; try (PreparedStatement pstmt = conn.prepareStatement(insertPM)) { pstmt.setString(1, maDocGia); // Sử dụng setString thay vì setInt pstmt.setInt(2, maSach); pstmt.executeUpdate();

String updateSach = "UPDATE Sach SET TrangThai = N'Sẵn sàng' WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(updateSach)) { pstmt.setInt(1, maSach); pstmt.executeUpdate();

System out println("Mượn sách thành công."); return true;

System out println("Lỗi khi mượn sách: " + e.getMessage()); return false;

@Override public boolean traSach(int maPhieuMuon) { try (Connection conn = db.openConnection()) { conn.setAutoCommit(false);

// Lấy mã sách từ phiếu mượn trước khi cập nhật int maSach = -1;

String getMaSach = "SELECT MaSach FROM PhieuMuon WHERE MaPhieu ?"; try (PreparedStatement pstmt = conn.prepareStatement(getMaSach)) { pstmt.setInt(1, maPhieuMuon);

ResultSet rs = pstmt.executeQuery(); if (rs.next()) { maSach = rs.getInt("MaSach");

System out println("Không tìm thấy phiếu mượn với mã: " + maPhieuMuon); return false;

String updatePM = "UPDATE PhieuMuon SET NgayTra = GETDATE() WHERE MaPhieu = ?"; try (PreparedStatement pstmt = conn.prepareStatement(updatePM)) { pstmt.setInt(1, maPhieuMuon); pstmt.executeUpdate();

// Cập nhật trạng thái sách - ĐẢM BẢO ĐÚNG GIÁ TRỊ CHECK

String updateSach = "UPDATE Sach SET TrangThai = N'Đã cho mượn' WHERE MaSach = ?"; try (PreparedStatement pstmt = conn.prepareStatement(updateSach)) { pstmt.setInt(1, maSach); int updated = pstmt.executeUpdate(); if (updated == 0) { conn.rollback();

System out println("Không tìm thấy sách với mã: " + maSach); return false;

System out println("Trả sách thành công."); return true;

System out println("Lỗi khi trả sách: " + e.getMessage()); return false;

@Override public List getAllPhieuMuon() {

List list = new ArrayList();

String sql = "SELECT * FROM PhieuMuon"; try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

PhieuMuon pm = new PhieuMuon(0, 0, 0, null); pm.setMaPhieu(rs.getInt("MaPhieu")); pm.setMaDocGia(rs.getInt("MaDocGia")); pm.setMaSach(rs.getInt("MaSach"));

568 pm.setNgayMuon(rs.getDate("NgayMuon")); pm.setNgayTra(rs.getDate("NgayTra")); list.add(pm);

System out println("Lỗi khi lấy danh sách phiếu mượn: " + e.getMessage()); } return list;

// ===== CÁC CHỨC NĂNG NÂNG CAO ====@Override public List findSachByTenTacGia(String tenTacGia) {

List list = new ArrayList();

String sql = "SELECT DISTINCT s.* FROM Sach s " + "JOIN ChiTietSachTacGia stg ON s.MaSach = stg.MaSach "

+ "JOIN TacGia tg ON stg.ID_TacGia = tg.ID_TacGia " + "WHERE tg.TenTacGia LIKE ?"; try (ResultSet rs = db.executeQuery(sql, "%" + tenTacGia + "%")) { while (rs != null && rs.next()) {

Sach s = new Sach(rs.getInt("MaSach"), rs.getString("TenSach"), rs.getInt("NamXuatBan"), rs.getString("NhaXuatBan"), rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi tìm sách theo tên tác giả: " + e.getMessage());

@Override public List getSachSortedByTenSach() {

List list = new ArrayList();

String sql = "SELECT * FROM Sach ORDER BY TenSach ASC"; try (ResultSet rs = db.executeQuery(sql)) { while (rs != null && rs.next()) {

Sach s = new Sach(0, sql, 0, sql, sql); s.setMaSach(rs.getInt("MaSach")); s.setTenSach(rs.getString("TenSach")); s.setTrangThai(rs.getString("TrangThai")); s.setTacGias(getTacGiaByMaSach(s.getMaSach())); list.add(s);

System out println("Lỗi khi lấy sách sắp xếp theo tên: " + e.getMessage());

- Implement là lớp triển khai giao diện DAO, thực hiện các logic tương tác thực tế với CSDL thông qua lớp DBConnection

+ Thao tác với bảng TacGia

+ Thao tác với bảng Sach

+ Thao tác với bảng PhieuMuon

+ Lấy toàn bộ tác giả từ bảng TacGia và chuyển thành danh sách đối tượng

+ Lấy thông tin một tác giả cụ thể theo MaTacGia

+ Thêm tác giả mới vào bảng TacGia

+ Cập nhật tên và quốc tịch của tác giả theo MaTacGia

+ Kiểm tra xem tác giả có liên kết với sách hay không trước khi xóa

+ Xóa tác giả nếu không còn liên kết trong bảng ChiTietSachTacGia

+ Lấy danh sách tất cả sách trong hệ thống và kèm danh sách tác giả liên kết

+ Truy xuất một cuốn sách cụ thể theo MaSach

+ Thêm sách mới vào bảng Sach, sau đó thêm các tác giả vào bảng ChiTietSachTacGia

+ Cập nhật thông tin sách, xóa tác giả cũ và cập nhật lại danh sách tác giả mới liên kết với sách

+ Xóa sách bằng cách xóa các liên kết trong ChiTietSachTacGia và PhieuMuon trước, sau đó xóa trong bảng Sach

+ Kiểm tra trạng thái sách trước khi cho mượn

+ Ghi nhận thông tin mượn vào bảng PhieuMuon với ngày mượn là ngày hiện tại + Cập nhật trạng thái sách thành "Đã cho mượn" khi mượn thành công

+ Lấy mã sách từ phiếu mượn để thực hiện thao tác trả sách

+ Cập nhật ngày trả cho phiếu mượn trong PhieuMuon

+ Cập nhật trạng thái sách thành "Sẵn sàng" sau khi trả

+ Lấy toàn bộ phiếu mượn từ bảng PhieuMuon và ánh xạ sang danh sách đối tượng

- Các chức năng nâng cao

+ Lấy danh sách sách đang có trạng thái "Đã cho mượn"

+ Truy vấn các phiếu mượn chưa trả và có số ngày mượn vượt quá giá trị cho trước + Lấy top 5 sách có số lần mượn nhiều nhất bằng cách thống kê dữ liệu trong bảng PhieuMuon

+ Tìm tất cả sách có liên quan đến tên tác giả được truyền vào bằng cách dùng LIKE và JOIN bảng

+ Trả về danh sách sách đã được sắp xếp theo thứ tự tên từ A đến Z

- Kết nối cơ sở dữ liệu thông qua DBConnection

- Dùng câu lệnh SQL để thao tác dữ liệu (SELECT, INSERT, UPDATE, DELETE)

- Truy xuất dữ liệu bằng ResultSet rồi chuyển thành đối tượng Java

- Dùng PreparedStatement để truyền tham số và tránh lỗi SQL Injection

- Sử dụng giao dịch (Transaction) khi thực hiện nhiều bước liên quan

- Kiểm tra logic trước khi xử lý (ví dụ: sách có sẵn mới được mượn)

- Quản lý liên kết nhiều-nhiều giữa sách và tác giả qua bảng phụ

- Trả kết quả về dạng danh sách hoặc true/false tùy thao tác

Các lớp quản lý

21 package com.hub.oop; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class QuanLyTacGia { private List danhSachTacGia = new ArrayList();

// Thêm tác giả public void themTacGia(TacGia tg) { danhSachTacGia.add(tg);

System.out.println("Đã thêm tác giả: " + tg);

// Xem danh sách public void xemDanhSachTacGia() { if (danhSachTacGia.isEmpty()) {

System.out.println("Không có tác giả nào."); return;

// Xem chi tiết tác giả theo ID public TacGia xemTacGia(int maTacGia) { for (TacGia tg : danhSachTacGia) { if (tg.getMaTacGia() == maTacGia) {

System.out.println("Thông tin tác giả: " + tg); return tg;

System.out.println("Không tìm thấy tác giả có ID: " + maTacGia); return null;

// Sửa thông tin tác giả public void suaTacGia(int maTacGia, String tenMoi, String quocTichMoi) { for (TacGia tg : danhSachTacGia) { if (tg.getMaTacGia() == maTacGia) { tg.setTenTacGia(tenMoi); tg.setQuocTich(quocTichMoi);

System.out.println("Đã cập nhật thông tin tác giả: " + tg); return;

System.out.println("Không tìm thấy tác giả để sửa.");

// Xóa tác giả – kiểm tra nếu vẫn còn sách thì không cho xóa public void xoaTacGia(int maTacGia, List danhSachSach) {

// Kiểm tra tác giả còn sách không

85 for (Sach s : danhSachSach) { for (TacGia tg : s.getDanhSachTacGia()) { if (tg.getMaTacGia() == maTacGia) {

System.out.println("Không thể xóa tác giả mã số " + maTacGia + " vì vẫn còn sách của họ trong thư viện."); return;

// Nếu không còn sách => xóa

Iterator iterator = danhSachTacGia.iterator(); while (iterator.hasNext()) {

TacGia tg = iterator.next(); if (tg.getMaTacGia() == maTacGia) { iterator.remove();

System.out.println("Đã xóa tác giả có mã số: " + maTacGia); return;

System.out.println("Không tìm thấy tác giả để xóa.");

// Tìm kiếm tác giả theo tên public void timKiemTheoTen(String keyword) { boolean timThay = false; for (TacGia tg : danhSachTacGia) { if (tg.getTenTacGia().toLowerCase().contains(keyword.toLowerCase())) {

System.out.println(tg); timThay = true;

System.out.println("Không tìm thấy tác giả nào khớp với từ khóa: " + keyword); }

} public List getDanhSachTacGia() { return danhSachTacGia;

Lớp QuanLyTacGia là lớp chức năng (logic class) dùng để quản lý danh sách các tác giả trong hệ thống thư viện Lớp này không đại diện cho một thực thể cụ thể mà đóng vai trò xử lý thao tác thêm, sửa, xóa và tìm kiếm tác giả, thông qua danh sách các đối tượng thuộc lớp TacGia

Lớp QuanLyTacGia có các chức năng chính như sau:

- Lưu trữ danh sách tác giả dưới dạng List

- Cung cấp các phương thức để thêm mới, cập nhật, xóa và tìm kiếm tác giả

- Hỗ trợ hiển thị danh sách tác giả hiện có

- Đảm nhận vai trò là cầu nối giữa giao diện người dùng và dữ liệu tác giả trong hệ thống

Lớp QuanLyTacGia khai báo một danh sách danhSachTacGia kiểu ArrayList, dùng để lưu trữ tất cả các đối tượng tác giả trong hệ thống Khi người dùng muốn thêm một tác giả mới, phương thức themTacGia(TacGia tg) sẽ thêm đối tượng tg vào danh sách thông qua lệnh danhSachTacGia.add(tg)

Phương thức xoaTacGiaTheoId(int id) sẽ tìm và xóa tác giả có mã id tương ứng Nó sử dụng vòng lặp để kiểm tra từng phần tử trong danh sách, nếu tìm thấy tác giả phù hợp thì xóa và trả về true; nếu không tìm thấy thì trả về false

Phương thức capNhatTacGia(int id, String tenMoi, String quocTichMoi) được dùng để cập nhật lại tên và quốc tịch của một tác giả dựa trên id Khi tìm thấy đối tượng phù hợp, hệ thống gọi setTenTacGia() và setQuocTich() để thay đổi thông tin

Phương thức timKiemTacGia(String tuKhoa) cho phép tìm kiếm tác giả theo tên gần đúng bằng cách chuyển cả tên và từ khóa về chữ thường bằng toLowerCase(), giúp tìm kiếm không phân biệt chữ hoa chữ thường Các tác giả khớp với từ khóa sẽ được thêm vào danh sách kết quả và trả về.

Cuối cùng, phương thức hienThiDanhSachTacGia() sẽ lặp qua danh sách danhSachTacGia và in thông tin của từng tác giả ra màn hình bằng System.out.println(tg) Việc gọi System.out.println(tg) sẽ tự động kích hoạt phương thức toString() của lớp TacGia để hiển thị đầy đủ nội dung của từng tác giả trong danh sách.

22 package com.hub.oop; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; public class QuanLySach { private List danhSachSach = new ArrayList(); private Scanner sc = new Scanner(System.in); private List danhSachTacGia; public QuanLySach(List danhSachTacGia) { this.danhSachTacGia = danhSachTacGia;

// Thêm sách public void themSach() {

System.out.print("Nhập mã sách: "); int ma = Integer.parseInt(sc.nextLine());

System.out.print("Nhập tên sách: ");

System.out.print("Nhập năm xuất bản: "); int nam = Integer.parseInt(sc.nextLine());

System.out.print("Nhập nhà xuất bản: ");

System.out.print("Nhập trạng thái (Sẵn sàng/Đã cho mượn): "); String tt = sc.nextLine();

Sach sach = new Sach(ma, ten, nam, nhaXB, tt); sach.setDanhSachTacGia(tacGiaChon); danhSachSach.add(sach);

System.out.println("Đã thêm sách.");

// Hiển thị danh sách public void hienThiDanhSach() { if (danhSachSach.isEmpty()) {

System.out.println("Không có sách.");

System.out.print("Nhập tên sách cần tìm: ");

String ten = sc.nextLine().toLowerCase(); boolean timThay = false; for (Sach s : danhSachSach) { if (s.getTenSach().toLowerCase().contains(ten)) { System.out.println(s); timThay = true;

System.out.println("Không tìm thấy sách.");

// Sửa sách public void suaSach() {

System.out.print("Nhập mã sách cần sửa: "); int ma = Integer.parseInt(sc.nextLine()); for (Sach s : danhSachSach) { if (s.getMaSach() == ma) {

System.out.print("Nhập tên mới: "); s.setTenSach(sc.nextLine());

System.out.print("Nhập năm xuất bản mới: "); s.setNamXuatBan(Integer.parseInt(sc.nextLine()));

System.out.print("Nhập nhà xuất bản mới: "); s.setNhaXuatBan(sc.nextLine());

System.out.print("Nhập trạng thái mới: ");

System.out.println("Có thay đổi tác giả không? (y/n): "); if (sc.nextLine().equalsIgnoreCase("y")) { s.setDanhSachTacGia(chonTacGia());

System.out.println("Đã cập nhật."); return;

System.out.println("Không tìm thấy sách.");

// Xóa sách public void xoaSach() {

System.out.print("Nhập mã sách cần xóa: "); int ma = Integer.parseInt(sc.nextLine());

Iterator it = danhSachSach.iterator(); while (it.hasNext()) {

Sach s = it.next(); if (s.getMaSach() == ma) { it.remove();

System.out.println("Đã xóa sách."); return;

System.out.println("Không tìm thấy sách.");

List chon = new ArrayList();

System.out.println("Chọn tác giả (nhập ID, kết thúc bằng -1):"); for (TacGia tg : danhSachTacGia) {

System.out.println(tg.getId() + " - " + tg.getTen());

} while (true) { int id = Integer.parseInt(sc.nextLine()); if (id == -1) break; for (TacGia tg : danhSachTacGia) { if (tg.getId() == id && !chon.contains(tg)) { chon.add(tg);

// 1 Tìm kiếm sách theo tên tác giả public void timSachTheoTacGia(String tenTacGia) {

System.out.println("Danh sách sách của tác giả " + tenTacGia + ":"); boolean found = false; for (Sach s : danhSachSach) { for (TacGia tg : s.getDanhSachTacGia()) { if (tg.getTen().toLowerCase().contains(tenTacGia.toLowerCase())) { System.out.println(s); found = true; break;

System.out.println("Không tìm thấy sách của tác giả " + tenTacGia); }

// 2 Sắp xếp sách theo tên (alphabet) public void sapXepTheoTen() { danhSachSach.sort(Comparator.comparing(Sach::getTenSach));

System.out.println("Danh sách sách đã sắp xếp theo tên:"); hienThiDanhSach();

// 3 Liệt kê sách đang được mượn public void lietKeSachDangMuon() {

System.out.println("Danh sách sách đang được mượn:"); boolean found = false; for (Sach s : danhSachSach) { if (s.getTrangThai().equalsIgnoreCase("Đã cho mượn")) {

System.out.println(s); found = true;

System.out.println("Không có sách nào đang được mượn");

// 4 Liệt kê phiếu mượn quá hạn (giả sử có danh sách phiếu mượn)

177 public void lietKePhieuMuonQuaHan(List danhSachPhieuMuon) {

System.out.println("Danh sách phiếu mượn quá hạn:");

Date now = new Date(); boolean found = false; for (PhieuMuon pm : danhSachPhieuMuon) { if (pm.getNgayTra() == null) { // Chưa trả sách long daysBetween = ChronoUnit.DAYS.between( pm.getNgayMuon().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), now.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() ); if (daysBetween > 30) {

System.out.println("Phiếu mượn #" + pm.getMaPhieu() +

", Đã quá hạn: " + (daysBetween - 30) + " ngày"); found = true;

System.out.println("Không có phiếu mượn nào quá hạn");

// 5 Thống kê top 5 sách được mượn nhiều nhất public void thongKeTop5SachMuonNhieu(List danhSachPhieuMuon) {

System.out.println("Top 5 sách được mượn nhiều nhất:");

// Tạo map đếm số lần mượn của mỗi sách

Map demSoLanMuon = danhSachPhieuMuon.stream() collect(Collectors.groupingBy(PhieuMuon::getMaSach,

// Sắp xếp theo số lần mượn giảm dần

List sorted = new ArrayList(demSoLanMuon.entrySet()); sorted.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));

// Hiển thị top 5 int count = 0; for (Map.Entry entry : sorted) { if (count++ >= 5) break; int maSach = entry.getKey(); long soLanMuon = entry.getValue();

System.out.println((count) + " " + s.getTenSach() +

System.out.println("Không có dữ liệu mượn sách");

Lớp QuanLySach là lớp chức năng chịu trách nhiệm quản lý danh sách các đối tượng Sách trong hệ thống thư viện Thông qua lớp này, hệ thống có thể thực hiện các thao tác thêm mới, cập nhật, xóa, tìm kiếm và hiển thị sách, từ đó tối ưu hóa quản lý thông tin sách cho người dùng Đây là lớp trung gian kết nối dữ liệu sách với các chức năng giao diện người dùng, đảm bảo luồng dữ liệu giữa backend và giao diện được đồng bộ và nhất quán.

Lớp QuanLySach cung cấp các chức năng chính sau:

- Lưu trữ danh sách sách thông qua một danh sách động List

- Thực hiện các thao tác CRUD (Create - Read - Update - Delete) đối với đối tượng sách

- Tìm kiếm sách theo từ khóa (tên sách)

- Hiển thị toàn bộ danh sách sách hiện có trong hệ thống

- Hỗ trợ cập nhật thông tin sách như tên, năm xuất bản, nhà xuất bản và trạng thái

Lớp QuanLySach khai báo một danh sách danhSachSach kiểu ArrayList, đóng vai trò lưu trữ tất cả các đối tượng Sach Phương thức themSach(Sach sach) sử dụng lệnh danhSachSach.add(sach) để thêm một cuốn sách mới vào danh sách

Khi người dùng muốn xóa một cuốn sách, phương thức xoaSachTheoMa(int maSach) sẽ duyệt qua danh sách và tìm đối tượng có maSach tương ứng Nếu tìm thấy, đối tượng đó sẽ bị xóa khỏi danh sách bằng danhSachSach.remove(sach), và phương thức trả về true Phương thức capNhatSach( ) cho phép cập nhật thông tin của một cuốn sách như tên, năm xuất bản, nhà xuất bản và trạng thái mượn trả Hệ thống sẽ tìm cuốn sách cần sửa theo mã sách, sau đó sử dụng các setter như setTenSach(), setNamXuatBan(), setNhaXuatBan(), setTrangThai() để thay đổi dữ liệu

Phương thức timKiemSach(String tuKhoa) cho phép người dùng tìm sách theo tên gần đúng Danh sách kết quả tìm được sẽ được lưu tạm thời trong một ArrayList và được trả về sau khi lọc

Cuối cùng, phương thức hienThiDanhSachSach() sẽ hiển thị toàn bộ sách hiện có trong hệ thống bằng cách duyệt qua danh sách và in ra từng đối tượng Sach thông qua phương thức System.out.println(sach) – khi đó, phương thức toString() của lớp Sach sẽ được gọi tự động để hiển thị thông tin chi tiết

QuanLyMuonSach is a Java class in the com.hub.oop package that functions as a library book-borrowing manager It stores two collections: danhSachSach (the catalog of books) and danhSachPhieuMuon (the list of loan records), and it uses nextMaPhieu to generate sequential loan IDs starting from 1 The constructor accepts a list of Sach objects as the book catalog, assigns it to danhSachSach, and initializes danhSachPhieuMuon as a new empty ArrayList to hold future loan transactions The file also imports common Java utilities like ArrayList, List, and Date to support collection handling and date management.

// Phương thức mượn sách public boolean muonSach(int maDocGia, int maSach) {

// Tìm sách trong danh sách

54 if (sach != null && sach.getTrangThai().equals("Sẵn sàng")) {

PhieuMuon phieuMuon = new PhieuMuon(nextMaPhieu++, maDocGia, maSach, new Date()); danhSachPhieuMuon.add(phieuMuon);

// Cập nhật trạng thái sách sach.setTrangThai("Đã cho mượn"); return true;

// Phương thức trả sách public boolean traSach(int maPhieu) {

PhieuMuon phieuMuon = timPhieuMuonTheoMa(maPhieu); if (phieuMuon != null && phieuMuon.getNgayTra() == null) {

// Cập nhật ngày trả phieuMuon.setNgayTra(new Date());

// Tìm sách và cập nhật trạng thái

Sach sach = timSachTheoMa(phieuMuon.getMaSach()); if (sach != null) { sach.setTrangThai("Sẵn sàng"); return true;

// Các phương thức hỗ trợ private Sach timSachTheoMa(int maSach) { for (Sach sach : danhSachSach) { if (sach.getMaSach() == maSach) { return sach;

} private PhieuMuon timPhieuMuonTheoMa(int maPhieu) { for (PhieuMuon phieu : danhSachPhieuMuon) { if (phieu.getMaPhieu() == maPhieu) { return phieu;

Lớp Main

30 package main; import java.time.LocalDate; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.InputMismatchException; import java.util.List; import java.util.Scanner; import dao.Implement; import model.PhieuMuon; import model.Sach; import model.TacGia; public class Main { public static void main(String[] args) {

Scanner scanner = new Scanner(System.in); boolean exit = false;

// Tạo đối tượng DAO từ Implement

Implement implementDAO = new Implement(); while (!exit) {

System.out.println("\n - HỆ THỐNG QUẢN LÝ THƯ VIỆN -"); System.out.println("1 Quản lý Tác Giả");

System.out.println("2 Quản lý Sách");

System.out.println("3 Quản lý Mượn/Trả Sách");

System.out.println("4 Chức năng Nâng cao & Thống kê");

System.out.print("Chọn chức năng: "); int choice = scanner.nextInt(); switch (choice) { case 1:

// Quản lý tác giả manageAuthors(scanner, implementDAO); break; case 2:

// Quản lý sách manageBooks(scanner, implementDAO); break; case 3:

// Quản lý mượn/trả sách manageBorrowReturn(scanner, implementDAO); break; case 4: showStatistics(scanner, implementDAO); break; case 0:

// Thoát chương trình exit = true;

System.out.println("Cảm ơn bạn đã sử dụng hệ thống!"); break; default:

System.out.println("Lựa chọn không hợp lệ Vui lòng chọn lại."); }

94 private static void manageAuthors(Scanner scanner, Implement implementDAO) {

System.out.println("\n - Quản lý Tác Giả -");

System.out.println("1 Thêm tác giả");

System.out.println("2 Sửa tác giả");

System.out.println("3 Xóa tác giả");

System.out.println("4 Xem danh sách tác giả");

System.out.println("5 Tìm kiếm tác giả");

System.out.print("Chọn chức năng: "); int choice = scanner.nextInt(); scanner.nextLine(); switch (choice) { case 1:

System.out.print("Nhập tên tác giả: ");

System.out.print("Nhập quốc tịch: ");

TacGia tacGia = new TacGia(0, tenTacGia, quocTich); implementDAO.addTacGia(tacGia); break; case 2:

System.out.print("Nhập ID tác giả cần sửa: "); int idTacGiaToUpdate = scanner.nextInt(); scanner.nextLine();

System.out.print("Nhập tên tác giả mới: ");

System.out.print("Nhập quốc tịch mới: ");

TacGia updatedTacGia = new TacGia(idTacGiaToUpdate, newTenTacGia, newQuocTich); implementDAO.updateTacGia(updatedTacGia);

System.out.print("Nhập ID tác giả cần xóa: "); int idTacGiaToDelete = scanner.nextInt(); implementDAO.deleteTacGia(idTacGiaToDelete); break; case 4:

System.out.println("Danh sách tác giả:");

List tacGias = implementDAO.getAllTacGia(); for (TacGia tg : tacGias) {

System.out.println("ID: " + tg.getIdTacGia() + " - Tên: " + tg.getTenTacGia()); } break; case 5:

System.out.print("Nhập từ khóa tìm kiếm: ");

List searchResults = implementDAO.searchTacGia(keyword); if (!searchResults.isEmpty()) {

System out println("Kết quả tìm kiếm:"); for (TacGia tg : searchResults) {

System out println("ID: " + tg.getIdTacGia() + " - Tên: " + tg.getTenTacGia() +

System out println("Không tìm thấy tác giả phù hợp.");

System out println("Lựa chọn không hợp lệ.");

// Quản lý Sách private static void manageBooks(Scanner scanner, Implement implementDAO) {

System out println("\n - Quản lý Sách -");

System out println("1 Thêm sách");

System out println("2 Sửa sách");

System out println("3 Xóa sách");

System out println("4 Xem danh sách sách");

System out println("5 Tìm kiếm sách");

System out print("Chọn chức năng: "); int choice = scanner.nextInt(); scanner.nextLine(); switch (choice) { case 1:

System out print("Nhập tên sách: ");

System out print("Nhập năm xuất bản: "); int namXuatBan = scanner.nextInt(); scanner.nextLine();

System out print("Nhập nhà xuất bản: ");

System out print("Nhập trạng thái sách (Sẵn sàng/Đã cho mượn): ");

System out println("Chọn tác giả cho sách:");

List tacGias = implementDAO.getAllTacGia(); for (TacGia tg : tacGias) {

System out println("ID: " + tg.getIdTacGia() + " - Tên: " + tg.getTenTacGia()); }

List selectedAuthors = new ArrayList(); while (true) {

System out print("Chọn ID tác giả (nhập -1 để kết thúc): "); int tacGiaId = scanner.nextInt(); scanner.nextLine(); if (tacGiaId == -1) break;

TacGia selectedTacGia = implementDAO.getTacGiaById(tacGiaId); if (selectedTacGia != null) { selectedAuthors.add(selectedTacGia);

System out println("Không tìm thấy tác giả với ID đã nhập!");

Sach sach = new Sach(0, tenSach, namXuatBan, nhaXuatBan, trangThai); sach.setTacGias(selectedAuthors); implementDAO.addSach(sach); break; case 2:

System out print("Nhập ID sách cần sửa: "); int idSachToUpdate = scanner.nextInt(); scanner.nextLine();

Sach existingBook = implementDAO.getSachById(idSachToUpdate); if (existingBook == null) {

System out println("Không tìm thấy sách với ID đã nhập!"); break;

System out print("Nhập tên sách mới: ");

System out print("Nhập năm xuất bản mới: "); int newNamXuatBan = scanner.nextInt(); scanner.nextLine();

System out print("Nhập nhà xuất bản mới: ");

System out print("Nhập trạng thái sách mới: ");

// Cập nhật thông tin sách

Sach updatedSach = new Sach(idSachToUpdate, newTenSach, newNamXuatBan, newNhaXuatBan, newTrangThai); updatedSach.setTacGias(existingBook.getTacGias()); implementDAO.updateSach(updatedSach); break; case 3:

System out print("Nhập ID sách cần xóa: "); int idSachToDelete = scanner.nextInt(); implementDAO.deleteSach(idSachToDelete); break; case 4:

System out println("Danh sách sách:");

List sachList = implementDAO.getAllSach(); for (Sach s : sachList) {

System out println("ID: " + s.getMaSach() + " - Tên: " + s.getTenSach() + " - Năm XB: "

+ s.getNamXuatBan() + " - NXB: " + s.getNhaXuatBan() + " - Trạng thái: " + s.getTrangThai());

// Hiển thị tác giả if (!s.getTacGias().isEmpty()) {

System out print(" Tác giả: "); for (TacGia tg : s.getTacGias()) {

System out print(tg.getTenTacGia() + ", ");

} break; case 5: searchBooks(scanner, implementDAO); break; default:

System out println("Lựa chọn không hợp lệ.");

} private static void searchBooks(Scanner scanner, Implement implementDAO)

System out println("\n - TÌM KIẾM SÁCH -");

System out println("1 Tìm theo tên sách");

System out println("2 Tìm theo tên tác giả");

System out print("Chọn cách tìm kiếm: "); int searchType = scanner.nextInt(); scanner.nextLine(); // Đọc dòng mới

System out print("Nhập từ khóa tìm kiếm: ");

List searchResults = new ArrayList(); switch (searchType) { case 1: // Tìm theo tên sách searchResults = implementDAO.findSachByTen(keyword); break; case 2: // Tìm theo tên tác giả searchResults = implementDAO.findSachByTenTacGia(keyword); break; default:

System out println("Lựa chọn không hợp lệ."); return;

// Hiển thị kết quả if (!searchResults.isEmpty()) {

System out println("\nKẾT QUẢ TÌM KIẾM:");

System out printf("%-10s %-30s %-20s %-15s\n", "Mã sách", "Tên sách", "Tác giả", "Trạng thái"); for (Sach s : searchResults) {

String authors s.getTacGias().stream().map(TacGia::getTenTacGia).reduce((a, b) -> a + ", " + b)

.orElse("Không có tác giả");

System out printf("%-10d %-30s %-20s %-15s\n", s.getMaSach(), s.getTenSach(), authors, s.getTrangThai());

System out println("Không tìm thấy sách phù hợp.");

// Quản lý Mượn/Trả Sách private static void manageBorrowReturn(Scanner scanner, Implement implementDAO) {

System out println("\n - Mượn/Trả Sách -");

System out println("1 Mượn sách");

System out println("2 Trả sách");

System out print("Chọn chức năng: "); try { int choice = scanner.nextInt(); scanner.nextLine(); switch (choice) { case 1:

System out print("Nhập mã sách: "); int maSachMuon = scanner.nextInt(); scanner.nextLine();

System out print("Nhập mã độc giả: ");

Sach sach = implementDAO.getSachById(maSachMuon); if (sach != null && sach.getTrangThai().equals("Sẵn sàng")) { boolean result = implementDAO.muonSach(maDocGia, maSachMuon); if (result) {

System out println("Sách mượn thành công!");

System out println("Không thể mượn sách Vui lòng thử lại.");

System out println("Sách không sẵn sàng mượn hoặc không tồn tại.");

System out print("Nhập mã phiếu mượn: "); int maPhieu = scanner.nextInt(); scanner.nextLine(); boolean result = implementDAO.traSach(maPhieu); if (result) {

System out println("Sách trả thành công!");

System out println("Không tìm thấy phiếu mượn hoặc có lỗi xảy ra.");

System out println("Lựa chọn không hợp lệ.");

System out println("Lỗi: Vui lòng nhập số!"); scanner.nextLine();

System out println("Đã xảy ra lỗi: " + e.getMessage());

// Tìm kiếm sách theo tác giả private static void searchBooksByAuthor(Scanner scanner, Implement implementDAO) {

System out print("Nhập tên tác giả để tìm sách: ");

List sachList = implementDAO.findSachByTenTacGia(tenTacGia); if (!sachList.isEmpty()) { for (Sach s : sachList) {

System out println(s.getTenSach() + " - Trạng thái: " + s.getTrangThai()); }

System out println("Không tìm thấy sách của tác giả này.");

// Thống kê private static void showStatistics(Scanner scanner, Implement implementDAO) {

System out println("\n - THỐNG KÊ VÀ CHỨC NĂNG NÂNG CAO -"); System out println("1 Sắp xếp sách theo tên (alphabet)");

System out println("2 Liệt kê sách đang được mượn");

System out println("3 Liệt kê phiếu mượn quá hạn");

System out println("4 Top 5 sách mượn nhiều nhất");

System out println("5 Tìm kiếm sách theo tên tác giả");

System out print("Chọn chức năng: "); int choice = scanner.nextInt(); scanner.nextLine(); switch (choice) { case 1: displaySortedBooks(implementDAO); break; case 2: displayBorrowedBooks(implementDAO);

414 break; case 3: displayOverdueBorrows(implementDAO); break; case 4: displayTop5Books(implementDAO); break; case 5:

// Di chuyển chức năng tìm kiếm sách vào đây

System out print("Nhập tên tác giả để tìm sách: ");

List sachList = implementDAO.findSachByTenTacGia(tenTacGia); if (!sachList.isEmpty()) {

System out println("Kết quả tìm kiếm:"); for (Sach s : sachList) {

System out println(s.getTenSach() + " - Trạng thái: " + s.getTrangThai()); }

System out println("Không tìm thấy sách của tác giả này.");

System out println("Lựa chọn không hợp lệ.");

} private static void displaySortedBooks(Implement implementDAO) {

System out println("\n - DANH SÁCH SÁCH SẮP XẾP THEO TÊN -"); List sortedBooks = implementDAO.getSachSortedByTenSach(); if (!sortedBooks.isEmpty()) {

System out printf("%-10s %-30s %-20s %-15s\n", "Mã sách", "Tên sách", "Tác giả", "Trạng thái");

String authors s.getTacGias().stream().map(TacGia::getTenTacGia).reduce((a, b) -> a + ", " + b)

.orElse("Không có tác giả");

System out printf("%-10d %-30s %-20s %-15s\n", s.getMaSach(), s.getTenSach(), authors, s.getTrangThai());

System out println("Không có sách nào trong hệ thống.");

} private static void displayBorrowedBooks(Implement implementDAO) {

System out println("\n - DANH SÁCH SÁCH ĐANG ĐƯỢC MƯỢN -"); List borrowedBooks = implementDAO.getSachDangMuon(); if (!borrowedBooks.isEmpty()) {

System out printf("%-10s %-30s %-20s\n", "Mã sách", "Tên sách", "Tác giả"); for (Sach s : borrowedBooks) {

String authors s.getTacGias().stream().map(TacGia::getTenTacGia).reduce((a, b) -> a + ", " + b)

.orElse("Không có tác giả");

System out printf("%-10d %-30s %-20s\n", s.getMaSach(), s.getTenSach(), authors);

System out println("Không có sách nào đang được mượn.");

478 private static void displayOverdueBorrows(Implement implementDAO) { final int SO_NGAY_QUA_HAN = 7;

System out println("\n - DANH SÁCH PHIẾU MƯỢN QUÁ HẠN (" + SO_NGAY_QUA_HAN + " ngày) -");

List overdueBorrows implementDAO.getPhieuMuonQuaHan(SO_NGAY_QUA_HAN); if (!overdueBorrows.isEmpty()) {

System out printf("%-10s %-10s %-10s %-15s %-15s\n", "Mã phiếu", "Mã ĐG", "Mã sách", "Ngày mượn",

"Số ngày quá"); for (PhieuMuon pm : overdueBorrows) {

LocalDate ngayMuon pm.getNgayMuon().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); long daysOverdue = ChronoUnit DAYS between(ngayMuon, LocalDate.now())

System out printf("%-10d %-10s %-10d %-15s %-15d\n", pm.getMaPhieu(), pm.getMaDocGia(), pm.getMaSach(), pm.getNgayMuon(), daysOverdue);

System out println("Không có phiếu mượn nào quá hạn.");

} private static void displayTop5Books(Implement implementDAO) {

List topBooks = implementDAO.getTop5SachMuonNhieuNhat(); System out println("\n - TOP 5 SÁCH MƯỢN NHIỀU NHẤT -");

System out printf("%-5s %-8s %-40s %-15s\n", "STT", "Mã sách", "Tên sách",

"Số lần mượn"); int stt = 1; for (Sach s : topBooks) {

System out printf("%-5d %-8d %-40s %-15d\n", stt++, s.getMaSach(), s.getTenSach(), s.getSoLanMuon());

- Lớp Main là điểm khởi đầu của ứng dụng quản lý thư viện, là trung tâm điều phối tất cả các hoạt động của phần mềm Sử dụng lớp DBConnection để kết nối tới database, đảm bảo cho toàn bộ các thao tác thêm, sửa, xóa, tìm kiếm được thực hiện thông suốt và nhất quán

- Main có nhiệm vụ hiển thị menu điều khiển, tiếp nhận lựa chọn từ người dùng và gọi tới các chức năng nghiệp vụ tương ứng

- Giao diện menu được thiết kế dưới dạng console, dễ sử dụng cho người dùng Menu được trình bày rõ ràng, chia thành các nhóm chức năng chính: Quản lý tác giả; Quản lý sách; Quản lý mượn/trả sách; Chức năng nâng cao & thống kê Mỗi lựa chọn menu sẽ tương ứng với một nghiệp vụ quản lý trong thư viện

- Đảm bảo sự kết nối và luân chuyển dữ liệu giữa các thực thể (tác giả, sách, phiếu mượn, độc giả) một cách nhất quán

- Kiểm soát luồng xử lý, quản lý vòng lặp chính của chương trình cho đến khi người dùng chọn thoát

Hệ thống hiển thị menu chính và các menu con được sắp xếp theo từng nhóm chức năng: Quản lý tác giả, Quản lý sách, Quản lý mượn/trả sách, và Chức năng nâng cao & thống kê, giúp người dùng dễ điều hướng và quản lý tác phẩm, mượn trả sách một cách hiệu quả.

- Lớp Main thực hiện nhập/xuất dữ liệu qua màn hình console một cách rõ ràng, thân thiện với các chỉ dẫn cụ thể để người dùng dễ dàng nhập thông tin

- Nếu người dùng nhập sai định dạng hoặc lựa chọn không hợp lệ, chương trình sẽ thông báo lỗi và yêu cầu nhập lại, hạn chế tối đa lỗi nhập liệu

Để bảo đảm tính nhất quán và tái sử dụng, ta gọi các chức năng nghiệp vụ đã được xây dựng trong các lớp quản lý Các chức năng này bao gồm thêm, sửa, xóa, tìm kiếm, thống kê, sắp xếp và liệt kê dữ liệu, giúp người dùng và quản trị viên thao tác dữ liệu một cách hiệu quả và dễ bảo trì Việc đóng gói các hành động nghiệp vụ vào lớp quản lý đồng thời tối ưu luồng xử lý dữ liệu, giảm sự phụ thuộc giữa giao diện người dùng và logic xử lý, và thuận lợi cho việc mở rộng trong tương lai.

- Giúp quản lý luồng chương trình, đảm bảo sau khi thao tác xong sẽ quay lại menu cha hoặc kết thúc chương trình khi người dùng chọn thoát

- Bắt đầu chương trình, hệ thống kết nối tới cơ sở dữ liệu và hiển thị menu chính với các lựa chọn chức năng cho người dùng

- Người dùng chọn chức năng bằng cách nhập số tương ứng trên menu (ví dụ: Quản lý Tác giả, Quản lý Sách, Quản lý Mượn/Trả sách, Thống kê )

- Hệ thống hiển thị menu con tương ứng với từng chức năng để người dùng thực hiện các thao tác chi tiết hơn (thêm, sửa, xóa, tìm kiếm, mượn/trả sách, v.v.)

- Người dùng nhập thông tin cần thiết cho từng thao tác Hệ thống kiểm tra tính hợp lệ của dữ liệu và thông báo kết quả thực hiện

- Sau mỗi thao tác, chương trình quay trở lại menu chức năng để người dùng tiếp tục sử dụng các chức năng khác hoặc có thể chọn “Thoát” để kết thúc chương trình

Toàn bộ quá trình được lặp lại liên tục nhờ vòng lặp tự động, đảm bảo người dùng thao tác thuận tiện và liên tục cho đến khi không còn nhu cầu sử dụng hệ thống.

DBConnection

This Java source file declares the package com.hub.oop and defines a DBConnection class, establishing the foundation for JDBC-based database connectivity It imports core JDBC interfaces and classes, including java.sql.Connection, java.sql.DriverManager, java.sql.PreparedStatement, java.sql.ResultSet, java.sql.SQLException, and java.sql.Statement, which enable creating connections, executing SQL queries, using prepared statements, handling results, and managing SQL exceptions Together, these elements lay the groundwork for robust and scalable database access in Java applications, supporting essential data operations through the JDBC API.

To connect to a SQL Server database, the code uses the Microsoft JDBC Driver for SQL Server with the driver class com.microsoft.sqlserver.jdbc.SQLServerDriver and a connection URL of jdbc:sqlserver://localhost:1433;databaseName=QuanLyThuVien;encrypt=true;trustServerCertificate=true It defines the database credentials as username 'sa' and password 'sa' and maintains a Connection object initialized to null In the DBConnection constructor, a try block attempts to establish the connection, setting up secure communication with the QuanLyThuVien database and enabling interaction via JDBC.

System.err.println("Khong tin thay driver JDBC: " + e.getMessage());

} } public Connection openConnection() { try { if (connection == null || connection.isClosed()) { connection DriverManager.getConnection(DB_URL, USER, PASS);

System.out.println("ket noi den CSDL thanh cong"); }

System.err.println("Loi khi ket noi xuong db " + e.getMessage());

} public ResultSet executeQuery(String query) {

Statement stmt = null; openConnection(); try { stmt = connection.createStatement(); rs = stmt.executeQuery(query);

// executeQuery(vSQL, [1,2,3] ) public ResultSet executeQuery(String query, Object params) {

PreparedStatement pstmt = null; openConnection(); try { pstmt = connection.prepareStatement(query); // thiet lap cac tham so for (int i = 0; i < params.length; i++) pstmt.setObject(i + 1, params[i]);

// thuc thi rs = pstmt.executeQuery();

/* Ham nay de thuc thi lenh insert/update/delete */ public int executeUpdate(String sql) { int affectedRows = 0;

Statement stmt = null; try { stmt = connection.createStatement(); affectedRows = stmt.executeUpdate(sql); } catch (SQLException e) {

// TODO Auto-generated catch block e.printStackTrace();

} public int executeUpdate(String sql, Object params) { int affectedRows = 0;

PreparedStatement pstmt = null; try { openConnection(); pstmt = connection.prepareStatement(sql);

119 for (int i = 0; i < params.length; i++) pstmt.setObject(i + 1, params[i]); affectedRows = pstmt.executeUpdate();

Lớp DBConnection là lớp chuyên dụng để thiết lập và quản lý kết nối giữa ứng dụng Java và cơ sở dữ liệu SQL Server Lớp này đảm nhận vai trò trung gian giúp thực thi các truy vấn (query) và cập nhật dữ liệu (insert, update, delete) một cách dễ dàng và có tổ chức thông qua JDBC (Java Database Connectivity)

Lớp DBConnection có các chức năng chính như sau:

- Thiết lập kết nối đến cơ sở dữ liệu SQL Server thông qua thông tin đăng nhập, tên database và driver JDBC

- Cung cấp phương thức thực thi truy vấn (executeQuery) để lấy dữ liệu từ cơ sở dữ liệu

- Cung cấp phương thức thực thi cập nhật (executeUpdate) để chèn, sửa hoặc xóa dữ liệu

- Hỗ trợ cả truy vấn thường và truy vấn có tham số thông qua PreparedStatement

- Quản lý đối tượng Connection một cách hiệu quả, tránh tạo lại kết nối nhiều lần không cần thiết

Lớp DBConnection định nghĩa các hằng số JDBC_DRIVER, DB_URL, USER và PASS để chứa thông tin cấu hình kết nối với SQL Server, bao gồm driver, đường dẫn đến database (QuanLyThuVien), và tài khoản truy cập

Khi đối tượng DBConnection được khởi tạo, constructor sẽ nạp driver JDBC bằng Class.forName(JDBC_DRIVER) Nếu driver không tìm thấy, chương trình sẽ in ra lỗi tương ứng

Phương thức openConnection() kiểm tra nếu connection đang null hoặc đã đóng (isClosed()), thì gọi DriverManager.getConnection() để thiết lập kết nối đến database Nếu thành công, sẽ in ra dòng thông báo "kết nối đến CSDL thành công" Để thực hiện truy vấn dữ liệu (SELECT), có hai phương thức executeQuery(): Dạng cơ bản nhận chuỗi SQL (String query), dùng Statement để thực hiện

Dạng nâng cao nhận thêm tham số (Object params) để truyền vào câu lệnh SQL động, dùng PreparedStatement để tránh lỗi SQL Injection

Tương tự, để cập nhật dữ liệu (INSERT, UPDATE, DELETE), lớp cung cấp hai phương thức executeUpdate():

Một phương thức dùng Statement thực thi câu lệnh SQL tĩnh

Một phương thức dùng PreparedStatement với tham số truyền vào (params), hỗ trợ thao tác linh hoạt và an toàn

Tất cả phương thức thực thi đều mở kết nối khi cần thiết và xử lý ngoại lệ SQLException để tránh chương trình bị gián đoạn khi xảy ra lỗi

Kết quả chạy chương trình

Ngày đăng: 12/09/2025, 08:59

HÌNH ẢNH LIÊN QUAN

2.1. Sơ đồ ERD - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
2.1. Sơ đồ ERD (Trang 11)
Hình 6: Chức năng Tìm kiếm thông tin tác giả - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 6 Chức năng Tìm kiếm thông tin tác giả (Trang 89)
Hình 11: Chức năng Tìm kiếm thông tin sách - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 11 Chức năng Tìm kiếm thông tin sách (Trang 92)
Hình 14: Chức năng Trả sách - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 14 Chức năng Trả sách (Trang 93)
Hình 16: Chức năng Tìm kiếm sách theo tên tác giả  4.4.2. Sắp xếp sách theo Tên sách (alphabet) - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 16 Chức năng Tìm kiếm sách theo tên tác giả 4.4.2. Sắp xếp sách theo Tên sách (alphabet) (Trang 94)
Hình 17: Chức năng Sắp xếp sách theo Tên sách (alphabet)  4.4.3. Liệt kê danh sách các sách đang được cho mượn - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 17 Chức năng Sắp xếp sách theo Tên sách (alphabet) 4.4.3. Liệt kê danh sách các sách đang được cho mượn (Trang 95)
Hình 19: Liệt kê các phiếu mượn đã quá hạn trả (ví dụ: mượn quá 30 ngày chưa trả)  4.4.5 - Bài tập nhóm môn lập trình hướng Đối tượng Đề tài hệ thống quản lý thư viện
Hình 19 Liệt kê các phiếu mượn đã quá hạn trả (ví dụ: mượn quá 30 ngày chưa trả) 4.4.5 (Trang 96)

🧩 Sản phẩm bạn có thể quan tâm

w