基于JSP+Servlet的供应链管理及仓储系统 - 源码深度解析

JavaScriptHTMLCSSMySQLJSP+Servlet
2026-03-183 浏览

文章摘要

本项目是一款基于JSP与Servlet技术构建的供应链管理及仓储系统,旨在解决传统供应链环节中信息流通不畅、数据更新滞后、库存与销售难以实时联动等核心痛点。系统通过整合供货管理与销售存储两大关键业务,为企业提供从采购入库到销售出库的全流程数字化管理能力,核心业务价值在于显著降低人工记录错误率、提升库...

在传统供应链管理领域,信息流通不畅、数据更新滞后以及库存与销售环节脱节是长期存在的痛点。企业往往依赖纸质单据和分散的Excel表格,导致数据一致性差、响应速度慢、决策依据不足。针对这些问题,一套集成化的供应链与仓储管理系统显得尤为重要。本文介绍的系统正是基于JSP与Servlet技术栈构建的“智链云仓”平台,旨在实现从采购、入库到销售、出库的全流程数字化管控。

系统采用经典的三层MVC架构,前端使用JSP负责视图渲染,Servlet作为控制器处理业务请求,JavaBean封装数据模型,并通过JDBC与MySQL数据库进行交互。这种架构清晰地将表示层、业务逻辑层和数据持久层分离,提高了代码的可维护性和可扩展性。系统支持多角色操作,包括系统管理员、采购专员、仓库管理员和销售人员,各角色根据权限访问不同功能模块。

数据库设计亮点

数据库设计是系统稳定性的基石。系统共设计了10张核心数据表,涵盖了用户、产品、库存、供应商、采购订单、销售记录等关键实体。以下重点分析几个核心表的设计思路。

用户表(user)的设计体现了权限管理的精细化:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `real_name` varchar(50) DEFAULT NULL,
  `role` enum('admin','purchaser','warehouse','sales') NOT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `status` tinyint(1) DEFAULT '1',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username_unique` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

该表通过role字段的枚举类型明确区分四种系统角色,status字段支持账户的启用/禁用状态管理,create_time自动记录用户创建时间。唯一索引username_unique确保了用户名的唯一性,为系统安全提供了基础保障。

库存表(inventory)的设计实现了库存变化的精准追踪:

CREATE TABLE `inventory` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL,
  `warehouse_id` int(11) NOT NULL,
  `quantity` int(11) NOT NULL DEFAULT '0',
  `safe_stock` int(11) NOT NULL DEFAULT '0',
  `last_updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `product_warehouse_unique` (`product_id`, `warehouse_id`),
  FOREIGN KEY (`product_id`) REFERENCES `product`(`id`),
  FOREIGN KEY (`warehouse_id`) REFERENCES `warehouse`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

该表通过product_idwarehouse_id的联合唯一索引,确保同一产品在同一仓库中只有一条库存记录。safe_stock字段设置了安全库存阈值,为库存预警功能提供数据支持。last_updated字段在每次更新时自动记录时间戳,便于追踪库存变化历史。外键约束保证了数据的一致性和完整性。

采购订单表(purchase_order)的设计支持完整的采购流程管理:

CREATE TABLE `purchase_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_number` varchar(50) NOT NULL,
  `supplier_id` int(11) NOT NULL,
  `total_amount` decimal(10,2) NOT NULL,
  `status` enum('pending','approved','rejected','completed') DEFAULT 'pending',
  `created_by` int(11) NOT NULL,
  `created_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `approved_by` int(11) DEFAULT NULL,
  `approved_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `order_number_unique` (`order_number`),
  FOREIGN KEY (`supplier_id`) REFERENCES `supplier`(`id`),
  FOREIGN KEY (`created_by`) REFERENCES `user`(`id`),
  FOREIGN KEY (`approved_by`) REFERENCES `user`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

