全开源ERP进销存源码:从数据库架构到业务逻辑全链路实战指南

2025-10-21 11:45:35 0点赞 2收藏 0评论

本文将深入解析全开源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系统的核心组成部分,其设计质量直接影响到系统性能和数据处理能力。进销存系统的数据库架构需遵循​​规范化设计原则​​,确保数据一致性、完整性和安全性,同时兼顾查询效率与扩展性。

全开源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进销存系统的核心模块,直接关系到企业的收入与资产管理的准确性。销售模块处理从报价到收款的全流程,而库存模块则需要实时准确地反映库存状态,支持企业的运营决策。

全开源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进销存源码:从数据库架构到业务逻辑全链路实战指南

系统安全与性能优化

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进销存源码:从数据库架构到业务逻辑全链路实战指南

总结

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

展开 收起
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

相关文章推荐

更多精彩文章
更多精彩文章
最新文章 热门文章
2
扫一下,分享更方便,购买更轻松