仓储管理作为企业供应链的核心环节,其效率直接影响到企业的运营成本与客户满意度。针对中小型企业在仓储管理中普遍存在的信息记录混乱、库存数据更新滞后、人工操作效率低下等痛点,本文介绍了一套基于SSH(Struts2 + Spring + Hibernate)整合框架开发的智能仓储管理平台。该系统通过数字化的业务流程,实现了实物库存与信息流的高度统一,为企业提供准确的库存视图和完整的操作追溯能力。
系统架构与技术栈
该平台采用经典的三层架构设计,严格分离表现层、业务逻辑层和数据持久层。表现层基于Struts2框架构建,通过配置struts.xml文件定义前端请求与后端Action方法的映射关系。Struts2的拦截器机制实现了统一的权限验证和操作日志记录,确保系统的安全性和可审计性。
业务逻辑层由Spring框架的IoC容器负责管理,通过依赖注入(DI)将各个Service组件及DAO层对象进行组装。事务管理采用Spring的声明式事务配置,在Service层实现,保证了业务操作的原子性。这种设计使得业务逻辑组件之间的耦合度降到最低,提高了代码的可测试性和可维护性。
数据持久层基于Hibernate ORM框架实现,通过实体类的映射文件将Java对象与数据库表关联。Hibernate的HQL语言以及Criteria查询API简化了复杂的数据检索操作,避免了手写繁琐的SQL语句。同时,Hibernate的一级缓存和二级缓存机制有效提升了数据访问性能。
数据库设计亮点分析
系统数据库包含7个核心表,设计合理,关系清晰。以下重点分析几个关键表的设计:
商品信息表(product)的设计体现了完整的库存管理需求:
CREATE TABLE `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(100) NOT NULL,
`product_model` varchar(50) DEFAULT NULL,
`unit` varchar(10) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`stock_quantity` int(11) DEFAULT '0',
`remark` varchar(500) DEFAULT NULL,
`category_id` int(11) DEFAULT NULL,
`manufacturer_id` int(11) DEFAULT NULL,
PRIMARY KEY (`product_id`),
KEY `fk_product_category` (`category_id`),
KEY `fk_product_manufacturer` (`manufacturer_id`),
CONSTRAINT `fk_product_category` FOREIGN KEY (`category_id`)
REFERENCES `product_category` (`category_id`),
CONSTRAINT `fk_product_manufacturer` FOREIGN KEY (`manufacturer_id`)
REFERENCES `manufacturer` (`manufacturer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该表设计包含商品基本属性、库存数量、价格信息,并通过外键关联商品分类和制造商表。stock_quantity字段实时反映当前库存数量,为库存预警和补货决策提供数据支持。价格字段采用decimal(10,2)类型,确保金额计算的精确性。
入库记录表(stock_in)的设计支持完整的入库流程追踪:
CREATE TABLE `stock_in` (
`in_id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`in_quantity` int(11) NOT NULL,
`in_date` datetime NOT NULL,
`handler` varchar(50) NOT NULL,
`remark` varchar(500) DEFAULT NULL,
`purchase_id` int(11) DEFAULT NULL,
PRIMARY KEY (`in_id`),
KEY `fk_stockin_product` (`product_id`),
KEY `fk_stockin_purchase` (`purchase_id`),
CONSTRAINT `fk_stockin_product` FOREIGN KEY (`product_id`)
REFERENCES `product` (`product_id`),
CONSTRAINT `fk_stockin_purchase` FOREIGN KEY (`purchase_id`)
REFERENCES `purchase` (`purchase_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该表记录了每次入库的详细信息,包括入库商品、数量、时间、经手人等,并与采购记录关联,实现了从采购到入库的完整链路追踪。时间戳字段为库存周转率分析提供了数据基础。
核心功能实现深度解析
商品信息管理模块
商品管理作为系统的基础模块,实现了商品的增删改查、分类管理和库存监控功能。通过Struts2的Action类处理前端请求,Spring Service层实现业务逻辑,Hibernate完成数据持久化。
商品查询功能的Service层实现:
@Service("productService")
@Transactional
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDAO productDAO;
@Override
public List<Product> findProductsByCriteria(String productName,
Integer categoryId,
Integer manufacturerId) {
DetachedCriteria criteria = DetachedCriteria.forClass(Product.class);
if (StringUtils.isNotBlank(productName)) {
criteria.add(Restrictions.like("productName", "%" + productName + "%"));
}
if (categoryId != null && categoryId > 0) {
criteria.add(Restrictions.eq("category.categoryId", categoryId));
}
if (manufacturerId != null && manufacturerId > 0) {
criteria.add(Restrictions.eq("manufacturer.manufacturerId", manufacturerId));
}
criteria.addOrder(Order.asc("productName"));
return productDAO.findByCriteria(criteria);
}
@Override
public Product getProductWithDetails(Integer productId) {
Product product = productDAO.findById(productId);
// 初始化懒加载关联对象
Hibernate.initialize(product.getCategory());
Hibernate.initialize(product.getManufacturer());
return product;
}
}
该服务方法利用Hibernate的Criteria API构建动态查询条件,支持按商品名称、分类、制造商等多条件组合查询。@Transactional注解确保方法在事务环境中执行,保证数据一致性。

