毕业设计电商系统怎么快速上线?Spring Boot+Vue架构+阿里云全栈服务部署实战

本文涉及的产品
云数据库 PolarDB MySQL 版,列存表分析加速 8核16GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
PolarDB Agent Express,2核4GB
简介: 本文详解电商系统毕设开发与阿里云部署全流程:涵盖模块化架构设计、JWT认证、多级缓存、Redis分布式锁防超卖、OSS文件存储及SLB+RDS+ECS云上部署,提供可复用的生产级项目模板。

一、为什么电商系统是毕设的最佳选择

每年计算机专业毕业设计中,选择电商系统作为课题的同学占比超过三分之一。这个现象背后有其必然性:电商系统的业务流程清晰完整,从用户注册登录到商品浏览下单再到支付配送,每个环节都有明确的技术实现点;业务逻辑既不过于简单(否则缺乏技术深度),也不过于复杂(否则毕设时间内无法完成);电商系统的技术栈覆盖全面,能够充分展示开发者的前后端开发能力、数据库设计能力和系统架构能力。

但与此同时,电商系统毕设也存在着几个普遍痛点:架构设计缺乏整体规划,很多同学直接照搬开源项目,导致模块边界混乱;数据表设计不规范,没有考虑实际业务场景的扩展性;部署能力薄弱,毕设答辩时程序只能在本地运行,无法演示云上部署效果。

本文将从一个完整的电商系统出发,详细讲解模块化架构设计、核心功能实现和阿里云产品部署的全流程。通过本文的学习,你不仅能够掌握一个符合生产环境标准的电商系统开发方法,还能获得一套可以直接复用于毕设的完整项目模板。

二、电商系统整体架构设计

2.1 架构演进与选型背景

传统的单体电商系统架构简单但存在明显的扩展瓶颈。当业务量增长时,单体应用的所有模块都需要整体扩容,无法针对热点模块单独优化。而且代码高度耦合,任何一个模块的修改都可能影响整个系统。

微服务架构通过将业务拆分为独立的服务单元,解决了扩展性问题,但同时带来了运维复杂度。对于毕设项目,建议采用"适度微服务"方案:将系统拆分为用户服务、商品服务、订单服务等核心模块,使用阿里云托管产品降低运维负担。

┌────────────────────────────────────────────────────────────────────┐
│                   电商系统阿里云部署架构图                          │
├────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐ │
│   │                    阿里云CDN内容分发                          │ │
│   │              (静态资源加速:图片/CSS/JS)                   │ │
│   └─────────────────────────────────────────────────────────────┘ │
│                              │                                    │
│                              ▼                                    │
│   ┌─────────────────────────────────────────────────────────────┐ │
│   │                    阿里云弹性负载均衡SLB                     │ │
│   │                   (请求分发:HTTP/HTTPS)                    │ │
│   └─────────────────────────────────────────────────────────────┘ │
│                              │                                    │
│                              ▼                                    │
│   ┌─────────────────────────────────────────────────────────────┐ │
│   │                    云服务器ECS集群                           │ │
│   │   ┌────────────┐ ┌────────────┐ ┌────────────┐             │ │
│   │   │ 用户服务   │ │ 商品服务   │ │ 订单服务   │             │ │
│   │   │  (2台ECS) │ │  (2台ECS) │ │  (2台ECS) │             │ │
│   │   └────────────┘ └────────────┘ └────────────┘             │ │
│   └─────────────────────────────────────────────────────────────┘ │
│                              │                                    │
│         ┌────────────────────┼────────────────────┐              │
│         ▼                    ▼                    ▼              │
│   ┌───────────┐        ┌───────────┐        ┌───────────┐       │
│   │  RDS MySQL│        │ Redis缓存 │        │ OSS对象   │       │
│   │ (主从架构) │        │ (集群版)  │        │   存储    │       │
│   └───────────┘        └───────────┘        └───────────┘       │
│                                                                     │
└────────────────────────────────────────────────────────────────────┘

2.2 技术栈选型依据

层级 技术选型 阿里云产品 选型理由
前端框架 Vue.js 3 轻量级、组件化生态完善
后端框架 Spring Boot 2.7 Java系主流、性能稳定
服务网关 Spring Cloud Gateway API网关 统一入口、流量管控
数据库 MySQL 8.0 RDS MySQL 托管运维、自动备份
缓存 Redis 7.0 Redis企业版 高性能、支持集群
文件存储 OSS OSS对象存储 海量存储、CDN加速
负载均衡 SLB 传统型负载均衡 免费使用、稳定可靠
日志服务 SLS 日志服务 集中管理、实时分析

三、用户模块:从登录认证到权限管理

3.1 模块职责与技术方案

用户模块是电商系统的入口模块,负责用户身份认证、权限管理和个人信息维护。在技术实现上,采用Spring Security+JWT的组合方案,实现无状态的分布式认证。

