补全了所有缺失的配置、脚手架、非核心代码和部署步骤。读完前面18章+这一部分,可以从零搭建一个完全一样的商城项目。
19. 环境搭建
19.1 需要的软件
| 软件 | 版本 | 用途 | 下载方式 |
|---|---|---|---|
| JDK | 17 | Java运行/编译 | winget install OpenJDK.OpenJDK.17 或 adoptium.net |
| Maven | 3.8+ | Java项目构建 | winget install Apache.Maven.3 或 maven.apache.org |
| MySQL | 8.0 | 数据库 | winget install Oracle.MySQL 或 dev.mysql.com |
| ZooKeeper | 3.8+ | Dubbo注册中心 | apache.org/dyn/closer.lua/zookeeper/ 解压即用 |
| Redis | 7.x | 验证码缓存 | Windows: github.com/microsoftarchive/redis/releases |
| Node.js | 20+ | 前端运行时 | winget install OpenJS.NodeJS.LTS 或 nodejs.org |
| IDE | – | IntelliJ IDEA (推荐) | jetbrains.com/idea |
19.2 启动中间件
MySQL:创建数据库和用户:
CREATE DATABASE mall CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'mall'@'localhost' IDENTIFIED BY 'nhZSCY2LPLjfm2ci';
GRANT ALL PRIVILEGES ON mall.* TO 'mall'@'localhost';
FLUSH PRIVILEGES;
然后执行建表脚本:
mysql -umall -pnhZSCY2LPLjfm2ci mall < mall.sql
执行本次新增的ALTER(给order表加items列):
ALTER TABLE `order` ADD COLUMN `items` text CHARACTER SET utf8mb4 NULL COMMENT '订单商品JSON快照';
ZooKeeper:解压→cp conf/zoo_sample.cfg conf/zoo.cfg→bin/zkServer.cmd(Windows)
Redis:启动 redis-server.exe(密码通过conf设requirepass 123456)
20. 项目初始化
20.1 父 POM(完整版)
文件内容见 C:Users24255Desktopmallpom.xml,关键结构:
<groupId>org.example</groupId>
<artifactId>mall</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>admin_service</module>
<module>user_service</module>
<module>goods_service</module>
<module>order_service</module>
</modules>
hutool-all 5.8.4 在父POM依赖中声明(所有模块自动继承)。 lombok 1.18.34 同样自动继承。
核心依赖版本管理:
| 依赖 | 版本 | 作用 |
|---|---|---|
| spring-boot-dependencies | 2.6.13 | SpringBoot所有starter版本统一管理 |
| dubbo-bom | 3.3.0 | Dubbo所有组件版本统一管理 |
| mybatis-spring-boot-starter | 2.2.2 | MyBatis集成SpringBoot |
| mysql-connector-java | 8.0.33 | MySQL驱动 |
| pagehelper | 2.1.0 | 分页插件 |
| java-jwt | 4.0.0 | JWT生成/解析 |
20.2 各子模块 POM
common/pom.xml:依赖 spring-boot-starter-web、java-jwt、pagehelper、spring-data-redis、dubbo-spring-boot-starter
admin_service/pom.xml 和 user_service/pom.xml:依赖 common、mysql-connector-java、mybatis-spring-boot-starter、spring-boot-starter-data-redis、dubbo-spring-boot-starter、dubbo-zookeeper-curator5
goods_service/pom.xml:同上 + pagehelper
order_service/pom.xml:同上 + 支付宝SDK:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.38.0.ALL</version>
</dependency>
20.3 完整 application.yml 配置
admin_service/src/main/resources/application.yml:
server:
port: 8091
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai
username: mall
password: nhZSCY2LPLjfm2ci
redis:
host: localhost
port: 6379
password: 123456
mybatis:
type-aliases-package: org.example.mall.common.bean
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
com:
picdir: /www/wwwroot/mall.dxkua.cn/mall/pic/
white-list:
rules:
- method: GET
regpath: /admin/captcha
- method: POST
regpath: /admin/login
user_service/src/main/resources/application.yml:
server:
port: 8092
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai
username: mall
password: nhZSCY2LPLjfm2ci
redis:
host: localhost
port: 6379
password: 123456
mybatis:
type-aliases-package: org.example.mall.common.bean
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
dubbo:
application:
name: user_service
qos-port: 28092
protocol:
name: dubbo
port: 38092
registry:
address: zookeeper://127.0.0.1:2181
white-list:
rules:
- method: GET
regpath: /user/captcha
- method: POST
regpath: /user/login
- method: POST
regpath: /user/reg
goods_service/src/main/resources/application.yml:
server:
port: 8090
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai
username: mall
password: nhZSCY2LPLjfm2ci
mybatis:
type-aliases-package: org.example.mall.common.bean
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
dubbo:
application:
name: goods_service
qos-port: 28090
protocol:
name: dubbo
port: 38090
registry:
address: zookeeper://127.0.0.1:2181
scan:
base-packages: org.example.mall.goods_service.service
order_service/src/main/resources/application.yml:
server:
port: 8093
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai
username: mall
password: nhZSCY2LPLjfm2ci
mybatis:
type-aliases-package: org.example.mall.common.bean
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
dubbo:
application:
name: order_service
qos-port: 28093
protocol:
name: dubbo
port: 38093
registry:
address: zookeeper://127.0.0.1:2181
com:
picdir: /www/wwwroot/mall.dxkua.cn/mall/pic/
alipay:
appId: ${ALIPAY_APP_ID:}
privateKey: ${ALIPAY_PRIVATE_KEY:}
publicKey: ${ALIPAY_PUBLIC_KEY:}
gateway: ${ALIPAY_GATEWAY:https://openapi-sandbox.dl.alipaydev.com/gateway.do}
signType: RSA2
returnUrl: ${ALIPAY_RETURN_URL:http://www.dxkua.cn/#/user/payResult}
notifyUrl: ${ALIPAY_NOTIFY_URL:http://www.dxkua.cn/order/notify}
20.4 各微服务启动类
admin_service 和 user_service:
@SpringBootApplication(scanBasePackages = {"org.example.mall"})
@MapperScan(basePackages = "org.example.mall.xxx_service.mapper")
public class XxxServiceApplication {
public static void main(String[] args) {
SpringApplication.run(XxxServiceApplication.class, args);
}
}
goods_service:
@SpringBootApplication(scanBasePackages = {"org.example.mall"})
@MapperScan(basePackages = "org.example.mall.goods_service.mapper")
@EnableDubbo(scanBasePackages = "org.example.mall.goods_service.service")
public class GoodsServiceApplication { ... }
order_service:
@SpringBootApplication(scanBasePackages = {"org.example.mall"})
@MapperScan(basePackages = "org.example.mall.order_service.mapper")
@EnableDubbo
@EnableScheduling // 定时取消超时订单
public class OrderServiceApplication { ... }
20.5 common 模块完整文件清单
| 目录 | 文件名 | 作用 |
|---|---|---|
bean/ |
Order.java | 订单实体(Long id, items JSON, detailList, totalPrice) |
bean/ |
OrderDetail.java | 订单商品明细DTO(goodsId/name/pic/price/count/subtotal) |
bean/ |
User.java | 用户实体(username, password+salt, money, status) |
bean/ |
Admin.java | 管理员实体(同User结构, status: 0正常1禁用) |
bean/ |
Goods.java | 商品实体(price, marketPrice, count, category关联, picList) |
bean/ |
GoodsPic.java | 商品图片(url, goodsId) |
bean/ |
Category.java | 分类实体(parentId, childlist) |
bean/ |
Cart.java | 购物车实体(count, goodsId, userId, goods关联) |
bean/ |
Addr.java | 地址实体(contact, phone, 省市区街道, status) |
bean/ |
Collect.java | 收藏实体(goodsId, userId, goods关联) |
bean/ |
RespBean.java | 统一响应体 {code, msg, data} |
bean/ |
Rule.java | 白名单规则 {method, regpath} |
service/ |
OrderService.java | 订单服务接口(create/createDirect/pay/notifyPay/queryAndUpdate/selectByUserId/search/selectById/updateStatus/delete) |
service/ |
GoodsService.java | 商品服务接口(insert/delete/update/selectById/selectByCondition/reduceStock) |
service/ |
UserService.java | 用户服务接口(login/reg/selectById/chgInfo/chgPwd/delete/updateStatus/search) |
service/ |
AdminService.java | 管理员服务接口(login/selectById/update/chgPwd/insert/delete/search) |
service/ |
CartService.java | 购物车服务接口(insert/delete/deleteByIds/update/search/selectById) |
service/ |
AddrService.java | 地址服务接口(insert/update/delete/setDefault/selectByUserId/selectById) |
service/ |
CollectService.java | 收藏服务接口(insert/delete/selectByGoodsIdAndUserId/selectByPage) |
utils/ |
JwtUtil.java | JWT生成/解析(generateJwt/parseJwtToMap) |
utils/ |
RedisUtil.java | Redis操作(set/get/delete/hasKey) |
config/ |
JacksonConfig.java | 所有Long序列化为String |
config/ |
RedisConfig.java | RedisTemplate Bean |
config/ |
WhiteListConfig.java | 白名单配置绑定 |
intercepter/ |
JwtInterceptor.java | 认证拦截器(验签名+刷新token) |
advice/ |
WebExceptionHandler.java | @ExceptionHandler全局异常处理 |
exception/ |
StException.java | 业务异常(构造传入message) |
20.6 工具类和配置类代码
StException.java:
package org.example.mall.common.exception;
public class StException extends Exception {
public StException(String message) { super(message); }
}
WebExceptionHandler.java:
package org.example.mall.common.advice;
import org.example.mall.common.bean.RespBean;
import org.example.mall.common.exception.StException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class WebExceptionHandler {
@ExceptionHandler(StException.class)
public RespBean handleSt(StException e) {
return RespBean.error(e.getMessage());
}
@ExceptionHandler(Exception.class)
public RespBean handle(Exception e) {
return RespBean.error("未知错误,请联系管理员");
}
}
Rule.java:
package org.example.mall.common.bean;
import lombok.Data;
@Data
public class Rule {
private String method; // GET/POST/PUT/DELETE
private String regpath; // 正则路径
}
RedisUtil.java(核心方法):
@Component
public class RedisUtil {
@Autowired private RedisTemplate<String, Object> redisTemplate;
public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); }
public Object get(String key) { return redisTemplate.opsForValue().get(key); }
public void delete(String key) { redisTemplate.delete(key); }
public boolean hasKey(String key) { return redisTemplate.hasKey(key); }
}
21. 各微服务完整Config/Controller/Mapper清单
21.1 goods_service(8090)
WebConfig:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${com.picdir}")
private String picdir;
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 图片静态资源映射(本地文件路径 → URL访问路径)
registry.addResourceHandler("/category/pic/**", "/goods/pic/**")
.addResourceLocations("file:" + picdir);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/category/**", "/goods/**")
.excludePathPatterns("/category/search", "/category/allParent",
"/category/{id}", "/category/**/pic/**",
"/goods", "/goods/search", "/goods/{id}", "/goods/**/pic/**");
}
}
GoodsController 关键端点:
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired private GoodsService goodsService;
@GetMapping // selectByPage(condition, pageNum, pageSize)
@GetMapping("/search") // selectByPage1(含子分类搜索)
@GetMapping("/{id}") // selectById(含关联图片+分类)
@PostMapping // insert(goods) + 图片处理
@PutMapping // update(goods) + 图片替换
@DeleteMapping("/{id}") // delete(id)
@PostMapping("/upload") // 图片上传
@GetMapping("/pic/{filename}") // 图片静态文件(通过ResourceHandler提供)
}
CategoryController 关键端点:
@RestController
@RequestMapping("/category")
public class CategoryController {
@GetMapping("/search") // selectByPage(condition, pageNum, pageSize)
@GetMapping("/allParent") // 查所有parent_id=0的父分类
@GetMapping("/{id}") // selectById
@PostMapping // insert
@PutMapping // update
@DeleteMapping("/{id}") // delete
@PostMapping("/upload") // 上传封面图
}
Mapper清单:
| Mapper | XML | 关键SQL |
|---|---|---|
| GoodsMapper | GoodsMapper.xml | insert/delete/update/selectByCondition/selectByid/selectByCondition1/selectByCategoryId/reduceStock |
| GoodsPicMapper | GoodsPicMapper.xml | insert(批量foreach)/delete(按goodsId)/selectByGoodsId |
| CategoryMapper | CategoryMapper.xml | insert/delete/update/selectByCondition/selectById/selectAllParent |
21.2 user_service(8092)
WebConfig:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/user/**", "/collect/**");
// /addr/**不在拦截范围——AddrController自己手动 @RequestHeader token
}
}
UserController 关键端点:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired private RedisUtil redisUtil;
@Autowired private UserService userService;
@GetMapping("/captcha") // 生成验证码→Redis存→返回base64图片
@PostMapping("/login") // 验验证码→用户名密码→返回JWT
@PostMapping("/reg") // 验验证码→注册新用户
@PutMapping("/chgInfo") // 修改个人信息
@PutMapping("/chgPwd") // 修改密码
@GetMapping("/info") // 获取当前登录用户信息
@GetMapping("/search") // 后台搜索用户列表
@PutMapping("/status") // 后台修改用户状态
@DeleteMapping("/{id}") // 后台删除用户
}
Mapper清单:
| Mapper | XML | 关键SQL |
|---|---|---|
| UserMapper | UserMapper.xml | insert/selectByUsername/selectById/updateById/delete/selectByCondition |
| CollectMapper | CollectMapper.xml | insert/delect/selectById/selectByGoodsIdAndUserId/selectByUserId(含goods JOIN) |
| AddrMapper | AddrMapper.xml | insert/update/delete/selectById/selectByUserId/clearDefault/setDefault |
21.3 admin_service(8091)
WebConfig:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/captcha", "/admin/login");
}
}
AdminController 关键端点:
@RestController
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/captcha") // 图形验证码
@PostMapping("/login") // 登录
@GetMapping("/info") // 当前管理员信息
@PutMapping("/chgPwd") // 改密码
@PutMapping("/chgInfo") // 改信息
@GetMapping("/search") // 搜索列表
@PostMapping // 新增
@PutMapping // 修改
@DeleteMapping("/{id}") // 删除
@GetMapping("/{id}") // 查单条
}
Mapper清单:
| Mapper | XML | 关键SQL |
|---|---|---|
| AdminMapper | AdminMapper.xml | insert/delete/update/selectByCondition/selectById/selectByUsername |
| DashboardMapper | DashboardMapper.xml | countOrders/countUsers/countGoods/countTodayOrders/selectTodayOrderItems/selectRecentOrders/selectRecentUsers/countOrdersByStatus |
21.4 order_service(8093)
WebConfig:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/cart/**");
// /order/**不拦截——OrderController按端点类型区分校验
}
}
CartController 关键端点:
@RestController
@RequestMapping("/cart")
public class CartController {
@PostMapping("/{goodsId}") // 加入购物车
@GetMapping // 查当前用户购物车列表
@PutMapping // 修改数量
@DeleteMapping("/{id}") // 删单条
@DeleteMapping // 批量删除(body传ids)
@GetMapping("/{id}") // 查单条
}
Mapper清单:
| Mapper | XML | 关键SQL |
|---|---|---|
| CartMapper | CartMapper.xml | insert/update/delete/deleteByIds(foreach)/selectByGoodsIdAndUserId/selectById/selectByCondition |
| OrderMapper | OrderMapper.xml | insert/selectByCondition(JOIN user)/selectById/selectByUserId/selectAddrById/updateById(动态SET)/delete/cancelExpiredOrders |
22. 前端项目完整脚手架
22.1 创建步骤
npm create vite@latest front -- --template vue
cd front
npm install
npm install element-plus @element-plus/icons-vue axios vue-router@4 pinia@3 pinia-plugin-persistedstate qs
npm install @wangeditor/editor @wangeditor/editor-for-vue
22.2 .env
VITE_SERVER_ADDR=http://www.dxkua.cn
# 本地开发: http://localhost
22.3 vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) }
}
})
22.4 index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>在线商城</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
22.5 前端源文件完整清单
| 目录 | 文件 | 作用 |
|---|---|---|
src/main.js |
– | 入口:创建App→全局注册所有ElementPlus图标→注册Pinia+持久化插件→注册Router→注册ElementPlus→挂载 |
src/App.vue |
– | 根组件:<transition name="fade"><router-view/></transition> |
src/assets/base.css |
– | CSS变量 --theme-color: #FF6800; --theme-bg-color: #303133 |
src/assets/main.css |
– | 全局样式 .center{width:1200px;margin:auto} + a去下划线+ul去点 |
src/stores/token.js |
Pinia | token状态管理(sessionStorage持久化),含token/updateToken/$reset |
src/stores/user.js |
Pinia | 用户信息状态管理(sessionStorage持久化),含user/updateUser/$reset |
src/api/index.js |
Axios实例 | baseURL+请求拦截器(加token)+响应拦截器(刷新token, 403处理) |
src/api/userApi.js |
API | captcha/login/reg/getInfo/chgPwd/chgInfo/search/updateStatus/delete |
src/api/AdminApi.js |
API | captcha/login/getInfo/chgPwd/chgInfo/search/insert/update/delete/selectById |
src/api/GoodsApi.js |
API | insert/delete/update/selectById/selectByPage/selectByPage1 |
src/api/CategoryApi.js |
API | insert/delete/update/selectById/selectByPage/selectAllParent |
src/api/cartApi.js |
API | insert/delete/deleteByIds/update/selectBycodition/selectById |
src/api/orderApi.js |
API | search/selectById/updateStatus/delete/create/createDirect/pay/cancel/myOrders/queryStatus |
src/api/collectApi.js |
API | insert/delect/selectByGoodsIdAndUserId/selectByPage |
src/api/addrApi.js |
API | insert/update/delete/setDefault/selectByUserId/selectById |
src/api/chatApi.js |
API | sendMessage(sessionId, message) |
src/router/index.js |
Router | 所有路由+导航守卫(公开页面放行, 其余需token, 管理员跳/admin/login) |
src/components/user/home/UserHeader.vue |
组件 | 顶部导航(首页/全部商品/新品上市/限时特惠/品牌专区/关于我们)+搜索框+登录状态+分类菜单 |
src/components/user/home/UserFooter.vue |
组件 | 底部(链接+版权) |
src/views/user/LoginView.vue |
页面 | 登录(用户名+密码+验证码), 卡片式表单 |
src/views/user/RegView.vue |
页面 | 注册 |
src/views/user/IndexView.vue |
页面 | 首页(轮播图+广告位+按父分类分组推荐商品) |
src/views/user/SearchView.vue |
页面 | 商品搜索/分类浏览(分类标签+5列网格+分页) |
src/views/user/GoodsView.vue |
页面 | 商品详情(轮播图+加入购物车+直接购买+收藏+富文本详情) |
src/views/user/CartView.vue |
页面 | 购物车(表格+全选+数量+删除+全删+结算) |
src/views/user/CreateOrderView.vue |
页面 | 结算页(双模式+地址+支付+商品清单+提交→支付) |
src/views/user/PayResultView.vue |
页面 | 支付结果(查状态+显示结果) |
src/views/user/UserCenterView.vue |
页面 | 个人中心(5个Tab面板:信息/密码/收藏/地址/订单) |
src/views/user/HomeView.vue |
布局 | 用户端父布局(Header+RouterView+Footer+ChatWidget) |
src/views/admin/LoginView.vue |
页面 | 管理员登录 |
src/views/admin/HomeView.vue |
布局 | 管理端父布局(顶栏+侧边栏+RouterView) |
src/views/admin/IndexView.vue |
页面 | 仪表盘(统计卡片+今日概览+状态分布+最近订单+最近用户) |
src/views/admin/UserView.vue |
页面 | 用户管理(搜索+表格+状态修改+删除) |
src/views/admin/OrderView.vue |
页面 | 订单管理(搜索+表格+状态修改+删除) |
src/views/admin/GoodsView.vue |
页面 | 商品管理(搜索+表格+级联分类+图片+富文本+增删改) |
src/views/admin/CategoryView.vue |
页面 | 分类管理(搜索+表格+图片+增删改) |
src/views/admin/AdminView.vue |
页面 | 管理员管理(搜索+表格+增删改) |
23. 部署步骤
23.1 打包
# 后端(项目根目录)
mvn clean package -DskipTests -q
# 前端
cd front && npm run build
产物:
admin_service/target/admin_service-0.0.1-SNAPSHOT.jar (~38MB)
user_service/target/user_service-0.0.1-SNAPSHOT.jar (~42MB)
goods_service/target/goods_service-0.0.1-SNAPSHOT.jar (~55MB)
order_service/target/order_service-0.0.1-SNAPSHOT.jar (~83MB)
front/dist/ (index.html + assets/*.js + assets/*.css)
23.2 部署到服务器
# 1. 部署前端 → nginx静态目录
cp -r front/dist/* /usr/share/nginx/html/
# 2. 部署nginx配置
cp nginx/conf/nginx.conf /etc/nginx/nginx.conf
nginx -t && nginx -s reload
# 3. 设置支付宝凭证环境变量
export ALIPAY_APP_ID=你的沙箱APPID
export ALIPAY_PRIVATE_KEY="你的应用私钥"
export ALIPAY_PUBLIC_KEY="支付宝公钥"
export ALIPAY_RETURN_URL=http://你的域名/#/user/payResult
export ALIPAY_NOTIFY_URL=http://你的域名/order/notify
# 4. 启动四个微服务
java -jar admin_service/target/admin_service-0.0.1-SNAPSHOT.jar &
java -jar user_service/target/user_service-0.0.1-SNAPSHOT.jar &
java -jar goods_service/target/goods_service-0.0.1-SNAPSHOT.jar &
java -jar order_service/target/order_service-0.0.1-SNAPSHOT.jar &
23.3 验证清单
| 步骤 | 地址 | 预期 |
|---|---|---|
| 用户端首页 | http://你的IP/ |
轮播图+推荐商品 |
| 管理端登录 | http://你的IP/#/admin/login |
登录表单 |
| 管理员登录 | admin / 密码同salt加密后 | 进入仪表盘 |
| 用户登录 | tom / 密码同salt加密后 | 首页显示用户名 |
| 地址管理 | 个人中心→地址管理 | 6条测试数据显示 |
| 下单→支付 | 购物车→结算→提交→跳支付宝 | 沙箱付款页面 |
| 支付结果 | 支付宝付款后跳回 | “支付成功” |
| 我的订单 | 个人中心→我的订单 | 订单卡片 |
24. 支付宝沙箱配置步骤
- 访问 open.alipay.com → 登录 →「控制台」→「沙箱环境」
- 获取 APPID、下载密钥生成工具生成 RSA2 密钥对
- 私钥自己保存 → 公钥上传到沙箱 → 支付宝返回支付宝公钥
- 设置环境变量:
export ALIPAY_APP_ID=获取的沙箱APPID export ALIPAY_PRIVATE_KEY="生成的私钥(完整Base64)" export ALIPAY_PUBLIC_KEY="支付宝返回的公钥" - 沙箱买家账号在沙箱控制台→「沙箱账号」获取,付款时用这个账号登录
- 沙箱网关:
https://openapi-sandbox.dl.alipaydev.com/gateway.do - 正式网关:
https://openapi.alipay.com/gateway.do(需签约产品+备案域名)
25. 从零到运行的完整checklist
□ 安装 JDK17 + Maven3.8+ + Node.js20+
□ 启动 MySQL → 创建 mall 库 → 执行 mall.sql → ALTER order 加 items 列
□ 启动 ZooKeeper (2181)
□ 启动 Redis (6379, 密码123456)
□ 创建 Maven 多模块项目 (父POM+5个子模块)
□ 创建所有 common Bean/Service/Utils/Config/Interceptor/Exception
□ 创建 admin_service 完整结构 (Application/Controller/Service/Mapper/Config/yml)
□ 创建 user_service 完整结构
□ 创建 goods_service 完整结构 (含 @EnableDubbo Dubbo服务暴露)
□ 创建 order_service 完整结构 (含支付宝Config+定时任务+@EnableScheduling)
□ 启动 goods_service → get http://localhost:8090/goods → 确认有数据返回
□ 启动 user_service → get http://localhost:8092/user/captcha → 确认返回验证码
□ 启动 admin_service → get http://localhost:8091/admin/captcha → 确认返回验证码
□ 启动 order_service → (先不配支付宝凭证)→ 购物车/下单功能正常 → 支付报错正常
□ 创建前端项目 → npm install → npm run dev → http://localhost:5173
□ 创建所有前端页面/API/Store → 逐页面验证
□ 配置支付宝沙箱凭证 → 重启 order_service → 完整支付流程验证
□ npm run build → 部署 dist/ → 配置 nginx → nginx -s reload
□ 公网验证:首页/登录/购物/下单/支付/个人中心/后台管理 逐项通过
文档版本:2026-07-28
适用方式:第一部分(1-18章)用于学习理解,第二部分(19-25章)用于从零复现