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

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

相关文章
|
13天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
11452 124
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
2天前
|
人工智能 JSON 监控
Claude Code 源码泄露:一份价值亿元的 AI 工程公开课
我以为顶级 AI 产品的护城河是模型。读完这 51.2 万行泄露的源码,我发现自己错了。
3459 8
|
1天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
1327 2
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
12天前
|
人工智能 IDE API
2026年国内 Codex 安装教程和使用教程:GPT-5.4 完整指南
Codex已进化为AI编程智能体,不仅能补全代码,更能理解项目、自动重构、执行任务。本文详解国内安装、GPT-5.4接入、cc-switch中转配置及实战开发流程,助你从零掌握“描述需求→AI实现”的新一代工程范式。(239字)
7462 139
|
2天前
|
云安全 供应链 安全
Axios投毒事件:阿里云安全复盘分析与关键防护建议
阿里云云安全中心和云防火墙第一时间响应
1144 0
|
3天前
|
人工智能 自然语言处理 数据挖掘
零基础30分钟搞定 Claude Code,这一步90%的人直接跳过了
本文直击Claude Code使用痛点,提供零基础30分钟上手指南:强调必须配置“工作上下文”(about-me.md+anti-ai-style.md)、采用Cowork/Code模式、建立标准文件结构、用提问式提示词驱动AI理解→规划→执行。附可复制模板与真实项目启动法,助你将Claude从聊天工具升级为高效执行系统。
|
2天前
|
人工智能 定位技术
Claude Code源码泄露:8大隐藏功能曝光
2026年3月,Anthropic因配置失误致Claude Code超51万行源码泄露,意外促成“被动开源”。代码中藏有8大未发布功能,揭示其向“超级智能体”演进的完整蓝图,引发AI编程领域震动。(239字)
2150 9
|
11天前
|
人工智能 并行计算 Linux
本地私有化AI助手搭建指南:Ollama+Qwen3.5-27B+OpenClaw阿里云/本地部署流程
本文提供的全流程方案,从Ollama安装、Qwen3.5-27B部署,到OpenClaw全平台安装与模型对接,再到RTX 4090专属优化,覆盖了搭建过程的每一个关键环节,所有代码命令可直接复制执行。使用过程中,建议优先使用本地模型保障隐私,按需切换云端模型补充功能,同时注重显卡温度与显存占用监控,确保系统稳定运行。
2550 9