基于JSP+Servlet的教材采购管理系统 - 源码深度解析

JavaJavaScriptHTMLCSSMySQLJSP+Servlet
2026-03-183 浏览

文章摘要

本系统基于JSP与Servlet技术栈构建,核心业务价值在于为高校或教育机构的教材采购部门提供一个集中化、流程化的管理解决方案。传统教材采购依赖纸质单据和人工沟通,存在信息不透明、订单易出错、库存统计滞后等痛点。本系统通过数字化流程,将教材信息维护、采购计划制定、订单生成、库存管理及供应商对接等环节...

在高校教育管理信息化进程中,教材采购作为连接教学计划与课堂教学的关键环节,其管理效率直接影响教学活动的正常开展。传统依赖纸质单据、人工统计和分散沟通的采购模式存在信息滞后、数据易出错、流程不透明等痛点。针对这一需求,基于JSP+Servlet技术栈构建的教材采购管理系统实现了从教材需求申报、采购计划制定、供应商对接、订单执行到库存管理的全流程数字化管控。

系统采用经典的三层架构模式,表现层使用JSP动态页面技术结合HTML/CSS/JavaScript实现用户交互界面,业务逻辑层通过Servlet控制器处理请求并调用JavaBean组件完成业务规则验证,数据持久层则基于JDBC技术封装DAO模式操作MySQL数据库。这种架构确保了业务逻辑、数据访问和用户界面的分离,提高了系统的可维护性和扩展性。

管理员登录界面

数据库架构设计

系统采用13张数据表构建完整的业务数据模型,核心表包括用户信息表、教材信息表、采购订单表和库存记录表。每张表都设计了规范的主外键约束和索引策略,确保数据的一致性和查询效率。

用户信息表(user)设计体现了多角色权限管理的核心思路:

CREATE TABLE user (
    user_id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(100) NOT NULL,
    real_name VARCHAR(50) NOT NULL,
    role ENUM('admin', 'teacher', 'student') NOT NULL,
    department_id INT,
    email VARCHAR(100),
    phone VARCHAR(20),
    status TINYINT DEFAULT 1,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login_time TIMESTAMP,
    FOREIGN KEY (department_id) REFERENCES department(department_id)
);

该表通过role字段实现三种用户角色的区分,department_id外键关联院系信息表,支持按院系进行数据隔离。status字段支持账户的启用/禁用状态管理,last_login_time记录用户最后登录时间用于安全审计。

采购订单表(purchase_order)的设计展现了复杂的业务流程数据建模:

CREATE TABLE purchase_order (
    order_id INT PRIMARY KEY AUTO_INCREMENT,
    order_number VARCHAR(50) UNIQUE NOT NULL,
    teacher_id INT NOT NULL,
    book_id INT NOT NULL,
    quantity INT NOT NULL CHECK (quantity > 0),
    unit_price DECIMAL(10,2) NOT NULL,
    total_amount DECIMAL(12,2) NOT NULL,
    order_status ENUM('pending', 'approved', 'rejected', 'completed') DEFAULT 'pending',
    approver_id INT,
    approve_time TIMESTAMP NULL,
    reject_reason TEXT,
    supplier_id INT,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expected_delivery_date DATE,
    actual_delivery_date DATE,
    FOREIGN KEY (teacher_id) REFERENCES user(user_id),
    FOREIGN KEY (book_id) REFERENCES textbook(book_id),
    FOREIGN KEY (approver_id) REFERENCES user(user_id),
    FOREIGN KEY (supplier_id) REFERENCES supplier(supplier_id)
);

订单表通过order_status字段实现采购审批工作流的状态跟踪,包含价格、数量、金额等完整的业务字段,并通过多个外键关联确保数据的引用完整性。expected_delivery_date和actual_delivery_date字段支持到货时间的管理和统计。

核心业务功能实现

用户身份认证与权限控制

系统采用基于Session的身份认证机制,用户登录后服务器端创建会话并存储用户身份信息。权限控制通过过滤器(Filter)实现,对需要认证的请求路径进行拦截验证。

