在现代企业运营中,库存管理作为供应链的核心环节,其效率直接影响企业的资金周转率和市场响应速度。传统的手工记录或简单电子表格方式已无法满足日益复杂的仓储需求,数据孤岛、信息滞后和操作错误等问题频发。针对这一痛点,我们设计并实现了一套企业级智能仓储管理平台,该系统基于成熟的SSM(Spring+Spring MVC+MyBatis)技术栈构建,通过信息化的手段为企业提供全方位的库存管控解决方案。
系统架构与技术栈选型
该平台采用经典的三层架构模式,严格遵循MVC设计原则。表现层使用Spring MVC框架处理前端请求与页面渲染,通过注解驱动的控制器实现请求路由和参数绑定。业务逻辑层由Spring框架的IoC容器统一管理服务组件,利用依赖注入实现模块解耦,并通过声明式事务管理确保数据一致性。数据持久层选用轻量级的MyBatis框架,通过XML映射文件实现对象关系映射,支持动态SQL满足复杂查询需求。
技术栈配置如下:
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!-- MyBatis集成 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- 权限管理 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
系统监控模块通过自定义健康检查端点实时收集运行指标,包括数据库连接池状态、服务响应时间等关键数据,为系统运维提供可视化支持。
数据库设计亮点分析
商品信息表(product)的设计优化
product表作为系统的核心数据载体,其设计体现了多方面的优化考虑:
CREATE TABLE `product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`type` bigint(20) DEFAULT NULL COMMENT '分类',
`xh` varchar(255) DEFAULT NULL COMMENT '型号',
`img` varchar(255) DEFAULT NULL COMMENT '图片',
`price` double(10,2) DEFAULT NULL COMMENT '进价',
`sale` double(10,2) DEFAULT NULL COMMENT '卖价',
`num` double(10,2) DEFAULT NULL COMMENT '库存',
`gmtTime` datetime DEFAULT NULL COMMENT '添加时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品信息'
设计亮点分析:
字段类型精准选择:库存数量(num)、进价(price)、卖价(sale)均采用double(10,2)类型,支持小数点后两位精度,满足金融计算要求。bigint(20)用于主键和分类字段,确保大规模数据下的ID唯一性。
索引策略优化:虽然没有显式定义外键索引,但通过type字段与商品分类表的关联,在实际查询中会建立适当的索引来提升联表查询性能。gmtTime字段为日期范围查询提供了时间维度筛选能力。
扩展性考虑:img字段存储商品图片路径,采用varchar(255)长度,支持相对路径和绝对路径存储。xh(型号)字段的设计允许同一商品存在不同规格变体,增强了商品管理的灵活性。

权限管理系统表设计
权限控制采用经典的RBAC(基于角色的访问控制)模型,通过sys_user_role、sys_role_menu、sys_menu三张表实现精细化的权限管理:
CREATE TABLE `sys_role_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
`menu_id` bigint(20) DEFAULT NULL COMMENT '菜单ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='角色与菜单对应关系'
CREATE TABLE `sys_menu` (
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
`url` varchar(200) DEFAULT NULL COMMENT '菜单URL',
`perms` varchar(500) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
`type` int(11) DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
`icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
`order_num` int(11) DEFAULT NULL COMMENT '排序',
PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=103 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='菜单管理'
权限模型优势:
- 多级菜单支持:parent_id字段实现菜单树形结构,支持无限级菜单嵌套
- 精细化权限控制:perms字段支持按钮级权限控制,如user:list,user:create
- 界面友好性:icon字段存储菜单图标,order_num控制菜单显示顺序
核心功能实现深度解析
1. 出入库流水记录与库存实时更新
系统通过inrecord和outrecord表分别记录进货和出货信息,确保每一笔库存变动都有迹可循:
CREATE TABLE `outrecord` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product` bigint(20) DEFAULT NULL COMMENT '商品',
`num` double(10,2) DEFAULT NULL COMMENT '出货数量',
`price` double(10,2) DEFAULT NULL COMMENT '出货成本',
`sale` double(10,2) DEFAULT NULL COMMENT '出货销售额',
`gmtTime` datetime DEFAULT NULL COMMENT '添加时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='出货信息'
对应的Java实体类设计体现了对象关系的完整映射:
@Entity
@Table(name = "outrecord")
public class OutrecordEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "product")
private Long product;
@Transient
private ProductEntity productEntity;
@Column(name = "num")
private Double num;
@Column(name = "price")
private Double price;
@Column(name = "sale")
private Double sale;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "gmtTime")
private Date gmtTime = new Date();
// Getter和Setter方法
public ProductEntity getProductEntity() {
return productEntity;
}
public void setProductEntity(ProductEntity productEntity) {
this.productEntity = productEntity;
}
public Double getProfit() {
return sale - price;
}
}
业务逻辑层通过Spring的声明式事务管理确保库存操作的原子性:
@Service
@Transactional
public class InventoryService {
@Autowired
private ProductMapper productMapper;
@Autowired
private OutrecordMapper outrecordMapper;
public void processOutbound(OutrecordEntity outrecord) {
// 1. 验证库存充足性
ProductEntity product = productMapper.selectById(outrecord.getProduct());
if (product.getNum() < outrecord.getNum()) {
throw new InventoryException("库存不足,当前库存:" + product.getNum());
}
// 2. 更新商品库存
product.setNum(product.getNum() - outrecord.getNum());
productMapper.updateById(product);
// 3. 记录出货信息
outrecord.setGmtTime(new Date());
outrecordMapper.insert(outrecord);
// 4. 记录操作日志
logService.recordOperation("出库操作", outrecord);
}
}

