1. 项目概述:现代企业采购系统的技术转型
去年为一家中型制造企业实施采购系统升级时,我深刻体会到传统采购流程的痛点:纸质审批流转慢、供应商比价效率低、库存联动不及时。这正是我们选择SpringBoot+Vue技术栈构建在线采购系统的初衷——用前后端分离架构解决企业采购管理的核心诉求。
这个系统实现了从采购申请到付款结算的全流程数字化,包含三大核心模块:供应商协同平台(资质审核、报价管理)、采购业务中心(需求提报、比价下单)、智能分析看板(支出分析、供应商评估)。技术选型上,后端采用SpringBoot 2.7 + MyBatis-Plus + Redis的组合,前端使用Vue3 + Element Plus,通过RESTful API进行数据交互。
关键提示:采购系统的特殊性在于需要同时满足财务合规性(审计留痕)和操作便捷性(快速比价),这对技术方案设计提出了双重挑战
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计与核心组件
2.1 后端SpringBoot技术栈解析
基础框架采用SpringBoot 2.7.18(LTS版本),相比3.x版本对老项目兼容性更好。核心依赖包括:
- spring-boot-starter-web:RESTful接口支持
- mybatis-plus-boot-starter 3.5.3:简化数据库操作
- hutool-all 5.8.16:Java工具包
- redisson-spring-boot-starter 3.23.1:分布式锁与缓存
数据库设计遵循采购业务特性:
sql复制CREATE TABLE `purchase_order` (
`id` bigint NOT NULL COMMENT '雪花算法ID',
`order_code` varchar(32) NOT NULL COMMENT '采购单号(规则:PO+年月日+4位序列)',
`supplier_id` bigint NOT NULL COMMENT '供应商ID',
`total_amount` decimal(12,2) DEFAULT NULL COMMENT '含税总金额',
`payment_terms` varchar(50) DEFAULT NULL COMMENT '付款条件',
`approval_status` tinyint DEFAULT '0' COMMENT '审批状态(0-草稿 1-审批中 2-已批准 3-已拒绝)',
`create_by` varchar(64) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_order_code` (`order_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购订单主表';
2.2 前端Vue3技术方案
前端工程采用Vue3 + Vite + TypeScript的技术组合,主要特点包括:
- 基于Composition API的逻辑封装
- 使用Pinia替代Vuex进行状态管理
- Element Plus组件库按需引入
- 自定义指令实现权限控制
采购单创建页面的核心逻辑示例:
javascript复制// 采购物品选择组件
const useItemSelector = () => {
const selectedItems = ref<PurchaseItem[]>([])
const addItem = (item: CatalogItem) => {
if (selectedItems.value.some(i => i.skuId === item.id)) {
ElMessage.warning('该物品已添加')
return
}
selectedItems.value.push({
skuId: item.id,
skuName: item.name,
specification: item.spec,
unit: item.unit,
quantity: 1,
taxRate: 0.13,
unitPrice: 0
})
}
return { selectedItems, addItem }
}
3. 核心业务模块实现细节
3.1 供应商协同管理
供应商准入采用工作流引擎(Activiti 7)实现多级审批:
- 供应商注册提交基础信息
- 系统自动校验工商信息(对接天眼查API)
- 采购专员初审资质文件
- 财务部复核银行账户
- 风控部门终审
关键技术点:
- 使用MinIO搭建文件服务器存储资质文件
- 采用Redis GEO实现就近供应商推荐
- 定时任务扫描资质有效期(Quartz集群方案)
3.2 智能比价采购流程
比价算法核心逻辑:
java复制public List<QuoteComparisonDTO> compareQuotes(Long itemId) {
// 获取所有供应商报价
List<SupplierQuote> quotes = quoteMapper.selectByItem(itemId);
return quotes.stream()
.filter(q -> q.getStatus() == QuoteStatus.APPROVED)
.sorted(Comparator
.comparing(SupplierQuote::getUnitPrice)
.thenComparing(q -> q.getSupplier().getScore()))
.map(q -> new QuoteComparisonDTO(
q.getSupplier().getName(),
q.getUnitPrice(),
q.getTaxRate(),
calculateTotalCost(q),
q.getDeliveryDays(),
q.getPaymentTerms()
)).limit(5) // 取最优5家
.collect(Collectors.toList());
}
private BigDecimal calculateTotalCost(SupplierQuote quote) {
return quote.getUnitPrice()
.multiply(BigDecimal.ONE.add(quote.getTaxRate()))
.setScale(2, RoundingMode.HALF_UP);
}
3.3 采购-库存联动机制
通过RabbitMQ实现库存实时更新:
- 采购单审批通过时发送MQ消息
- 库存服务监听消息并更新预计入库量
- 采购收货时触发库存实际增加
- 财务付款后关闭采购单
消息队列配置示例:
yaml复制spring:
rabbitmq:
host: mq-prod.example.com
port: 5672
virtual-host: /procurement
publisher-confirm-type: correlated
listener:
simple:
acknowledge-mode: manual
prefetch: 10
4. 典型问题排查与性能优化
4.1 高并发下单问题
现象:大促期间提交采购单出现"库存超卖"
解决方案:
- 采用Redisson分布式锁控制库存扣减
- 数据库增加乐观锁版本号
- 引入Sentinel进行流量控制
关键代码:
java复制@Transactional
public boolean placeOrder(PurchaseOrderDTO order) {
RLock lock = redissonClient.getLock("stock_lock:" + order.getItemId());
try {
boolean locked = lock.tryLock(3, 15, TimeUnit.SECONDS);
if (!locked) throw new BusinessException("系统繁忙,请稍后重试");
ItemStock stock = stockMapper.selectForUpdate(order.getItemId());
if (stock.getAvailable() < order.getQuantity()) {
throw new BusinessException("库存不足");
}
stockMapper.deductStock(order.getItemId(), order.getQuantity());
return orderMapper.insert(convertToEntity(order)) > 0;
} finally {
lock.unlock();
}
}
4.2 大数据量导出优化
采购历史导出性能提升方案:
- 采用POI的SXSSFWorkbook实现流式导出
- 服务端分页查询(每页5000条)
- 前端使用Web Worker处理下载
核心导出逻辑:
java复制public void exportPurchaseHistory(HttpServletResponse response,
PurchaseQuery query) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=purchase_history.xlsx");
try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) {
Sheet sheet = workbook.createSheet("采购记录");
// 写入表头...
int pageNo = 1;
while (true) {
Page<PurchaseOrder> page = orderService.pageQuery(query, pageNo, 5000);
if (page.getRecords().isEmpty()) break;
for (PurchaseOrder order : page.getRecords()) {
Row row = sheet.createRow(sheet.getLastRowNum() + 1);
// 填充数据...
}
pageNo++;
}
workbook.write(response.getOutputStream());
}
}
5. 部署与运维实践
5.1 容器化部署方案
Docker Compose编排文件示例:
yaml复制version: '3.8'
services:
backend:
image: registry.example.com/procurement-backend:${TAG:-latest}
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- REDIS_HOST=redis
depends_on:
- redis
- mysql
frontend:
image: registry.example.com/procurement-frontend:${TAG:-latest}
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
MYSQL_DATABASE: procurement
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6-alpine
command: redis-server --requirepass ${REDIS_PASS}
volumes:
mysql_data:
5.2 监控与日志方案
-
Prometheus + Grafana监控看板配置:
- JVM内存/线程监控
- 接口响应时间P99
- 数据库连接池使用率
-
ELK日志收集关键配置:
properties复制# logback-spring.xml
<appender name="ELK" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>logstash:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"procurement","env":"${spring.profiles.active}"}</customFields>
</encoder>
</appender>
在最近一次系统升级中,我们发现Vue3的静态节点提升特性使得采购单列表页的首次渲染速度提升了40%,同时SpringBoot的延迟初始化配置减少了30%的启动时间。这些优化对于需要频繁部署更新的采购系统尤为重要