// 用户认证核心配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
   

    @Autowired
    private JwtAuthenticationFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
   
        http
            .csrf().disable()
            .cors().configurationSource(corsConfigurationSource())
            .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeHttpRequests(auth -> auth
                .antMatchers("/api/auth/**", "/api/product/list").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

3.2 JWT Token生成与验证

@Component
public class JwtTokenProvider {
   

    @Value("${jwt.secret:your-secret-key}")
    private String jwtSecret;

    @Value("${jwt.expiration:604800000}")
    private long jwtExpiration;

    // 生成Token
    public String generateToken(Authentication authentication) {
   
        String username = authentication.getName();
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpiration);

        return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(SignatureAlgorithm.HS512, jwtSecret)
            .compact();
    }

    // 从Token获取用户名
    public String getUsernameFromToken(String token) {
   
        Claims claims = Jwts.parser()
            .setSigningKey(jwtSecret)
            .parseClaimsJws(token)
            .getBody();
        return claims.getSubject();
    }

    // 验证Token
    public boolean validateToken(String token) {
   
        try {
   
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
   
            return false;
        }
    }
}

3.3 用户数据表设计

-- 用户信息表
CREATE TABLE `sys_user` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
    `username` VARCHAR(50) NOT NULL COMMENT '用户名',
    `password` VARCHAR(128) NOT NULL COMMENT '密码(BCrypt加密)',
    `nickname` VARCHAR(50) DEFAULT NULL COMMENT '昵称',
    `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
    `phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
    `avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像URL(存储OSS地址)',
    `status` TINYINT DEFAULT 1 COMMENT '状态:0禁用 1正常',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 角色表
CREATE TABLE `sys_role` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `role_name` VARCHAR(50) NOT NULL COMMENT '角色名称',
    `role_key` VARCHAR(50) NOT NULL COMMENT '角色标识',
    `description` VARCHAR(200) DEFAULT NULL COMMENT '角色描述',
    `status` TINYINT DEFAULT 1,
    `create_time` DATETIME,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

-- 用户角色关联表
CREATE TABLE `sys_user_role` (
    `user_id` BIGINT NOT NULL,
    `role_id` BIGINT NOT NULL,
    PRIMARY KEY (`user_id`, `role_id`)
) ENGINE=InnoDB COMMENT='用户角色关联表';

-- 权限表(RBAC)
CREATE TABLE `sys_permission` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `parent_id` BIGINT DEFAULT 0 COMMENT '父权限ID',
    `name` VARCHAR(50) NOT NULL COMMENT '权限名称',
    `permission_key` VARCHAR(100) NOT NULL COMMENT '权限标识',
    `url` VARCHAR(255) DEFAULT NULL COMMENT '权限URL',
    `type` TINYINT DEFAULT 1 COMMENT '类型:1菜单 2按钮',
    `sort` INT DEFAULT 0,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';

四、商品模块:高并发场景下的缓存策略

4.1 模块职责边界

商品模块是电商系统中数据量最大、访问最频繁的模块。单个电商平台的商品数量可能达到百万级别,每天的访问PV可能过亿。因此,商品模块的架构设计必须充分考虑性能问题。

┌──────────────────────────────────────────────────────────────────┐
│                   商品模块数据访问架构                             │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│   用户请求 → CDN边缘节点 → Nginx本地缓存 → Redis分布式缓存       │
│                                    ↓                              │
│                              MySQL主数据库                        │
│                                                                   │
│   热点数据(热门商品):CDN缓存(1小时) + Redis缓存(10分钟)         │
│   普通数据(普通商品):Redis缓存(10分钟) + MySQL                 │
│   冷门数据(长尾商品):直接查询MySQL                             │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

4.2 商品数据表设计

-- 商品分类表(支持三级分类)
CREATE TABLE `product_category` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `parent_id` BIGINT DEFAULT 0 COMMENT '父分类ID',
    `name` VARCHAR(50) NOT NULL COMMENT '分类名称',
    `icon` VARCHAR(255) DEFAULT NULL COMMENT '分类图标(OSS)',
    `sort` INT DEFAULT 0 COMMENT '排序',
    `status` TINYINT DEFAULT 1,
    PRIMARY KEY (`id`),
    KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表';

-- 商品SPU表
CREATE TABLE `product_spu` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `category_id` BIGINT NOT NULL COMMENT '所属分类',
    `name` VARCHAR(200) NOT NULL COMMENT '商品名称',
    `subtitle` VARCHAR(500) DEFAULT NULL COMMENT '商品副标题',
    `brand` VARCHAR(100) DEFAULT NULL COMMENT '品牌',
    `keywords` VARCHAR(500) DEFAULT NULL COMMENT '搜索关键词',
    `description` TEXT COMMENT '商品详情(富文本)',
    `status` TINYINT DEFAULT 1 COMMENT '状态:0下架 1上架',
    `sales_count` INT DEFAULT 0 COMMENT '销量',
    `view_count` INT DEFAULT 0 COMMENT '浏览量',
    `create_time` DATETIME,
    `update_time` DATETIME,
    PRIMARY KEY (`id`),
    KEY `idx_category_id` (`category_id`),
    KEY `idx_brand` (`brand`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品SPU表';

-- 商品SKU表
CREATE TABLE `product_sku` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `spu_id` BIGINT NOT NULL COMMENT '所属SPU',
    `specs` VARCHAR(500) NOT NULL COMMENT '规格JSON',
    `price` DECIMAL(10,2) NOT NULL COMMENT '售价',
    `original_price` DECIMAL(10,2) DEFAULT NULL COMMENT '原价',
    `stock` INT DEFAULT 0 COMMENT '库存',
    `sku_code` VARCHAR(50) NOT NULL COMMENT 'SKU编码',
    `image` VARCHAR(255) DEFAULT NULL COMMENT 'SKU主图(OSS)',
    `status` TINYINT DEFAULT 1,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_sku_code` (`sku_code`),
    KEY `idx_spu_id` (`spu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品SKU表';

-- 商品图片表
CREATE TABLE `product_image` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `sku_id` BIGINT NOT NULL,
    `image_url` VARCHAR(255) NOT NULL COMMENT '图片URL(OSS)',
    `sort` INT DEFAULT 0,
    `is_main` TINYINT DEFAULT 0 COMMENT '是否主图',
    PRIMARY KEY (`id`),
    KEY `idx_sku_id` (`sku_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品图片表';

4.3 商品查询服务实现

@Service
public class ProductService {
   

    @Autowired
    private ProductSpuMapper spuMapper;

    @Autowired
    private ProductSkuMapper skuMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private AlibabaCloudOSSService ossService;

    private static final String PRODUCT_DETAIL_CACHE = "product:detail:";
    private static final String PRODUCT_LIST_CACHE = "product:list:";

    /**
     * 获取商品详情(多级缓存)
     */
    public ProductDetailVO getProductDetail(Long spuId) {
   
        String cacheKey = PRODUCT_DETAIL_CACHE + spuId;

        // 1. 查询Redis缓存
        ProductDetailVO cached = (ProductDetailVO) redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
   
            // 异步增加浏览量
            incrementViewCountAsync(spuId);
            return cached;
        }

        // 2. 查询数据库
        ProductSpu spu = spuMapper.selectById(spuId);
        if (spu == null || spu.getStatus() != 1) {
   
            throw new BusinessException("商品不存在或已下架");
        }

        // 3. 构建详情对象
        ProductDetailVO vo = buildProductDetailVO(spu);

        // 4. 写入Redis缓存(10分钟)
        redisTemplate.opsForValue().set(cacheKey, vo, 10, TimeUnit.MINUTES);

        // 5. 异步增加浏览量
        incrementViewCountAsync(spuId);

        return vo;
    }

    /**
     * 商品分页列表查询
     */
    public PageResult<ProductListVO> getProductList(ProductQueryDTO dto) {
   
        String cacheKey = PRODUCT_LIST_CACHE + dto.getCategoryId() + ":" 
                        + dto.getPage() + ":" + dto.getSize();

        // 1. 尝试从缓存获取
        PageResult cached = (PageResult) redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
   
            return cached;
        }

        // 2. 构建查询条件
        Example example = new Example(ProductSpu.class);
        Example.Criteria criteria = example.createCriteria()
            .andEqualTo("status", 1);

        if (dto.getCategoryId() != null) {
   
            // 查询当前分类及子分类
            List<Long> categoryIds = getCategoryAndChildrenIds(dto.getCategoryId());
            criteria.andIn("categoryId", categoryIds);
        }

        if (StringUtils.hasText(dto.getKeyword())) {
   
            criteria.andLike("name", "%" + dto.getKeyword() + "%");
        }

        // 3. 价格区间筛选
        if (dto.getMinPrice() != null) {
   
            // 需要联查SKU表获取最低价,此处简化处理
        }

        // 4. 排序
        if ("price_asc".equals(dto.getSort())) {
   
            example.setOrderByClause("price asc");
        } else if ("sales".equals(dto.getSort())) {
   
            example.setOrderByClause("sales_count desc");
        } else {
   
            example.setOrderByClause("create_time desc");
        }

        // 5. 分页查询
        PageHelper.startPage(dto.getPage(), dto.getSize());
        List<ProductSpu> list = spuMapper.selectByExample(example);
        Page<ProductSpu> page = (Page<ProductSpu>) list;

        // 6. 转换为VO
        List<ProductListVO> voList = list.stream()
            .map(this::convertToListVO)
            .collect(Collectors.toList());

        PageResult result = new PageResult<>(voList, page.getTotal(), page.getPages());

        // 7. 缓存结果
        redisTemplate.opsForValue().set(cacheKey, result, 5, TimeUnit.MINUTES);

        return result;
    }

    /**
     * 异步增加浏览量
     */
    @Async
    public void incrementViewCountAsync(Long spuId) {
   
        spuMapper.incrementViewCount(spuId);
    }
}

