基于JSP+Servlet的图书信息管理系统 - 源码深度解析

JavaJavaScriptHTMLCSSMySQLJSP+Servlet
2026-03-054 浏览

文章摘要

本项目是一款基于JSP和Servlet技术栈构建的图书信息管理系统,旨在为中小型图书馆、书店或企业内部资料室提供一个稳定、易用的核心业务管理平台。系统核心业务价值在于解决了传统纸质或Excel表格管理图书时存在的效率低下、信息易出错、查询统计困难等痛点。通过将图书信息、借阅记录、用户数据数字化集中管...

在数字化信息管理日益重要的今天,图书资料的高效管理成为各类机构的基础需求。传统的纸质登记或电子表格管理方式存在效率低下、易出错、查询统计困难等诸多弊端。为此,我们设计并实现了一套基于JSP和Servlet技术的图书管理解决方案,命名为“智慧图书库”。

该系统采用经典的Java EE Web开发架构,严格遵循MVC设计模式。JSP负责前端视图的渲染,Servlet作为控制器处理所有业务请求,JavaBean则用于封装实体数据模型,JDBC实现与MySQL数据库的持久化交互。这种分层架构清晰地分离了表示层、控制层和模型层,确保了代码的良好可维护性和可扩展性。

数据库架构设计与核心表分析

系统底层由12张数据表构成,支撑着完整的图书管理业务流程。其中,book(图书信息表)、borrow(借阅记录表)和reader(读者信息表)的设计尤为关键,它们共同构成了业务逻辑的核心。

book表的设计充分考虑了图书信息的完整性和查询效率。除了基本的书名、作者、出版社字段外,还包含了ISBN、分类号、馆藏位置等详细信息。其主键bookId采用自增策略,确保唯一性。status字段使用枚举类型定义了图书的当前状态(如在架、借出、维修中),为图书流通状态管理提供了清晰的状态机。

CREATE TABLE `book` (
  `bookId` int(11) NOT NULL AUTO_INCREMENT,
  `bookName` varchar(100) NOT NULL,
  `author` varchar(50) NOT NULL,
  `publisher` varchar(100) NOT NULL,
  `isbn` varchar(20) NOT NULL,
  `categoryId` int(11) NOT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `location` varchar(50) DEFAULT NULL,
  `status` enum('AVAILABLE','BORROWED','MAINTENANCE') DEFAULT 'AVAILABLE',
  `createTime` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`bookId`),
  KEY `idx_category` (`categoryId`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

borrow表作为系统的核心业务表,记录了完整的借阅生命周期。其设计亮点在于对时间维度的精细管理。borrowDate(借书日期)、dueDate(应还日期)和actualReturnDate(实际归还日期)三个日期字段的配合,可以精确计算借阅时长、是否超期。renewCount字段记录了续借次数,实现了业务规则的约束。

CREATE TABLE `borrow` (
  `borrowId` int(11) NOT NULL AUTO_INCREMENT,
  `readerId` int(11) NOT NULL,
  `bookId` int(11) NOT NULL,
  `borrowDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `dueDate` date NOT NULL,
  `actualReturnDate` datetime DEFAULT NULL,
  `renewCount` int(11) DEFAULT '0',
  `status` enum('BORROWING','RETURNED','OVERDUE') DEFAULT 'BORROWING',
  PRIMARY KEY (`borrowId`),
  KEY `idx_reader` (`readerId`),
  KEY `idx_book` (`bookId`),
  KEY `idx_dueDate` (`dueDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

reader表的设计则体现了读者管理的灵活性。通过readerTypeId关联读者类型表,可以实现不同读者群体(如学生、教师、职工)的差异化权限管理,如借书数量上限、借阅期限等。certificateFee字段支持证件费管理,满足实际运营需求。

核心功能实现解析

1. 用户认证与会话管理

系统通过Filter实现了统一的权限验证机制。AuthFilter会拦截所有需要登录的请求,检查Session中是否存在用户信息。以下是核心的过滤器代码:

public class AuthFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpSession session = httpRequest.getSession(false);
        
        String path = httpRequest.getRequestURI();
        if (path.endsWith("login.jsp") || path.endsWith("login") || 
            path.contains("/css/") || path.contains("/js/")) {
            chain.doFilter(request, response);
            return;
        }
        
        if (session == null || session.getAttribute("user") == null) {
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/admin/login.jsp");
            return;
        }
        
        chain.doFilter(request, response);
    }
}

用户登录功能由LoginServlet处理,它验证用户凭证后建立会话:

public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        
        AdminService adminService = new AdminService();
        Admin admin = adminService.login(username, password);
        
        if (admin != null) {
            HttpSession session = request.getSession();
            session.setAttribute("user", admin);
            response.sendRedirect("index.jsp");
        } else {
            request.setAttribute("error", "用户名或密码错误");
            request.getRequestDispatcher("/admin/login.jsp").forward(request, response);
        }
    }
}

管理员登录界面

2. 图书检索与分页查询

