第二部分:从零复现指南

补全了所有缺失的配置、脚手架、非核心代码和部署步骤。读完前面18章+这一部分,可以从零搭建一个完全一样的商城项目。


19. 环境搭建

19.1 需要的软件

软件 版本 用途 下载方式
JDK 17 Java运行/编译 winget install OpenJDK.OpenJDK.17adoptium.net
Maven 3.8+ Java项目构建 winget install Apache.Maven.3maven.apache.org
MySQL 8.0 数据库 winget install Oracle.MySQLdev.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.LTSnodejs.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.cfgbin/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.xmluser_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_serviceuser_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. 支付宝沙箱配置步骤

  1. 访问 open.alipay.com → 登录 →「控制台」→「沙箱环境」
  2. 获取 APPID、下载密钥生成工具生成 RSA2 密钥对
  3. 私钥自己保存 → 公钥上传到沙箱 → 支付宝返回支付宝公钥
  4. 设置环境变量:
    export ALIPAY_APP_ID=获取的沙箱APPID
    export ALIPAY_PRIVATE_KEY="生成的私钥(完整Base64)"
    export ALIPAY_PUBLIC_KEY="支付宝返回的公钥"
  5. 沙箱买家账号在沙箱控制台→「沙箱账号」获取,付款时用这个账号登录
  6. 沙箱网关https://openapi-sandbox.dl.alipaydev.com/gateway.do
  7. 正式网关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章)用于从零复现

暂无评论

发送评论 编辑评论


				
上一篇
下一篇