4.4 阿里云OSS文件上传

@Service
public class AlibabaCloudOSSService {
   

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.access-key-id}")
    private String accessKeyId;

    @Value("${aliyun.oss.access-key-secret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucket-name}")
    private String bucketName;

    /**
     * 上传商品图片到OSS
     */
    public String uploadProductImage(MultipartFile file, Long skuId) {
   
        // 1. 验证文件
        validateImageFile(file);

        // 2. 生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String newFileName = "product/" + skuId + "/" 
                           + UUID.randomUUID().toString().replace("-", "") 
                           + extension;

        // 3. 创建OSSClient
        OSS ossClient = new OSSClientBuilder()
            .build(endpoint, accessKeyId, accessKeySecret);

        try {
   
            // 4. 上传文件
            ossClient.putObject(bucketName, newFileName, file.getInputStream());

            // 5. 返回访问URL
            return "https://" + bucketName + "." + endpoint + "/" + newFileName;
        } finally {
   
            ossClient.shutdown();
        }
    }

    /**
     * 生成带签名的访问URL(用于私有读权限的Bucket)
     */
    public String generateSignedUrl(String objectKey, int expireSeconds) {
   
        OSS ossClient = new OSSClientBuilder()
            .build(endpoint, accessKeyId, accessKeySecret);

        try {
   
            Date expiration = new Date(System.currentTimeMillis() + expireSeconds * 1000L);
            URL url = ossClient.generatePresignedUrl(bucketName, objectKey, expiration);
            return url.toString();
        } finally {
   
            ossClient.shutdown();
        }
    }
}

