1.初始化项目
idea新建空项目
添加各个模块
gulimall-product商品服务

gulimall-ware仓储服务

gulimall-order订单服务

同理创建
gulimall-coupon优惠券服务
gulimall-member会员服务
同时添加springboot web依赖和springcloud-routing openfeign依赖
聚合模块
在根目录下添加pom文件,添加下列代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.leggasai.gulimall</groupId> <artifactId>gulimall</artifactId> <version>0.0.1-SNAPSHOT</version> <name>gulimall</name> <description>聚合服务</description> <packaging>pom</packaging> <modules> <module>gulimall-ware</module> <module>gulimall-member</module> <module>gulimall-order</module> <module>gulimall-product</module> <module>gulimall-coupon</module> </modules> </project>
|
将pom文件加入maven,刷新maven
更改.gitignore文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| HELP.md target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ ### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans .sts4-cache ### IntelliJ IDEA ### .idea *.iws *.iml *.ipr ### NetBeans ### /nbproject/private/ /nbbuild/ /dist/ /nbdist/ /.nb-gradle/ build/ !**/src/main/**/build/ !**/src/test/**/build/ ### VS Code ### .vscode/ **/mvnw **/mvnw.cmd **/.mvn **/target/ **/.gitignore
|
2.数据库设计
数据库分为 订单数据库、用户数据库、库存数据库、商品数据库、优惠数据库
gmall_数据库设计.pdm
订单数据库表
包含了订单信息,退货信息,订单项等
gulimall_oms.sql
用户数据库表
包含了用户信息,会员积分,用户收藏,收货地址等
gulimall_ums.sql
库存数据库表
包含库存工作单,采购单,库存表等
gulimall_wms.sql
商品数据库表
包含SPU表,SKU表,商品分类表,商品评价表,属性表等
gulimall_pms.sql
优惠数据库表
包含优惠券信息,积分表,秒杀信息等,商品优惠信息等
gulimall_sms.sql
3.快速开发代码生成
主要使用人人开源的renren-generator、renren-fast、renren-fast-vue
引入必要的依赖
创建公共模块
创建common模块,在其pom文件中添加一些公共的依赖,如mysql-connector-java,mybatis等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| <?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> <artifactId>gulimall</artifactId> <groupId>com.leggasai.gulimall</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gulimall-common</artifactId> <description>公共类</description> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <mybatis-plus.version>3.2.0</mybatis-plus.version> <lombok.version>1.18.8</lombok.version> <httpcore.version>4.4.12</httpcore.version> <commons-lang.version>2.6</commons-lang.version> <mysql-connector-java.version>8.0.17</mysql-connector-java.version> <servlet-api.version>2.5</servlet-api.version> </properties> <dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>${httpcore.version}</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>${commons-lang.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> </dependencies> </project>
|
其他模块在其pom文件中引入common模块
1 2 3 4 5
| <dependency> <groupId>com.leggasai.gulimall</groupId> <artifactId>gulimall-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
|
配置Mybatis-Plus
官方链接:简介 | MyBatis-Plus (baomidou.com)
1.添加依赖
在commom模块的pom中添加mybatis-plus的代码
1 2 3 4 5
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency>
|
2.配置
配置数据源
在各个模块的application.yml中添加如下配置
1 2 3 4 5 6
| spring: datasource: username: root password: root url: jdbc:mysql://192.168.241.128:3306/gulimall_pms driver-class-name: com.mysql.cj.jdbc.Driver
|
配置Mybatis-Plus
在各个模块的application.yml中添加如下配置
1 2 3 4 5
| mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml global-config: db-config: id-type: auto
|
4.分布式组件

- Nacos:注册中心(服务发现/注册)
- Nacos:配置中心(动态配置管理)
- Ribbon:负载均衡
- Feign:声明式HTTP客户端,RPC
- Sentinel:服务容错(服务限流、服务降级、服务熔断)
- Gateway:API网关
- Sleuth:调用链监控
- Seata:分布式事务解决方案
在common模块中引入Spring-cloud-Alibaba依赖
版本说明 · alibaba/spring-cloud-alibaba Wiki (github.com)
1 2 3 4 5 6 7 8 9 10 11
| <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2021.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
dependencyManagement的用法:
- 对项目所依赖jar包进行版本管理的管理器。
- 使用pom.xml中的dependencyManagement元索能让所有在子模块中引用一个依赖而不用显式的列出版本号。也就是子模块不需要列出版本,子模块中的pom依赖会找到dependencyManagement所在jar包的版本,并引用这个jar对应的版本号。
- dependencyManagement只是声明依赖, 并不实现引入,因此子项目需要显示的声明需要用的依赖。
- 一般用于父工程,如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
4.1 Nacos
Quick Start for Nacos Spring Cloud Projects
本地下载Nacos
下载链接:Nacos
本地启动:
1 2
| startup.cmd -m standalone
|
启动成功截图

访问地址:Nacos
服务发现
在子模块application.yml中添加如下代码
1 2 3 4 5 6 7
| spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 application: name: gulimall-member
|
在启动类上加入注解@EnableDiscoveryClient以开启服务发现
1 2 3 4 5 6 7 8 9 10
| @MapperScan("com.leggasai.gulimall.member.dao") @SpringBootApplication @EnableDiscoveryClient public class GulimallCouponApplication {
public static void main(String[] args) { SpringApplication.run(GulimallCouponApplication.class, args); }
}
|
远程调用
在pom模块中添加openFeign依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
|
在主类中开启,添加@EnableFeignClients(basePackages = “com.leggasai.gulimall.member.feign”),对应你存放远程调用服务的包路径
1 2 3 4 5 6 7 8 9 10 11
| @MapperScan("com.leggasai.gulimall.member.dao") @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages = "com.leggasai.gulimall.member.feign") public class GulimallMemberApplication {
public static void main(String[] args) { SpringApplication.run(GulimallMemberApplication.class, args); }
}
|
新建远程调用服务文件,路径对应上述basePackages,并编写接口
这里的接口要和被调用类中声明的一致,包括接口路径
1 2 3 4 5 6 7 8
|
@FeignClient("gulimall-coupon") public interface CouponFeignService { @RequestMapping("/coupon/coupon/test") public R test(); }
|
1 2 3 4 5 6 7 8
|
@RequestMapping("/test") public R test(){ CouponEntity couponEntity = new CouponEntity(); couponEntity.setCouponName("满减200-100"); return R.ok().put("coupons", Arrays.asList(couponEntity)); }
|
使用远程调用,注入远程调用服务,调用其中的接口方法即可
1 2 3 4 5 6 7 8 9 10
| @Autowired CouponFeignService couponFeignService; @RequestMapping("/test") public R test(){ R r = couponFeignService.test(); HashMap<String, Object> map = new HashMap<>(); map.put("member","jyc"); map.put("coupons",r.get("coupons")); return R.ok(map); }
|
配置中心
参考文档Nacos-config-example
在pom模块中添加依赖
1 2 3 4 5
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
|
注意新版本需要引入spring-cloud-starter-bootstrap依赖来加载bootstrap.properties文件
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>3.0.2</version> </dependency>
|
新建bootstrap.properties文件,不能在application.yml中写,否则不能动态生效
1 2
| spring.application.name=gulimall-coupon spring.cloud.nacos.config.server-addr=127.0.0.1:8848
|
打开Nacos配置中心,添加配置,Data ID必须为spring.application.name加properties