采购入库流程实现
采购入库模块实现了从采购计划到实物入库的完整业务流程。系统通过工作流方式确保每个环节的数据准确性和操作规范性。
入库操作的Action控制类:
public class StockInAction extends ActionSupport {
private StockIn stockIn;
private List<Product> productList;
private StockInService stockInService;
private ProductService productService;
// 准备入库页面数据
public String prepareStockIn() {
productList = productService.findAllActiveProducts();
return SUCCESS;
}
// 执行入库操作
public String executeStockIn() {
try {
// 验证入库数量
if (stockIn.getInQuantity() <= 0) {
addActionError("入库数量必须大于0");
return INPUT;
}
// 设置入库时间
stockIn.setInDate(new Date());
// 调用服务层完成入库
stockInService.processStockIn(stockIn);
addActionMessage("入库操作成功完成");
return SUCCESS;
} catch (Exception e) {
addActionError("入库操作失败: " + e.getMessage());
return ERROR;
}
}
// Getter和Setter方法
public StockIn getStockIn() { return stockIn; }
public void setStockIn(StockIn stockIn) { this.stockIn = stockIn; }
@Autowired
public void setStockInService(StockInService stockInService) {
this.stockInService = stockInService;
}
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
}
该Action类通过Spring的依赖注入获取服务层实例,实现了入库操作的完整控制流程。输入验证、业务处理、异常处理等环节都得到了妥善处理。
入库服务的核心业务逻辑:
@Service("stockInService")
@Transactional
public class StockInServiceImpl implements StockInService {
@Autowired
private StockInDAO stockInDAO;
@Autowired
private ProductDAO productDAO;
@Override
public void processStockIn(StockIn stockIn) {
// 1. 保存入库记录
stockInDAO.save(stockIn);
// 2. 更新商品库存数量
Product product = productDAO.findById(stockIn.getProduct().getProductId());
int newQuantity = product.getStockQuantity() + stockIn.getInQuantity();
product.setStockQuantity(newQuantity);
productDAO.update(product);
// 3. 记录操作日志
logStockInOperation(stockIn, product);
}
private void logStockInOperation(StockIn stockIn, Product product) {
// 记录详细的入库日志,用于审计和追溯
SystemLogger.info("入库操作: 商品[" + product.getProductName() +
"], 数量[" + stockIn.getInQuantity() +
"], 操作人[" + stockIn.getHandler() + "]");
}
}
该服务方法在@Transactional注解的保护下,确保入库记录保存和库存数量更新这两个操作要么全部成功,要么全部回滚,保证了数据的原子性。

出库发货管理
出库管理模块处理销售出库、调拨出库等多种出库类型,确保库存数据的实时准确更新。
出库验证与库存扣减逻辑:
@Service("shipmentService")
@Transactional
public class ShipmentServiceImpl implements ShipmentService {
@Override
public ShipmentResult processShipment(Shipment shipment) {
ShipmentResult result = new ShipmentResult();
try {
// 验证库存充足性
Product product = productDAO.findById(shipment.getProduct().getProductId());
if (product.getStockQuantity() < shipment.getShipQuantity()) {
result.setSuccess(false);
result.setMessage("库存不足,当前库存: " + product.getStockQuantity());
return result;
}
// 执行出库操作
executeShipment(shipment, product);
result.setSuccess(true);
result.setMessage("出库操作成功完成");
} catch (Exception e) {
result.setSuccess(false);
result.setMessage("出库操作失败: " + e.getMessage());
// 事务将自动回滚
}
return result;
}
private void executeShipment(Shipment shipment, Product product) {
// 保存出库记录
shipment.setShipDate(new Date());
shipmentDAO.save(shipment);
// 扣减库存
int newQuantity = product.getStockQuantity() - shipment.getShipQuantity();
product.setStockQuantity(newQuantity);
productDAO.update(product);
// 库存预警检查
checkStockWarning(product);
}
}
出库操作首先进行库存验证,防止超卖情况发生。库存扣减后自动触发库存预警检查,为库存补货提供及时提醒。