五、订单模块:高并发下的库存扣减方案

5.1 订单状态机设计

订单模块是电商系统中并发压力最大的模块。双十一等大促期间,订单系统的TPS可能达到数万级别。如何在这种压力下保证库存不超卖、订单不重复,是订单模块设计的核心挑战。

┌──────────────────────────────────────────────────────────────────┐
│                   订单全生命周期状态流转                           │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│   ┌─────────┐                                                    │
│   │ 待支付  │ ←←←←←←← (订单超时自动取消)                         │
│   └───┬─────┘                                                    │
│       │ 支付成功                                                  │
│       ▼                                                          │
│   ┌─────────┐                                                    │
│   │ 已支付  │ ─────────────────→ ┌─────────┐                    │
│   └───┬─────┘                       │ 退款中  │                    │
│       │ 超时关闭                     └────┬────┘                  │
│       ▼                                 │                        │
│   ┌─────────┐                           │                        │
│   │ 已取消  │ ───────────────────────────┴────→ 已退款           │
│   └─────────┘                                                    │
│                                                                   │
│       │ 商家发货                                                  │
│       ▼                                                          │
│   ┌─────────┐                                                    │
│   │ 待发货  │                                                    │
│   └───┬─────┘                                                    │
│       │ 物流揽收                                                  │
│       ▼                                                          │
│   ┌─────────┐                                                    │
│   │ 已发货  │                                                    │
│   └───┬─────┘                                                    │
│       │ 确认收货                                                  │
│       ▼                                                          │
│   ┌─────────┐                                                    │
│   │ 已完成  │ ←←←←←←← (7天后自动完成)                            │
│   └─────────┘                                                    │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

5.2 订单数据表设计

-- 订单主表
CREATE TABLE `order_info` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `order_no` VARCHAR(32) NOT NULL COMMENT '订单号',
    `user_id` BIGINT NOT NULL COMMENT '用户ID',
    `total_amount` DECIMAL(10,2) NOT NULL COMMENT '订单总金额',
    `pay_amount` DECIMAL(10,2) NOT NULL COMMENT '实付金额',
    `freight_amount` DECIMAL(10,2) DEFAULT 0.00 COMMENT '运费',
    `discount_amount` DECIMAL(10,2) DEFAULT 0.00 COMMENT '优惠金额',
    `pay_type` TINYINT DEFAULT NULL COMMENT '支付方式:1微信 2支付宝',
    `status` TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态',
    `receiver_name` VARCHAR(50) NOT NULL COMMENT '收货人姓名',
    `receiver_phone` VARCHAR(20) NOT NULL COMMENT '收货人电话',
    `receiver_address` VARCHAR(255) NOT NULL COMMENT '收货地址',
    `remark` VARCHAR(500) DEFAULT NULL COMMENT '订单备注',
    `create_time` DATETIME,
    `pay_time` DATETIME COMMENT '支付时间',
    `ship_time` DATETIME COMMENT '发货时间',
    `receive_time` DATETIME COMMENT '收货时间',
    `finish_time` DATETIME COMMENT '完成时间',
    `cancel_time` DATETIME COMMENT '取消时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_order_no` (`order_no`),
    KEY `idx_user_id` (`user_id`),
    KEY `idx_status` (`status`),
    KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单主表';

-- 订单商品表
CREATE TABLE `order_item` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `order_id` BIGINT NOT NULL,
    `sku_id` BIGINT NOT NULL,
    `sku_name` VARCHAR(200) NOT NULL COMMENT '商品名称(快照)',
    `sku_specs` VARCHAR(500) DEFAULT NULL COMMENT '规格(快照)',
    `sku_image` VARCHAR(255) DEFAULT NULL COMMENT '商品图片(快照)',
    `price` DECIMAL(10,2) NOT NULL COMMENT '购买价格',
    `quantity` INT NOT NULL COMMENT '购买数量',
    `sub_total` DECIMAL(10,2) NOT NULL COMMENT '小计金额',
    PRIMARY KEY (`id`),
    KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单商品表';