- 命名空间:用来配置隔离
- 默认使用public(保留空间),默认新增的所有配置都在public空间
- 应用:
- 配置开发,测试,生产环境的不同命名空间
- 每一个微服务相互隔离,创建不同的命名空间
- 需要使用spring.cloud.nacos.config.namespace=id,指定对应命名控件ID
- 配置集:所有配置的集合
- 配置集ID:Data ID
- 配置分组:对配置进行分组
- 默认所有的配置集都属于DEFAULT_GROUP
- 需要使用spring.cloud.nacos.config.group指定对应的配置分组
本项目规则:
- 每个微服务创建自己的
命名空间
,使用配置分组
区分环境,dev、prop、test
- 微服务任何配置信息,任何配置文件都可以放在配置中心中
- 配置中心的配置会被优先使用
网关
网关是所有流量的入口,功能包括路由转发、权限校验、限流控制。本项目使用Spring Cloud Gateway作为网关。
Spring Cloud Gateway
新建gulimall-gateway模块

修改pom文件和根目录下的pom文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.6</version> <relativePath/> </parent> <groupId>com.leggasai.gulimall</groupId> <artifactId>gulimall-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <name>gulimall-gateway</name> <description>API Gateway</description> <properties> <java.version>8</java.version> <spring-cloud.version>2020.0.1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>com.leggasai.gulimall</groupId> <artifactId>gulimall-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
|
开启服务的注册和发现。先在Nacos配置中心处,新建一个命名空间gateway,用于存放和gateway网关有关的配置项。
1 2 3
| spring.application.name=gulimall-gateway spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=6f924aa0-39f6-4a86-9be9-f13562a9af7f
|
排除数据库相关配置。在Application.java中添加如下
1
| @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
|
否则运行会报错

添加路由规则,新建application.yml(此处为了本地调式方便,以后统一写在Nacos配置中心)
1 2 3 4 5 6 7 8
| spring: cloud: gateway: routes: - id: test_route uri: https://www.baidu.com predicates: - Query=url, baidu
|
5.商品服务
三级分类
递归查询
需要实现类似京东
的商品分类树形结构,pms_category
表中通过cat_id
和parent_cid
建立层级关系。使用递归查询构建树形结构

逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Override public List<CategoryEntity> listWithTree() { List<CategoryEntity> entities = this.baseMapper.selectList(null); List<CategoryEntity> levelOneMenus = entities.stream().filter(categoryEntity -> categoryEntity.getParentCid().equals(0L) ).map((item) -> { item.setChildren(getChildren(item, entities)); return item; }).sorted((t1,t2)->{ return (t1.getSort()==null?0:t1.getSort())-(t2.getSort()==null?0:t2.getSort()); }).collect(Collectors.toList()); return levelOneMenus; } private List<CategoryEntity> getChildren(CategoryEntity root,List<CategoryEntity> list){ List<CategoryEntity> children = list.stream().filter(categoryEntity -> categoryEntity.getParentCid().equals(root.getCatId()) ).map((item) -> { item.setChildren(getChildren(item, list)); return item; }).sorted((t1,t2)->{ return (t1.getSort()==null?0:t1.getSort())-(t2.getSort()==null?0:t2.getSort()); }).collect(Collectors.toList()); return children; }
|
配置网关
先将后台管理的请求转发到网关
修改renren-fast-vue中static\config\index.js中的代码如下:
1
| window.SITE_CONFIG['baseUrl'] = 'http://localhost:88/api';
|
配置gateway的application.yml
拦截所有/api/**
的请求,并进行路径重写,重写为/renren-fast/**
参考文档:Spring Cloud Gateway
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| spring: cloud: gateway: routes: - id: test_route uri: https://www.baidu.com predicates: - Query=url, baidu
- id: admin_route uri: lb://renren-fast predicates: - Path=/api/** filters: - RewritePath=/api/(?<segment>/?.*), /renren-fast/$\{segment}
|
成功显示验证码

配置跨域

在gateway网关中配置跨域,添加config文件夹
Spring Cloud Gateway 解决跨域问题_springcloudgateway跨域配置-CSDN博客
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration public class CorsConfig { @Bean public CorsWebFilter corsWebFilter(){ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedOriginPattern("*"); corsConfiguration.setAllowCredentials(true); source.registerCorsConfiguration("/**",corsConfiguration); return new CorsWebFilter(source); } }
|
菜单增删改查
配置网关路由,注意顺序,更具体的路由必须在前,否则会被/api/**
拦截
1 2 3 4 5 6 7 8 9 10 11 12 13
| - id: product_route uri: lb://gulimall-product predicates: - Path=/api/product/** filters: - RewritePath=/api/(?<segment>/?.*), /$\{segment}
- id: admin_route uri: lb://renren-fast predicates: - Path=/api/** filters: - RewritePath=/api/(?<segment>/?.*), /renren-fast/$\{segment}
|
在gulimall-product中开启服务发现
1 2 3 4 5 6 7
| cloud: nacos: discovery: server-addr: 127.0.0.1:8848 application: name: gulimall-product
|
删除
开启逻辑删除,配置Mybatis-plus
1 2 3 4 5 6 7
| mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml global-config: db-config: id-type: auto logic-delete-value: 1 logic-not-delete-value: 0
|
如果逻辑删除字段的值需要和上述全局配置不同,可以在实体类上通过注解实现
1 2 3 4
|
@TableLogic(value = "1",delval = "0") private Integer showStatus;
|
问题
P16安装SASS
先找和本地node版本对应的node-sass的版本
修改前端package.json中node-sass版本至对应的版本
本人node为14.17.1,node-sass为4.14.1
单独安装node-sass
1
| npm i node-sass@4.14.1 --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
|
若执行成功
若失败,先清除node-sass缓存,再查找其他原因,可以降低node版本
1 2
| npm rebuild node-sass npm uninstall node-sass
|
P46验证码加载不出
首先renren-fast不要引入common依赖,而是根据renren-fast的springboot版本单独引入对应的spring-cloud-alibaba
并进行依赖管理。然后引入spring-cloud-starter-alibaba-nacos-discovery
和spring-cloud-loadbalancer
(实际发现不引入也行?)
版本说明 · alibaba/spring-cloud-alibaba Wiki (github.com)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <exclusions> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
SKU和SPU概念
SPU:标准化产品单元(Standard Product Unit),是商品信息聚合的最小单位,是一组可复用标准化信息的集合,主要也是为了在交易端对一组同类型商品做页面的聚合展示,解决的是一品多型号多规格等等多属性的问题;
例如:iPhone X 可以确定一个产品即为一个SPU。
SKU:最小的库存单位(StockKeeping Unit),sku
是库存存贮的最小单位,商品的进货、销售、售价、库存等最终都是打在sku
身上的,最终的交易都决定在一个sku
个体上;
例如:iPhone X 64G 银色 则是一个SKU。
可以理解为类和对象的关系,SPU是类/模板,SKU是对象/实例,有多种属性。一个SPU对应多个SKU。