超市仓库管理系统是现代零售业不可或缺的核心业务支撑系统。随着零售行业规模不断扩大,商品种类日益增多,传统的人工管理方式已经无法满足高效、精准的库存管理需求。一个设计良好的仓库管理系统能够实现商品入库、出库、盘点、调拨等全流程数字化管理,大幅提升库存周转效率,降低人力成本。
本项目基于SpringBoot+Vue.js技术栈开发,采用前后端分离架构,后端使用Java语言结合SpringBoot框架实现业务逻辑,前端使用Vue.js构建用户界面,数据库选用MySQL关系型数据库存储业务数据。系统主要面向中小型超市的仓储管理需求,提供完整的商品生命周期管理解决方案。
提示:在实际开发中,SpringBoot+Vue.js的组合是目前企业级应用开发的主流选择,SpringBoot简化了后端服务的配置和部署,Vue.js则提供了灵活高效的前端开发体验。
后端技术栈:
前端技术栈:
数据库:
开发工具:
系统采用模块化设计,主要分为以下几个功能模块:
基础数据管理模块
库存管理模块
报表统计模块
系统管理模块
商品表(t_product)
sql复制CREATE TABLE `t_product` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`product_code` varchar(64) NOT NULL COMMENT '商品编码',
`product_name` varchar(100) NOT NULL COMMENT '商品名称',
`category_id` bigint NOT NULL COMMENT '分类ID',
`specification` varchar(200) DEFAULT NULL COMMENT '规格',
`unit` varchar(20) NOT NULL COMMENT '单位',
`purchase_price` decimal(10,2) DEFAULT NULL COMMENT '采购价',
`selling_price` decimal(10,2) DEFAULT NULL COMMENT '销售价',
`min_stock` int DEFAULT '0' COMMENT '最低库存',
`max_stock` int DEFAULT '0' COMMENT '最高库存',
`status` tinyint DEFAULT '1' COMMENT '状态(0-停用,1-启用)',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_product_code` (`product_code`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品信息表';
库存表(t_inventory)
sql复制CREATE TABLE `t_inventory` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`warehouse_id` bigint NOT NULL COMMENT '仓库ID',
`product_id` bigint NOT NULL COMMENT '商品ID',
`quantity` int NOT NULL DEFAULT '0' COMMENT '当前库存',
`lock_quantity` int DEFAULT '0' COMMENT '锁定库存',
`version` int DEFAULT '0' COMMENT '版本号(用于乐观锁)',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_warehouse_product` (`warehouse_id`,`product_id`),
KEY `idx_product` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存表';
入库单表(t_stock_in)
sql复制CREATE TABLE `t_stock_in` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_no` varchar(32) NOT NULL COMMENT '入库单号',
`warehouse_id` bigint NOT NULL COMMENT '仓库ID',
`supplier_id` bigint DEFAULT NULL COMMENT '供应商ID',
`total_amount` decimal(10,2) DEFAULT NULL COMMENT '总金额',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态(0-待审核,1-已审核,2-已入库,3-已取消)',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`create_user` bigint NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_warehouse` (`warehouse_id`),
KEY `idx_supplier` (`supplier_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='入库单表';
系统采用关系型数据库设计,主要表之间的关系如下:
注意:在实际设计中,需要考虑数据一致性和性能平衡。例如库存表设计采用了"仓库ID+商品ID"的唯一索引,确保同一商品在同一仓库只有一条库存记录。
商品管理是系统的基础模块,主要包括商品信息的增删改查、商品分类管理、商品导入导出等功能。
核心代码实现:
java复制@RestController
@RequestMapping("/api/product")
public class ProductController {
@Autowired
private ProductService productService;
/**
* 分页查询商品列表
*/
@GetMapping("/list")
public R list(@RequestParam Map<String, Object> params) {
PageUtils page = productService.queryPage(params);
return R.ok().put("data", page);
}
/**
* 保存商品
*/
@PostMapping("/save")
public R save(@RequestBody ProductEntity product) {
// 校验商品编码是否已存在
if (productService.existsProductCode(product.getProductCode())) {
return R.error("商品编码已存在");
}
product.setCreateTime(new Date());
product.setUpdateTime(new Date());
productService.save(product);
return R.ok();
}
/**
* 更新商品
*/
@PostMapping("/update")
public R update(@RequestBody ProductEntity product) {
product.setUpdateTime(new Date());
productService.updateById(product);
return R.ok();
}
/**
* 删除商品
*/
@PostMapping("/delete")
public R delete(@RequestBody Long[] ids) {
// 检查商品是否有关联库存
if (inventoryService.existsInventoryByProductIds(ids)) {
return R.error("存在关联库存,无法删除");
}
productService.removeByIds(Arrays.asList(ids));
return R.ok();
}
}
商品导入功能实现要点:
库存管理是系统的核心模块,主要包括入库、出库、调拨、盘点等业务功能。
入库业务流程:
入库单创建代码示例:
java复制@Service
public class StockInServiceImpl implements StockInService {
@Autowired
private StockInDao stockInDao;
@Autowired
private StockInDetailDao stockInDetailDao;
@Autowired
private InventoryService inventoryService;
@Transactional(rollbackFor = Exception.class)
@Override
public void saveStockIn(StockInDTO stockInDTO) {
// 生成入库单号
String orderNo = generateOrderNo("SI");
// 保存入库单主表
StockInEntity stockIn = new StockInEntity();
BeanUtils.copyProperties(stockInDTO, stockIn);
stockIn.setOrderNo(orderNo);
stockIn.setStatus(StockInStatus.PENDING.getCode());
stockIn.setCreateTime(new Date());
stockIn.setUpdateTime(new Date());
stockInDao.insert(stockIn);
// 保存入库单明细
List<StockInDetailEntity> detailList = stockInDTO.getDetailList();
BigDecimal totalAmount = BigDecimal.ZERO;
for (StockInDetailEntity detail : detailList) {
detail.setStockInId(stockIn.getId());
detail.setCreateTime(new Date());
// 计算明细金额
BigDecimal amount = detail.getPrice().multiply(
new BigDecimal(detail.getQuantity()));
detail.setAmount(amount);
totalAmount = totalAmount.add(amount);
stockInDetailDao.insert(detail);
}
// 更新入库单总金额
stockIn.setTotalAmount(totalAmount);
stockInDao.updateById(stockIn);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void approveStockIn(Long id) {
// 查询入库单
StockInEntity stockIn = stockInDao.selectById(id);
if (stockIn == null) {
throw new BusinessException("入库单不存在");
}
if (stockIn.getStatus() != StockInStatus.PENDING.getCode()) {
throw new BusinessException("入库单状态不正确");
}
// 查询入库明细
List<StockInDetailEntity> details = stockInDetailDao.selectList(
new QueryWrapper<StockInDetailEntity>()
.eq("stock_in_id", id));
// 更新库存
for (StockInDetailEntity detail : details) {
inventoryService.increaseInventory(
stockIn.getWarehouseId(),
detail.getProductId(),
detail.getQuantity());
}
// 更新入库单状态
stockIn.setStatus(StockInStatus.COMPLETED.getCode());
stockIn.setUpdateTime(new Date());
stockInDao.updateById(stockIn);
}
private String generateOrderNo(String prefix) {
// 生成规则: 前缀 + 年月日 + 4位随机数
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateStr = sdf.format(new Date());
int randomNum = (int)((Math.random() * 9 + 1) * 1000);
return prefix + dateStr + randomNum;
}
}
库存扣减是出库业务的核心操作,需要考虑并发情况下的数据一致性问题。本系统采用乐观锁机制解决并发问题。
库存扣减代码示例:
java复制@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
private InventoryDao inventoryDao;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean decreaseInventory(Long warehouseId, Long productId, int quantity) {
// 查询库存记录
InventoryEntity inventory = inventoryDao.selectOne(
new QueryWrapper<InventoryEntity>()
.eq("warehouse_id", warehouseId)
.eq("product_id", productId));
if (inventory == null) {
throw new BusinessException("库存记录不存在");
}
// 检查库存是否充足
if (inventory.getQuantity() - inventory.getLockQuantity() < quantity) {
throw new BusinessException("库存不足");
}
// 使用乐观锁更新库存
int updateCount = inventoryDao.updateInventory(
warehouseId, productId, quantity, inventory.getVersion());
if (updateCount == 0) {
// 更新失败,说明版本号已变化
throw new OptimisticLockingFailureException("库存更新冲突,请重试");
}
return true;
}
}
系统采用RBAC(基于角色的访问控制)模型实现权限管理,主要包含用户、角色、权限三个核心实体。
权限验证流程:
Spring Security配置示例:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll();
http.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JWT认证过滤器:
java复制public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = userDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
系统测试采用黑盒测试方法,主要验证各功能模块是否符合需求规格说明书的要求。
商品管理测试用例:
| 测试场景 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 添加商品 | 1. 输入完整商品信息 2. 点击保存 |
提示保存成功,商品列表中显示新增商品 | 符合预期 |
| 添加重复编码商品 | 1. 输入已存在的商品编码 2. 点击保存 |
提示"商品编码已存在" | 符合预期 |
| 删除有库存的商品 | 1. 选择有关联库存的商品 2. 点击删除 |
提示"存在关联库存,无法删除" | 符合预期 |
入库业务测试用例:
| 测试场景 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 正常入库 | 1. 创建入库单 2. 添加商品明细 3. 提交审核 4. 审核通过 |
库存数量增加,入库单状态变为"已完成" | 符合预期 |
| 入库数量为负 | 1. 创建入库单 2. 输入负数的入库数量 3. 点击保存 |
提示"入库数量必须大于0" | 符合预期 |
| 重复审核 | 1. 对已审核的入库单再次点击审核 | 提示"入库单状态不正确" | 符合预期 |
系统使用JMeter进行性能测试,主要测试高并发情况下的系统表现。
测试环境:
测试结果:
| 测试场景 | 线程数 | 平均响应时间(ms) | 错误率 | TPS |
|---|---|---|---|---|
| 商品查询 | 100 | 235 | 0% | 425 |
| 商品查询 | 500 | 612 | 0% | 816 |
| 入库操作 | 100 | 348 | 0% | 287 |
| 入库操作 | 500 | 1256 | 2.3% | 398 |
性能优化措施:
数据库优化
缓存优化
代码优化
JVM优化
系统安全测试主要关注以下几个方面:
认证与授权
输入验证
会话管理
数据安全
安全加固措施:
系统采用前后端分离部署方式,推荐以下两种部署方案:
方案一:传统部署
方案二:容器化部署
后端服务部署:
mvn clean packagejava -jar warehouse-system.jar --spring.profiles.active=prod前端项目部署:
npm run build数据库初始化:
CREATE DATABASE warehouse CHARSET utf8mb4 COLLATE utf8mb4_general_ci;系统监控指标:
常用运维命令:
tail -f logs/application.logps aux | grep javamysqldump -u root -p warehouse > backup.sqlredis-cli --bigkeys提示:对于生产环境,建议使用专业的监控系统如Prometheus+Grafana,以及日志系统如ELK,实现全方位的系统监控和日志分析。
本项目实现了一个功能完善的超市仓库管理系统,主要特点包括:
在实际开发过程中,积累了一些有价值的经验:
本系统还有以下可以扩展的方向:
对于希望进一步学习的开发者,建议深入研究以下技术:
在实际项目开发中,根据业务规模和团队能力选择合适的扩展方向,循序渐进地完善系统功能。