该表通过status字段完整跟踪采购订单的生命周期,从待审批到已完成的全流程状态管理。created_byapproved_by分别记录创建人和审批人,结合时间戳字段,实现了操作痕迹的全记录,为审计提供了完整的数据支撑。

核心功能实现深度解析

1. 用户登录与权限验证

系统采用基于角色的访问控制机制,用户登录后,系统根据其角色权限动态加载对应的功能菜单。登录验证Servlet负责处理认证逻辑:

@WebServlet("/login")
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");
        
        UserService userService = new UserService();
        User user = userService.authenticate(username, password);
        
        if (user != null && user.getStatus() == 1) {
            HttpSession session = request.getSession();
            session.setAttribute("currentUser", user);
            session.setMaxInactiveInterval(30 * 60); // 30分钟超时
            
            // 根据角色跳转到不同首页
            String redirectUrl = getRedirectUrlByRole(user.getRole());
            response.sendRedirect(redirectUrl);
        } else {
            request.setAttribute("errorMsg", "用户名或密码错误,或账户已被禁用");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
    
    private String getRedirectUrlByRole(String role) {
        switch (role) {
            case "admin": return "/admin/dashboard.jsp";
            case "purchaser": return "/purchaser/dashboard.jsp";
            case "warehouse": return "/warehouse/dashboard.jsp";
            case "sales": return "/sales/dashboard.jsp";
            default: return "/login.jsp";
        }
    }
}

管理员登录界面

2. 产品信息管理

产品管理模块支持产品的增删改查、分类管理和库存状态查看。产品列表查询Servlet展示了复杂的数据查询和分页处理:

@WebServlet("/product/list")
public class ProductListServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        int page = 1;
        int pageSize = 10;
        String keyword = request.getParameter("keyword");
        String categoryId = request.getParameter("categoryId");
        
        try {
            page = Integer.parseInt(request.getParameter("page"));
        } catch (NumberFormatException e) {
            // 使用默认值
        }
        
        ProductService productService = new ProductService();
        PageResult<ProductVO> pageResult = productService.getProducts(page, pageSize, keyword, categoryId);
        
        // 获取分类列表用于筛选
        CategoryService categoryService = new CategoryService();
        List<Category> categories = categoryService.getAllCategories();
        
        request.setAttribute("pageResult", pageResult);
        request.setAttribute("categories", categories);
        request.setAttribute("keyword", keyword);
        request.setAttribute("categoryId", categoryId);
        
        request.getRequestDispatcher("/admin/product-list.jsp").forward(request, response);
    }
}

对应的JSP页面使用JSTL和EL表达式渲染产品列表:

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table class="table table-striped">
    <thead>
        <tr>
            <th>产品编号</th>
            <th>产品名称</th>
            <th>分类</th>
            <th>单位</th>
            <th>采购价</th>
            <th>销售价</th>
            <th>库存数量</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        <c:forEach items="${pageResult.data}" var="product">
            <tr>
                <td>${product.productCode}</td>
                <td>${product.productName}</td>
                <td>${product.categoryName}</td>
                <td>${product.unitName}</td>
                <td>¥${product.purchasePrice}</td>
                <td>¥${product.salePrice}</td>
                <td>
                    <span class="badge ${product.totalStock < product.safeStock ? 'badge-warning' : 'badge-success'}">
                        ${product.totalStock}
                    </span>
                </td>
                <td>
                    <a href="/product/edit?id=${product.id}" class="btn btn-sm btn-primary">编辑</a>
                    <a href="/product/delete?id=${product.id}" class="btn btn-sm btn-danger" 
                       onclick="return confirm('确定删除该产品吗?')">删除</a>
                </td>
            </tr>
        </c:forEach>
    </tbody>
</table>

<!-- 分页控件 -->
<nav>
    <ul class="pagination">
        <c:forEach begin="1" end="${pageResult.totalPages}" var="i">
            <li class="page-item ${i == pageResult.currentPage ? 'active' : ''}">
                <a class="page-link" href="?page=${i}&keyword=${param.keyword}&categoryId=${param.categoryId}">${i}</a>
            </li>
        </c:forEach>
    </ul>
