SpringCloud电商微服务项目衣拉客搭建指南
衣拉客电商微服务项目搭建指南(初学者从 0 到 1 实战)
结合我们之前学习的 Nacos、Gateway、Feign、MyBatis 等组件,本文将以 “衣拉客电商系统” 为例,详细拆解微服务项目的完整搭建流程 —— 从需求分析、系统设计到工程落地,每个步骤都标注 “为什么这么做” 和 “易错点”,帮初学者建立 “微服务项目结构” 的清晰认知,避免盲目抄代码。
该项目内容来源于张hw老师,经过整理再创作
一、项目概述:先搞懂 “做什么” 和 “整体架构”
在搭框架前,我们先明确项目定位和整体结构,避免后续开发偏离方向。
1.1 项目需求:B2C 电商平台的核心模块
“衣拉客” 是全品类 B2C 电商系统,分网站前台(用户使用)和管理后台(管理员使用)两大模块:
模块 | 核心功能 |
---|---|
网站前台 | 首页展示、商品搜索、购物车、订单下单、用户中心(注册 / 登录 / 个人信息) |
管理后台 | 商品管理(新增 / 编辑 / 上下架)、订单管理(发货 / 取消)、用户管理、权限控制 |
以下是 B2C、C2C、B2B2C 模式的商家角色对比表
对比维度 | B2C(企业对消费者) | C2C(消费者对消费者) | B2B2C(企业对商家对消费者) |
---|---|---|---|
模式核心 | 企业直接卖给个人,无中间商家 | 个人通过平台互相卖,平台仅搭框架 | 平台整合第三方商家,一起卖给个人 |
商家主体 | 品牌 / 零售企业(如京东自营、苹果官网) | 个人 / 小微卖家(如闲鱼用户、淘宝个人店) | 第三方品牌 / 经销商(如天猫旗舰店、京东 POP 店) |
责任核心 | 企业全担(品控、物流、售后直接负责) | 卖家自担(平台仅协助纠纷,不控品质) | 商家主担 + 平台监管(平台管规则、商家管履约) |
平台角色 | 企业自身即平台(或用工具建平台) | 纯 “交易工具”(提供支付、搜索) | 纯 “生态管理者”(招商、定规则、分流量) |
典型案例 | 京东自营、苹果官网、小米有品 | 闲鱼、淘宝个人卖家、Poshmark | 天猫、京东 POP 模式、亚马逊第三方 |
1.2 系统架构图:微服务的 “骨架”
整个系统基于 “微服务架构” 设计,按 “业务领域” 拆分服务,配合中间件实现高可用,架构图如下:
二、系统设计:搭框架前的 “设计决策”
设计阶段决定了后续开发的 “效率” 和 “可维护性”,核心关注数据库分库和技术选型。
2.1 数据库分库设计:按 “业务领域” 拆分
微服务架构中,数据库不能 “所有服务共用一个库”(否则回到单体架构),需按 “服务职责” 分库,避免跨库查询,提升性能和隔离性:
分库名称 | 对应服务 | 核心表 |
---|---|---|
zh_user | 用户服务(zh-user-service) | t_user(用户基本信息)、t_user_address(收货地址)、t_login_record(登录记录) |
zh_goods | 商品服务(zh-goods-service) | t_goods(商品基本信息)、t_category(商品分类)、t_stock(库存) |
zh_order | 订单服务(zh-order-service) | t_order(订单主表)、t_order_item(订单明细)、t_cart(购物车) |
zh_system | 系统服务(zh-system-service) | t_system_user(管理员信息)、t_role(角色)、t_menu(菜单权限) |
zh_business | 运营服务(zh-business-service) | t_activity(促销活动)、t_news(新闻)、t_partner(合作伙伴) |
设计理由:
每个服务只操作自己的库,避免 “一个库挂了影响所有服务”;
后续扩展时,可单独对某个库做分表(如订单库数据多了分表),不影响其他库。
2.2 技术选型:“用什么工具” 和 “为什么用”
技术选型需结合 “项目需求” 和 “团队熟悉度”,本项目基于 Java 生态,核心技术栈如下(关联我们之前学的内容):
技术领域 | 选型 | 作用(为什么用) |
---|---|---|
主框架 | Spring Boot 2.7.5 | 快速开发微服务,自动配置减少 XML |
微服务治理 | Spring Cloud Alibaba 2021.0.4.0 | 包含 Nacos(注册 / 配置中心)、Sentinel(熔断降级),国内生态成熟 |
服务注册 / 配置 | Nacos | 替代 Eureka+Config,一站式解决服务注册和配置管理,之前已详细学习 |
服务网关 | Spring Cloud Gateway | 替代 Zuul,非阻塞性能好,统一入口路由、鉴权,之前已学习网关配置 |
服务调用 | OpenFeign | 声明式 HTTP 调用,简化服务间通信,之前学过 Feign 整合 Sentinel |
数据访问 | MyBatis + MySQL | 关系型数据库访问,MyBatis 灵活适配复杂 SQL,之前学过 MyBatis 整合 Nacos 配置 |
缓存 | Redis | 缓存高频数据(如商品详情、用户登录态),减轻数据库压力 |
消息队列 | RabbitMQ | 异步处理(如订单下单后发消息通知库存)、秒杀削峰,之前已学习 RabbitMQ 消息模型 |
搜索 | Elasticsearch | 商品全文搜索(如按名称 / 描述搜商品),比数据库模糊查询快 |
前端技术 | 前台:Thymeleaf;后台:Vue+ElementUI | 前台用模板引擎快速开发,后台用 Vue 实现动态交互 |
安全框架 | Spring Security | 管理后台权限控制(登录验证、角色权限),下文会详细实战 |
三、工程搭建:从 “父工程” 到 “子服务” 的完整步骤
微服务项目采用 “Maven 多模块” 结构,按 “父工程→子服务→Web 层” 的顺序搭建,确保依赖统一、结构清晰。
3.1 第一步:搭建父工程(zh_shop)
父工程的核心作用是统一管理依赖版本和抽取公共依赖,避免子服务依赖版本混乱。
3.1.1 操作步骤
用 IDEA 新建 Maven 项目,GroupId 填
com.zh
,ArtifactId 填zh_shop
,打包方式选pom
;删除父工程的
src
文件夹(父工程不写业务代码,只做依赖管理);配置
pom.xml
,核心是dependencyManagement
(统一版本)和公共依赖。
3.1.2 父工程 pom.xml 详解
<?xml version="1.0" encoding="UTF-8"?><project xmlns="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><!-- 1. 父工程坐标(子工程会继承) --><groupId>com.zh</groupId><artifactId>zh_shop</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging> <!-- 父工程必须是pom打包 --><!-- 2. 统一版本管理:子工程引入依赖时不用写version --><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-cloud.version>2021.0.3</spring-cloud.version><spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version><spring-boot.version>2.7.5</spring-boot.version></properties><!-- 3. 继承Spring Boot父依赖:所有Spring Boot项目的基础 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring-boot.version}</version><relativePath/> <!-- 从Maven仓库拉取,不找本地 --></parent><!-- 4. 核心:统一管理微服务依赖版本 --><dependencyManagement><dependencies><!-- Spring Cloud 核心依赖(如Gateway、OpenFeign) --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope> <!-- 父工程特有,导入依赖列表 --></dependency><!-- Spring Cloud Alibaba 依赖(如Nacos、Sentinel) --><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></dependencies></dependencyManagement><!-- 5. 公共依赖:所有子服务都会继承(避免重复引入) --><dependencies><!-- Spring Boot Web:所有服务都需要HTTP接口能力 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Nacos配置中心:所有服务从Nacos拉取配置 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!-- Bootstrap依赖:新版本Spring Cloud移除了,必须手动加,否则Nacos配置拉取失败 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency></dependencies><!-- 6. 统一打包插件:子服务打包时继承 --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration></plugin></plugins></build></project>
3.1.3 关键说明
dependencyManagement
vsdependencies
:dependencyManagement只 “声明版本”,不实际引入依赖;
dependencies会实际引入,且子服务会继承。
Bootstrap 依赖:之前学 Nacos 配置中心时强调过,必须加这个依赖,否则bootstrap.yml不生效,Nacos 配置拉取失败。
3.2 第二步:搭建子服务工程(核心微服务)
子服务按 “业务领域” 拆分,共 7 个核心服务,结构如下:
zh_shop(父工程)├─ zh-common(公共模块:实体类、工具类)├─ zh-user-service(用户服务)├─ zh-goods-service(商品服务)├─ zh-order-service(订单服务)├─ zh-system-service(系统服务)├─ zh-business-service(运营服务)├─ zh-pay-service(支付服务)└─ zh-gateway(网关服务)
3.2.1 先搭 “公共模块 zh-common”(所有服务都依赖)
zh-common
是 “工具库”,存放所有服务共用的代码,避免重复开发:
新建 Maven 子模块,ArtifactId 为
zh-common
;核心内容:
实体类(如
User
、Goods
、Order
,对应数据库表);工具类(如
Result
统一响应类、日期工具、加密工具);公共依赖(如 FastJSON、Lombok)。
示例:统一响应类 Result.java(所有服务接口返回统一格式):
package com.zh.common.entity;import lombok.Data;import java.util.List;/*** 统一响应类:所有接口返回此格式,前端好处理*/@Datapublic class Result<T> {// 状态码:200=成功,401=权限不足,400=参数错误,500=系统错误private Integer code;// 提示信息private String message;// 单个数据(如详情接口)private T data;// 多个数据(如列表接口)private List<T> dataList;// 成功静态方法(简化代码)public static <T> Result<T> success() {Result<T> result = new Result<>();result.setCode(200);result.setMessage("SUCCESS");return result;}public static <T> Result<T> success(T data) {Result<T> result = success();result.setData(data);return result;}// 失败静态方法public static <T> Result<T> fail(Integer code, String message) {Result<T> result = new Result<>();result.setCode(code);result.setMessage(message);return result;}}
注意:zh-common
不需要application.yml
和启动类,因为它不是独立运行的服务,只是依赖模块。
3.2.2 搭建 “业务服务”(以 zh-system-service 为例)
所有业务服务(用户、商品、订单等)的搭建流程一致,这里以 “系统服务(权限 / 菜单)” 为例:
步骤 1:新建子模块
父工程右键→New→Module→Maven,ArtifactId 为zh-system-service
。
步骤 2:配置 pom.xml(引入依赖)
<?xml version="1.0" encoding="UTF-8"?><project xmlns="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"><parent><groupId>com.zh</groupId><artifactId>zh_shop</artifactId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>zh-system-service</artifactId><dependencies><!-- 1. 服务注册发现:注册到Nacos --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 2. 引入公共模块:使用实体类和工具类 --><dependency><groupId>com.zh</groupId><artifactId>zh-common</artifactId><version>1.0-SNAPSHOT</version></dependency><!-- 3. MyBatis:操作数据库(系统库zh_system) --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency><!-- 4. MySQL驱动:连接数据库 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- 5. 分页插件:列表接口分页 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>4.1.3</version></dependency></dependencies></project>
步骤 3:配置 application.yml(服务端口、Nacos、数据库)
server:port: 8006 # 系统服务端口,确保不与其他服务冲突(如用户服务8001,商品服务8002)spring:application:name: system-service # 服务名,注册到Nacos的标识,必须无下划线cloud:nacos:discovery:server-addr: 127.0.0.1:8848 # Nacos地址,和其他服务一致service: ${spring.application.name}# 数据库配置(系统库zh_system)datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/zh_system?useSSL=false&serverTimezone=UTCusername: rootpassword: root# MyBatis配置mybatis:mapper-locations: classpath:mybatis/mapper/*.xml # Mapper.xml文件路径type-aliases-package: com.zh.system.entity # 实体类包名,简化XML中的类名
步骤 4:编写启动类(开启服务注册和 MyBatis 扫描)
package com.zh.system;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClient // 开启服务注册发现,注册到Nacos@MapperScan("com.zh.system.mapper") // 扫描MyBatis的Mapper接口public class SystemServiceApplication {public static void main(String[] args) {SpringApplication.run(SystemServiceApplication.class, args);}}
步骤 5:编写核心业务代码(以 “用户登录查询” 为例)
实体类(com.zh.system.entity.SystemUser):对应
zh_system
库的t_system_user
表;Mapper 接口(com.zh.system.mapper.SystemUserMapper):数据库操作;
package com.zh.system.mapper;import com.zh.system.entity.SystemUser;import org.apache.ibatis.annotations.Select;public interface SystemUserMapper {// 根据用户名查询管理员信息@Select("select * from t_system_user where suname = #{username}")SystemUser selectByUsername(String username);}
Service 层(com.zh.system.service.SystemUserService):业务逻辑;
package com.zh.system.service;import com.zh.system.entity.SystemUser;import com.zh.system.mapper.SystemUserMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class SystemUserService {@Autowiredprivate SystemUserMapper systemUserMapper;// 根据用户名查询用户public SystemUser getByUsername(String username) {return systemUserMapper.selectByUsername(username);}}
Controller 层(com.zh.system.controller.SystemUserController):对外提供接口;
package com.zh.system.controller;import com.zh.common.entity.Result;import com.zh.system.entity.SystemUser;import com.zh.system.service.SystemUserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/system/user")public class SystemUserController {@Autowiredprivate SystemUserService systemUserService;// 提供给管理后台调用:根据用户名查询管理员@RequestMapping("/getByUsername")public Result<SystemUser> getByUsername(@RequestParam String username) {SystemUser user = systemUserService.getByUsername(username);if (user == null) {return Result.fail(400, "用户名不存在");}return Result.success(user);}}
3.2.3 搭建 “网关服务 zh-gateway”(特殊配置)
网关是所有请求的入口,配置和普通服务不同,需注意 “排除 Web 依赖”(Gateway 基于 WebFlux,和 MVC 冲突):
步骤 1:新建子模块 zh-gateway,配置 pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="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"><parent><groupId>com.zh</groupId><artifactId>zh_shop</artifactId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>zh-gateway</artifactId><dependencies><!-- 1. Gateway核心依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- 2. 服务注册发现:从Nacos获取服务列表 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 3. 负载均衡:Gateway转发时负载均衡 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!-- 4. 排除Web依赖:Gateway基于WebFlux,和MVC冲突 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency></dependencies></project>
步骤 2:配置 application.yml(网关路由)
server:port: 8080 # 网关端口,对外暴露的统一入口spring:application:name: zh-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848# Gateway核心配置:路由规则gateway:discovery:locator:enabled: true # 开启“服务名路由”:http://网关地址/服务名/接口路径# 自定义路由规则(可选,比服务名路由更灵活)routes:# 路由1:管理后台→系统服务- id: route-system # 路由唯一IDuri: lb://system-service # 转发到system-service,lb=负载均衡predicates:- Path=/system/** # 匹配路径:/system开头的请求filters:- StripPrefix=1 # 去掉路径前缀:/system/user/getByUsername → /user/getByUsername# 路由2:前台→商品服务- id: route-goodsuri: lb://goods-servicepredicates:- Path=/goods/**filters:- StripPrefix=1
步骤 3:启动类
package com.zh.gateway;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClientpublic class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}}
测试网关:启动 Gateway 和 SystemService 后,访问http://localhost:8080/system/user/getByUsername?username=admin
,会转发到system-service
的/user/getByUsername
接口,返回管理员信息。
3.3 第三步:搭建 Web 层工程(前台 + 后台)
Web 层是 “用户直接访问的界面层”,分前台(用户用)和后台(管理员用),负责 “页面展示” 和 “调用微服务接口”。
3.3.1 管理后台(zh-web-manage,Vue+ElementUI)
后台是管理员操作的界面,用 Vue+ElementUI 开发,核心是 “调用微服务接口” 和 “权限控制”。
步骤 1:新建 Maven 子模块 zh-web-manage,配置 pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="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"><parent><groupId>com.zh</groupId><artifactId>zh_shop</artifactId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>zh-web-manage</artifactId><dependencies><!-- 1. 服务注册发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 2. OpenFeign:调用微服务接口 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- 3. Spring Security:权限控制(登录、角色权限) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- 4. Thymeleaf:模板引擎(可选,若用Vue可不用) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- 5. 引入公共模块 --><dependency><groupId>com.zh</groupId><artifactId>zh-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
步骤 2:核心功能:Spring Security 登录权限(重点)
后台需要 “管理员登录验证” 和 “角色权限控制”,这里以 “登录功能” 为例:
Feign 接口(调用系统服务):
package com.zh.manage.feign;import com.zh.common.entity.Result;import com.zh.system.entity.SystemUser;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;// 调用system-service服务@FeignClient(name = "system-service", contextId = "systemUserFeign")public interface SystemUserFeign {// 对应system-service的/system/user/getByUsername接口@RequestMapping("/system/user/getByUsername")Result<SystemUser> getByUsername(@RequestParam String username);}
自定义 UserDetailsService(登录验证逻辑):
package com.zh.manage.security;import com.zh.common.entity.Result; import com.zh.manage.feign.SystemUserFeign; import com.zh.system.entity.SystemUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component;@Component public class MyUserDetailsService implements UserDetailsService {@Autowiredprivate SystemUserFeign systemUserFeign;@Autowiredprivate PasswordEncoder passwordEncoder;// 登录时自动调用:根据用户名查询用户@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 1. 调用系统服务查询用户Result<SystemUser> result = systemUserFeign.getByUsername(username);SystemUser user = result.getData();if (user == null) {throw new UsernameNotFoundException("用户名不存在");}// 2. 构建权限列表(后续从系统服务获取角色权限)String authorities = "ROLE_ADMIN"; // 临时给管理员权限// 3. 返回Spring Security需要的User对象(密码需加密)return new User(user.getSuname(),passwordEncoder.encode(user.getSupwd()), // 密码加密(数据库密码应存加密后的值)AuthorityUtils.commaSeparatedStringToAuthorityList(authorities));} }
Spring Security 配置类:
package com.zh.manage.security;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {// 密码加密器(必须配置,否则登录报错)@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 配置拦截规则和登录页面@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login.html", "/css/**", "/js/**").permitAll() // 静态资源和登录页不用认证.anyRequest().authenticated() // 其他请求必须登录.and().formLogin().loginPage("/login.html") // 自定义登录页.loginProcessingUrl("/login") // 登录请求路径(表单action="login").defaultSuccessUrl("/main.html") // 登录成功跳转页.permitAll().and().csrf().disable(); // 关闭CSRF(开发阶段方便测试)}}
登录页面(放在
resources/templates/login.html
):<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>管理后台登录</title></head><body><!-- 登录表单:action="/login"对应Security配置的loginProcessingUrl --><form action="/login" method="post"><input type="text" name="username" placeholder="用户名"><br><input type="password" name="password" placeholder="密码"><br><!-- 错误提示 --><span style="color: red" th:if="${param.error}" th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}"></span><br><button type="submit">登录</button></form></body></html>
3.3.2 网站前台(zh-web-front,Thymeleaf)
前台是用户访问的界面,用 Thymeleaf 模板引擎开发,核心是 “调用商品、订单服务” 展示数据,搭建流程和后台类似,重点是 “页面渲染” 和 “用户交互”(如商品列表、加入购物车)。
四、跨服务实体类调用:避免重复定义
微服务中,多个服务可能用到同一个实体类(如User
在用户服务和订单服务都需要),此时不能每个服务都定义一次,需通过 “依赖公共模块” 或 “依赖其他服务” 实现共享。
4.1 方案 1:通过公共模块共享(推荐)
将实体类放在zh-common
中,所有服务依赖zh-common
,这是最规范的方式:
在
zh-common
的com.zh.common.entity
包下定义User
类;其他服务(如订单服务)引入zh-common依赖,直接 import 使用:
import com.zh.common.entity.User; // 从公共模块导入
4.2 方案 2:依赖其他服务(特殊场景)
若实体类只在两个服务间共享,且不想放公共模块,可直接依赖对方服务(不推荐,耦合度高):
在用户服务(zh-user-service)中定义
User
类;在订单服务(zh-order-service)的 pom.xml 中引入用户服务依赖:
<dependency><groupId>com.zh</groupId><artifactId>zh-user-service</artifactId><version>1.0-SNAPSHOT</version></dependency>
订单服务中直接使用User类:
import com.zh.user.entity.User; // 从用户服务导入
注意:方案 2 会导致 “订单服务依赖用户服务”,若用户服务修改User
类,订单服务可能报错,优先用方案 1。
五、项目启动与验证:确保整个链路通
搭建完成后,按以下顺序启动服务,验证是否正常运行:
启动 Nacos Server(
startup.cmd -m standalone
);启动所有微服务(用户、商品、订单、系统、网关);
启动 Web 层(后台、前台);
验证:
访问 Nacos 控制台(
http://localhost:8848/nacos
),查看所有服务是否注册成功;访问网关地址(
http://localhost:8080
),测试后台登录和接口调用。
六、初学者重点 & 易错点总结
依赖冲突:
Gateway 必须排除
spring-boot-starter-web
,否则和 WebFlux 冲突;所有服务的 Spring Boot、Spring Cloud 版本必须兼容(父工程统一管理)。
Nacos 相关:
服务名不能有下划线,否则 Gateway 路由和负载均衡会报错;
必须加
spring-cloud-starter-bootstrap
,否则bootstrap.yml
不生效。
MyBatis 相关:
启动类必须加
@MapperScan
,否则 Mapper 接口无法扫描;mapper-locations
路径必须正确,否则找不到 Mapper.xml。
权限控制:
Spring Security 必须配置
PasswordEncoder
,否则登录时密码无法匹配;静态资源必须配置
permitAll
,否则登录页样式加载失败。
七、后续扩展方向
集成 Sentinel:给核心接口(如下单、支付)加熔断降级,避免故障扩散;
集成 RabbitMQ:实现订单异步处理(如下单后发消息通知库存服务);
集成 Redis:缓存商品详情和用户登录态,减轻数据库压力;
前端优化:后台用 Vue CLI 构建,前台用 Vue 实现单页应用(SPA)。
通过本案例,希望你能理解微服务项目的 “分层思想” 和 “依赖管理”,后续开发时能按 “业务拆分服务、公共代码抽模块” 的思路,搭建可维护、可扩展的微服务框架。