@WebFilter("/*")
public class AuthenticationFilter 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().substring(httpRequest.getContextPath().length());
        
        // 公开访问路径
        if (path.startsWith("/login") || path.startsWith("/static/")) {
            chain.doFilter(request, response);
            return;
        }
        
        // 检查用户是否登录
        if (session == null || session.getAttribute("currentUser") == null) {
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
            return;
        }
        
        User currentUser = (User) session.getAttribute("currentUser");
        
        // 基于角色的权限验证
        if (!hasPermission(currentUser, path)) {
            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    private boolean hasPermission(User user, String path) {
        // 实现基于路径和角色的权限验证逻辑
        return true;
    }
}

教材信息管理模块

教材信息管理提供完整的CRUD操作,支持教材基本信息、库存状态、供应商信息的维护。管理员可以添加新教材、更新库存信息、设置采购参数等。

@WebServlet("/textbook/*")
public class TextbookServlet extends HttpServlet {
    private TextbookDAO textbookDAO = new TextbookDAO();
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        String action = request.getPathInfo();
        
        switch (action) {
            case "/add":
                addTextbook(request, response);
                break;
            case "/update":
                updateTextbook(request, response);
                break;
            case "/delete":
                deleteTextbook(request, response);
                break;
            default:
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
    
    private void addTextbook(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        try {
            Textbook textbook = new Textbook();
            textbook.setIsbn(request.getParameter("isbn"));
            textbook.setBookName(request.getParameter("bookName"));
            textbook.setAuthor(request.getParameter("author"));
            textbook.setPublisher(request.getParameter("publisher"));
            textbook.setEdition(request.getParameter("edition"));
            textbook.setPrice(new BigDecimal(request.getParameter("price")));
            textbook.setSupplierId(Integer.parseInt(request.getParameter("supplierId")));
            
            textbookDAO.addTextbook(textbook);
            
            request.setAttribute("message", "教材添加成功");
            request.getRequestDispatcher("/textbook/list.jsp").forward(request, response);
        } catch (Exception e) {
            request.setAttribute("error", "添加教材失败: " + e.getMessage());
            request.getRequestDispatcher("/textbook/add.jsp").forward(request, response);
        }
    }
}

教材信息管理

采购订单审批工作流

采购订单审批是系统的核心业务流程,包含教师提交采购申请、管理员审批、供应商分配、订单执行状态跟踪等环节。系统通过状态机模式管理订单生命周期。

public class OrderService {
    private OrderDAO orderDAO = new OrderDAO();
    
    public void approveOrder(int orderId, int approverId, String comments) {
        Connection conn = null;
        try {
            conn = DatabaseUtil.getConnection();
            conn.setAutoCommit(false);
            
            // 获取订单当前状态
            PurchaseOrder order = orderDAO.getOrderById(orderId);
            if (!"pending".equals(order.getOrderStatus())) {
                throw new IllegalStateException("订单状态不正确,无法审批");
            }
            
            // 更新订单状态
            orderDAO.updateOrderStatus(orderId, "approved", approverId, comments);
            
            // 记录审批日志
            AuditLogService.logApproval(approverId, orderId, "approved", comments);
            
            // 触发库存预占操作
            InventoryService.reserveInventory(order.getBookId(), order.getQuantity());
            
            conn.commit();
        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            throw new RuntimeException("审批操作失败", e);
        } finally {
            DatabaseUtil.closeConnection(conn);
        }
    }
}

购物车与订单生成

教师和学生用户可以将所需教材加入购物车,系统支持批量生成采购订单。购物车数据存储在Session中,确保用户操作的连贯性。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>购物车</title>
</head>
<body>
    <h2>我的购物车</h2>
    <c:if test="${not empty cartItems}">
        <table border="1">
            <tr>
                <th>教材名称</th>
                <th>作者</th>
                <th>出版社</th>
                <th>单价</th>
                <th>数量</th>
                <th>小计</th>
                <th>操作</th>
            </tr>
            <c:forEach var="item" items="${cartItems}">
                <tr>
                    <td>${item.textbook.bookName}</td>
                    <td>${item.textbook.author}</td>
                    <td>${item.textbook.publisher}</td>
                    <td>¥${item.textbook.price}</td>
                    <td>
                        <input type="number" name="quantity" value="${item.quantity}" 
                               min="1" onchange="updateQuantity(${item.textbook.bookId}, this.value)">
                    </td>
                    <td>¥${item.textbook.price * item.quantity}</td>
                    <td>
                        <button onclick="removeFromCart(${item.textbook.bookId})">删除</button>
                    </td>
                </tr>
            </c:forEach>
        </table>
        <div>总金额: ¥${totalAmount}</div>
        <button onclick="submitOrder()">提交采购申请</button>
    </c:if>
</body>
</html>

查看购物车

数据访问层设计

系统采用DAO模式封装所有数据库操作,提供统一的数据访问接口。BaseDAO抽象类封装了通用的CRUD操作方法,各实体DAO继承基类并实现特定业务逻辑。

public abstract class BaseDAO<T> {
    protected Connection getConnection() throws SQLException {
        return DatabaseUtil.getConnection();
    }
    