-- 物流信息表
CREATE TABLE `order_shipping` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `order_id` BIGINT NOT NULL,
    `express_company` VARCHAR(50) DEFAULT NULL COMMENT '快递公司',
    `express_no` VARCHAR(50) DEFAULT NULL COMMENT '快递单号',
    `ship_time` DATETIME COMMENT '发货时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流信息表';

5.3 订单创建与库存扣减实现

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
   

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private ProductSkuMapper skuMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private AlibabaCloudMQService mqService;

    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(CreateOrderRequest request) {
   
        // 1. 分布式锁防止重复下单
        String lockKey = "lock:order:create:" + request.getUserId();
        String lockValue = UUID.randomUUID().toString();

        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);

        if (!locked) {
   
            throw new BusinessException("请勿重复提交订单");
        }

        try {
   
            // 2. 校验并扣减库存(Redis预扣减)
            List<OrderItemDTO> items = request.getItems();
            Map<Long, Integer> stockDeductMap = new HashMap<>();

            for (OrderItemDTO item : items) {
   
                // 校验库存
                String stockKey = "stock:" + item.getSkuId();
                String currentStock = redisTemplate.opsForValue().get(stockKey);

                if (currentStock == null) {
   
                    // 缓存未命中,从数据库加载
                    ProductSku sku = skuMapper.selectById(item.getSkuId());
                    currentStock = String.valueOf(sku.getStock());
                    redisTemplate.opsForValue().set(stockKey, currentStock, 1, TimeUnit.HOURS);
                }

                int stock = Integer.parseInt(currentStock);
                if (stock < item.getQuantity()) {
   
                    throw new BusinessException("商品库存不足:" + item.getSkuName());
                }

                // Redis扣减库存
                Long newStock = redisTemplate.opsForValue()
                    .decrement(stockKey, item.getQuantity());

                if (newStock < 0) {
   
                    // 扣减失败,回补并报错
                    redisTemplate.opsForValue().increment(stockKey, item.getQuantity());
                    throw new BusinessException("商品库存不足:" + item.getSkuName());
                }

                stockDeductMap.put(item.getSkuId(), item.getQuantity());
            }

            // 3. 计算订单金额
            BigDecimal totalAmount = calculateTotalAmount(items);
            BigDecimal discountAmount = calculateDiscount(request);
            BigDecimal payAmount = totalAmount.subtract(discountAmount);

            // 4. 生成订单号
            String orderNo = generateOrderNo();

            // 5. 创建订单
            Order order = new Order();
            order.setOrderNo(orderNo);
            order.setUserId(request.getUserId());
            order.setTotalAmount(totalAmount);
            order.setDiscountAmount(discountAmount);
            order.setPayAmount(payAmount);
            order.setStatus(OrderStatus.PENDING_PAY.getCode());
            order.setReceiverName(request.getReceiverName());
            order.setReceiverPhone(request.getReceiverPhone());
            order.setReceiverAddress(request.getReceiverAddress());
            order.setCreateTime(new Date());

            orderMapper.insert(order);

            // 6. 保存订单商品
            for (OrderItemDTO item : items) {
   
                ProductSku sku = skuMapper.selectById(item.getSkuId());
                ProductSpu spu = spuMapper.selectById(sku.getSpuId());

                OrderItem orderItem = new OrderItem();
                orderItem.setOrderId(order.getId());
                orderItem.setSkuId(item.getSkuId());
                orderItem.setSkuName(spu.getName());
                orderItem.setSkuSpecs(sku.getSpecs());
                orderItem.setSkuImage(getMainImage(item.getSkuId()));
                orderItem.setPrice(sku.getPrice());
                orderItem.setQuantity(item.getQuantity());
                orderItem.setSubTotal(sku.getPrice().multiply(new BigDecimal(item.getQuantity())));

                orderItemMapper.insert(orderItem);
            }

            // 7. 发送订单创建消息(用于后续库存数据库同步)
            mqService.sendOrderCreatedMessage(order.getId(), stockDeductMap);

            // 8. 设置订单超时(30分钟)
            redisTemplate.opsForValue().set(
                "order:timeout:" + orderNo, 
                orderNo, 
                30, 
                TimeUnit.MINUTES
            );

            log.info("订单创建成功:{}", orderNo);
            return order;

        } finally {
   
            // 释放分布式锁
            String currentLock = redisTemplate.opsForValue().get(lockKey);
            if (lockValue.equals(currentLock)) {
   
                redisTemplate.delete(lockKey);
            }
        }
    }

    private String generateOrderNo() {
   
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) 
               + RandomStringUtils.randomNumeric(6);
    }
}

5.4 库存数据库同步与超卖防护

@Service
public class StockSyncService {
   

