全开源ERP进销存源码:从数据库架构到业务逻辑全链路实战指南
本文将深入解析全开源ERP进销存系统源码实现,从数据库架构设计到核心业务逻辑实现,为开发者提供全链路实战指南。通过分析系统架构、数据模型及关键代码,帮助读者掌握构建高可用、高并发的企业级进销存系统的核心技术。
进销存源码:c.csymzs.top
系统架构设计:技术选型与分层架构
ERP进销存系统的技术架构直接决定了系统的稳定性、可扩展性和维护性。现代ERP系统普遍采用前后端分离的架构模式,后端基于Spring Boot 3.2.5等成熟框架,前端则采用Vue 3 + Element Plus的组合,数据库优先选择MySQL 8.0及以上版本。
在技术栈选择上,系统架构需考虑多维度因素。后端框架可选择Spring Boot(适合中大型企业,生态完善)或Django(适合快速开发中小型系统);前端可根据业务场景选择Vue 3(管理后台)或React(复杂交互场景);数据库则需在MySQL(关系型,事务支持强)与PostgreSQL(支持复杂查询与JSON字段)之间权衡。对于需要移动端支持的场景,UniApp/Flutter等跨平台框架可有效降低开发成本。
系统的分层架构通常遵循经典三层模式:表现层、业务层和数据层。表现层负责用户交互,通过RESTful API与后端通信;业务层采用领域驱动设计(DDD)划分采购、库存、销售等独立领域,通过聚合根管理数据一致性;数据层则通过MySQL存储业务数据,Redis缓存热点数据,结合消息队列处理异步任务。这种分层设计使得系统具备高内聚低耦合的特性,各层职责明确,便于团队协作与后期维护。
微服务化是大型ERP系统的演进方向。通过将采购、销售、库存等模块拆分为独立服务,结合API网关(如Spring Cloud Gateway)实现统一路由和限流熔断,可显著提升系统的弹性伸缩能力。服务间通信可采用gRPC(高性能)或HTTP/REST(简单易用),根据业务场景灵活选择。容器化部署(Docker+Kubernetes)则进一步提升了系统的部署效率和运维便利性。
数据库架构设计:核心表结构与优化策略
数据库作为ERP系统的核心组成部分,其设计质量直接影响到系统性能和数据处理能力。进销存系统的数据库架构需遵循规范化设计原则,确保数据一致性、完整性和安全性,同时兼顾查询效率与扩展性。