    protected List<T> executeQuery(String sql, ResultSetHandler<T> handler, Object... params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            
            rs = pstmt.executeQuery();
            return handler.handle(rs);
        } catch (SQLException e) {
            throw new RuntimeException("数据库查询失败", e);
        } finally {
            DatabaseUtil.closeResultSet(rs);
            DatabaseUtil.closeStatement(pstmt);
            DatabaseUtil.closeConnection(conn);
        }
    }
    
    protected int executeUpdate(String sql, Object... params) {
        // 实现更新操作
    }
}

public class TextbookDAO extends BaseDAO<Textbook> {
    private static final String INSERT_SQL = "INSERT INTO textbook " +
            "(isbn, book_name, author, publisher, edition, price, supplier_id) " +
            "VALUES (?, ?, ?, ?, ?, ?, ?)";
    
    public void addTextbook(Textbook textbook) {
        executeUpdate(INSERT_SQL, 
            textbook.getIsbn(), textbook.getBookName(), textbook.getAuthor(),
            textbook.getPublisher(), textbook.getEdition(), textbook.getPrice(),
            textbook.getSupplierId());
    }
    
    public Textbook getTextbookById(int bookId) {
        String sql = "SELECT * FROM textbook WHERE book_id = ?";
        List<Textbook> result = executeQuery(sql, new TextbookResultSetHandler(), bookId);
        return result.isEmpty() ? null : result.get(0);
    }
}

库存管理机制

库存管理模块实现实时库存跟踪、安全库存预警、库存调整记录等功能。系统通过触发器自动更新库存数量,确保数据的一致性。

DELIMITER $$
CREATE TRIGGER update_inventory_after_order_completion
AFTER UPDATE ON purchase_order
FOR EACH ROW
BEGIN
    IF NEW.order_status = 'completed' AND OLD.order_status != 'completed' THEN
        UPDATE inventory 
        SET current_stock = current_stock + NEW.quantity,
            last_restock_date = NEW.actual_delivery_date
        WHERE book_id = NEW.book_id;
    END IF;
END$$
DELIMITER ;

库存管理界面

系统优化与扩展方向

性能优化策略

  1. 数据库查询优化:对频繁查询的字段建立复合索引,如订单状态+创建时间的组合索引,提升查询性能
  2. 连接池配置:使用DBCP或HikariCP连接池管理数据库连接,减少连接创建开销
  3. 页面静态化:对教材目录等相对静态的内容生成静态页面,降低服务器压力

功能扩展建议

  1. 移动端适配:开发响应式界面或独立的移动应用,支持教师通过手机提交采购申请
  2. 供应商门户:为教材供应商提供外部接入接口,支持订单状态查询和发货信息回传
  3. 智能推荐:基于历史采购数据和课程信息,智能推荐合适的教材版本和供应商

技术架构升级

  1. 框架迁移:考虑从原生Servlet向Spring Boot框架迁移,获得更好的开发效率和生态支持
  2. 缓存集成:引入Redis缓存热点数据,如教材信息、用户权限数据等
  3. 异步处理:使用消息队列处理耗时的操作,如邮件通知、报表生成等

该系统通过严谨的架构设计和完整的业务功能实现,为高校教材采购管理提供了可靠的数字化解决方案。模块化的设计使得系统具有良好的可维护性和扩展性,为后续的功能增强和技术升级奠定了坚实基础。

本文关键词
JSPServlet教材采购管理系统源码解析数据库设计

上下篇

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