    @Autowired
    private ProductSkuMapper skuMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 消费订单创建消息,同步扣减数据库库存
     */
    @RabbitListener(queues = "stock:deduct:queue")
    @Transactional
    public void handleStockDeduct(StockDeductMessage message) {
   
        for (Map.Entry<Long, Integer> entry : message.getStockMap().entrySet()) {
   
            Long skuId = entry.getKey();
            Integer quantity = entry.getValue();

            // 使用乐观锁更新数据库
            int rows = skuMapper.deductStockWithVersion(skuId, quantity);

            if (rows == 0) {
   
                // 数据库库存不足,需要回滚Redis
                redisTemplate.opsForValue()
                    .increment("stock:" + skuId, quantity);

                log.error("数据库库存扣减失败,SKU: {}, 数量: {}", skuId, quantity);
            }
        }
    }
}
<!-- StockMapper.xml -->
<update id="deductStockWithVersion">
    UPDATE product_sku 
    SET stock = stock - #{quantity},
        version = version + 1,
        update_time = NOW()
    WHERE id = #{skuId} 
      AND stock >= #{quantity}
      AND version = #{version}
</update>

六、支付模块:阿里云聚合支付集成

6.1 支付流程概述

┌──────────────────────────────────────────────────────────────────┐
│                     支付流程时序图                                 │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│   用户    前端服务    订单服务    支付服务    支付宝/微信         │
│    │        │          │          │           │                   │
│    │──下单──▶│         │          │           │                   │
│    │        │──创建订单─▶│          │           │                   │
│    │◀─订单信息─┤          │          │           │                   │
│    │        │          │          │           │                   │
│    │──发起支付─▶│         │          │           │                   │
│    │        │───────────▶│          │           │                   │
│    │        │          │───支付请求──▶│          │                   │
│    │        │          │◀───支付链接──┤          │                   │
│    │◀─支付链接─┤          │          │           │                   │
│    │        │          │          │           │                   │
│    │───────────支付宝/微信扫码支付────────▶│          │                   │
│    │        │          │          │◀──异步回调──┤                   │
│    │        │          │◀──更新订单状态─┤           │                   │
│    │◀─支付成功─┤          │          │           │                   │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

6.2 支付服务实现

@Service
@Slf4j
public class PaymentService {
   

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private WxPayService wxPayService;

    /**
     * 创建支付订单
     */
    public PaymentResponse createPayment(PaymentRequest request) {
   
        // 1. 查询订单
        Order order = orderMapper.selectByOrderNo(request.getOrderNo());
        if (order == null) {
   
            throw new BusinessException("订单不存在");
        }

        if (order.getStatus() != OrderStatus.PENDING_PAY.getCode()) {
   
            throw new BusinessException("订单状态不允许支付");
        }

        // 2. 根据支付方式调用对应服务
        PaymentResponse response = new PaymentResponse();
        response.setOrderNo(order.getOrderNo());
        response.setAmount(order.getPayAmount());

        if (PaymentType.ALIPAY.getCode().equals(request.getPayType())) {
   
            // 支付宝支付
            String payUrl = alipayService.createPayOrder(order);
            response.setPayUrl(payUrl);
            response.setPayType(PaymentType.ALIPAY);
        } else if (PaymentType.WXPAY.getCode().equals(request.getPayType())) {
   
            // 微信支付
            String codeUrl = wxPayService.createNativeOrder(order);
            response.setCodeUrl(codeUrl);
            response.setPayType(PaymentType.WXPAY);
        }

        return response;
    }

    /**
     * 支付宝异步回调处理
     */
    public void handleAlipayNotify(String notifyData) {
   
        try {
   
            // 验签
            boolean signVerified = alipayService.verifyNotify(notifyData);
            if (!signVerified) {
   
                log.error("支付宝回调验签失败");
                return;
            }

            // 解析回调数据
            AlipayTradeNotifyResponse response = alipayService.parseNotifyResponse(notifyData);

            String orderNo = response.getOutTradeNo();
            String tradeStatus = response.getTradeStatus();

            // 处理支付结果
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
   
                updateOrderPaid(orderNo, PaymentType.ALIPAY, response.getTradeNo());
            }

        } catch (Exception e) {
   
            log.error("处理支付宝回调异常", e);
        }
    }

    @Transactional
    public void updateOrderPaid(String orderNo, PaymentType payType, String transactionId) {
   
        Order order = orderMapper.selectByOrderNo(orderNo);

        if (order == null || order.getStatus() != OrderStatus.PENDING_PAY.getCode()) {
   
            return;
        }

        order.setStatus(OrderStatus.PAID.getCode());
        order.setPayType(payType.getCode());
        order.setPayTime(new Date());
        order.setTransactionId(transactionId);

        orderMapper.updateById(order);

        log.info("订单支付成功:{}", orderNo);
    }
}

七、阿里云云上部署实战

7.1 服务器与数据库准备

阿里云产品清单

