Java项目实战:企业级电商平台全流程开发(Spring Cloud Alibaba+微服务架构)
第二十三章 Java项目实战:企业级电商平台全流程开发(Spring Cloud Alibaba+微服务架构)
一、章节学习目标与重点
1.1 学习目标
- 理解企业级电商平台的核心业务架构与技术选型逻辑,掌握从需求分析到系统上线的全流程开发方法。
- 熟练运用Spring Cloud Alibaba生态组件(Nacos、Sentinel、RocketMQ等)构建高可用、高并发的微服务集群。
- 独立完成电商平台核心模块(用户、商品、订单、支付、物流)的需求分析、架构设计、代码实现与测试部署。
- 解决电商场景中的关键技术问题(分布式事务、高并发库存扣减、秒杀限流、数据一致性等)。
- 掌握企业级项目的工程化实践(代码规范、版本控制、CI/CD流程、监控运维),具备独立负责中大型Java项目的能力。
1.2 学习重点
- 电商平台微服务拆分(基于DDD领域驱动设计)与整体架构设计。
- 核心模块实战:用户认证授权、商品管理与搜索、订单创建与支付、物流跟踪全流程实现。
- 高并发场景解决方案:秒杀系统设计、库存防超卖、缓存分层架构。
- 分布式问题解决:基于Seata的分布式事务、基于RocketMQ的可靠消息投递。
- 项目工程化与运维:Docker容器化部署、K8s编排、Prometheus+Grafana监控。
二、项目概述:企业级电商平台核心规划
2.1 项目背景与业务范围
💡 本项目是一款面向C端用户的全品类电商平台,支持商品浏览、搜索、加入购物车、下单支付、物流跟踪、售后维权等核心功能,同时提供商家管理、平台运营等后台能力。项目目标是支撑日均100万活跃用户、峰值10万QPS的高并发场景,确保系统高可用(99.9%)、数据一致性与安全性。
核心业务范围:
- 用户域:注册、登录、个人信息管理、地址管理、权限控制。
- 商品域:商品发布、分类管理、库存管理、商品搜索、商品评价。
- 订单域:购物车、订单创建、订单支付、订单查询、订单取消。
- 支付域:支付渠道整合(支付宝、微信支付)、支付回调、退款处理。
- 物流域:物流单创建、物流信息跟踪、收货确认。
- 运营域:促销活动(秒杀、满减)、优惠券、数据统计分析。
2.2 技术架构设计
基于Spring Cloud Alibaba生态构建微服务架构,整体架构分为6层:客户端层、网关层、微服务层、中间件层、数据层、运维层,架构图如下:
┌─────────────────────────────────────────────────────────────────────────┐ │ 客户端层 │ │ (Web端、APP端、小程序端、商家后台) │ └───────────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────────┐ │ 网关层(Spring Cloud Gateway) │ │ (路由转发、统一认证、限流熔断、安全过滤) │ └─┬───────────────┬───────────────┬───────────────┬───────────────┬───────┘ │ │ │ │ │ ┌─▼───────┐ ┌───▼───────┐ ┌───▼───────┐ ┌───▼───────┐ ┌───▼───────┐ │用户服务 │ │商品服务 │ │订单服务 │ │支付服务 │ │物流服务 │ │(User-Svc)│ │(Product-Svc)│ │(Order-Svc)│ │(Pay-Svc) │ │(Logistics-Svc)│ └─┬───────┘ └───┬───────┘ └───┬───────┘ └───┬───────┘ └───┬───────┘ │ │ │ │ │ ┌─▼───────────────▼───────────────▼───────────────▼───────────────▼───────┐ │ 中间件层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Nacos │ │ Sentinel │ │ RocketMQ │ │ Redis │ │ │ │(注册/配置) │ │(限流熔断) │ │(消息队列) │ │(缓存/锁) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Seata │ │ Elasticsearch│ │ SkyWalking │ │ │ │(分布式事务)│ │(商品搜索) │ │(链路追踪) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─┬───────────────┬───────────────┬───────────────┬───────────────┬───────┘ │ │ │ │ │ ┌─▼───────┐ ┌───▼───────┐ ┌───▼───────┐ ┌───▼───────┐ ┌───▼───────┐ │用户数据库│ │商品数据库│ │订单数据库│ │支付数据库│ │物流数据库│ │(MySQL) │ │(MySQL) │ │(MySQL) │ │(MySQL) │ │(MySQL) │ └─────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ │ │ │ │ ┌─▼───────────────▼───────────────▼───────────────▼───────────────▼───────┐ │ 运维层 │ │ (Docker+K8s部署、Prometheus+Grafana监控、ELK日志分析、CI/CD流程) │ └─────────────────────────────────────────────────────────────────────────┘ 2.3 技术栈选型
| 技术层面 | 选型方案 | 核心优势 |
|---|---|---|
| 开发语言 | Java 11 | 稳定性强、生态完善、长期支持 |
| 开发框架 | Spring Boot 2.7.x、Spring Cloud Alibaba 2021.0.4.0 | 微服务生态成熟、组件丰富、国内企业广泛使用 |
| 网关 | Spring Cloud Gateway | 异步非阻塞、性能优异、支持动态路由 |
| 注册/配置中心 | Nacos | 高可用、支持动态配置、服务发现功能完善 |
| 限流熔断 | Sentinel | 轻量级、支持多种限流策略、适配微服务场景 |
| 消息队列 | RocketMQ | 高吞吐、低延迟、支持事务消息 |
| 分布式事务 | Seata | 对业务侵入低、支持AT/TCC模式 |
| 缓存 | Redis 6.x | 高性能、支持多种数据结构、集群部署 |
| 搜索引擎 | Elasticsearch 7.17.x | 全文检索高效、支持商品搜索与过滤 |
| 数据库 | MySQL 8.0(主从复制) | 稳定性强、生态完善、支持读写分离 |
| 容器化/编排 | Docker、Kubernetes | 环境一致性、弹性伸缩、简化部署 |
| 监控运维 | Prometheus+Grafana、SkyWalking、ELK | 全链路可观测、问题快速定位 |
| 构建工具 | Maven 3.8.x | 依赖管理便捷、插件丰富 |
| 版本控制 | Git+GitLab | 分布式版本控制、支持分支管理 |
三、项目初始化:工程结构与基础配置
3.1 工程结构设计(多模块)
采用Maven多模块结构,分为“父工程+公共模块+微服务模块”,确保代码复用与统一管理:
e-commerce-platform/ # 父工程(统一依赖管理) ├── pom.xml # 父POM,管理所有依赖版本 ├── common/ # 公共模块(通用工具、实体类、异常处理) │ ├── common-core/ # 核心工具(加密、脱敏、日期处理) │ ├── common-db/ # 数据库相关(MyBatis配置、分页插件) │ ├── common-security/ # 安全相关(JWT、权限注解) │ └── common-web/ # Web相关(全局异常、统一响应) ├── api/ # 接口模块(微服务API定义、Feign客户端) │ ├── user-api/ # 用户服务API │ ├── product-api/ # 商品服务API │ └── order-api/ # 订单服务API └── service/ # 微服务实现模块 ├── user-service/ # 用户服务 ├── product-service/ # 商品服务 ├── order-service/ # 订单服务 ├── pay-service/ # 支付服务 └── logistics-service/ # 物流服务 3.2 父工程POM配置(核心依赖管理)
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example.ecommerce</groupId><artifactId>e-commerce-platform</artifactId><version>1.0.0</version><packaging>pom</packaging><name>电商平台父工程</name><!-- 统一依赖版本管理 --><properties><java.version>11</java.version><spring-boot.version>2.7.15</spring-boot.version><spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version><mybatis-plus.version>3.5.3.1</mybatis-plus.version><mysql.version>8.0.33</mysql.version><redis.version>6.2.14</redis.version><lombok.version>1.18.28</lombok.version></properties><!-- 依赖管理(子模块继承,无需指定版本) --><dependencyManagement> <<dependencies><!-- Spring Boot 父依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!-- Spring Cloud Alibaba 依赖管理 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!-- 数据库相关 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!-- 工具类 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><optional>true</optional></dependency> </</dependencies></dependencyManagement><modules><module>common</module><module>api</module><module>service</module></modules></project>3.3 公共模块核心组件实现
3.3.1 统一响应结果(common-web)
importlombok.Data;/** * 统一API响应结果 */@DatapublicclassR<T>{privateint code;// 响应码(200成功,其他失败)privateString msg;// 响应信息privateT data;// 响应数据// 成功响应(无数据)publicstatic<T>R<T>success(){returnnewR<>(200,"操作成功",null);}// 成功响应(有数据)publicstatic<T>R<T>success(T data){returnnewR<>(200,"操作成功", data);}// 失败响应publicstatic<T>R<T>error(int code,String msg){returnnewR<>(code, msg,null);}// 常用失败响应(参数错误)publicstatic<T>R<T>paramError(){returnnewR<>(400,"参数错误",null);}// 常用失败响应(未授权)publicstatic<T>R<T>unauthorized(){returnnewR<>(401,"未授权",null);}}3.3.2 全局异常处理(common-web)
importlombok.extern.slf4j.Slf4j;importorg.springframework.http.HttpStatus;importorg.springframework.validation.BindingResult;importorg.springframework.validation.FieldError;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseStatus;importorg.springframework.web.bind.annotation.RestControllerAdvice;/** * 全局异常处理器 */@Slf4j@RestControllerAdvicepublicclassGlobalExceptionHandler{// 业务异常处理@ExceptionHandler(BusinessException.class)publicR<Void>handleBusinessException(BusinessException e){ log.error("业务异常:{}", e.getMessage(), e);returnR.error(e.getCode(), e.getMessage());}// 参数校验异常处理@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)publicR<Void>handleValidException(MethodArgumentNotValidException e){BindingResult bindingResult = e.getBindingResult();StringBuilder errorMsg =newStringBuilder("参数校验失败:");for(FieldError fieldError : bindingResult.getFieldErrors()){ errorMsg.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(",");}String msg = errorMsg.substring(0, errorMsg.length()-1); log.error(msg);returnR.error(400, msg);}// 通用异常处理@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)publicR<Void>handleException(Exception e){ log.error("系统异常:", e);returnR.error(500,"系统繁忙,请稍后再试");}}// 自定义业务异常publicclassBusinessExceptionextendsRuntimeException{privateint code;publicBusinessException(int code,String message){super(message);this.code = code;}publicintgetCode(){return code;}}3.3.3 数据库配置(common-db)
importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;/** * MyBatis-Plus 配置 */@Configuration@MapperScan("com.example.ecommerce.**.mapper")// 扫描所有模块的Mapper接口publicclassMybatisPlusConfig{// 分页插件@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptor interceptor =newMybatisPlusInterceptor(); interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));return interceptor;}// 开启驼峰命名自动转换@BeanpublicConfigurationCustomizerconfigurationCustomizer(){return configuration -> configuration.setMapUnderscoreToCamelCase(true);}}3.4 微服务基础配置(以用户服务为例)
3.4.1 应用配置(application.yml)
spring:application:name: user-service # 服务名称(注册到Nacos)cloud:nacos:discovery:server-addr: localhost:8848# Nacos服务发现地址config:server-addr: localhost:8848# Nacos配置中心地址file-extension: yaml # 配置文件格式namespace: public # 命名空间datasource:url: jdbc:mysql://localhost:3306/ecommerce_user?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: root password: root123 driver-class-name: com.mysql.cj.jdbc.Driver redis:host: localhost port:6379password:database:0server:port:8081# 服务端口mybatis-plus:mapper-locations: classpath:mapper/*.xml# Mapper XML文件路径type-aliases-package: com.example.ecommerce.user.entity # 实体类别名包configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志management:endpoints:web:exposure:include: health,info,prometheus # 暴露监控端点endpoint:health:show-details: always # 显示健康检查详情# 自定义配置user:jwt:secret: ecommerce-user-jwt-secret-2024# JWT密钥expire:7200000# 过期时间(2小时)3.4.2 启动类
importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cloud.client.discovery.EnableDiscoveryClient;importorg.springframework.cloud.openfeign.EnableFeignClients;/** * 用户服务启动类 */@SpringBootApplication(scanBasePackages ="com.example.ecommerce")@EnableDiscoveryClient// 开启服务注册发现@EnableFeignClients(basePackages ="com.example.ecommerce.api")// 开启Feign调用publicclassUserServiceApplication{publicstaticvoidmain(String[] args){SpringApplication.run(UserServiceApplication.class, args);}}四、核心模块实战:用户服务开发
4.1 需求分析与数据模型
4.1.1 核心需求
- 用户注册:手机号验证码注册、用户名密码注册,支持重复手机号校验。
- 用户登录:手机号+密码登录、手机号+验证码登录、第三方登录(微信、QQ)。
- 个人信息管理:查询/修改昵称、头像、性别等基本信息。
- 地址管理:新增、查询、修改、删除收货地址,设置默认地址。
- 权限控制:普通用户、商家用户、管理员用户的权限区分。
4.1.2 数据模型设计(MySQL)
-- 用户表CREATETABLE`user`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'用户ID',`username`varchar(50)NOTNULLCOMMENT'用户名',`phone`varchar(20)NOTNULLCOMMENT'手机号',`password`varchar(100)NOTNULLCOMMENT'加密后的密码',`avatar`varchar(255)DEFAULT''COMMENT'头像URL',`gender`tinyintDEFAULT0COMMENT'性别(0-未知,1-男,2-女)',`status`tinyintNOTNULLDEFAULT1COMMENT'状态(1-正常,0-禁用)',`user_type`tinyintNOTNULLDEFAULT0COMMENT'用户类型(0-普通用户,1-商家,2-管理员)',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),UNIQUEKEY`uk_phone`(`phone`),UNIQUEKEY`uk_username`(`username`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='用户表';-- 收货地址表CREATETABLE`user_address`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'地址ID',`user_id`bigintNOTNULLCOMMENT'用户ID',`receiver`varchar(50)NOTNULLCOMMENT'收货人',`phone`varchar(20)NOTNULLCOMMENT'收货人手机号',`province`varchar(20)NOTNULLCOMMENT'省份',`city`varchar(20)NOTNULLCOMMENT'城市',`district`varchar(20)NOTNULLCOMMENT'区县',`detail_address`varchar(255)NOTNULLCOMMENT'详细地址',`is_default`tinyintNOTNULLDEFAULT0COMMENT'是否默认地址(1-是,0-否)',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),KEY`idx_user_id`(`user_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='收货地址表';-- 验证码表CREATETABLE`sms_code`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'ID',`phone`varchar(20)NOTNULLCOMMENT'手机号',`code`varchar(10)NOTNULLCOMMENT'验证码',`scene`varchar(20)NOTNULLCOMMENT'场景(register-注册,login-登录)',`expire_time`datetimeNOTNULLCOMMENT'过期时间',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',PRIMARYKEY(`id`),KEY`idx_phone_scene`(`phone`,`scene`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='验证码表';4.2 核心功能实现
4.2.1 实体类与Mapper
// 用户实体类importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.annotation.TableId;importcom.baomidou.mybatisplus.annotation.TableName;importlombok.Data;importjava.time.LocalDateTime;@Data@TableName("user")publicclassUser{@TableId(type =IdType.AUTO)privateLong id;privateString username;privateString phone;privateString password;privateString avatar;privateInteger gender;// 0-未知,1-男,2-女privateInteger status;// 1-正常,0-禁用privateInteger userType;// 0-普通用户,1-商家,2-管理员privateLocalDateTime createTime;privateLocalDateTime updateTime;}// 用户Mapper接口importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importorg.apache.ibatis.annotations.Mapper;importorg.apache.ibatis.annotations.Param;@MapperpublicinterfaceUserMapperextendsBaseMapper<User>{// 根据手机号查询用户UserselectByPhone(@Param("phone")String phone);// 根据用户名查询用户UserselectByUsername(@Param("username")String username);}4.2.2 服务层实现(用户注册)
importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.common.core.util.PasswordUtil;importcom.example.ecommerce.user.entity.SmsCode;importcom.example.ecommerce.user.entity.User;importcom.example.ecommerce.user.mapper.SmsCodeMapper;importcom.example.ecommerce.user.mapper.UserMapper;importcom.example.ecommerce.user.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.time.LocalDateTime;@ServicepublicclassUserServiceImplimplementsUserService{@AutowiredprivateUserMapper userMapper;@AutowiredprivateSmsCodeMapper smsCodeMapper;@AutowiredprivatePasswordUtil passwordUtil;/** * 手机号验证码注册 */@Override@Transactional(rollbackFor =Exception.class)publicvoidregisterBySms(String phone,String code,String username,String password){// 1. 校验验证码SmsCode smsCode = smsCodeMapper.selectOne(newLambdaQueryWrapper<SmsCode>().eq(SmsCode::getPhone, phone).eq(SmsCode::getScene,"register").ge(SmsCode::getExpireTime,LocalDateTime.now()));if(smsCode ==null||!smsCode.getCode().equals(code)){thrownewBusinessException(400,"验证码无效或已过期");}// 2. 校验手机号是否已注册User existUser = userMapper.selectByPhone(phone);if(existUser !=null){thrownewBusinessException(400,"该手机号已注册");}// 3. 校验用户名是否已存在User existUsername = userMapper.selectByUsername(username);if(existUsername !=null){thrownewBusinessException(400,"用户名已被占用");}// 4. 密码加密String encryptedPassword = passwordUtil.encryptPassword(password);// 5. 保存用户信息User user =newUser(); user.setPhone(phone); user.setUsername(username); user.setPassword(encryptedPassword); user.setGender(0);// 默认未知性别 user.setStatus(1);// 正常状态 user.setUserType(0);// 普通用户 userMapper.insert(user);// 6. 删除已使用的验证码 smsCodeMapper.deleteById(smsCode.getId());}}4.2.3 控制器实现(用户注册与登录)
importcom.example.ecommerce.common.web.result.R;importcom.example.ecommerce.user.dto.UserLoginDTO;importcom.example.ecommerce.user.dto.UserRegisterDTO;importcom.example.ecommerce.user.entity.User;importcom.example.ecommerce.user.service.UserService;importcom.example.ecommerce.user.service.SmsService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.*;importjavax.validation.Valid;importjavax.validation.constraints.NotBlank;@RestController@RequestMapping("/api/user")@ValidatedpublicclassUserController{@AutowiredprivateUserService userService;@AutowiredprivateSmsService smsService;/** * 发送注册验证码 */@GetMapping("/sms/register")publicR<Void>sendRegisterSms(@NotBlank(message ="手机号不能为空")@RequestParamString phone){ smsService.sendSms(phone,"register");returnR.success();}/** * 手机号验证码注册 */@PostMapping("/register/sms")publicR<Void>registerBySms(@Valid@RequestBodyUserRegisterDTO registerDTO){ userService.registerBySms( registerDTO.getPhone(), registerDTO.getCode(), registerDTO.getUsername(), registerDTO.getPassword());returnR.success("注册成功");}/** * 手机号密码登录 */@PostMapping("/login")publicR<String>login(@Valid@RequestBodyUserLoginDTO loginDTO){String token = userService.loginByPassword(loginDTO.getPhone(), loginDTO.getPassword());returnR.success(token);}/** * 获取用户信息 */@GetMapping("/info")publicR<User>getUserInfo(@RequestHeader("X-User-Id")Long userId){User user = userService.getById(userId);// 脱敏处理:隐藏密码 user.setPassword(null);returnR.success(user);}}// 注册DTOimportlombok.Data;importjavax.validation.constraints.NotBlank;importjavax.validation.constraints.Size;@DatapublicclassUserRegisterDTO{@NotBlank(message ="手机号不能为空")privateString phone;@NotBlank(message ="验证码不能为空")privateString code;@NotBlank(message ="用户名不能为空")@Size(min =4, max =20, message ="用户名长度为4-20位")privateString username;@NotBlank(message ="密码不能为空")@Size(min =8, max =20, message ="密码长度为8-20位")privateString password;}// 登录DTOimportlombok.Data;importjavax.validation.constraints.NotBlank;@DatapublicclassUserLoginDTO{@NotBlank(message ="手机号不能为空")privateString phone;@NotBlank(message ="密码不能为空")privateString password;}4.2.4 JWT认证实现(common-security)
importio.jsonwebtoken.Claims;importio.jsonwebtoken.Jwts;importio.jsonwebtoken.security.Keys;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.stereotype.Component;importjavax.crypto.SecretKey;importjava.util.Date;@ComponentpublicclassJwtTokenProvider{@Value("${user.jwt.secret}")privateString secret;@Value("${user.jwt.expire}")privatelong expire;@AutowiredprivateUserDetailsService userDetailsService;// 生成密钥privateSecretKeygetSecretKey(){returnKeys.hmacShaKeyFor(secret.getBytes());}// 生成JWT令牌publicStringgenerateToken(Long userId,String username){returnJwts.builder().setSubject(userId.toString())// 存储用户ID.claim("username", username)// 存储用户名.setIssuedAt(newDate()).setExpiration(newDate(System.currentTimeMillis()+ expire)).signWith(getSecretKey()).compact();}// 验证令牌有效性publicbooleanvalidateToken(String token){try{Jwts.parserBuilder().setSigningKey(getSecretKey()).build().parseClaimsJws(token);returntrue;}catch(Exception e){returnfalse;}}// 从令牌中获取用户IDpublicLonggetUserIdFromToken(String token){Claims claims =Jwts.parserBuilder().setSigningKey(getSecretKey()).build().parseClaimsJws(token).getBody();returnLong.parseLong(claims.getSubject());}// 获取认证信息publicAuthenticationgetAuthentication(String token){String userId =getUserIdFromToken(token);UserDetails userDetails = userDetailsService.loadUserByUsername(userId.toString());returnnewUsernamePasswordAuthenticationToken(userDetails,"", userDetails.getAuthorities());}}五、核心模块实战:商品服务与库存管理
5.1 需求分析与数据模型
5.1.1 核心需求
- 商品管理:商家发布商品、编辑商品信息、上下架商品。
- 分类管理:多级商品分类(如电子产品→手机→智能手机)。
- 库存管理:库存增减、库存锁定(下单时)、库存释放(订单取消)。
- 商品搜索:支持关键词搜索、分类筛选、价格区间筛选、销量排序。
- 商品评价:用户对已购买商品进行评分和评论。
5.1.2 数据模型设计
-- 商品分类表CREATETABLE`product_category`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'分类ID',`name`varchar(50)NOTNULLCOMMENT'分类名称',`parent_id`bigintNOTNULLDEFAULT0COMMENT'父分类ID(0为一级分类)',`sort`intNOTNULLDEFAULT0COMMENT'排序(数字越小越靠前)',`status`tinyintNOTNULLDEFAULT1COMMENT'状态(1-启用,0-禁用)',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),KEY`idx_parent_id`(`parent_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='商品分类表';-- 商品表CREATETABLE`product`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'商品ID',`name`varchar(255)NOTNULLCOMMENT'商品名称',`category_id`bigintNOTNULLCOMMENT'分类ID',`price`decimal(10,2)NOTNULLCOMMENT'售价',`original_price`decimal(10,2)DEFAULTNULLCOMMENT'原价',`stock`intNOTNULLDEFAULT0COMMENT'库存',`sales`intNOTNULLDEFAULT0COMMENT'销量',`cover_img`varchar(255)NOTNULLCOMMENT'封面图URL',`detail`textCOMMENT'商品详情',`status`tinyintNOTNULLDEFAULT1COMMENT'状态(1-上架,0-下架)',`merchant_id`bigintNOTNULLCOMMENT'商家ID',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),KEY`idx_category_id`(`category_id`),KEY`idx_merchant_id`(`merchant_id`), FULLTEXT KEY`ft_name`(`name`)COMMENT'商品名称全文索引')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='商品表';-- 商品库存锁定表(防止超卖)CREATETABLE`product_stock_lock`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'ID',`product_id`bigintNOTNULLCOMMENT'商品ID',`order_id`bigintNOTNULLCOMMENT'订单ID',`lock_num`intNOTNULLCOMMENT'锁定库存数量',`expire_time`datetimeNOTNULLCOMMENT'过期时间',`status`tinyintNOTNULLDEFAULT0COMMENT'状态(0-锁定中,1-已解锁,2-已扣减)',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),KEY`idx_product_id`(`product_id`),KEY`idx_order_id`(`order_id`),KEY`idx_expire_time`(`expire_time`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='商品库存锁定表';-- 商品评价表CREATETABLE`product_comment`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'评价ID',`product_id`bigintNOTNULLCOMMENT'商品ID',`user_id`bigintNOTNULLCOMMENT'用户ID',`order_id`bigintNOTNULLCOMMENT'订单ID',`score`tinyintNOTNULLCOMMENT'评分(1-5分)',`content`varchar(500)DEFAULT''COMMENT'评价内容',`img_urls`varchar(1000)DEFAULT''COMMENT'评价图片URL(多个用逗号分隔)',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',PRIMARYKEY(`id`),KEY`idx_product_id`(`product_id`),KEY`idx_user_id`(`user_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='商品评价表';5.2 核心功能实现(库存管理与防超卖)
5.2.1 库存锁定(下单时)
importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.product.entity.Product;importcom.example.ecommerce.product.entity.ProductStockLock;importcom.example.ecommerce.product.mapper.ProductMapper;importcom.example.ecommerce.product.mapper.ProductStockLockMapper;importcom.example.ecommerce.product.service.ProductService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.time.LocalDateTime;importjava.util.concurrent.TimeUnit;@ServicepublicclassProductServiceImplimplementsProductService{@AutowiredprivateProductMapper productMapper;@AutowiredprivateProductStockLockMapper stockLockMapper;@AutowiredprivateStringRedisTemplate redisTemplate;// 分布式锁前缀privatestaticfinalString STOCK_LOCK_KEY ="product:stock:lock:";/** * 锁定库存(下单时) * @param productId 商品ID * @param orderId 订单ID * @param lockNum 锁定数量 * @return 锁定是否成功 */@Override@Transactional(rollbackFor =Exception.class)publicbooleanlockStock(Long productId,Long orderId,Integer lockNum){// 1. 获取分布式锁,防止并发扣减库存String lockKey = STOCK_LOCK_KEY + productId;Boolean lockSuccess = redisTemplate.opsForValue().setIfAbsent(lockKey,"locked",30,TimeUnit.SECONDS);if(Boolean.FALSE.equals(lockSuccess)){thrownewBusinessException(400,"当前库存紧张,请稍后再试");}try{// 2. 校验库存是否充足Product product = productMapper.selectById(productId);if(product ==null|| product.getStatus()!=1){thrownewBusinessException(400,"商品不存在或已下架");}if(product.getStock()< lockNum){thrownewBusinessException(400,"库存不足");}// 3. 扣减可用库存(数据库乐观锁,防止超卖)int updateCount = productMapper.updateStock( productId, lockNum, product.getStock()// 乐观锁版本号(库存当前值));if(updateCount ==0){thrownewBusinessException(400,"库存扣减失败,请稍后再试");}// 4. 记录库存锁定信息ProductStockLock stockLock =newProductStockLock(); stockLock.setProductId(productId); stockLock.setOrderId(orderId); stockLock.setLockNum(lockNum);// 锁定过期时间:30分钟(订单未支付则自动解锁) stockLock.setExpireTime(LocalDateTime.now().plusMinutes(30)); stockLock.setStatus(0);// 0-锁定中 stockLockMapper.insert(stockLock);returntrue;}finally{// 5. 释放分布式锁 redisTemplate.delete(lockKey);}}/** * 解锁库存(订单取消或过期) */@Override@Transactional(rollbackFor =Exception.class)publicvoidunlockStock(Long productId,Long orderId){// 1. 查询库存锁定记录ProductStockLock stockLock = stockLockMapper.selectOne(newLambdaQueryWrapper<ProductStockLock>().eq(ProductStockLock::getProductId, productId).eq(ProductStockLock::getOrderId, orderId).eq(ProductStockLock::getStatus,0)// 仅解锁锁定中的记录);if(stockLock ==null){return;}// 2. 更新锁定状态为已解锁 stockLockMapper.update(null,newLambdaUpdateWrapper<ProductStockLock>().eq(ProductStockLock::getId, stockLock.getId()).set(ProductStockLock::getStatus,1));// 3. 恢复可用库存 productMapper.increaseStock(productId, stockLock.getLockNum());}/** * 确认扣减库存(订单支付成功) */@Override@Transactional(rollbackFor =Exception.class)publicvoidconfirmStockLock(Long productId,Long orderId){ stockLockMapper.update(null,newLambdaUpdateWrapper<ProductStockLock>().eq(ProductStockLock::getProductId, productId).eq(ProductStockLock::getOrderId, orderId).eq(ProductStockLock::getStatus,0).set(ProductStockLock::getStatus,2)// 2-已扣减);}}5.2.2 商品搜索实现(Elasticsearch)
- 引入Elasticsearch依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>- 配置Elasticsearch:
spring:elasticsearch:uris: http://localhost:9200username:password:- 商品文档实体类:
importlombok.Data;importorg.springframework.data.annotation.Id;importorg.springframework.data.elasticsearch.annotations.Document;importorg.springframework.data.elasticsearch.annotations.Field;importorg.springframework.data.elasticsearch.annotations.FieldType;importjava.math.BigDecimal;importjava.time.LocalDateTime;@Data@Document(indexName ="product")// ES索引名称publicclassProductDoc{@IdprivateLong id;// 商品ID@Field(type =FieldType.Text, analyzer ="ik_max_word")privateString name;// 商品名称(分词搜索)@Field(type =FieldType.Long)privateLong categoryId;// 分类ID@Field(type =FieldType.Keyword)privateString categoryName;// 分类名称(精确匹配)@Field(type =FieldType.Double)privateBigDecimal price;// 售价(排序)@Field(type =FieldType.Integer)privateInteger stock;// 库存@Field(type =FieldType.Integer)privateInteger sales;// 销量(排序)@Field(type =FieldType.Keyword)privateString coverImg;// 封面图@Field(type =FieldType.Text, analyzer ="ik_max_word")privateString detail;// 商品详情(分词搜索)@Field(type =FieldType.Integer)privateInteger status;// 状态(1-上架,0-下架)@Field(type =FieldType.Date)privateLocalDateTime createTime;// 创建时间}- 商品搜索Repository:
importorg.springframework.data.elasticsearch.repository.ElasticsearchRepository;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceProductDocRepositoryextendsElasticsearchRepository<ProductDoc,Long>{}- 搜索服务实现:
importorg.elasticsearch.index.query.BoolQueryBuilder;importorg.elasticsearch.index.query.QueryBuilders;importorg.elasticsearch.search.sort.SortOrder;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.PageRequest;importorg.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;importorg.springframework.data.elasticsearch.core.SearchHit;importorg.springframework.data.elasticsearch.core.SearchHits;importorg.springframework.data.elasticsearch.core.query.NativeSearchQuery;importorg.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;importjava.util.List;importjava.util.stream.Collectors;@ServicepublicclassProductSearchService{@AutowiredprivateElasticsearchRestTemplate elasticsearchRestTemplate;/** * 商品搜索(支持关键词、分类、价格区间、排序) */publicPage<ProductDoc>searchProducts(String keyword,Long categoryId,BigDecimal minPrice,BigDecimal maxPrice,Integer sortType,Integer pageNum,Integer pageSize){// 构建查询条件BoolQueryBuilder boolQuery =QueryBuilders.boolQuery();// 1. 关键词搜索(商品名称或详情)if(keyword !=null&&!keyword.isEmpty()){ boolQuery.should(QueryBuilders.matchQuery("name", keyword)).should(QueryBuilders.matchQuery("detail", keyword));}// 2. 分类筛选if(categoryId !=null){ boolQuery.filter(QueryBuilders.termQuery("categoryId", categoryId));}// 3. 价格区间筛选if(minPrice !=null){ boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice));}if(maxPrice !=null){ boolQuery.filter(QueryBuilders.rangeQuery("price").lte(maxPrice));}// 4. 只查询上架商品 boolQuery.filter(QueryBuilders.termQuery("status",1));// 构建排序条件(0-默认,1-价格升序,2-价格降序,3-销量降序)NativeSearchQueryBuilder queryBuilder =newNativeSearchQueryBuilder().withQuery(boolQuery).withPageable(PageRequest.of(pageNum -1, pageSize));switch(sortType){case1: queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));break;case2: queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));break;case3: queryBuilder.withSort(SortBuilders.fieldSort("sales").order(SortOrder.DESC));break;default:// 默认按创建时间降序 queryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));break;}NativeSearchQuery searchQuery = queryBuilder.build();SearchHits<ProductDoc> searchHits = elasticsearchRestTemplate.search(searchQuery,ProductDoc.class);// 转换为Page对象List<ProductDoc> productDocs = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());long total = searchHits.getTotalHits();returnnewPageImpl<>(productDocs,PageRequest.of(pageNum -1, pageSize), total);}}六、核心模块实战:订单与支付服务开发
6.1 订单服务核心实现(分布式事务)
6.1.1 订单创建全流程
订单创建涉及“库存锁定、订单保存、消息发送”等跨服务操作,需保证分布式事务一致性,采用“Seata AT模式+RocketMQ可靠消息”方案:
- 订单服务调用商品服务锁定库存(Seata全局事务)。
- 订单服务保存订单信息(本地事务)。
- 订单服务发送“订单创建”消息(RocketMQ事务消息)。
- 支付服务、物流服务消费消息,初始化支付单和物流单。
6.1.2 订单服务核心代码
importcom.alibaba.fastjson.JSON;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.common.mq.RocketMQTemplate;importcom.example.ecommerce.order.entity.Order;importcom.example.ecommerce.order.entity.OrderItem;importcom.example.ecommerce.order.mapper.OrderItemMapper;importcom.example.ecommerce.order.mapper.OrderMapper;importcom.example.ecommerce.order.service.OrderService;importcom.example.ecommerce.order.vo.OrderCreateVO;importcom.example.ecommerce.product.api.ProductFeignClient;importcom.example.ecommerce.product.api.dto.ProductDTO;importcom.example.ecommerce.user.api.UserFeignClient;importcom.example.ecommerce.user.api.dto.UserAddressDTO;importio.seata.spring.annotation.GlobalTransactional;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.math.BigDecimal;importjava.time.LocalDateTime;importjava.util.List;importjava.util.stream.Collectors;@ServicepublicclassOrderServiceImplimplementsOrderService{@AutowiredprivateOrderMapper orderMapper;@AutowiredprivateOrderItemMapper orderItemMapper;@AutowiredprivateUserFeignClient userFeignClient;@AutowiredprivateProductFeignClient productFeignClient;@AutowiredprivateRocketMQTemplate rocketMQTemplate;/** * 创建订单(全局事务) */@Override@GlobalTransactional(name ="create-order-transaction", rollbackFor =Exception.class)publicOrdercreateOrder(OrderCreateVO createVO,Long userId){// 1. 获取用户地址信息UserAddressDTO address = userFeignClient.getUserAddressById(createVO.getAddressId(), userId);if(address ==null){thrownewBusinessException(400,"收货地址不存在");}// 2. 校验商品信息并锁定库存List<Long> productIds = createVO.getItems().stream().map(OrderCreateVO.OrderItemVO::getProductId).collect(Collectors.toList());// 调用商品服务批量查询商品信息List<ProductDTO> productList = productFeignClient.getProductsByIds(productIds);if(productList.size()!= productIds.size()){thrownewBusinessException(400,"部分商品不存在");}// 3. 计算订单总金额,锁定库存BigDecimal totalAmount =BigDecimal.ZERO;Long orderId =System.currentTimeMillis();// 生成订单ID(实际用雪花算法)for(OrderCreateVO.OrderItemVO itemVO : createVO.getItems()){ProductDTO product = productList.stream().filter(p -> p.getId().equals(itemVO.getProductId())).findFirst().orElseThrow(()->newBusinessException(400,"商品不存在:"+ itemVO.getProductId()));// 校验商品状态if(product.getStatus()!=1){thrownewBusinessException(400,"商品已下架:"+ product.getName());}// 锁定库存(调用商品服务)boolean lockSuccess = productFeignClient.lockStock( product.getId(), orderId, itemVO.getQuantity());if(!lockSuccess){thrownewBusinessException(400,"商品"+ product.getName()+"库存不足");}// 累加总金额BigDecimal itemAmount = product.getPrice().multiply(newBigDecimal(itemVO.getQuantity())); totalAmount = totalAmount.add(itemAmount);}// 4. 保存订单主表Order order =newOrder(); order.setId(orderId); order.setUserId(userId); order.setReceiver(address.getReceiver()); order.setReceiverPhone(address.getPhone()); order.setReceiverAddress(address.getProvince()+ address.getCity()+ address.getDistrict()+ address.getDetailAddress()); order.setTotalAmount(totalAmount); order.setStatus(0);// 0-待支付 order.setCreateTime(LocalDateTime.now()); order.setUpdateTime(LocalDateTime.now()); orderMapper.insert(order);// 5. 保存订单明细表List<OrderItem> orderItems = createVO.getItems().stream().map(itemVO ->{ProductDTO product = productList.stream().filter(p -> p.getId().equals(itemVO.getProductId())).findFirst().get();OrderItem orderItem =newOrderItem(); orderItem.setOrderId(orderId); orderItem.setProductId(product.getId()); orderItem.setProductName(product.getName()); orderItem.setProductImg(product.getCoverImg()); orderItem.setPrice(product.getPrice()); orderItem.setQuantity(itemVO.getQuantity()); orderItem.setTotalPrice(product.getPrice().multiply(newBigDecimal(itemVO.getQuantity())));return orderItem;}).collect(Collectors.toList()); orderItemMapper.batchInsert(orderItems);// 6. 发送订单创建消息(事务消息)sendOrderCreateMsg(order);return order;}/** * 发送订单创建事务消息 */privatevoidsendOrderCreateMsg(Order order){// 构建消息体OrderCreateMsg msg =newOrderCreateMsg(); msg.setOrderId(order.getId()); msg.setUserId(order.getUserId()); msg.setTotalAmount(order.getTotalAmount()); msg.setCreateTime(order.getCreateTime());// 发送RocketMQ事务消息 rocketMQTemplate.sendMessageInTransaction("order-transaction-group","order-create-topic",org.springframework.messaging.support.MessageBuilder.withPayload(JSON.toJSONString(msg)).build(), order // 附加参数(事务回调时使用));}}6.2 支付服务核心实现(对接支付宝)
6.2.1 支付流程设计
- 用户下单后,调用支付服务创建支付单。
- 支付服务对接支付宝,生成支付链接或二维码。
- 用户完成支付后,支付宝回调支付服务接口。
- 支付服务更新支付状态,调用订单服务更新订单状态。
- 支付服务发送“支付成功”消息,物流服务消费消息创建物流单。
6.2.2 支付宝对接核心代码
- 引入支付宝SDK依赖:
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.38.0.ALL</version></dependency>- 支付宝配置:
importcom.alipay.api.AlipayClient;importcom.alipay.api.DefaultAlipayClient;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassAlipayConfig{@Value("${alipay.gateway-url}")privateString gatewayUrl;@Value("${alipay.app-id}")privateString appId;@Value("${alipay.private-key}")privateString privateKey;@Value("${alipay.public-key}")privateString publicKey;@Value("${alipay.sign-type}")privateString signType;@Value("${alipay.charset}")privateString charset;@BeanpublicAlipayClientalipayClient(){returnnewDefaultAlipayClient( gatewayUrl, appId, privateKey,"json", charset, publicKey, signType );}}- 支付服务实现:
importcom.alibaba.fastjson.JSON;importcom.alipay.api.AlipayApiException;importcom.alipay.api.request.AlipayTradePagePayRequest;importcom.alipay.api.response.AlipayTradePagePayResponse;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.common.mq.RocketMQTemplate;importcom.example.ecommerce.order.api.OrderFeignClient;importcom.example.ecommerce.pay.entity.PayOrder;importcom.example.ecommerce.pay.mapper.PayOrderMapper;importcom.example.ecommerce.pay.service.PayService;importcom.example.ecommerce.pay.vo.PayCreateVO;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.math.BigDecimal;importjava.time.LocalDateTime;importjava.util.UUID;@ServicepublicclassPayServiceImplimplementsPayService{@AutowiredprivateAlipayClient alipayClient;@AutowiredprivatePayOrderMapper payOrderMapper;@AutowiredprivateOrderFeignClient orderFeignClient;@AutowiredprivateRocketMQTemplate rocketMQTemplate;@Value("${alipay.return-url}")privateString returnUrl;// 支付成功跳转页面@Value("${alipay.notify-url}")privateString notifyUrl;// 支付回调接口/** * 创建支付宝支付订单 */@Override@Transactional(rollbackFor =Exception.class)publicStringcreateAlipayOrder(PayCreateVO createVO,Long userId){// 1. 校验订单是否存在且状态为待支付boolean orderValid = orderFeignClient.checkOrderStatus(createVO.getOrderId(), userId,0);if(!orderValid){thrownewBusinessException(400,"订单无效或已支付");}// 2. 查询订单金额BigDecimal orderAmount = orderFeignClient.getOrderAmount(createVO.getOrderId());// 3. 创建支付单String payOrderNo ="PAY"+System.currentTimeMillis()+ UUID.randomUUID().toString().substring(0,8);PayOrder payOrder =newPayOrder(); payOrder.setPayOrderNo(payOrderNo); payOrder.setOrderId(createVO.getOrderId()); payOrder.setUserId(userId); payOrder.setPayAmount(orderAmount); payOrder.setPayType(1);// 1-支付宝,2-微信支付 payOrder.setStatus(0);// 0-待支付 payOrder.setCreateTime(LocalDateTime.now()); payOrderMapper.insert(payOrder);// 4. 调用支付宝SDK生成支付链接AlipayTradePagePayRequest request =newAlipayTradePagePayRequest(); request.setReturnUrl(returnUrl); request.setNotifyUrl(notifyUrl);// 构建请求参数JSONObject bizContent =newJSONObject(); bizContent.put("out_trade_no", payOrderNo);// 商户订单号 bizContent.put("total_amount", orderAmount);// 支付金额 bizContent.put("subject","电商平台订单支付:"+ createVO.getOrderId());// 订单标题 bizContent.put("product_code","FAST_INSTANT_TRADE_PAY");// 产品码 request.setBizContent(bizContent.toString());try{AlipayTradePagePayResponse response = alipayClient.pageExecute(request);if(response.isSuccess()){// 返回支付宝支付页面HTMLreturn response.getBody();}else{thrownewBusinessException(400,"创建支付订单失败:"+ response.getMsg());}}catch(AlipayApiException e){thrownewBusinessException(400,"支付宝接口调用失败:"+ e.getMessage());}}/** * 支付宝支付回调处理 */@Override@Transactional(rollbackFor =Exception.class)publicStringhandleAlipayNotify(JSONObject notifyData){// 1. 验证签名(省略,参考支付宝SDK文档)boolean signValid =verifyAlipaySign(notifyData);if(!signValid){return"fail";}// 2. 获取回调参数String outTradeNo = notifyData.getString("out_trade_no");// 商户订单号String tradeNo = notifyData.getString("trade_no");// 支付宝交易号String tradeStatus = notifyData.getString("trade_status");// 交易状态// 3. 只处理支付成功的回调if(!"TRADE_SUCCESS".equals(tradeStatus)){return"success";}// 4. 查询支付单PayOrder payOrder = payOrderMapper.selectOne(newLambdaQueryWrapper<PayOrder>().eq(PayOrder::getPayOrderNo, outTradeNo).eq(PayOrder::getStatus,0));if(payOrder ==null){return"success";// 已处理过,直接返回成功}// 5. 更新支付单状态 payOrder.setStatus(1);// 1-已支付 payOrder.setTradeNo(tradeNo); payOrder.setPayTime(LocalDateTime.now()); payOrderMapper.updateById(payOrder);// 6. 调用订单服务更新订单状态为已支付 orderFeignClient.updateOrderStatus(payOrder.getOrderId(),1);// 7. 确认商品库存扣减 orderFeignClient.confirmStockLock(payOrder.getOrderId());// 8. 发送支付成功消息PaySuccessMsg msg =newPaySuccessMsg(); msg.setOrderId(payOrder.getOrderId()); msg.setPayOrderNo(outTradeNo); msg.setTradeNo(tradeNo); msg.setPayAmount(payOrder.getPayAmount()); msg.setPayTime(payOrder.getPayTime()); rocketMQTemplate.send("pay-success-topic",MessageBuilder.withPayload(JSON.toJSONString(msg)).build());return"success";}/** * 验证支付宝签名(具体实现参考支付宝SDK文档) */privatebooleanverifyAlipaySign(JSONObject notifyData){// 省略签名验证逻辑returntrue;}}七、高并发场景实战:秒杀系统设计与实现
7.1 秒杀系统核心挑战与解决方案
7.1.1 核心挑战
- 高并发请求:秒杀活动期间QPS峰值极高,需防止系统被压垮。
- 库存超卖:多个用户同时抢购同一商品,需保证库存准确性。
- 接口防刷:防止恶意用户通过脚本抢购,占用库存。
- 响应延迟:需快速返回抢购结果,提升用户体验。
7.1.2 解决方案架构
采用“前端限流+网关限流+缓存预热+库存预扣减+异步处理”的多层防护架构:
- 前端:按钮置灰、倒计时、限制单用户抢购次数。
- 网关:Sentinel限流,限制单IP、单用户的请求频率。
- 缓存:Redis预热秒杀商品库存,减少数据库访问。
- 库存:Redis预扣减库存,异步同步到数据库,防止超卖。
- 消息队列:RocketMQ异步处理订单创建,提升系统吞吐量。
7.2 秒杀系统核心实现
7.2.1 秒杀商品预热(缓存初始化)
importcom.example.ecommerce.product.entity.Product;importcom.example.ecommerce.product.mapper.ProductMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.scheduling.annotation.Scheduled;importorg.springframework.stereotype.Component;importjava.util.List;@ComponentpublicclassSeckillProductPreload{@AutowiredprivateProductMapper productMapper;@AutowiredprivateStringRedisTemplate redisTemplate;// 秒杀商品库存缓存Key前缀privatestaticfinalString SECKILL_STOCK_KEY ="seckill:stock:";// 秒杀商品状态缓存Key前缀privatestaticfinalString SECKILL_STATUS_KEY ="seckill:status:";/** * 定时预热秒杀商品(活动开始前10分钟执行) */@Scheduled(cron ="0 50 * * * ?")// 每小时50分执行(示例)publicvoidpreloadSeckillProducts(){// 查询当天待开始的秒杀商品(实际应根据活动时间筛选)List<Product> seckillProducts = productMapper.selectSeckillProducts();for(Product product : seckillProducts){Long productId = product.getId();Integer stock = product.getStock();// 1. 缓存秒杀商品库存 redisTemplate.opsForValue().set(SECKILL_STOCK_KEY + productId, stock.toString());// 2. 缓存秒杀商品状态(0-未开始,1-进行中,2-已结束) redisTemplate.opsForValue().set(SECKILL_STATUS_KEY + productId,"0");// 3. 预热商品信息到Redis(供前端查询) redisTemplate.opsForHash().putAll("seckill:product:"+ productId,Map.of("id", productId.toString(),"name", product.getName(),"price", product.getPrice().toString(),"coverImg", product.getCoverImg(),"stock", stock.toString()));}}}7.2.2 秒杀接口实现(高并发防护)
importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.common.mq.RocketMQTemplate;importcom.example.ecommerce.order.api.dto.SeckillOrderCreateDTO;importcom.example.ecommerce.order.api.OrderFeignClient;importcom.example.ecommerce.product.api.ProductFeignClient;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Service;importjava.util.UUID;importjava.util.concurrent.TimeUnit;@ServicepublicclassSeckillServiceImplimplementsSeckillService{@AutowiredprivateStringRedisTemplate redisTemplate;@AutowiredprivateOrderFeignClient orderFeignClient;@AutowiredprivateProductFeignClient productFeignClient;@AutowiredprivateRocketMQTemplate rocketMQTemplate;// 缓存Key定义privatestaticfinalString SECKILL_STOCK_KEY ="seckill:stock:";privatestaticfinalString SECKILL_STATUS_KEY ="seckill:status:";privatestaticfinalString SECKILL_USER_LIMIT_KEY ="seckill:user:limit:";privatestaticfinalString SECKILL_ORDER_KEY ="seckill:order:";/** * 秒杀抢购接口 */@OverridepublicStringseckill(Long productId,Long userId){// 1. 校验秒杀状态String status = redisTemplate.opsForValue().get(SECKILL_STATUS_KEY + productId);if(!"1".equals(status)){thrownewBusinessException(400,"秒杀未开始或已结束");}// 2. 单用户限购校验(每人限抢1件)String userLimitKey = SECKILL_USER_LIMIT_KEY + productId +":"+ userId;Boolean hasLimit = redisTemplate.hasKey(userLimitKey);if(Boolean.TRUE.equals(hasLimit)){thrownewBusinessException(400,"每人限购1件,请勿重复抢购");}// 3. Redis预扣减库存(原子操作,防止超卖)Long remainStock = redisTemplate.opsForValue().decrement(SECKILL_STOCK_KEY + productId);if(remainStock ==null|| remainStock <0){// 库存不足,恢复库存 redisTemplate.opsForValue().increment(SECKILL_STOCK_KEY + productId);thrownewBusinessException(400,"手慢无!库存已抢完");}try{// 4. 记录用户限购标识(有效期24小时) redisTemplate.opsForValue().set(userLimitKey,"1",24,TimeUnit.HOURS);// 5. 生成秒杀订单号String seckillOrderNo ="SECKILL"+System.currentTimeMillis()+ UUID.randomUUID().toString().substring(0,8);// 6. 发送异步创建订单消息SeckillOrderCreateDTO createDTO =newSeckillOrderCreateDTO(); createDTO.setSeckillOrderNo(seckillOrderNo); createDTO.setProductId(productId); createDTO.setUserId(userId); createDTO.setQuantity(1);// 秒杀商品每人限1件 rocketMQTemplate.send("seckill-order-create-topic",org.springframework.messaging.support.MessageBuilder.withPayload(createDTO).build());// 7. 缓存秒杀订单关联关系(供查询) redisTemplate.opsForValue().set(SECKILL_ORDER_KEY + seckillOrderNo, userId +":"+ productId,24,TimeUnit.HOURS);// 8. 返回秒杀订单号(用户凭此查询结果)return seckillOrderNo;}catch(Exception e){// 异常回滚:恢复库存和限购标识 redisTemplate.opsForValue().increment(SECKILL_STOCK_KEY + productId); redisTemplate.delete(userLimitKey);thrownewBusinessException(400,"秒杀失败,请稍后再试");}}/** * 查询秒杀结果 */@OverridepublicStringquerySeckillResult(String seckillOrderNo,Long userId){// 1. 校验订单关联关系String orderInfo = redisTemplate.opsForValue().get(SECKILL_ORDER_KEY + seckillOrderNo);if(orderInfo ==null){thrownewBusinessException(400,"秒杀订单不存在");}String[] infoArr = orderInfo.split(":");if(!userId.toString().equals(infoArr[0])){thrownewBusinessException(403,"无权查询该订单");}// 2. 调用订单服务查询订单状态Integer orderStatus = orderFeignClient.queryOrderStatusBySeckillNo(seckillOrderNo);if(orderStatus ==null){return"处理中";// 订单正在创建}elseif(orderStatus ==0){return"抢购成功,请尽快支付";// 待支付}else{return"抢购失败";// 订单创建失败}}}7.2.3 秒杀订单异步创建(RocketMQ消费者)
importcom.alibaba.fastjson.JSON;importcom.example.ecommerce.common.core.exception.BusinessException;importcom.example.ecommerce.order.api.dto.SeckillOrderCreateDTO;importcom.example.ecommerce.order.entity.Order;importcom.example.ecommerce.order.entity.OrderItem;importcom.example.ecommerce.order.mapper.OrderMapper;importcom.example.ecommerce.order.mapper.OrderItemMapper;importcom.example.ecommerce.product.api.ProductFeignClient;importcom.example.ecommerce.product.api.dto.ProductDTO;importcom.example.ecommerce.user.api.UserFeignClient;importcom.example.ecommerce.user.api.dto.UserAddressDTO;importorg.apache.rocketmq.spring.annotation.RocketMQMessageListener;importorg.apache.rocketmq.spring.core.RocketMQListener;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importorg.springframework.transaction.annotation.Transactional;importjava.math.BigDecimal;importjava.time.LocalDateTime;@Component@RocketMQMessageListener(topic ="seckill-order-create-topic", consumerGroup ="seckill-order-group")publicclassSeckillOrderCreateListenerimplementsRocketMQListener<SeckillOrderCreateDTO>{@AutowiredprivateOrderMapper orderMapper;@AutowiredprivateOrderItemMapper orderItemMapper;@AutowiredprivateProductFeignClient productFeignClient;@AutowiredprivateUserFeignClient userFeignClient;@Override@Transactional(rollbackFor =Exception.class)publicvoidonMessage(SeckillOrderCreateDTO createDTO){Long productId = createDTO.getProductId();Long userId = createDTO.getUserId();String seckillOrderNo = createDTO.getSeckillOrderNo();try{// 1. 获取商品信息(再次校验,防止商品下架)ProductDTO product = productFeignClient.getProductById(productId);if(product ==null|| product.getStatus()!=1){thrownewBusinessException(400,"商品不存在或已下架");}// 2. 获取用户默认地址UserAddressDTO defaultAddress = userFeignClient.getUserDefaultAddress(userId);if(defaultAddress ==null){thrownewBusinessException(400,"用户未设置收货地址");}// 3. 锁定库存(最终校验,防止Redis与数据库库存不一致)boolean lockSuccess = productFeignClient.lockStock(productId,Long.parseLong(seckillOrderNo),1);if(!lockSuccess){thrownewBusinessException(400,"库存锁定失败");}// 4. 计算订单金额BigDecimal totalAmount = product.getPrice().multiply(newBigDecimal(1));// 5. 创建订单主表Order order =newOrder(); order.setId(Long.parseLong(seckillOrderNo));// 秒杀订单号作为订单ID order.setUserId(userId); order.setReceiver(defaultAddress.getReceiver()); order.setReceiverPhone(defaultAddress.getPhone()); order.setReceiverAddress(defaultAddress.getProvince()+ defaultAddress.getCity()+ defaultAddress.getDistrict()+ defaultAddress.getDetailAddress()); order.setTotalAmount(totalAmount); order.setStatus(0);// 待支付 order.setCreateTime(LocalDateTime.now()); order.setUpdateTime(LocalDateTime.now()); order.setOrderType(1);// 1-秒杀订单 orderMapper.insert(order);// 6. 创建订单明细表OrderItem orderItem =newOrderItem(); orderItem.setOrderId(Long.parseLong(seckillOrderNo)); orderItem.setProductId(productId); orderItem.setProductName(product.getName()); orderItem.setProductImg(product.getCoverImg()); orderItem.setPrice(product.getPrice()); orderItem.setQuantity(1); orderItem.setTotalPrice(totalAmount); orderItemMapper.insert(orderItem);}catch(Exception e){// 订单创建失败,解锁库存(通过消息队列发送解锁通知) productFeignClient.unlockStock(productId,Long.parseLong(seckillOrderNo));// 清除用户限购标识 redisTemplate.delete(SECKILL_USER_LIMIT_KEY + productId +":"+ userId);// 恢复Redis库存 redisTemplate.opsForValue().increment(SECKILL_STOCK_KEY + productId);thrownewRuntimeException("秒杀订单创建失败:"+ e.getMessage());}}}7.2.4 秒杀系统限流配置(Sentinel)
spring:cloud:sentinel:transport:dashboard: localhost:8083scg:fallback:response-body:'{"code":429,"msg":"秒杀太火爆,请稍后再试"}'datasource:# 秒杀接口限流规则(Nacos动态配置)ds1:nacos:server-addr: localhost:8848dataId: seckill-sentinel-rule groupId: DEFAULT_GROUP rule-type: flow Nacos中seckill-sentinel-rule配置内容:
[{"resource":"/api/seckill/{productId}","limitApp":"default","grade":1,"count":500,"strategy":0,"controlBehavior":2,"clusterMode":false}]resource:限流资源(秒杀接口路径)。grade:限流类型(1=QPS)。count:QPS阈值(500)。controlBehavior:限流策略(2=排队等待)。
7.3 秒杀系统压测与优化
7.3.1 压测工具与场景
使用JMeter模拟10万用户并发抢购场景:
- 线程组配置:10万线程, ramp-up时间10秒。
- 采样器:HTTP请求(POST /api/seckill/1)。
- 监听器:聚合报告、响应时间曲线、吞吐量曲线。
7.3.2 优化方向与效果
| 优化措施 | 优化前QPS | 优化后QPS | 响应时间优化 |
|---|---|---|---|
| Redis缓存预热+预扣减 | 500 | 3000 | 500ms→80ms |
| Sentinel限流+排队策略 | 3000 | 5000 | 80ms→50ms |
| 异步订单创建+消息队列 | 5000 | 8000 | 50ms→30ms |
| JVM调优(G1GC+内存分配) | 8000 | 10000 | 30ms→20ms |
八、项目工程化与运维部署
8.1 代码规范与版本控制
8.1.1 代码规范(基于Alibaba Java Coding Guidelines)
- 命名规范:
- 类名:帕斯卡命名法(如
UserService)。 - 方法名/变量名:驼峰命名法(如
createOrder)。 - 常量名:全大写+下划线(如
SECKILL_STOCK_KEY)。 - 包名:全小写(如
com.example.ecommerce.user.service)。
- 类名:帕斯卡命名法(如
- 代码格式:
- 缩进:4个空格(禁止Tab)。
- 行宽:不超过120字符。
- 方法长度:不超过80行,超过则拆分。
- 异常处理:捕获异常后必须处理(日志记录或业务降级),禁止空catch块。
- 工具集成:
- IDEA安装Alibaba Java Coding Guidelines插件,实时检测违规代码。
- 集成SonarQube,提交代码前执行
mvn sonar:sonar,修复高危问题。
8.1.2 Git版本控制流程(GitFlow)
- 分支管理:
main:生产环境分支,仅用于发布。develop:开发分支,日常开发合并到此分支。feature/*:功能分支(如feature/user-register),从develop创建,完成后合并回develop。release/*:发布分支(如release/v1.0.0),从develop创建,测试通过后合并到main和develop。hotfix/*:紧急修复分支(如hotfix/login-bug),从main创建,修复后合并到main和develop。
- 提交规范:
- 提交信息格式:
type(scope): description。 - 类型(type):feat(新功能)、fix(bug修复)、docs(文档)、style(格式)、refactor(重构)、test(测试)、chore(构建)。
- 示例:
feat(user): 新增手机号验证码注册功能。
- 提交信息格式:
8.2 CI/CD流程(Jenkins+Docker+K8s)
8.2.1 流程设计
- 持续集成(CI):
- 开发者提交代码到GitLab。
- Jenkins触发自动构建:拉取代码→编译→单元测试→代码扫描→构建Docker镜像→推送镜像到Harbor。
- 持续部署(CD):
- 镜像推送成功后,Jenkins更新K8s资源配置(Deployment镜像版本)。
- K8s执行滚动更新,无需停机。
8.2.2 Jenkinsfile配置(Pipeline)
pipeline { agent any environment { PROJECT_NAME ='user-service' IMAGE_REPO ='192.168.1.100:8080/ecommerce/'+ PROJECT_NAME IMAGE_TAG ="${env.BUILD_NUMBER}-${env.GIT_COMMIT.substring(0,8)}" K8S_CONFIG ='user-service-deploy.yaml'} stages {stage('拉取代码'){ steps { git url:'http://gitlab.example.com/ecommerce/user-service.git', branch:'develop'}}stage('编译打包'){ steps { sh 'mvn clean package -Dmaven.test.skip=true'}}stage('代码扫描'){ steps { sh 'mvn sonar:sonar -Dsonar.host.url=http://sonarqube.example.com:9000'}}stage('构建Docker镜像'){ steps { sh "docker build -t ${IMAGE_REPO}:${IMAGE_TAG} ."}}stage('推送镜像到Harbor'){ steps { sh "docker login -u admin -p Harbor12345 192.168.1.100:8080" sh "docker push ${IMAGE_REPO}:${IMAGE_TAG}"}}stage('部署到K8s'){ steps { sh "sed -i 's#{{IMAGE_REPO}}#${IMAGE_REPO}#g' ${K8S_CONFIG}" sh "sed -i 's#{{IMAGE_TAG}}#${IMAGE_TAG}#g' ${K8S_CONFIG}" sh "kubectl apply -f ${K8S_CONFIG} -n ecommerce-dev"}}} post { success { echo '构建部署成功!'// 发送通知到钉钉群 sh 'curl -H "Content-Type: application/json" -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"${PROJECT_NAME} 构建部署成功,版本:${IMAGE_TAG}\"}}" https://oapi.dingtalk.com/robot/send?access_token=xxx'} failure { echo '构建部署失败!' sh 'curl -H "Content-Type: application/json" -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"${PROJECT_NAME} 构建部署失败,构建号:${BUILD_NUMBER}\"}}" https://oapi.dingtalk.com/robot/send?access_token=xxx'}}}8.3 K8s部署配置(完整示例)
8.3.1 命名空间与ConfigMap
# namespace.yamlapiVersion: v1 kind: Namespace metadata:name: ecommerce-dev ---# configmap.yamlapiVersion: v1 kind: ConfigMap metadata:name: ecommerce-config namespace: ecommerce-dev data:NACOS_SERVER_ADDR:"nacos-service:8848"REDIS_HOST:"redis-service:6379"ELASTICSEARCH_ADDR:"elasticsearch-service:9200"ROCKETMQ_NAMESRV_ADDR:"rocketmq-namesrv:9876"8.3.2 微服务Deployment配置(user-service)
# user-service-deploy.yamlapiVersion: apps/v1 kind: Deployment metadata:name: user-service namespace: ecommerce-dev labels:app: user-service spec:replicas:2selector:matchLabels:app: user-service strategy:rollingUpdate:maxSurge:1maxUnavailable:0template:metadata:labels:app: user-service spec:containers:-name: user-service image:{{IMAGE_REPO}}:{{IMAGE_TAG}}ports:-containerPort:8081env:-name: NACOS_SERVER_ADDR valueFrom:configMapKeyRef:name: ecommerce-config key: NACOS_SERVER_ADDR -name: REDIS_HOST valueFrom:configMapKeyRef:name: ecommerce-config key: REDIS_HOST resources:requests:cpu:"200m"memory:"512Mi"limits:cpu:"500m"memory:"1Gi"livenessProbe:httpGet:path: /actuator/health port:8081initialDelaySeconds:60periodSeconds:10readinessProbe:httpGet:path: /actuator/health port:8081initialDelaySeconds:30periodSeconds:58.3.3 服务暴露(Service+Ingress)
# user-service-svc.yamlapiVersion: v1 kind: Service metadata:name: user-service namespace: ecommerce-dev spec:selector:app: user-service ports:-port:8081targetPort:8081type: ClusterIP ---# ingress.yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata:name: ecommerce-ingress namespace: ecommerce-dev annotations:nginx.ingress.kubernetes.io/rewrite-target: /$2 spec:rules:-host: api.ecommerce.example.com http:paths:-path: /user(/|$)(.*)pathType: Prefix backend:service:name: user-service port:number:8081-path: /product(/|$)(.*)pathType: Prefix backend:service:name: product-service port:number:8082-path: /order(/|$)(.*)pathType: Prefix backend:service:name: order-service port:number:80838.4 监控与运维体系
8.4.1 全链路监控(Prometheus+Grafana+SkyWalking)
- 指标监控:Prometheus采集系统指标(CPU、内存)、应用指标(QPS、响应时间)、业务指标(订单数、支付金额),Grafana定制仪表盘。
- 链路追踪:SkyWalking监控微服务调用链路,定位性能瓶颈。
- 日志分析:ELK收集分布式日志,支持按TraceID检索全链路日志。
8.4.2 告警配置(Prometheus AlertManager)
# alertmanager.ymlglobal:resolve_timeout: 5m route:group_by:['alertname']group_wait: 10s group_interval: 10s repeat_interval: 1h receiver:'dingtalk'receivers:-name:'dingtalk'webhook_configs:-url:'https://oapi.dingtalk.com/robot/send?access_token=xxx'send_resolved:true核心告警规则:
groups:-name: ecommerce-alert-rules rules:-alert: HighCpuUsage expr: avg(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) > 0.8 for: 2m labels:severity: warning annotations:summary:"服务器CPU使用率过高"description:"服务器{{ $labels.instance }} CPU使用率持续2分钟超过80%,当前值:{{ $value }}"-alert: ServiceUnavailable expr: up{job=~"ecommerce-.*"} == 0 for: 1m labels:severity: critical annotations:summary:"微服务不可用"description:"服务{{ $labels.job }}已下线1分钟,请及时排查"-alert: HighErrorRate expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) > 0.01 for: 1m labels:severity: warning annotations:summary:"接口错误率过高"description:"错误率持续1分钟超过1%,当前值:{{ $value }}"九、项目总结与扩展方向
9.1 项目核心成果
✅ 本章节基于Spring Cloud Alibaba微服务架构,完成了企业级电商平台的全流程开发,实现了用户、商品、订单、支付、物流、秒杀等核心模块,达成以下目标:
- 架构层面:构建了高可用、高并发的微服务集群,支持水平扩展,满足10万QPS峰值需求。
- 功能层面:覆盖电商核心业务流程,支持用户注册登录、商品搜索、下单支付、物流跟踪、秒杀活动等功能。
- 技术层面:解决了分布式事务、库存防超卖、高并发限流、数据一致性等关键技术问题。
- 工程化层面:实现了代码规范、CI/CD自动化部署、全链路监控,具备企业级项目交付能力。
9.2 扩展方向
- 功能扩展:
- 新增会员体系(积分、等级、权益)。
- 支持多商家入驻与店铺管理。
- 增加推荐系统(基于用户行为的商品推荐)。
- 接入更多支付渠道(银联、Apple Pay)。
- 技术扩展:
- 引入服务网格(Istio),实现流量灰度发布、服务熔断、安全通信。
- 采用分库分表(Sharding-JDBC),解决大数据量存储问题。
- 接入AI能力(智能客服、恶意订单识别)。
- 实现多区域部署与异地容灾。
- 性能优化:
- 静态资源CDN加速,提升前端加载速度。
- 数据库读写分离+分库分表,提升数据访问效率。
- 引入分布式缓存集群(Redis Cluster),提升缓存可用性。
- 采用异步化、事件驱动架构,进一步提升系统吞吐量。
9.3 学习建议
企业级电商平台是Java微服务开发的经典场景,涵盖了Java开发的核心技术栈与工程实践。建议读者:
- 动手实践:按照章节步骤搭建项目,重点掌握微服务拆分、分布式事务、高并发处理等核心技术。
- 深入源码:阅读Spring Cloud Alibaba、Seata、RocketMQ等框架源码,理解底层实现原理。
- 关注行业动态:了解云原生、服务网格、低代码等新技术在电商场景的应用。
- 积累项目经验:参与实际项目开发,解决真实业务问题,提升工程化能力。
从Java基础语法到企业级微服务架构,从单一应用开发到分布式系统部署,本书构建了一套完整的Java开发知识体系。希望读者能够将所学知识融会贯通,在实际工作中灵活运用,成长为一名优秀的Java开发工程师。