2. 基于Shiro的权限控制体系
系统采用Apache Shiro框架实现安全的身份认证和权限控制,AbstractController作为所有控制器的基类,提供统一的用户信息获取方法:
public abstract class AbstractController {
protected Logger logger = LoggerFactory.getLogger(getClass());
protected SysUserEntity getUser() {
return ShiroUtils.getUserEntity();
}
protected Long getUserId() {
return getUser().getUserId();
}
protected boolean hasPermission(String permission) {
return ShiroUtils.getSubject().isPermitted(permission);
}
}
@RestController
@RequestMapping("/api/inventory")
public class InventoryController extends AbstractController {
@Autowired
private InventoryService inventoryService;
@PostMapping("/outbound")
public R outbound(@RequestBody OutrecordEntity outrecord) {
// 权限校验
if (!hasPermission("inventory:outbound")) {
return R.error("无操作权限");
}
try {
inventoryService.processOutbound(outrecord);
return R.ok("出库成功");
} catch (InventoryException e) {
logger.error("出库操作失败,用户ID:{}", getUserId(), e);
return R.error(e.getMessage());
}
}
}
Shiro配置类实现详细的权限规则定义:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
// 设置登录页面
shiroFilter.setLoginUrl("/login");
shiroFilter.setUnauthorizedUrl("/unauthorized");
// 定义过滤链
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/api/**", "authc");
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilter;
}
@Bean
public Realm myRealm() {
UserRealm realm = new UserRealm();
realm.setCredentialsMatcher(new HashedCredentialsMatcher("SHA-256"));
return realm;
}
}

3. 商品分类与库存预警机制
系统支持多级商品分类管理,并通过实时库存监控实现智能预警:
@Service
public class ProductCategoryService {
@Autowired
private ProductMapper productMapper;
/**
* 获取库存预警商品列表
*/
public List<ProductEntity> getLowStockProducts(Double threshold) {
Map<String, Object> params = new HashMap<>();
params.put("threshold", threshold);
return productMapper.selectByMap(params);
}
/**
* 按分类统计库存情况
*/
public Map<Long, CategoryStats> getCategoryStats() {
List<CategoryStats> stats = productMapper.selectCategoryStats();
return stats.stream()
.collect(Collectors.toMap(
CategoryStats::getCategoryId,
Function.identity()
));
}
}
<!-- MyBatis映射文件中的复杂查询 -->
<mapper namespace="com.learn.mapper.ProductMapper">
<select id="selectLowStockProducts" resultType="com.learn.entity.ProductEntity">
SELECT p.*, c.name as categoryName
FROM product p
LEFT JOIN category c ON p.type = c.id
WHERE p.num < #{threshold}
ORDER BY p.num ASC
</select>
<select id="selectCategoryStats" resultType="com.learn.vo.CategoryStats">
SELECT
p.type as categoryId,
c.name as categoryName,
COUNT(p.id) as productCount,
SUM(p.num) as totalStock,
AVG(p.price) as avgCost
FROM product p
LEFT JOIN category c ON p.type = c.id
GROUP BY p.type, c.name
</select>
</mapper>