用户权限管理
系统采用基于角色的访问控制(RBAC)模型,不同的用户角色拥有不同的操作权限。
用户权限验证拦截器:
public class AuthorizationInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// 获取当前Action的注解信息
Class<?> actionClass = invocation.getAction().getClass();
PermissionRequired permission = actionClass.getAnnotation(PermissionRequired.class);
if (permission != null) {
// 从Session中获取当前用户信息
User currentUser = (User) invocation.getInvocationContext()
.getSession().get("currentUser");
if (currentUser == null) {
return "login"; // 跳转到登录页面
}
// 检查用户权限
if (!hasPermission(currentUser, permission.value())) {
return "unauthorized"; // 权限不足页面
}
}
return invocation.invoke();
}
private boolean hasPermission(User user, String requiredPermission) {
// 检查用户角色是否包含所需权限
return user.getRole().getPermissions()
.stream()
.anyMatch(p -> p.getPermissionCode().equals(requiredPermission));
}
}
该拦截器在每次Action执行前进行权限验证,确保只有授权用户才能访问相应功能。通过注解方式声明权限要求,使权限控制更加灵活和精确。

实体模型与数据持久化
系统采用面向对象的领域模型设计,通过Hibernate实现对象关系映射。每个实体类对应数据库中的一张表,实体之间的关系通过关联映射实现。
商品实体类的Hibernate映射配置:
<hibernate-mapping>
<class name="com.warehouse.entity.Product" table="product">
<id name="productId" column="product_id" type="integer">
<generator class="identity"/>
</id>
<property name="productName" column="product_name"
type="string" length="100" not-null="true"/>
<property name="productModel" column="product_model"
type="string" length="50"/>
<property name="unit" column="unit" type="string" length="10"/>
<property name="price" column="price" type="big_decimal"/>
<property name="stockQuantity" column="stock_quantity"
type="integer" not-null="true"/>
<property name="remark" column="remark" type="string" length="500"/>
<!-- 多对一关联:商品分类 -->
<many-to-one name="category" column="category_id"
class="com.warehouse.entity.ProductCategory"
not-null="false" lazy="false"/>
<!-- 多对一关联:制造商 -->
<many-to-one name="manufacturer" column="manufacturer_id"
class="com.warehouse.entity.Manufacturer"
not-null="false" lazy="false"/>
<!-- 一对多关联:入库记录 -->
<set name="stockInRecords" inverse="true" lazy="true">
<key column="product_id"/>
<one-to-many class="com.warehouse.entity.StockIn"/>
</set>
<!-- 一对多关联:出库记录 -->
<set name="shipmentRecords" inverse="true" lazy="true">
<key column="product_id"/>
<one-to-many class="com.warehouse.entity.Shipment"/>
</set>
</class>
</hibernate-mapping>
该映射配置定义了商品实体的完整属性映射和关联关系。通过lazy属性控制关联对象的加载策略,在保证性能的同时满足不同的数据访问需求。
基于Hibernate的通用DAO实现:
@Repository
public class BaseDAOImpl<T> implements BaseDAO<T> {
@Autowired
private SessionFactory sessionFactory;
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
@Override
public T findById(Serializable id, Class<T> entityClass) {
return (T) getCurrentSession().get(entityClass, id);
}
@Override
public List<T> findAll(Class<T> entityClass) {
Criteria criteria = getCurrentSession().createCriteria(entityClass);
criteria.addOrder(Order.asc("id"));
return criteria.list();
}
@Override
public void save(T entity) {
getCurrentSession().saveOrUpdate(entity);
}
@Override
public void delete(T entity) {
getCurrentSession().delete(entity);
}
@Override
public List<T> findByCriteria(DetachedCriteria criteria) {
Criteria executableCriteria = criteria.getExecutableCriteria(getCurrentSession());
return executableCriteria.list();
}
}
该通用DAO基类封装了常用的数据访问操作,提供了类型安全的数据访问接口。通过泛型技术实现了代码的重用,减少了重复的DAO实现代码。
系统配置与集成
系统的整体配置通过Spring的ApplicationContext统一管理,各层组件通过依赖注入方式组装。
Spring应用上下文的核心配置:
<beans xmlns="http://www.springframework.org/schema/beans">
<!-- 数据源配置 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/warehouse_db"/>
<property name="username" value="warehouse_user"/>
<property name="password" value="warehouse_pass"/>
<property name="initialSize" value="5"/>
<property name="maxActive" value="20"/>
</bean>
<!-- SessionFactory配置 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>com/warehouse/entity/Product.hbm.xml</value>
<value>com/warehouse/entity/StockIn.hbm.xml</value>
<!-- 其他实体映射文件 -->
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 事务管理器配置 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 声明式事务配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*"