产品 规格 用途 成本估算
ECS实例 2核4G * 2台 应用服务 约200元/月
RDS MySQL 2核4G高可用版 数据库 约300元/月
Redis 2G集群版 缓存 约150元/月
OSS 40G标准存储 文件存储 约10元/月
SLB 公网类型 负载均衡 约50元/月
合计 - - 约710元/月

7.2 应用服务部署配置

第一步:购买并配置ECS实例

在阿里云ECS控制台创建两台实例,选择CentOS 7.x系统盘,配置安全组规则开放80/443/8080端口。

# 连接ECS服务器
ssh root@your-ecs-ip

# 安装Java运行环境
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel

# 验证Java安装
java -version

# 安装Maven
yum install -y maven

# 安装Docker
yum install -y docker
systemctl start docker
systemctl enable docker

第二步:配置RDS MySQL

在阿里云RDS控制台创建MySQL 8.0高可用实例,配置白名单允许ECS内网访问。

# 从应用服务器连接RDS
mysql -h your-rds-endpoint -P 3306 -u your-username -p

# 创建数据库
CREATE DATABASE ecommerce DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

# 执行建表脚本(使用前述SQL)
source /path/to/init.sql;

第三步:构建并部署应用

# 在开发机器上构建
mvn clean package -DskipTests

# 上传JAR包到ECS
scp target/ecommerce-1.0.0.jar root@ecs1:/app/
scp target/ecommerce-1.0.0.jar root@ecs2:/app/

# 在ECS上创建启动脚本
cat > /app/start.sh << EOF
#!/bin/bash
export JAVA_OPTS="-Xms512m -Xmx1024m"
export SPRING_PROFILES_ACTIVE=prod
export MYSQL_HOST=your-rds-endpoint
export REDIS_HOST=your-redis-host
export OSS_ENDPOINT=your-oss-endpoint

java \$JAVA_OPTS -jar /app/ecommerce-1.0.0.jar
EOF

chmod +x /app/start.sh

# 启动应用
cd /app && nohup ./start.sh > app.log 2>&1 &

7.3 负载均衡配置

在阿里云SLB控制台创建传统型负载均衡实例:

  1. 添加后端服务器组,绑定两台ECS实例
  2. 配置健康检查(HTTP协议,检查路径:/actuator/health)
  3. 配置监听端口:80端口(HTTP)
# 验证部署
curl http://slb-public-ip/api/product/list

7.4 Nginx反向代理配置

# /etc/nginx/conf.d/ecommerce.conf