4. 进货信息管理的完整业务流程
进货管理模块实现了从采购到入库的完整流程控制:
@Entity
@Table(name = "inrecord")
public class InrecordEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "product")
private Long product;
@Transient
private ProductEntity productEntity;
@Column(name = "num")
private Double num;
@Column(name = "price")
private Double price;
@Column(name = "remark")
private String remark;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "gmttime")
private Date gmttime = new Date();
// 业务逻辑方法
public Double getTotalCost() {
return num * price;
}
public void updateProductStock() {
if (productEntity != null) {
Double currentStock = productEntity.getNum() != null ? productEntity.getNum() : 0;
productEntity.setNum(currentStock + num);
}
}
}
进货管理的服务层实现包含完整的业务验证逻辑:
@Service
@Transactional
public class InrecordService {
@Autowired
private InrecordMapper inrecordMapper;
@Autowired
private ProductMapper productMapper;
public R addInrecord(InrecordEntity inrecord) {
try {
// 参数验证
if (inrecord.getProduct() == null) {
return R.error("请选择商品");
}
if (inrecord.getNum() == null || inrecord.getNum() <= 0) {
return R.error("请输入正确的进货数量");
}
// 获取商品信息
ProductEntity product = productMapper.selectById(inrecord.getProduct());
if (product == null) {
return R.error("商品不存在");
}
// 设置关联对象
inrecord.setProductEntity(product);
// 更新库存
inrecord.updateProductStock();
productMapper.updateById(product);
// 保存进货记录
inrecord.setGmttime(new Date());
inrecordMapper.insert(inrecord);
return R.ok("进货记录添加成功");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
logger.error("进货操作失败", e);
return R.error("系统错误,请稍后重试");
}
}
}

实体模型设计的精妙之处
系统的实体类设计充分体现了面向对象的思想和业务逻辑的封装:
/**
* 商品信息实体类
*/
public class ProductEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Long type;
private String xh;
private String img;
private Double price;
private Double sale;
private Double num;
private Date gmtTime;
// 关联对象
private CategoryEntity categoryEntity;
// 业务方法
public Double getProfitMargin() {
if (price == null || price == 0) return 0.0;
return (sale - price) / price * 100;
}
public String getStockStatus() {
if (num == null) return "未知";
if (num < 10) return "紧缺";
if (num < 50) return "正常";
return "充足";
}
// Getter和Setter方法
public CategoryEntity getCategoryEntity() {
return categoryEntity;
}
public void setCategoryEntity(CategoryEntity categoryEntity) {
this.categoryEntity = categoryEntity;
}
}
这种设计模式的优点在于:
- 业务逻辑内聚:将相关的业务计算方法封装在实体类中
- 对象关系清晰:通过关联对象实现自然的对象导航
- 数据一致性:确保业务规则在实体层面得到统一处理
功能展望与系统优化方向
基于当前系统架构,未来可以从以下几个方向进行深度优化和功能扩展:
1. 引入Redis缓存提升系统性能
实现思路:对热点数据进行缓存,如商品信息、用户权限数据等
@Service
public class ProductServiceWithCache {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ProductMapper productMapper;
public ProductEntity getProductById(Long id) {
String cacheKey = "product:" + id;
ProductEntity product = (ProductEntity) redisTemplate.opsForValue().get(cacheKey);
if (product == null) {
product = productMapper.selectById(id);
if (product != null) {
redisTemplate.opsForValue().set(cacheKey, product, Duration.ofHours(1));
}
}
return product;
}
}
2. 集成消息队列实现异步处理
应用场景:库存预警通知、操作日志记录等非实时性要求