</nav>

产品管理界面

3. 采购订单管理

采购订单模块实现了从创建、审批到入库的完整业务流程。订单创建Servlet处理复杂的表单数据和业务逻辑:

@WebServlet("/purchase/create")
public class PurchaseCreateServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 获取当前登录用户
        HttpSession session = request.getSession();
        User currentUser = (User) session.getAttribute("currentUser");
        
        if (currentUser == null || !"purchaser".equals(currentUser.getRole())) {
            response.sendError(403, "权限不足");
            return;
        }
        
        try {
            String supplierId = request.getParameter("supplierId");
            String remark = request.getParameter("remark");
            
            // 解析订单项数据
            String[] productIds = request.getParameterValues("productId");
            String[] quantities = request.getParameterValues("quantity");
            String[] prices = request.getParameterValues("price");
            
            List<PurchaseOrderItem> items = new ArrayList<>();
            BigDecimal totalAmount = BigDecimal.ZERO;
            
            for (int i = 0; i < productIds.length; i++) {
                int productId = Integer.parseInt(productIds[i]);
                int quantity = Integer.parseInt(quantities[i]);
                BigDecimal price = new BigDecimal(prices[i]);
                
                PurchaseOrderItem item = new PurchaseOrderItem();
                item.setProductId(productId);
                item.setQuantity(quantity);
                item.setUnitPrice(price);
                item.setTotalPrice(price.multiply(BigDecimal.valueOf(quantity)));
                
                items.add(item);
                totalAmount = totalAmount.add(item.getTotalPrice());
            }
            
            // 生成订单号
            String orderNumber = "PO" + System.currentTimeMillis();
            
            // 创建采购订单
            PurchaseOrderService orderService = new PurchaseOrderService();
            boolean success = orderService.createPurchaseOrder(orderNumber, 
                    Integer.parseInt(supplierId), totalAmount, remark, currentUser.getId(), items);
            
            if (success) {
                response.sendRedirect("/purchase/list?msg=create_success");
            } else {
                request.setAttribute("errorMsg", "创建采购订单失败");
                request.getRequestDispatcher("/purchaser/purchase-create.jsp").forward(request, response);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("errorMsg", "系统错误:" + e.getMessage());
            request.getRequestDispatcher("/purchaser/purchase-create.jsp").forward(request, response);
        }
    }
}

4. 库存预警与自动提醒

系统通过定时任务检查库存状态,当库存低于安全阈值时自动触发预警机制:

@Component
public class InventoryAlertService {
    private static final Logger logger = LoggerFactory.getLogger(InventoryAlertService.class);
    
    public void checkLowStockAlert() {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseUtil.getConnection();
            String sql = "SELECT p.product_name, i.quantity, i.safe_stock, w.warehouse_name " +
                       "FROM inventory i " +
                       "JOIN product p ON i.product_id = p.id " +
                       "JOIN warehouse w ON i.warehouse_id = w.id " +
                       "WHERE i.quantity <= i.safe_stock AND p.status = 1";
            
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            
            List<LowStockAlert> alerts = new ArrayList<>();
            while (rs.next()) {
                LowStockAlert alert = new LowStockAlert();
                alert.setProductName(rs.getString("product_name"));
                alert.setCurrentStock(rs.getInt("quantity"));
                alert.setSafeStock(rs.getInt("safe_stock"));
                alert.setWarehouseName(rs.getString("warehouse_name"));
                alerts.add(alert);
            }
            
            if (!alerts.isEmpty()) {
                sendAlertNotification(alerts);
                logger.warn("发现 {} 个产品库存低于安全阈值", alerts.size());
            }
            
        } catch (SQLException e) {
            logger.error("库存预警检查失败", e);
        } finally {
            DatabaseUtil.close(conn, pstmt, rs);
        }
    }
    
    private void sendAlertNotification(List<LowStockAlert> alerts) {
        // 实现邮件、短信或系统内消息通知
        // 这里可以集成消息队列进行异步处理
    }
}