1. 核心数据表结构
以下是进销存系统中最关键的数据表及其结构设计:
商品表(product)作为系统的基础表,不仅存储商品基本信息,还关联库存、价格等核心数据。其DDL定义如下:
CREATE TABLE product (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品ID',
sku VARCHAR(20) NOT NULL COMMENT 'SKU编码',
name VARCHAR(100) NOT NULL COMMENT '商品名称',
category_id BIGINT NOT NULL COMMENT '分类ID',
spec VARCHAR(200) COMMENT '规格参数',
unit VARCHAR(10) DEFAULT 'PCS' COMMENT '单位',
purchase_price DECIMAL(10,2) COMMENT '采购价',
sale_price DECIMAL(10,2) COMMENT '销售价',
stock INT DEFAULT 0 COMMENT '库存数量',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_sku (sku),
INDEX idx_category (category_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
采购订单表(purchase_order)记录了企业的采购流程,需要与供应商、商品、库存等多模块关联:
CREATE TABLE purchase_order (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_no VARCHAR(20) NOT NULL COMMENT '采购单号',
supplier_id BIGINT NOT NULL COMMENT '供应商ID',
amount DECIMAL(12,2) COMMENT '订单金额',
order_date DATE NOT NULL COMMENT '下单日期',
status TINYINT DEFAULT 0 COMMENT '状态(0-草稿,1-已审核,2-已完成)',
create_by BIGINT COMMENT '创建人',
audit_by BIGINT COMMENT '审核人',
audit_time TIMESTAMP COMMENT '审核时间',
PRIMARY KEY (id),
INDEX idx_order_no (order_no),
INDEX idx_supplier (supplier_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
库存明细表(stock_detail)是追踪库存变化的关键表,记录所有库存操作流水:
CREATE TABLE stock_detail (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
product_id BIGINT NOT NULL COMMENT '商品ID',
operation_type ENUM('IN', 'OUT', 'ADJUST') COMMENT '操作类型',
quantity INT NOT NULL COMMENT '数量',
before_stock INT COMMENT '操作前库存',
after_stock INT COMMENT '操作后库存',
reference_no VARCHAR(50) COMMENT '关联单号',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_product_operation (product_id, operation_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 表关系与业务逻辑设计
进销存系统的表关系设计需体现业务逻辑一致性。商品表与库存表通过商品ID关联,形成一对多关系(一个商品对应多条库存记录);采购订单表与供应商表关联,支持供应商管理和评估;销售订单表则与客户表关联,记录客户交易历史。这种关系设计确保了数据的参照完整性,为复杂业务查询奠定基础。
3. 数据库性能优化策略
为提高数据库性能,需采用多维度优化策略。索引优化是基础,需为高频查询字段建立适当索引,如为库存表添加商品ID与仓库ID的联合索引idx_product_warehouse。对于大规模数据,可采用分库分表策略,按时间或业务维度拆分历史数据。以下是读写分离配置示例:
# application.yml
spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://master:3306/erp?useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://slave:3306/erp?useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
查询优化同样重要,需避免SELECT *操作,使用EXPLAIN分析慢查询,并结合缓存机制(Redis)提升高频访问数据的响应速度。库存查询等热点操作可通过Redis缓存,将响应时间控制在200ms以内。
采购管理模块源码解析:从订单创建到入库流程
采购管理是企业供应链的起点,其核心业务流程包括采购申请、供应商选择、订单创建、审核、入库及财务结算等环节。在ERP系统中,这一流程通过状态机机制实现全链路跟踪与控制。
1. 采购订单创建与审核
采购订单的创建涉及多层级数据验证,包括库存检查、供应商状态验证及价格比对等。以下是采购订单创建的Java代码示例:
@RestController
@RequestMapping("/purchase")
public class PurchaseOrderController {
@Autowired
private PurchaseOrderService purchaseOrderService;
@PostMapping("/order")
public ResponseEntity createOrder(
@RequestBody @Valid PurchaseOrderCreateCmd cmd) {
PurchaseOrder order = purchaseOrderService.createOrder(cmd);
return ResponseEntity.ok(order);
}
}
@Service
@Transactional
public class PurchaseOrderServiceImpl implements PurchaseOrderService {
public PurchaseOrder createOrder(PurchaseOrderCreateCmd cmd) {
// 验证供应商状态
Supplier supplier = supplierService.getById(cmd.getSupplierId());
if (supplier == null || !supplier.isActive()) {
throw new BusinessException("供应商不可用");
}
// 生成采购单号
String orderNo = generateOrderNo();
// 创建采购订单
PurchaseOrder order = new PurchaseOrder();
order.setOrderNo(orderNo);
order.setSupplierId(cmd.getSupplierId());
order.setOrderDate(new Date());
order.setStatus(PurchaseOrderStatus.DRAFT);
// 计算订单金额
BigDecimal totalAmount = BigDecimal.ZERO;
for (PurchaseItem item : cmd.getItems()) {
// 验证商品信息
Product product = productService.getBySku(item.getSku());
if (product == null) {
throw new BusinessException("商品不存在: " + item.getSku());
}
// 创建订单项
PurchaseOrderItem orderItem = new PurchaseOrderItem();
orderItem.setProductId(product.getId());
orderItem.setSku(item.getSku());
orderItem.setQuantity(item.getQuantity());
orderItem.setPrice(item.getPrice());
orderItem.setAmount(item.getPrice().multiply(
new BigDecimal(item.getQuantity())));
order.addItem(orderItem);
totalAmount = totalAmount.add(orderItem.getAmount());
}
order.setAmount(totalAmount);
purchaseOrderMapper.insert(order);
// 记录操作日志
operationLogService.log("创建采购单", order.getId());
return order;
}
}
采购订单审核是内部控制的重要环节,确保采购行为符合公司政策。审核流程通常包括权限验证、库存资金检查等步骤:
@Service
@Transactional
public class PurchaseOrderServiceImpl implements PurchaseOrderService {
public void auditOrder(Long orderId, Long auditorId) {
PurchaseOrder order = getById(orderId);
if (order == null) {
throw new BusinessException("采购订单不存在");
}
if (order.getStatus() != PurchaseOrderStatus.DRAFT) {
throw new BusinessException("订单状态不正确,无法审核");
}
// 权限验证
User auditor = userService.getById(auditorId);
if (!hasAuditPermission(auditor)) {
throw new BusinessException("无审核权限");
}
// 库存与资金检查
for (PurchaseOrderItem item : order.getItems()) {
Product product = productService.getById(item.getProductId());
// 检查采购价格是否合理
if (item.getPrice().compareTo(product.getPurchasePrice()) > 0) {
throw new BusinessException("采购价格过高: " + product.getSku());
}
}
// 更新订单状态
order.setStatus(PurchaseOrderStatus.APPROVED);
order.setAuditBy(auditorId);
order.setAuditTime(new Date());
update(order);
// 发送审核通知
notificationService.sendAuditNotification(order);
}
}
2. 采购入库流程
采购入库是采购与库存的衔接点,需要确保实物与信息的一致性。入库操作需更新库存数量并记录库存明细:
@Service
@Transactional
public class PurchaseOrderServiceImpl implements PurchaseOrderService {
public void receiveGoods(Long orderId, List items) {
PurchaseOrder order = getById(orderId);
if (order == null || order.getStatus() != PurchaseOrderStatus.APPROVED) {
throw new BusinessException("订单状态不正确");
}
// 验证入库商品与订单一致性
validateReceiveItems(order, items);
// 更新库存
for (ReceiveItem item : items) {
Product product = productService.getBySku(item.getSku());
// 更新商品库存
int originalStock = product.getStock();
product.setStock(originalStock + item.getQuantity());
productService.update(product);
// 记录库存明细
StockDetail stockDetail = new StockDetail();
stockDetail.setProductId(product.getId());
stockDetail.setOperationType(StockOperationType.IN);
stockDetail.setQuantity(item.getQuantity());
stockDetail.setBeforeStock(originalStock);
stockDetail.setAfterStock(product.getStock());
stockDetail.setReferenceNo(order.getOrderNo());
stockDetailMapper.insert(stockDetail);
}
// 更新订单状态
order.setStatus(PurchaseOrderStatus.COMPLETED);
order.setCompleteTime(new Date());
update(order);
// 触发财务应付账款生成
accountService.generatePayable(order);
}
private void validateReceiveItems(PurchaseOrder order, List items) {
// 验证入库数量不超过订单数量
Map orderQuantityMap = order.getItems().stream()
.collect(Collectors.toMap(PurchaseOrderItem::getSku,
PurchaseOrderItem::getQuantity));
for (ReceiveItem item : items) {
Integer orderQuantity = orderQuantityMap.get(item.getSku());
if (orderQuantity == null) {
throw new BusinessException("非订单商品: " + item.getSku());
}
if (item.getQuantity() > orderQuantity) {
throw new BusinessException("入库数量超过订单数量: " + item.getSku());
}
}
}
}
3. 采购退货处理
采购退货是采购管理的逆向流程,需要处理质量不合格或错发商品的退回。退货流程涉及库存扣减、供应商账款调整等操作:
@Service
@Transactional
public class PurchaseReturnServiceImpl implements PurchaseReturnService {
public PurchaseReturn createReturn(PurchaseReturnCreateCmd cmd) {
// 验证原采购订单
PurchaseOrder order = purchaseOrderService.getById(cmd.getOrderId());
if (order == null) {
throw new BusinessException("采购订单不存在");
}
// 创建退货单
PurchaseReturn purchaseReturn = new PurchaseReturn();
purchaseReturn.setReturnNo(generateReturnNo());
purchaseReturn.setOrderId(cmd.getOrderId());
purchaseReturn.setSupplierId(order.getSupplierId());
purchaseReturn.setReason(cmd.getReason());
purchaseReturn.setStatus(ReturnStatus.DRAFT);
// 处理退货商品
BigDecimal totalAmount = BigDecimal.ZERO;
for (ReturnItem item : cmd.getItems()) {
// 验证商品是否属于原订单
PurchaseOrderItem orderItem = findOrderItem(order, item.getSku());
if (orderItem == null) {
throw new BusinessException("商品不属于原订单: " + item.getSku());
}
// 创建退货项
PurchaseReturnItem returnItem = new PurchaseReturnItem();
returnItem.setSku(item.getSku());
returnItem.setQuantity(item.getQuantity());
returnItem.setPrice(orderItem.getPrice());
returnItem.setAmount(orderItem.getPrice()
.multiply(new BigDecimal(item.getQuantity())));
purchaseReturn.addItem(returnItem);
totalAmount = totalAmount.add(returnItem.getAmount());
}
purchaseReturn.setAmount(totalAmount);
purchaseReturnMapper.insert(purchaseReturn);
return purchaseReturn;
}
public void processReturn(Long returnId) {
PurchaseReturn purchaseReturn = getById(returnId);
if (purchaseReturn.getStatus() != ReturnStatus.APPROVED) {
throw new BusinessException("退货单未审核");
}
// 扣减库存
for (PurchaseReturnItem item : purchaseReturn.getItems()) {
Product product = productService.getBySku(item.getSku());
product.setStock(product.getStock() - item.getQuantity());
productService.update(product);
// 记录库存变动
StockDetail stockDetail = new StockDetail();
stockDetail.setProductId(product.getId());
stockDetail.setOperationType(StockOperationType.OUT);
stockDetail.setQuantity(item.getQuantity());
stockDetail.setReferenceNo(purchaseReturn.getReturnNo());
stockDetailMapper.insert(stockDetail);
}
// 更新退货单状态
purchaseReturn.setStatus(ReturnStatus.COMPLETED);
purchaseReturn.setCompleteTime(new Date());
update(purchaseReturn);
// 调整供应商应付款
accountService.adjustPayable(purchaseReturn);
}
}
销售与库存管理模块源码解析
销售与库存管理是ERP进销存系统的核心模块,直接关系到企业的收入与资产管理的准确性。销售模块处理从报价到收款的全流程,而库存模块则需要实时准确地反映库存状态,支持企业的运营决策。

1. 销售流程处理
销售流程始于销售报价,止于商品出库及应收账款生成。以下是销售订单创建的关键代码,其中包含库存预留机制:
@Service
@Transactional
public class SalesOrderServiceImpl implements SalesOrderService {
@Autowired
private ProductMapper productMapper;
@Autowired
private StockService stockService;
public SalesOrder createOrder(SalesOrderCreateCmd cmd) {
SalesOrder order = new SalesOrder();
order.setOrderNo(generateOrderNo());
order.setCustomerId(cmd.getCustomerId());
order.setOrderDate(new Date());
order.setStatus(SalesOrderStatus.PENDING);
// 验证客户信用
Customer customer = customerService.getById(cmd.getCustomerId());
if (customer.getCreditStatus() != CreditStatus.NORMAL) {
throw new BusinessException("客户信用状态异常,无法下单");
}
BigDecimal totalAmount = BigDecimal.ZERO;
// 处理订单项
for (OrderItem item : cmd.getItems()) {
Product product = productMapper.selectBySku(item.getSku());
if (product == null) {
throw new BusinessException("商品不存在: " + item.getSku());
}
// 检查库存
if (!stockService.checkStock(product.getId(), item.getQuantity())) {
throw new StockNotEnoughException(product.getSku());
}
// 计算金额
BigDecimal itemAmount = product.getSalePrice()
.multiply(new BigDecimal(item.getQuantity()));
SalesOrderItem orderItem = new SalesOrderItem();
orderItem.setProductId(product.getId());
orderItem.setSku(item.getSku());
orderItem.setQuantity(item.getQuantity());
orderItem.setPrice(product.getSalePrice());
orderItem.setAmount(itemAmount);
order.addItem(orderItem);
totalAmount = totalAmount.add(itemAmount);
}
order.setAmount(totalAmount);
salesOrderMapper.insert(order);
// 预留库存
for (OrderItem item : cmd.getItems()) {
Product product = productMapper.selectBySku(item.getSku());
stockService.reserveStock(product.getId(), item.getQuantity(),
order.getOrderNo());
}
return order;
}
}
销售出库是库存扣减的触发点,需要确保库存数据的实时一致性:
@Service
@Transactional
public class SalesOrderServiceImpl implements SalesOrderService {
public void deliverOrder(Long orderId) {
SalesOrder order = getById(orderId);
if (order.getStatus() != SalesOrderStatus.APPROVED) {
throw new BusinessException("订单状态不正确,无法发货");
}
// 扣减库存
for (SalesOrderItem item : order.getItems()) {
Product product = productService.getById(item.getProductId());
if (!stockService.deductStock(product.getId(), item.getQuantity())) {
throw new StockNotEnoughException(product.getSku());
}
// 记录出库明细
StockOut stockOut = new StockOut();
stockOut.setOrderNo(order.getOrderNo());
stockOut.setSku(item.getSku());
stockOut.setQuantity(item.getQuantity());
stockOut.setWarehouseId(order.getWarehouseId());
stockOutMapper.insert(stockOut);
}
// 更新订单状态
order.setStatus(SalesOrderStatus.DELIVERED);
order.setDeliveryTime(new Date());
update(order);
// 生成应收账款
accountService.generateReceivable(order);
}
}
2. 库存管理机制
库存管理是进销存系统的核心枢纽,需要实时跟踪库存变化,并提供准确的库存数据。以下是库存扣减的核心逻辑:
@Service
public class StockServiceImpl implements StockService {
@Autowired
private ProductMapper productMapper;
@Autowired
private StockDetailMapper stockDetailMapper;
@Transactional
public boolean deductStock(Long productId, Integer quantity) {
Product product = productMapper.selectById(productId);
if (product.getStock() < quantity) {
return false;
}
// 更新库存
int originalStock = product.getStock();
product.setStock(originalStock - quantity);
productMapper.updateStock(product);
// 记录库存明细
StockDetail detail = new StockDetail();
detail.setProductId(productId);
detail.setOperationType(StockOperationType.DEDUCT);
detail.setQuantity(quantity);
detail.setBeforeStock(originalStock);
detail.setAfterStock(product.getStock());
detail.setCreateTime(new Date());
stockDetailMapper.insert(detail);
// 检查库存预警
checkStockAlert(product);
return true;
}
private void checkStockAlert(Product product) {
// 获取商品分类的安全库存配置
CategoryConfig config = categoryService.getConfig(product.getCategoryId());
if (product.getStock() <= config.getSafeStock()) {
// 触发库存预警
alertService.sendStockAlert(product, config.getSafeStock());
}
}
}
对于高并发场景下的库存操作,需要使用分布式锁防止超卖:
@Service
public class RedisStockServiceImpl implements StockService {
@Autowired
private RedisTemplate redisTemplate;
public boolean deductStockWithLock(Long productId, Integer quantity) {
String lockKey = "stock_lock:" + productId;
String stockKey = "stock:" + productId;
// 获取分布式锁
String requestId = UUID.randomUUID().toString();
try {
// 尝试加锁,最多等待1秒,锁有效期3秒
boolean locked = tryGetLock(lockKey, requestId, 1, 3);
if (!locked) {
throw new BusinessException("系统繁忙,请重试");
}
// 检查库存
Integer currentStock = (Integer) redisTemplate.opsForValue().get(stockKey);
if (currentStock == null) {
// 从数据库加载库存到缓存
currentStock = loadStockFromDB(productId);
}
if (currentStock < quantity) {
return false;
}
// 扣减缓存库存
redisTemplate.opsForValue().decrement(stockKey, quantity);
// 异步更新数据库
sendStockUpdateMessage(productId, quantity);
return true;
} finally {
// 释放锁
releaseLock(lockKey, requestId);
}
}
private boolean tryGetLock(String lockKey, String requestId,
long waitTime, long leaseTime) {
// 使用Redis实现分布式锁
// 具体实现参考Redisson或自定义实现
return true;
}
}
3. 库存盘点与调拨
库存盘点确保账实相符,是库存管理的重要环节:
@Service
@Transactional
public class StockCheckServiceImpl implements StockCheckService {
public StockCheckResult performStockCheck(Long warehouseId,
List items) {
StockCheckResult result = new StockCheckResult();
result.setWarehouseId(warehouseId);
result.setCheckTime(new Date());
List variances = new ArrayList<>();
for (StockCheckItem item : items) {
Product product = productService.getBySku(item.getSku());
// 系统库存
Integer systemStock = product.getStock();
// 实际盘点库存
Integer physicalStock = item.getQuantity();
if (!systemStock.equals(physicalStock)) {
// 记录差异
StockVariance variance = new StockVariance();
variance.setSku(item.getSku());
variance.setSystemStock(systemStock);
variance.setPhysicalStock(physicalStock);
variance.setDifference(physicalStock - systemStock);
variances.add(variance);
// 调整库存
adjustStock(product, physicalStock, "STOCK_CHECK");
}
}
result.setVariances(variances);
result.setStatus(variances.isEmpty() ?
CheckStatus.PASSED : CheckStatus.HAS_VARIANCE);
return result;
}
private void adjustStock(Product product, Integer newStock, String reason) {
Integer originalStock = product.getStock();
product.setStock(newStock);
productService.update(product);
// 记录库存调整
StockAdjustment adjustment = new StockAdjustment();
adjustment.setProductId(product.getId());
adjustment.setOriginalStock(originalStock);
adjustment.setNewStock(newStock);
adjustment.setReason(reason);
adjustment.setAdjustTime(new Date());
stockAdjustmentMapper.insert(adjustment);
}
}
库存调拨处理多仓库间的货物转移,需要同时减少源仓库库存并增加目标仓库库存:
@Service
@Transactional
public class StockTransferServiceImpl implements StockTransferService {
public void transferStock(StockTransferDTO dto) {
// 验证源仓库库存是否充足
for (TransferItem item : dto.getItems()) {
Product product = productService.getBySku(item.getSku());
WarehouseStock sourceStock = stockService.getStock(
dto.getFromWarehouseId(), product.getId());
if (sourceStock.getQuantity() < item.getQuantity()) {
throw new StockNotEnoughException("库存不足,SKU: " + item.getSku());
}
}
// 执行调拨
for (TransferItem item : dto.getItems()) {
Product product = productService.getBySku(item.getSku());
// 减少源仓库库存
stockService.deductSpecificStock(dto.getFromWarehouseId(),
product.getId(), item.getQuantity());
// 增加目标仓库库存
stockService.addStock(dto.getToWarehouseId(),
product.getId(), item.getQuantity());
// 记录调拨明细
StockTransferRecord record = new StockTransferRecord();
record.setProductId(product.getId());
record.setFromWarehouseId(dto.getFromWarehouseId());
record.setToWarehouseId(dto.getToWarehouseId());
record.setQuantity(item.getQuantity());
record.setTransferTime(new Date());
stockTransferMapper.insert(record);
}
// 更新调拨单状态
completeTransferOrder(dto.getTransferOrderId());
}
}

系统安全与性能优化
ERP进销存系统作为企业的核心运营平台,其安全性和性能直接关系到企业经营的稳定性和效率。本节将深入探讨系统的安全控制机制和性能优化方案。
1. 安全控制机制
系统的安全控制主要包括身份认证、权限管理和数据保护三个层面。基于RBAC(基于角色的访问控制)模型,系统可以为不同角色分配不同的数据访问和操作权限。
以下是Spring Security的配置示例,实现了API接口的安全控制:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/purchase/**").hasAnyRole("PURCHASE", "ADMIN")
.antMatchers("/api/sales/**").hasAnyRole("SALES", "ADMIN")
.antMatchers("/api/inventory/**").hasAnyRole("INVENTORY", "ADMIN")
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
对于敏感数据如用户密码、支付信息等,系统采用加密存储策略:
@Service
public class AesUtils {
private static final String KEY = "erp-secret-key-2025";
public static String encrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(KEY.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(
cipher.doFinal(data.getBytes()));
}
public static String decrypt(String encryptedData) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(KEY.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(
Base64.getDecoder().decode(encryptedData)));
}
}
2. 性能优化方案
ERP系统需要处理大量并发操作,性能优化是系统设计的关键考量。以下是主要的优化策略及实现方案。
缓存策略是提升系统性能的首要手段,特别是对于商品信息、库存数据等高频访问内容:
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private RedisTemplate redisTemplate;
@Cacheable(value = "productCache", key = "#sku")
public Product getBySku(String sku) {
return productMapper.selectBySku(sku);
}
@CacheEvict(value = "productCache", key = "#product.sku")
public void update(Product product) {
productMapper.updateById(product);
}
@Cacheable(value = "stockCache", key = "#productId")
public Integer getStock(Long productId) {
// 先尝试从缓存获取
String cacheKey = "stock:" + productId;
Integer stock = (Integer) redisTemplate.opsForValue().get(cacheKey);
if (stock != null) {
return stock;
}
// 缓存未命中,从数据库加载
Product product = productMapper.selectById(productId);
if (product != null) {
stock = product.getStock();
// 写入缓存,设置5分钟过期
redisTemplate.opsForValue().set(cacheKey, stock, 5, TimeUnit.MINUTES);
return stock;
}
return 0;
}
}
数据库优化包括索引优化、查询优化和分库分表等策略:
-- 为高频查询字段添加索引
ALTER TABLE product ADD INDEX idx_sku_category (sku, category_id);
ALTER TABLE sales_order ADD INDEX idx_customer_date (customer_id, order_date);
ALTER TABLE purchase_order ADD INDEX idx_status_supplier (status, supplier_id);
-- 库存明细表的复合索引优化查询性能
ALTER TABLE stock_detail ADD INDEX idx_product_operation (product_id, operation_type);
ALTER TABLE stock_detail ADD INDEX idx_operation_time (operation_type, create_time);
对于高并发场景下的库存操作,可以使用Redis原子操作防止超卖:
@Service
public class RedisInventoryService {
public boolean deductStock(Long productId, Integer quantity) {
String stockKey = "stock:" + productId;
// 使用Lua脚本保证原子性
String luaScript = "local key = KEYS[1] " +
"local quantity = tonumber(ARGV[1]) " +
"local current = tonumber(redis.call('GET', key) or 0) " +
"if current >= quantity then " +
" redis.call('DECRBY', key, quantity) " +
" return 1 " +
"else " +
" return 0 " +
"end";
DefaultRedisScript script = new DefaultRedisScript<>();
script.setScriptText(luaScript);
script.setResultType(Long.class);
Long result = redisTemplate.execute(script,
Arrays.asList(stockKey), quantity);
return result == 1;
}
}
异步处理是提升系统响应速度的重要手段,将非实时性操作如日志记录、消息通知等异步化:
@Service
@Async
public class AsyncService {
@Autowired
private EmailService emailService;
@Autowired
private OperationLogService logService;
@Async("taskExecutor")
public void processStockOperationAsync(StockOperation operation) {
// 记录操作日志
logService.logStockOperation(operation);
// 发送库存预警邮件
if (operation.getType() == StockOperationType.DEDUCT) {
Product product = productService.getById(operation.getProductId());
if (product.getStock() < product.getSafeStock()) {
emailService.sendStockAlert(product);
}
}
}
}
读写分离是数据库层面的重要优化手段,通过将读操作和写操作分发到不同的数据库实例,提升系统吞吐量:
# application.yml 读写分离配置
spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://master:3306/erp
username: root
password: root
slave1:
url: jdbc:mysql://slave1:3306/erp
username: root
password: root
slave2:
url: jdbc:mysql://slave2:3306/erp
username: root
password: root
通过以上安全性和性能优化措施,ERP进销存系统可以确保数据安全的同时,提供高效稳定的服务能力,满足企业日常运营和决策分析的需求。

总结
本文全面解析了ERP进销存系统的源码实现,从系统架构、数据库设计、采购管理、销售库存到安全性能优化,提供了全链路实战指南。通过深入分析核心模块的代码实现,揭示了系统内部的工作机制和最佳实践。
