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

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDSClaw,2核4GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 本文详解电商系统毕设开发与阿里云部署全流程:涵盖模块化架构设计、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部署微服务架构

相关文章
|
16天前
|
SQL NoSQL 关系型数据库
数据库分类一次讲清|转行学DB第2天
数据库小学妹(UI转行萌新)用通俗语言拆解数据库分类:从关系型(MySQL/Oracle)、NoSQL(Redis/MongoDB/Cassandra)、NewSQL(TiDB)到2026年爆火的向量数据库(Pinecone/Milvus),按数据模型、部署架构、业务负载三大维度梳理,配场景化案例与选学路径,助新手轻松入门。
|
存储 安全 前端开发
springboot057洗衣店订单管理系统
springboot057洗衣店订单管理系统
|
2月前
|
人工智能 API 机器人
OpenClaw 用户部署和使用指南汇总
本文档为OpenClaw(原MoltBot)官方使用指南,涵盖一键部署(阿里云轻量服务器年仅68元)、钉钉/飞书/企微等多平台AI员工搭建、典型场景实践及高频问题FAQ。同步更新产品化修复进展,助力用户高效落地7×24小时主动执行AI助手。
27046 203
|
1月前
|
人工智能 安全 前端开发
阿里开源 Team 版 OpenClaw,5分钟完成本地安装
HiClaw 是 OpenClaw 的升级版,通过引入 Manager Agent 架构和分布式设计,解决了 OpenClaw 在安全性、多任务协作、移动端体验、记忆管理等方面的核心痛点。
1916 60
阿里开源 Team 版 OpenClaw,5分钟完成本地安装
|
11天前
|
SQL 运维 监控
【生产避坑】Flink CDC + SQL Server 无增量?5分钟定位,直接抄解决方案
【生产避坑】Flink CDC同步SQL Server时增量失效?80%问题源于SQL Server Agent未启动!本文5分钟定位根因:先查CDC开关→再验CT表数据→最终确认Agent状态。附完整排查流程、3种启动方案及监控建议,直击要害,照抄即用,快速恢复实时同步!
114 6
|
14天前
|
分布式计算 MaxCompute iOS开发
TorchEasyRec 在 macOS 上的功能限制总结
本文总结tzrec在macOS上的功能限制:核心依赖(如torchrec、fbgemm-gpu、graphlearn等)无法安装;分布式训练、原生数据管线、Embedding模块、Triton/CUDA算子、TDM树模型等功能完全不可用;优化器与模型导出部分失效;单元测试大多因强依赖而失败。
112 15
|
9天前
|
Windows Python
SBTI 人格测试人一多网站就崩?试试这个本机就能轻松下载的 SBTI 测试
SBTI人格测试火爆致官网崩坏?这款Windows桌面版解压即用,离线答题不卡顿、不抢带宽,支持单机多测、随时分享。源自开源项目,尊重原作者,GitHub可下载或联系作者秒发包。(239字)
1287 11
|
3月前
|
Kubernetes 应用服务中间件 API
应对 Nginx Ingress 退役,是时候理清这些易混淆的概念了
本文希望提供一种更简单的方式,来理解这些容易混淆的技术概念:Nginx、Ingress、Ingress Controller、Ingress API、Nginx Ingress、Higress、Gateway API。
1726 111
下一篇
开通oss服务