库存管理界面

5. 销售出库与库存同步

销售模块确保出库操作与库存数据的实时同步,避免超卖情况:

@WebServlet("/sale/checkout")
public class SaleCheckoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 使用事务确保数据一致性
        Connection conn = null;
        try {
            conn = DatabaseUtil.getConnection();
            conn.setAutoCommit(false); // 开启事务
            
            // 解析销售数据
            SaleDTO saleData = parseSaleData(request);
            
            // 检查库存是否充足
            if (!checkInventorySufficient(conn, saleData.getItems())) {
                throw new Exception("库存不足,无法完成销售");
            }
            
            // 生成销售单
            String saleNumber = generateSaleNumber();
            int saleId = createSaleOrder(conn, saleNumber, saleData);
            
            // 扣减库存
            for (SaleItem item : saleData.getItems()) {
                deductInventory(conn, item.getProductId(), item.getQuantity());
            }
            
            // 记录销售明细
            createSaleItems(conn, saleId, saleData.getItems());
            
            conn.commit(); // 提交事务
            
            // 返回成功响应
            response.getWriter().write("{\"success\":true,\"saleNumber\":\"" + saleNumber + "\"}");
            
        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.rollback(); // 回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            response.getWriter().write("{\"success\":false,\"message\":\"" + e.getMessage() + "\"}");
        } finally {
            DatabaseUtil.close(conn);
        }
    }
}

实体模型与业务逻辑

系统通过精心设计的JavaBean实体类来映射业务对象,每个实体类都封装了相应的属性和业务方法:

public class Product {
    private Integer id;
    private String productCode;
    private String productName;
    private Integer categoryId;
    private Integer unitId;
    private BigDecimal purchasePrice;
    private BigDecimal salePrice;
    private String description;
    private Integer status;
    private Date createTime;
    
    // 关联对象
    private String categoryName;
    private String unitName;
    private Integer totalStock;
    private Integer safeStock;
    
    // 构造方法、getter、setter省略
}

public class PurchaseOrder {
    private Integer id;
    private String orderNumber;
    private Integer supplierId;
    private BigDecimal totalAmount;
    private String status;
    private Integer createdBy;
    private Date createdTime;
    private Integer approvedBy;
    private Date approvedTime;
    private String remark;
    
    // 关联数据
    private String supplierName;
    private String creatorName;
    private String approverName;
    private List<PurchaseOrderItem> items;
    
    public boolean canBeApproved() {
        return "pending".equals(this.status);
    }
    
    public boolean canBeCompleted() {
        return "approved".equals(this.status);
    }
}

功能展望与优化方向

  1. 移动端支持:开发基于React Native或Flutter的移动应用,支持仓库管理人员通过手机进行扫码入库、库存盘点等操作。移动端可与现有系统通过RESTful API进行数据交互。

  2. 数据分析与报表增强:集成Apache Superset或Metabase等BI工具,提供更丰富的库存周转率分析、销售趋势预测、供应商绩效评估等高级分析功能。

  3. 物联网集成:通过RFID技术实现货物的自动识别和追踪,与温湿度传感器集成实现冷链仓储的智能监控,提升仓储管理的自动化水平。

  4. 微服务架构改造:将单体应用拆分为用户服务、产品服务、库存服务、订单服务等微服务,采用Spring Cloud生态实现服务治理,提高系统的可伸缩性和可维护性。

  5. 供应链金融集成:与银行或第三方金融平台对接,实现基于真实贸易数据的供应链金融服务,如应收账款融资、库存质押等,拓展系统的商业价值。

系统在安全性方面还可进一步加强,如增加操作日志审计、数据加密

本文关键词
JSPServlet供应链管理仓储系统源码解析

上下篇

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