upstream backend {
   
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
   
    listen 80;
    server_name your-domain.com;

    # 前端静态资源
    location / {
   
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # API代理
    location /api/ {
   
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 超时配置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 静态资源代理到OSS
    location /oss/ {
   
        proxy_pass https://your-bucket.oss-cn-beijing.aliyuncs.com/;
    }
}

7.5 SSL证书配置(HTTPS)

server {
   
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /etc/nginx/ssl/your-cert.pem;
    ssl_certificate_key /etc/nginx/ssl/your-key.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_protocols TLSv1.2 TLSv1.3;

    # 安全头配置
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # 其他配置同上...
}

# HTTP重定向到HTTPS
server {
   
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

八、竞品对比分析

对比维度 阿里云部署方案 自建服务器方案 其他云平台
部署效率 图形化控制台,操作简单 需要手动配置全部组件 界面和阿里云类似
运维成本 托管服务,免维护 需要专职运维 介于两者之间
成本投入 按需付费,弹性计费 一次性投入高,但无持续费用 定价策略各异
产品生态 阿里云系产品深度集成 需自行集成 产品线丰富
数据库托管 RDS一键创建,自动备份 需自行搭建主从 提供托管服务
安全防护 免费DDoS基础防护 需自行配置 类似阿里云
适用场景 快速上线、弹性业务 有预算限制的场景 企业级应用

九、总结与延伸

本文系统讲解了电商系统的完整开发与阿里云部署方案,覆盖了从架构设计到云上部署的全流程。核心要点回顾:

  • 模块化架构:采用DDD思想划分用户、商品、订单、支付等核心模块
  • 高性能设计:通过多级缓存(CDN→Nginx→Redis)应对高并发场景
  • 分布式锁:使用Redis分布式锁防止库存超卖和重复下单
  • 消息队列:通过异步消息实现系统解耦和最终一致性
  • 云原生部署:基于阿里云ECS+RDS+Redis+OSS构建完整的云上基础设施

对于正在准备毕设的同学,建议从本文的架构设计中汲取思路,不必完全照搬。核心是理解为什么这样设计,以及如何在自己的项目中应用这些技术方案。

进阶学习路径建议

  • 初级阶段:完成单体电商系统的本地开发
  • 中级阶段:引入Redis缓存、异步消息等技术优化性能
  • 高级阶段:学习Docker容器化,使用阿里云ACK部署微服务架构

相关文章
|
2月前
|
SQL NoSQL 关系型数据库
数据库分类一次讲清|转行学DB第2天
数据库小学妹(UI转行萌新)用通俗语言拆解数据库分类:从关系型(MySQL/Oracle)、NoSQL(Redis/MongoDB/Cassandra)、NewSQL(TiDB)到2026年爆火的向量数据库(Pinecone/Milvus),按数据模型、部署架构、业务负载三大维度梳理,配场景化案例与选学路径,助新手轻松入门。
|
4月前
|
人工智能 API 机器人
OpenClaw 用户部署和使用指南汇总
本文档为OpenClaw(原MoltBot)官方使用指南,涵盖一键部署(阿里云轻量服务器年仅68元)、钉钉/飞书/企微等多平台AI员工搭建、典型场景实践及高频问题FAQ。同步更新产品化修复进展,助力用户高效落地7×24小时主动执行AI助手。
29620 253
|
5月前
|
Kubernetes 应用服务中间件 API
应对 Nginx Ingress 退役,是时候理清这些易混淆的概念了
本文希望提供一种更简单的方式,来理解这些容易混淆的技术概念:Nginx、Ingress、Ingress Controller、Ingress API、Nginx Ingress、Higress、Gateway API。
2430 154
|
5月前
|
前端开发 Java API
Spring Boot 整合 x-easypdf:5 分钟搞定 PDF 生成与中文排版
在 Java 开发中,生成 PDF 文档常面临中文乱码、排版困难、依赖库收费等痛点。本文推荐一款基于 PDFBox 深度封装的国产开源神器 —— x-easypdf。它内置中文字体,API 简洁易用,支持组件化开发。本文将通过一个“企业录用通知书生成器”的实战 Demo,带你体验 5 分钟快速实现 PDF 生成的全过程。
874 1
|
6月前
|
存储 缓存 搜索推荐
电商系统云架构设计
本文深入解析支撑千万级电商业务的云架构设计,涵盖高并发处理、数据层优化、智能搜索与推荐、大促保障等核心环节。基于云原生与微服务理念,构建弹性、稳定、高效的技术体系,助力企业应对流量峰值与复杂业务挑战,实现规模化发展。
438 0
|
12月前
|
SQL 自然语言处理 数据库
告别切屏|阿里云DMS MCP+通义灵码30分钟搞定电商秒杀开发
近日,阿里云数据管理DMS发布 开源DMS MCP Server,支持RDS、PolarDB、OLAP、NoSQL等40+主流数据源连接的多云通用数据MCP Server,一站式解决跨源数据安全访问。点击访问开源DMS MCP Server GitHub地址:https://github.com/aliyun/alibabacloud-dms-mcp-server
816 0
|
11月前
|
SQL 人工智能 安全
深度复盘MCP安全风暴:一个工单如何演变成数据库“特洛伊木马”危机?
近期,安全公司 General Analysis 披露的MCP安全漏洞在技术圈引发了巨大震动。这个"特洛伊木马"式的安全漏洞暴露了一个现实:AI时代,传统的数据库访问方式已经无法满足安全需求。阿里云数据管理DMS新推出的DMS MCP Server,正是为AI时代的数据库安全访问而生,它不仅完美解决了传统MCP的安全隐患,更为企业提供了一个安全、智能、高效的数据访问新范式。
743 5
|
SQL 关系型数据库 网络安全
Navicat Premium 17 最新版下载与配置:5分钟完成企业级数据库工具部署
Navicat Premium 17 是一款支持多种主流数据库(如 MySQL、Oracle、PostgreSQL 等)的多数据库管理工具,提供可视化数据建模、SQL 编辑和数据同步等功能。试用版提供 14 天全功能体验,商业版支持跨平台使用。安装环境要求 Windows 10/11 或 macOS 12.0+,最低配置为 4GB 内存。下载并解压安装包后,按步骤启动安装程序、接受许可协议、自定义安装路径并完成安装。首次运行时需激活许可证并配置数据库连接。常见问题包括无法写入注册表、试用期续费及连接数据库权限问题。高级功能涵盖 SSH 通道加速、自动化任务调度和性能调优建议。
5605 19
|
存储 数据采集 监控
阿里云DTS踩坑经验分享系列|SLS同步至ClickHouse集群
作为强大的日志服务引擎,SLS 积累了用户海量的数据。为了实现数据的自由流通,DTS 开发了以 SLS 为源的数据同步插件。目前,该插件已经支持将数据从 SLS 同步到 ClickHouse。通过这条高效的同步链路,客户不仅能够利用 SLS 卓越的数据采集和处理能力,还能够充分发挥 ClickHouse 在数据分析和查询性能方面的优势,帮助企业显著提高数据查询速度,同时有效降低存储成本,从而在数据驱动决策和资源优化配置上取得更大成效。
904 9
|
JavaScript 前端开发 API
【独家揭秘】如何从零开始,用Vue.js打造你的专属电商平台?
【8月更文挑战第30天】本教程将指导你使用Vue.js及其生态,包括Element UI,从零开始构建一个具备首页、商品列表、详情页、购物车及登录注册功能的基础电商平台前端。通过实践,你不仅将学会构建完整的Web应用,还将掌握Vue.js的高级特性和多种实用插件的使用方法,逐步提升应用的功能并优化用户体验。
561 0