跳到正文
Joeplover
后端开发·2026-06-10·约 5 分钟阅读

ERP 订单管理系统:Spring Boot + Vue 3 全栈

完整的企业级 ERP 订单管理系统,Spring Boot 3 后端 + Vue 3 前端 + MySQL + RabbitMQ + Redis + Docker。

仓库管理

项目背景

这是一个完整的企业级 ERP 订单管理系统,采用前后端分离架构。前端使用 Vue 3 + TypeScript + Vite + Element Plus,后端使用 Spring Boot 3 + Spring Security + JWT。项目覆盖了企业订单管理的核心流程:订单创建、审批流转、商品管理、库存追踪、用户权限管理。

为什么做这个项目?ERP 系统是企业数字化的核心基础设施。虽然市面上有成熟的 ERP 解决方案(SAP、用友、金蝶),但对于中小企业和定制化场景,一个轻量级的自研 ERP 往往更灵活、成本更低。这个项目就是为此而生。

技术选型

组件选择理由
后端框架Spring Boot 3 + Java 21最新 LTS,虚拟线程支持
安全框架Spring Security + JWT完善的认证授权体系
ORMMyBatis-Plus代码生成、分页、Lambda 查询
数据库MySQL成熟的关系型数据库
前端Vue 3 + TypeScript类型安全、组合式 API
UI 框架Element Plus企业级 UI 组件库
构建Vite极速开发体验
部署Docker Compose前后端一键部署

架构设计

系统采用经典的前后端分离架构:

前端 (Vue 3 + Element Plus)
  │ REST API (JWT Auth)
  ▼
后端 (Spring Boot)
  ├── Controller 层
  ├── Service 层
  ├── Mapper 层 (MyBatis-Plus)
  └── 数据库 (MySQL)

核心模块:

  1. 订单管理 — 订单 CRUD、状态流转(待审核→已审核→已发货→已完成→已取消)
  2. 商品管理 — 商品信息、分类、SKU 管理
  3. 用户权限 — 基于 JWT 的多角色权限控制(管理员/操作员/审核员)
  4. 库存管理 — 入库、出库、库存盘点

核心实现

Spring Security + JWT 配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthenticationFilter,
                UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

JWT 认证过滤器

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            try {
                Claims claims = JwtUtil.parseToken(token);
                String userId = claims.getSubject();
                String role = claims.get("role", String.class);

                UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(
                        userId, null,
                        List.of(new SimpleGrantedAuthority("ROLE_" + role))
                    );
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (Exception e) {
                SecurityContextHolder.clearContext();
            }
        }
        filterChain.doFilter(request, response);
    }
}

订单状态机设计

订单管理中最重要的部分是状态流转。使用枚举定义所有状态和允许的转换:

public enum OrderStatus {
    PENDING("待审核"),
    APPROVED("已审核"),
    SHIPPED("已发货"),
    COMPLETED("已完成"),
    CANCELLED("已取消");

    private final String displayName;

    public boolean canTransitionTo(OrderStatus target) {
        return switch (this) {
            case PENDING -> target == APPROVED || target == CANCELLED;
            case APPROVED -> target == SHIPPED || target == CANCELLED;
            case SHIPPED -> target == COMPLETED;
            case COMPLETED, CANCELLED -> false; // 终态
        };
    }
}

@Service
public class OrderService {
    @Transactional
    public void updateStatus(Long orderId, OrderStatus newStatus) {
        Order order = orderMapper.selectById(orderId);
        if (!order.getStatus().canTransitionTo(newStatus)) {
            throw new BusinessException("非法状态转换");
        }
        order.setStatus(newStatus);
        orderMapper.updateById(order);
        // 记录操作日志
        operationLogService.log(orderId, "状态变更",
            order.getStatus().getDisplayName() + " → " + newStatus.getDisplayName());
    }
}

前端订单列表(Vue 3 + Element Plus)

<template>
  <el-table :data="orders" v-loading="loading">
    <el-table-column prop="orderNo" label="订单号" width="180" />
    <el-table-column prop="customerName" label="客户名称" />
    <el-table-column prop="totalAmount" label="总金额">
      <template #default="{ row }">
        ¥{{ row.totalAmount.toFixed(2) }}
      </template>
    </el-table-column>
    <el-table-column prop="status" label="状态">
      <template #default="{ row }">
        <el-tag :type="statusType(row.status)">
          {{ statusMap[row.status] }}
        </el-tag>
      </template>
    </el-table-column>
    <el-table-column label="操作" width="200">
      <template #default="{ row }">
        <el-button size="small" @click="viewDetail(row)">查看</el-button>
        <el-button size="small" type="primary"
                   @click="handleApprove(row)"
                   v-if="row.status === 'PENDING'">审核</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

踩坑记录

1. JWT Token 刷新机制
最初 JWT 的过期时间设置较短(30 分钟),用户体验很差,频繁需要重新登录。设置太长又存在安全风险。解决方案:实现了双 Token 机制——Access Token(15 分钟过期)+ Refresh Token(7 天过期),Access Token 过期后自动用 Refresh Token 刷新。

2. 跨域配置(CORS)
前后端分离架构下,前端开发环境(localhost:5173)访问后端(localhost:8080)会遇到 CORS 限制。解决方案:在 Spring Security 配置中添加 CORS 配置,允许开发环境来源。

3. 数据库事务边界
订单创建涉及多个表的写入(订单主表、订单明细表、库存扣减表),部分操作失败会导致数据不一致。解决方案:使用 @Transactional 注解确保整个操作的原子性,并引入乐观锁防止并发扣库存。

4. Element Plus 表格性能
当订单数据量较大(>1 万条)时,前端渲染卡顿。解决方案:后端实现分页查询 + 前端虚拟滚动,限制每页显示 20 条。

总结

这是一个完整的全栈项目,从前端界面到后端 API 到数据库设计,覆盖了企业级应用的完整链路。订单状态机的设计是 ERP 系统中最体现业务深度的部分——好的状态机设计能让代码逻辑清晰、业务边界明确。Spring Security + JWT 的整合是安全的核心,双 Token 机制在安全性和体验之间取得了平衡。

通过这个项目,我完整地实践了"前后端分离 + 企业级权限控制 + 复杂业务状态管理"的全栈开发模式,对 Spring Boot 和 Vue 3 的企业级开发有了深入的理解。