图书检索功能支持多条件组合查询,通过BookServlet处理查询请求。后端采用预编译的PreparedStatement防止SQL注入,同时实现分页逻辑以提高查询性能。

public class BookServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        String action = request.getParameter("action");
        if ("search".equals(action)) {
            String bookName = request.getParameter("bookName");
            String author = request.getParameter("author");
            String categoryId = request.getParameter("categoryId");
            String pageStr = request.getParameter("page");
            
            int page = 1;
            int pageSize = 10;
            if (pageStr != null && !pageStr.isEmpty()) {
                page = Integer.parseInt(pageStr);
            }
            
            BookService bookService = new BookService();
            PageResult<Book> result = bookService.searchBooks(bookName, author, 
                    categoryId, page, pageSize);
            
            request.setAttribute("bookList", result.getData());
            request.setAttribute("totalPages", result.getTotalPages());
            request.setAttribute("currentPage", page);
            request.getRequestDispatcher("/admin/book-list.jsp").forward(request, response);
        }
    }
}

对应的Service层处理复杂查询逻辑:

public PageResult<Book> searchBooks(String bookName, String author, 
                                   String categoryId, int page, int pageSize) {
    StringBuilder sql = new StringBuilder("SELECT * FROM book WHERE 1=1");
    List<Object> params = new ArrayList<>();
    
    if (bookName != null && !bookName.trim().isEmpty()) {
        sql.append(" AND bookName LIKE ?");
        params.add("%" + bookName.trim() + "%");
    }
    if (author != null && !author.trim().isEmpty()) {
        sql.append(" AND author LIKE ?");
        params.add("%" + author.trim() + "%");
    }
    if (categoryId != null && !categoryId.trim().isEmpty()) {
        sql.append(" AND categoryId = ?");
        params.add(Integer.parseInt(categoryId));
    }
    
    // 获取总数
    String countSql = "SELECT COUNT(*) FROM (" + sql + ") as total";
    int total = jdbcTemplate.queryForObject(countSql, Integer.class, params.toArray());
    
    // 分页查询
    sql.append(" ORDER BY createTime DESC LIMIT ? OFFSET ?");
    params.add(pageSize);
    params.add((page - 1) * pageSize);
    
    List<Book> books = jdbcTemplate.query(sql.toString(), 
            new BeanPropertyRowMapper<>(Book.class), params.toArray());
    
    return new PageResult<>(books, total, page, pageSize);
}

图书检索界面

3. 图书借阅业务流程

借阅功能涉及多个数据表的协同操作,需要保证事务的原子性。BorrowServlet处理借阅请求时,会同时更新book表的状态和创建borrow记录。

public class BorrowServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        int readerId = Integer.parseInt(request.getParameter("readerId"));
        int bookId = Integer.parseInt(request.getParameter("bookId"));
        
        BorrowService borrowService = new BorrowService();
        try {
            boolean success = borrowService.borrowBook(readerId, bookId);
            if (success) {
                request.setAttribute("message", "借书成功");
            } else {
                request.setAttribute("error", "借书失败,图书可能已被借出");
            }
        } catch (Exception e) {
            request.setAttribute("error", "系统错误:" + e.getMessage());
        }
        request.getRequestDispatcher("/admin/borrow-result.jsp").forward(request, response);
    }
}

Service层使用声明式事务管理确保数据一致性:

public class BorrowService {
    @Transactional
    public boolean borrowBook(int readerId, int bookId) {
        // 检查读者借书数量是否超限
        String checkReaderSql = "SELECT COUNT(*) FROM borrow WHERE readerId = ? AND status = 'BORROWING'";
        int borrowingCount = jdbcTemplate.queryForObject(checkReaderSql, Integer.class, readerId);
        
        Reader reader = getReaderById(readerId);
        if (borrowingCount >= reader.getMaxBorrowCount()) {
            throw new RuntimeException("借书数量已达上限");
        }
        
        // 检查图书状态
        String checkBookSql = "SELECT status FROM book WHERE bookId = ?";
        String status = jdbcTemplate.queryForObject(checkBookSql, String.class, bookId);
        if (!"AVAILABLE".equals(status)) {
            return false;
        }
        
        // 更新图书状态
        String updateBookSql = "UPDATE book SET status = 'BORROWED' WHERE bookId = ?";
        jdbcTemplate.update(updateBookSql, bookId);
        
        // 创建借阅记录
        String insertBorrowSql = "INSERT INTO borrow (readerId, bookId, dueDate) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL ? DAY))";
        int borrowDays = reader.getBorrowDays();
        jdbcTemplate.update(insertBorrowSql, readerId, bookId, borrowDays);
        
        return true;
    }
}

图书借阅界面

4. 图书归还与续借处理

归还功能需要处理可能的超期费用计算,而续借功能则要检查续借次数限制。以下是归还操作的核心代码:

public class ReturnServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        int borrowId = Integer.parseInt(request.getParameter("borrowId"));
        
        ReturnService returnService = new ReturnService();
        ReturnResult result = returnService.returnBook(borrowId);
        
        request.setAttribute("result", result);
        request.getRequestDispatcher("/admin/return-result.jsp").forward(request, response);
    }
}

public class ReturnService {
    @Transactional
    public ReturnResult returnBook(int borrowId) {
        // 获取借阅记录
        Borrow borrow = getBorrowById(borrowId);
        if (borrow == null || !"BORROWING".equals(borrow.getStatus())) {
            throw new RuntimeException("无效的借阅记录");
        }
        
        // 计算超期天数和费用
        LocalDate dueDate = borrow.getDueDate().toLocalDate();
        LocalDate returnDate = LocalDate.now();
        long overdueDays = ChronoUnit.DAYS.between(dueDate, returnDate);
        overdueDays = overdueDays > 0 ? overdueDays : 0;
        
        BigDecimal fee = BigDecimal.ZERO;
        if (overdueDays > 0) {
            fee = calculateOverdueFee(overdueDays);
        }
        
        // 更新借阅记录
        String updateBorrowSql = "UPDATE borrow SET actualReturnDate = NOW(), status = 'RETURNED', overdueFee = ? WHERE borrowId = ?";
        jdbcTemplate.update(updateBorrowSql, fee, borrowId);
        
        // 更新图书状态
        String updateBookSql = "UPDATE book SET status = 'AVAILABLE' WHERE bookId = ?";
        jdbcTemplate.update(updateBookSql, borrow.getBookId());
        
        return new ReturnResult(true, fee, overdueDays);
    }
}

图书归还界面

实体模型与业务对象设计

系统采用JavaBean作为实体模型,每个Bean对应数据库中的一张表,封装了业务数据的属性和基本行为。以Book类为例:

public class Book {
    private int bookId;
    private String bookName;
    private String author;
    private String publisher;
    private String isbn;
    private int categoryId;
    private BigDecimal price;
    private String location;
    private String status;
    private Date createTime;
    
    // 构造函数
    public Book() {}
    
    public Book(String bookName, String author, String publisher, String isbn) {
        this.bookName = bookName;
        this.author = author;
        this.publisher = publisher;
        this.isbn = isbn;
    }
    
    // Getter和Setter方法
    public int getBookId() { return bookId; }
    public void setBookId(int bookId) { this.bookId = bookId; }
    
    public String getBookName() { return bookName; }
    public void setBookName(String bookName) { this.bookName = bookName; }
    
    // ... 其他属性的Getter和Setter
    
    // 业务方法
    public boolean isAvailable() {
        return "AVAILABLE".equals(status);
    }
    
    public boolean canBorrow() {
        return isAvailable() && !"MAINTENANCE".equals(status);
    }
}

读者实体Reader包含了类型管理和权限控制:

public class Reader {
    private int readerId;
    private String readerName;
    private String certificateNumber;
    private int readerTypeId;
    private String phone;
    private String email;
    private Date registrationDate;
    private BigDecimal certificateFee;
    private int maxBorrowCount;
    private int borrowDays;
    
    // ... 属性和方法
    
    public boolean canBorrowMore() {
        // 检查当前借书数量是否达到上限的逻辑
        return getCurrentBorrowCount() < maxBorrowCount;
    }
}

系统优化与功能扩展展望

基于当前系统架构,未来可以从以下几个方向进行深度优化和功能扩展:

  1. 引入全文检索技术:当前的关键词搜索基于SQL的LIKE操作,在大数据量下性能有限。可以集成Elasticsearch或Solr实现高效的全文检索,支持分词、同义词、拼音搜索等高级功能。

  2. 实现分布式会话管理:当前系统依赖单机Session,不利于横向扩展。可以引入Redis等分布式缓存存储会话数据,实现多实例部署下的会话共享。

  3. 构建RESTful API接口:将核心业务功能封装为RESTful API,支持移动端App、微信小程序等多终端访问,扩展系统使用场景。

  4. 增强数据分析能力:在现有业务数据基础上,构建数据仓库,实现借阅趋势分析、热门图书统计、读者行为分析等BI功能,为管理决策提供数据支持。

  5. 引入工作流引擎:对于复杂的图书采购、报废审批流程,可以集成Activiti等工作流引擎,实现流程的可视化配置和灵活管理。

  6. 升级前端技术栈:将JSP视图层逐步替换为Vue.js或React等现代前端框架,实现前后端分离架构,提升用户体验和开发效率。

智慧图书库系统通过严谨的架构设计和扎实的技术实现,为中小型图书管理机构提供了稳定可靠的核心业务支撑。其清晰的代码结构和完善的业务逻辑为后续的功能扩展和技术升级奠定了坚实基础。随着技术的不断演进,该系统有望发展成为功能更加丰富、性能更加优越的综合性图书管理平台。

本文关键词
JSPServlet图书管理系统数据库设计MVC

上下篇

上一篇
没有更多文章
下一篇
没有更多文章