商品系统接口

商城的核心自然是商品,而商品多了以后,肯定要进行分类,并且不同的商品会有不同的品牌信息,我们需要依次去完成:品牌、商品分类、商品的开发。

品牌在系统搭建后,增删改查甚至文件上传都可以正常使用。

接下来完善商品分类及商品功能的增删改查功能。

参考课前资料中的《后台管理系统接口文档.md》

   程序源码论坛-1024,网址 www.cx1314.cn  仅分享最流行最优质的IT资源!	

   不同于其他论坛平台,这里只有精品、稀有资源,已泛滥、已过时、垃圾资源不录入!

   Java,前端,python,人工智能,大数据,云计算...持续更新资源-最新完整且均不加密、、、

活动线报,宅男福利,最新大片…

   程序员的新大陆-更新最快的IT资源社区!开发者必备平台!

   欢迎访问:www.cx1314.cn      百度搜索->  程序源码论坛

1. 商品分类

数据结构:

1
2
3
4
5
6
7
8
9
10
CREATE TABLE `pms_category` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
`name` char(50) DEFAULT NULL COMMENT '分类名称',
`parent_id` bigint(20) DEFAULT NULL COMMENT '父分类id',
`status` tinyint(4) DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`icon` char(255) DEFAULT NULL COMMENT '图标地址',
`unit` char(50) DEFAULT NULL COMMENT '计量单位',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1433 DEFAULT CHARSET=utf8mb4 COMMENT='商品三级分类';

因为商品分类会有层级关系,因此这里我们加入了parent_id字段,对本表中的其它分类进行自关联。

1584591973794

查看控制台,浏览器会发出如下请求

1584592964081

参照接口文档,开发接口

1.1. CategoryController

请求地址:parent/{parentId},因为/pms/category已经配置在CategoryController上

请求方式:GET

请求参数:parentId

响应:ResponseVO<List<CategoryEntity>>

给CategoryController添加一个查询方法:

1
2
3
4
5
6
@ApiOperation("根据父id查询分类")
@GetMapping("parent/{parentId}")
public ResponseVo<List<CategoryEntity>> queryCategory(@PathVariable("parentId")Long parentId){
List<CategoryEntity> categoryEntityList = this.categoryService.queryCategory(parentId);
return ResponseVo.ok(categoryEntityList);
}

1.2. CategoryService

在CategoryService接口中添加接口方法

1
List<CategoryEntity> queryCategory(Long parentId);

在CategoryServiceImpl实现类中实现该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
private CategoryMapper categoryMapper;

@Override
public List<CategoryEntity> queryCategory(Long parentId) {
// 构造查询条件
QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
// 如果parentId为-1,说明用户没有传该字段,查询所有
if (parentId != -1){
wrapper.eq("parent_id", parentId);
}

return this.categoryMapper.selectList(wrapper);
}

1.3. 重启测试

1567475835910

1.4. 根据父节点查询

新增商品时,先根据parentId=0查询一级节点,选择一级分类后,需要根据父节点查询子节点。

1567476312461

2. 商品信息

2.1. SPU和SKU设计

SPU:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集

SKU:Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品

以图为例来看:

1526085541996

  • 本页的 华为Mate10 就是一个商品集(SPU)
  • 因为颜色、内存等不同,而细分出不同的Mate10,如亮黑色128G版。(SKU)

可以看出:

  • SPU是一个抽象的商品集概念,为了方便后台的管理。
  • SKU才是具体要销售的商品,每一个SKU的价格、库存可能会不一样,用户购买的是SKU而不是SPU

表结构设计:

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
-- spu表 --
CREATE TABLE `pms_spu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品id',
`name` varchar(200) DEFAULT NULL COMMENT '商品名称',
`category_id` bigint(20) DEFAULT NULL COMMENT '所属分类id',
`brand_id` bigint(20) DEFAULT NULL COMMENT '品牌id',
`publish_status` tinyint(4) DEFAULT NULL COMMENT '上架状态[0 - 下架,1 - 上架]',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='spu信息';

-- 商品描述表 --
CREATE TABLE `pms_spu_desc` (
`spu_id` bigint(20) NOT NULL COMMENT '商品id',
`decript` longtext COMMENT '商品介绍',
PRIMARY KEY (`spu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='spu信息介绍';

-- sku表 --
CREATE TABLE `pms_sku` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'skuId',
`spu_id` bigint(20) DEFAULT NULL COMMENT 'spuId',
`name` varchar(255) DEFAULT NULL COMMENT 'sku名称',
`category_id` bigint(20) DEFAULT NULL COMMENT '所属分类id',
`brand_id` bigint(20) DEFAULT NULL COMMENT '品牌id',
`default_image` varchar(255) DEFAULT NULL COMMENT '默认图片',
`title` varchar(255) DEFAULT NULL COMMENT '标题',
`subtitle` varchar(2000) DEFAULT NULL COMMENT '副标题',
`price` decimal(18,4) DEFAULT NULL COMMENT '价格',
`weight` int(20) DEFAULT NULL COMMENT '重量(克)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku信息';

-- sku图片表 --
CREATE TABLE `pms_sku_images` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`sku_id` bigint(20) DEFAULT NULL COMMENT 'sku_id',
`url` varchar(255) DEFAULT NULL COMMENT '图片地址',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`default_status` int(11) DEFAULT NULL COMMENT '默认图[0 - 不是默认图,1 - 是默认图]',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku图片';

2.2. 规格参数设计

1567485141477

商品规格参数有以下特点:

  • 规格参数都有分组
  • 同一类SPU(三级分类,如手机)的规格参数是统一的。例如:iphone X,galaxy S10等。
  • 同一spu,有些规格参数是不变的,如:摄像头像素、摄像头数量等;而有些规格参数的,会随着你选择的sku发生变化,如:内存、机身颜色、存储等。
  • 有些规格参数需要作为sku选项(销售属性),例如:机身颜色、存储、版本等
  • 有些规格参数需要参与检索(检索属性),例如:屏幕尺寸、分辨率、操作系统等
  • 有些规格参数需要快速展示在商品介绍的上方

综上,表设计如下:

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
-- 规格参数分组(属性分组)
CREATE TABLE `pms_attr_group` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分组id',
`name` char(20) DEFAULT NULL COMMENT '组名',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`icon` varchar(255) DEFAULT NULL COMMENT '组图标',
`category_id` bigint(20) DEFAULT NULL COMMENT '所属分类id',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='属性分组';

-- 规格参数表
CREATE TABLE `pms_attr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '属性id',
`name` char(30) DEFAULT NULL COMMENT '属性名',
`search_type` tinyint(4) DEFAULT NULL COMMENT '是否需要检索[0-不需要,1-需要]',
`icon` varchar(255) DEFAULT NULL COMMENT '属性图标',
`value_select` char(255) DEFAULT NULL COMMENT '可选值列表[用逗号分隔]',
`type` tinyint(4) DEFAULT NULL COMMENT '属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]',
`enable` bigint(20) DEFAULT NULL COMMENT '启用状态[0 - 禁用,1 - 启用]',
`show_desc` tinyint(4) DEFAULT NULL COMMENT '快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整',
`category_id` bigint(20) DEFAULT NULL COMMENT '所属分类',
`group_id` bigint(20) DEFAULT NULL COMMENT '规格分组id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品属性';

-- 通用规格参数值表
CREATE TABLE `pms_spu_attr_value` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`spu_id` bigint(20) DEFAULT NULL COMMENT '商品id',
`attr_id` bigint(20) DEFAULT NULL COMMENT '属性id',
`attr_name` varchar(200) DEFAULT NULL COMMENT '属性名',
`attr_value` varchar(200) DEFAULT NULL COMMENT '属性值',
`sort` int(11) DEFAULT NULL COMMENT '顺序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='spu属性值';

-- 销售规格参数值表
CREATE TABLE `pms_sku_attr_value` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`sku_id` bigint(20) DEFAULT NULL COMMENT 'sku_id',
`attr_id` bigint(20) DEFAULT NULL COMMENT 'attr_id',
`attr_name` varchar(200) DEFAULT NULL COMMENT '销售属性名',
`attr_value` varchar(200) DEFAULT NULL COMMENT '销售属性值',
`sort` int(11) DEFAULT NULL COMMENT '顺序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku销售属性&值';

2.3. 规格属性查询

1584621122426

2.3.1. 查询规格分组

查看控制台,对应的发送了3个请求:

1584621550824

其中有一个是查询分组。结合接口文档:

请求地址:category/{cid},Controller上已经标记了/pms/attrgroup

请求方式:GET

请求参数:一些基本分页条件已经封装到PageParamVo,然后有一个占位符参数(商品分类:225)

正确响应:ResponseVo<PageResultVO>

AttrGroupController中添加Controller方法:

1
2
3
4
5
6
7
@ApiOperation("根据三级分类id查询")
@GetMapping("category/{cid}")
public ResponseVo<List<AttrGroupEntity>> queryByCidPage(@PathVariable("cid")Long cid){

List<AttrGroupEntity> groupEntities = this.attrGroupService.list(new QueryWrapper<AttrGroupEntity>().eq("category_id", cid));
return ResponseVo.ok(groupEntities);
}

测试效果:

1584621584538

2.3.2. 查询分组下的规格参数

点击属性分组下的维护关联关系,可以查看该分组下的所有属性,并可以添加、删除关联关系。

1584669844142

参考接口文档:

请求地址:group/{gid},已经在AttrController上配置/pms/attr

请求方式:GET

请求参数:gid

正确响应:Response<List>

AttrController添加方法:

1
2
3
4
5
6
@GetMapping("group/{gid}")
@ApiOperation("分页查询")
public ResponseVo<List<AttrEntity>> queryAttrsByGid(@PathVariable("gid")Long gid){
List<AttrEntity> attrEntities = this.attrService.list(new QueryWrapper<AttrEntity>().eq("group_id", gid));
return ResponseVo.ok(attrEntities);
}

测试:

1584670473377

2.4. 商品查询

2.4.1. 查询商品列表

1567513319657

查看控制台:

1584674738425

结合接口文档

请求地址:category/{categoryId},SpuInfoController类上的路径是/pms/spuinfo

请求方式:GET

请求参数:PageParamVo+ categoryId

正确响应:ResponseVo

SpuInfoController添加方法:

1
2
3
4
5
6
7
@ApiOperation("spu商品信息查询")
@GetMapping("category/{categoryId}")
public ResponseVo<PageResultVo> querySpuInfo(PageParamVo pageParamVo, @PathVariable("categoryId")Long categoryId){

PageResultVo pageResultVo = this.spuService.querySpuInfo(pageParamVo, categoryId);
return ResponseVo.ok(pageResultVo);
}

SpuInfoService接口方法:

1
PageResultVo querySpuInfo(PageParamVo pageParamVo, Long categoryId);

SpuInfoServiceImpl实现类实现该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public PageResultVo querySpuInfo(PageParamVo pageParamVo, Long categoryId) {

// 封装查询条件
QueryWrapper<SpuEntity> wrapper = new QueryWrapper<>();
// 如果分类id不为0,要根据分类id查,否则查全部
if (categoryId != 0){
wrapper.eq("category_id", categoryId);
}
// 如果用户输入了检索条件,根据检索条件查
String key = pageParamVo.getKey();
if (StringUtils.isNotBlank(key)){
wrapper.and(t -> t.like("name", key).or().like("id", key));
}

return new PageResultVo(this.page(pageParamVo.getPage(), wrapper));
}

测试:

1567520074569

2.4.2. 查询SPU下的SKU

找到库存管理下的商品库存

1567521129311

点击一个商品的库存维护

1584771702197

结合接口文档:

请求地址:spu/{spuId}

请求方式:GET

请求参数:spuId

正确响应:Resp<List<SkuEntity>>

给SkuInfoController添加方法:

1
2
3
4
5
6
7
8
9
10
/**
* 根据spuId查询sku列表
*/
@GetMapping("spu/{spuId}")
@ApiOperation("根据spuId查询sku列表")
public ResponseVo<List<SkuEntity>> list(@PathVariable("spuId")Long spuId){
List<SkuEntity> skuEntities = skuService.list(new QueryWrapper<SkuEntity>().eq("spu_id", spuId));

return ResponseVo.ok(skuEntities);
}

测试:

1567521804729

2.4.3. 查询SKU的库存信息

sku列表中的库存维护

1567523065617

1584775206306

参照接口文档:

请求地址:/sku/{skuId} 在gmall-wms系统的WareSkuController中已经配置了/wms/waresku/

请求方式:GET

请求参数:skuId

正确响应:ResponseVo<List<WareSkuEntity>>

WareSkuController添加方法:

1
2
3
4
5
6
7
@ApiOperation("根据skuId查询库存信息")
@GetMapping("sku/{skuId}")
public ResponseVo<List<WareSkuEntity>> queryWareSkuBySkuId(@PathVariable("skuId")Long skuId){

List<WareSkuEntity> wareSkuEntities = this.wareSkuService.list(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId));
return ResponseVo.ok(wareSkuEntities);
}

测试:

1584779661541

2.5. 商品新增

1567560984539

点击添加spu按钮,跳转到新增spu页面

1567561565352

填写完表单,点击下一步

1584697495113

进入录入spu属性信息,但是没有显示spu属性(即规格参数)。

2.5.1. 查询分类下的分组及其规格参数

当添加商品时,应该根据用户选择的商品分类,显示不同规格参数名,让用户填写对应的参数值。上图控制台发送的这个请求,就是根据分类id查询分组及组下的属性,并动态生成一个表单,让用户填写参数值

参照接口文档:

请求地址:/withattrs/{catId}

请求方式:GET

请求参数:catId

正确响应:ResponseVo<List<?>>

这里的响应数据比AttrGroupEntity多出来一个字段,就是组下的属性列表attrEntities。所以要给AttrGroupEntity扩展一个字段,有两种扩展方式:

  1. 直接在AttrGroupEntity中添加一个字段attrEntities
  2. 编写一个扩展类GroupVo继承AttrGroupEntity,然后扩展一个attrEntities

推荐使用第二种方式,因为AttrGroupEntity作为一个基础实体类和数据库操作密切相关,很多人都会用到。

GroupVo实体类:

1584698223491

AttrGroupController添加方法:

1
2
3
4
5
6
7
@ApiOperation("根据三级分类id查询分组及组下的规格参数")
@GetMapping("/withattrs/{catId}")
public ResponseVo<List<GroupVo>> queryByCid(@PathVariable("catId")Long cid){

List<GroupVo> groupVos = this.attrGroupService.queryByCid(cid);
return ResponseVo.ok(groupVos);
}

AttrGroupService的接口方法:

1
List<GroupVo> queryByCid(Long cid);

AttrGroupServiceImpl实现类实现接口方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public List<GroupVo> queryByCid(Long cid) {
// 查询所有的分组
List<AttrGroupEntity> attrGroupEntities = this.list(new QueryWrapper<AttrGroupEntity>().eq("category_id", cid));

// 查询出每组下的规格参数
return attrGroupEntities.stream().map(attrGroupEntity -> {
GroupVo groupVo = new GroupVo();
BeanUtils.copyProperties(attrGroupEntity, groupVo);
// 查询规格参数,只需查询出每个分组下的通用属性就可以了(不需要销售属性)
List<AttrEntity> attrEntities = this.attrMapper.selectList(new QueryWrapper<AttrEntity>().eq("group_id", attrGroupEntity.getId()).eq("type", 1));
groupVo.setAttrEntities(attrEntities);
return groupVo;
}).collect(Collectors.toList());
}

测试:

1584714398957

2.5.2. 查询分类下的销售属性

点击“下一步”进入第三步,页面没有数据。查看控制台发送了查询请求:

1584714509858

参照接口文档:

请求地址:category/{cid}?type=0&searchType=1

请求方式:GET

请求参数:cid, type, searchType

正确响应:ResponseVo<List<AttrEntity>>

AttrController:

1
2
3
4
5
6
7
8
@GetMapping("category/{cid}")
@ApiOperation("分类查询")
public ResponseVo<List<AttrEntity>> queryAttrsByCid(@PathVariable("cid")Long cid,
@RequestParam(value = "type", required = false)Integer type,
@RequestParam(value = "searchType", required = false) Integer searchType){
List<AttrEntity> attrEntities = this.attrService.queryAttrsByCid(cid, type, searchType);
return ResponseVo.ok(attrEntities);
}

AttrService:

1
List<AttrEntity> queryAttrsByCid(Long cid, Integer type, Integer searchType);

AttrServiceImpl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public List<AttrEntity> queryAttrsByCid(Long cid, Integer type, Integer searchType) {
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
// 分类id如果为0,查询所有分类的规格参数
if (cid != 0) {
queryWrapper.eq("category_id", cid);
}
// 如果参数类型不为空
if (type != null) {
queryWrapper.eq("type", type);
}
// 如果参数类型不为空
if (searchType != null) {
queryWrapper.eq("search_type", searchType);
}
return this.list(queryWrapper);
}

2.5.3. 为页面提交的数据构建数据模型

1584718209086

每个sku都可以再次展开,sku基本信息,优惠信息,以及图片上传

1567576282861

最后点击确定,显示保存成功!?查看数据库你会发现它只保存了spu的基本信息。

查看控制台,可以看到:

1584718286014

提交的数据非常复杂,如下:

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{
"name": "华为mate30pro",
"brandId": 2,
"categoryId": 225,
"publishStatus": 1,
"spuImages": ["https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/2e3c0156-a8a5-4ae2-8e5d-e3061069fa95_eda8c4c43653595f (1).jpg", "https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/41af1ab5-6625-4ef3-8991-ddece4933fe8_eda8c4c43653595f (1).jpg"],
"baseAttrs": [{
"id": 1,
"name": "上市年份",
"valueSelected": ["2019"]
}, {
"id": 2,
"name": "产品名称",
"valueSelected": ["HUAWEI Mate 30"]
}, {
"id": 6,
"name": "CPU品牌",
"valueSelected": ["麒麟"]
}, {
"id": 7,
"name": "CPU型号",
"valueSelected": ["麒麟990 5G"]
}, {
"id": 8,
"name": "分辨率",
"valueSelected": ["FHD+ 2340×1080 像素"]
}, {
"id": 9,
"name": "屏幕尺寸",
"valueSelected": ["7"]
}],
"skus": [{
"attr_3": "黑色",
"price": "5000",
"stock": 0,
"growBounds": "2000",
"buyBounds": "1000",
"work": [1, 0, 1, 0],
"fullCount": "2",
"discount": "90",
"fullPrice": "5000",
"reducePrice": "500",
"fullAddOther": 1,
"images": ["https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/d877660d-93a3-4d9a-8c8d-ce5f5e5e1904_eda8c4c43653595f (1).jpg", "https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/01f785b4-b984-4246-8724-5a1d2c423fd0_e9ad9735fc3f0686.jpg"],
"name": "华为mate30pro 黑色,8G,256G",
"title": "华为 HUAWEI Mate 30 5G 麒麟990 4000万超感光徕卡影像双超级快充8GB+256GB亮黑色5G全网通游戏手机",
"subTitle": "华为mate30pro 黑色,8G,256G",
"weight": "500",
"attr_4": "8G",
"attr_5": "256G",
"ladderAddOther": 1,
"subtitle": "【直降500元!到手价4999元!享12期免息!低至13.7元/天】双4000万徕卡电影四摄;Mate30直降500元享12期》",
"saleAttrs": [{
"attrId": "3",
"attrValue": "黑色"
}, {
"attrId": "4",
"attrValue": "8G"
}, {
"attrId": "5",
"attrValue": "256G"
}]
}, {
"attr_3": "黑色",
"price": "6000",
"stock": 0,
"growBounds": "1000",
"buyBounds": "1000",
"work": [1, 0, 1, 0],
"fullCount": "3",
"discount": "80",
"fullPrice": "6000",
"reducePrice": "2000",
"fullAddOther": 1,
"images": ["https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/7cf5c7d2-f9a2-4767-8e90-d41b67a5ffd2_e9ad9735fc3f0686.jpg", "https://ggmall.oss-cn-shanghai.aliyuncs.com/2020-03-20/8e7189ce-5043-4d4c-8a8b-e3728360e451_802254cca298ae79 (1).jpg"],
"name": "华为mate30pro 黑色,8G,512G",
"title": "华为 HUAWEI Mate 30 5G 麒麟990 4000万超感光徕卡影像双超级快充8GB+128GB亮黑色5G全网通游戏手机",
"subTitle": "华为mate30pro 黑色,8G,512G",
"weight": "510",
"attr_4": "8G",
"attr_5": "512G",
"ladderAddOther": 1,
"subtitle": "【直降500元!到手价4499元!享12期免息!低至12.3元/天】双4000万徕卡电影四摄;Mate30直降500元享12期》",
"saleAttrs": [{
"attrId": "3",
"attrValue": "黑色"
}, {
"attrId": "4",
"attrValue": "8G"
}, {
"attrId": "5",
"attrValue": "512G"
}]
}]
}

由于提交的是json数据,所以只能通过一个对象来进行接收,这就需要咱们来构建一个VO对象。涉及的表肯定也不只spu一张表。

这么复杂的数据结构,我们一层层的剥茧抽丝式的查看:

2.5.2.1. 先看json数据的最外层

对应pms_spu表的信息,还多了三个字段:spuImages、baseAttrs、skus。也就是说需要对SpuInfoEntity进行扩展。首选可以确定这三个字段是集合,因为值都有方括号。

1584718471261

创建SpuVO对象:

1584718569421

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* spuInfo扩展对象
* 包含:spuInfo基本信息、spuImages图片信息、baseAttrs基本属性信息、skus信息
*/
@Data
public class SpuVO extends SpuInfoEntity {

// 图片信息
private List<?> spuImages;

// 基本属性信息
private List<?> baseAttrs;

// sku信息
private List<?> skus;
}

接下来就分析这三个集合中,都是什么数据类型的数据。

2.5.2.2. spuImages

首先spuImages很简单,就是字符串数组:

1567582227035

也就是说,SpuInfoVO对象是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* spu扩展对象
* 包含:spu基本信息、spuImages图片信息、baseAttrs基本属性信息、skus信息
*/
@Data
public class SpuVO extends SpuInfoEntity {

// 图片信息
private List<String> spuImages;

// 基本属性信息
private List<?> baseAttrs;

// sku信息
private List<?> skus;
}

2.5.2.3. baseAttrs

对应的表是pms_spu_attr_value,对应的实体类是SpuAttrValueEntity

1567582744402

注意:attrValue的值在实体类中是String,而传过来时参数名是valueSelected,值为集合类型。

所以,必须扩展SpuAttrValueEntity类:

1567584097320

重写setter方法,因为参数接收时的本质是调用setter方法接收的:

1
2
3
4
5
6
7
8
9
10
public class SpuAttrValueVo extends SpuAttrValueEntity {

public void setValueSelected(List<Object> valueSelected){
// 如果接受的集合为空,则不设置
if (CollectionUtils.isEmpty(valueSelected)){
return;
}
this.setAttrValue(StringUtils.join(valueSelected, ","));
}
}

现在SpuInfoVO中的第二参数的集合泛型也搞定了:

1
2
3
4
5
6
7
8
9
10
11
12
@Data
public class SpuVo extends SpuEntity {

// 图片信息
private List<String> spuImages;

// 基本属性信息
private List<SpuAttrValueVo> baseAttrs;

// sku信息
private List<?> skus;
}

2.5.2.4. skus

一部分字段对应的是pms_sku这张表,对应的实体类是SkuEntity。

1584719056119

images这个字段保存到pms_sku_images这张表。

一部分字段对应的是sms_sku_bounds表,对应的实体类是gmall-sms服务中的SkuBoundsEntity

1567585469132

一部分字段对应的表是sms_sku_full_reduction,对应的实体类是gmall-sms微服务中的SkuFullReductionEntity

1567585679204

一部分字段对应的表是sms_sku_ladder,对应的实体类是gmall-sms微服务的SkuLadderEntity

1567586094915

最后一个字段就是saleAttrs,对应的是pms_sku_attr_value,实体类是List<SkuAttrValueEntity>

1567586459917

由于java是单继承,所以这里只能选择一个继承,其他的字段在从对应的实体类中copy过来。这里选择扩展SkuEntity这个实体类:(注意:带下划线的字段为垃圾字段,不用接收)

1584719555226

内容如下:

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
@Data
public class SkuVo extends SkuEntity {
private List<String> images;

// 积分活动
private BigDecimal growBounds;
private BigDecimal buyBounds;
/**
* 优惠生效情况[1111(四个状态位,从右到左);
* 0 - 无优惠,成长积分是否赠送;
* 1 - 无优惠,购物积分是否赠送;
* 2 - 有优惠,成长积分是否赠送;
* 3 - 有优惠,购物积分是否赠送【状态位0:不赠送,1:赠送】]
*/
private List<Integer> work;

// 满减活动
private BigDecimal fullPrice;
private BigDecimal reducePrice;
private Integer fullAddOther;

private Integer fullCount;
private BigDecimal discount;
/**
* 是否叠加其他优惠[0-不可叠加,1-可叠加]
*/
private Integer addOther;

private List<SkuAttrValueEntity> saleAttrs;
}

最终的SpuVO:

1
2
3
4
5
6
7
8
9
10
11
12
@Data
public class SpuVo extends SpuEntity {

// 图片信息
private List<String> spuImages;

// 基本属性信息
private List<SpuAttrValueVo> baseAttrs;

// sku信息
private List<SkuVo> skus;
}

2.5.3. 完成SPU新增功能

SpuController:改造之前的新增方法

1
2
3
4
5
6
7
8
9
10
/**
* 保存
*/
@PostMapping
@ApiOperation("保存")
public ResponseVo<Object> save(@RequestBody SpuVo spuVo){
spuService.bigSave(spuVo);

return ResponseVo.ok();
}

SpuService接口添加方法:

1
void bigSave(SpuVo spu);

SpuServiceImpl实现类实现新增方法:

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
@Autowired
private SpuDescMapper descMapper;

@Autowired
private SpuAttrValueService baseService;

@Override
public void bigSave(SpuVo spuVo) {
/// 1.保存spu相关
// 1.1. 保存spu基本信息 spu_info
spuVo.setPublishStatus(1); // 默认是已上架
spuVo.setCreateTime(new Date());
spuVo.setUpdateTime(spuVo.getCreateTime()); // 新增时,更新时间和创建时间一致
this.save(spuVo);
Long spuId = spuVo.getId(); // 获取新增后的spuId

// 1.2. 保存spu的描述信息 spu_info_desc
SpuDescEntity spuInfoDescEntity = new SpuDescEntity();
// 注意:spu_info_desc表的主键是spu_id,需要在实体类中配置该主键不是自增主键
spuInfoDescEntity.setSpuId(spuId);
// 把商品的图片描述,保存到spu详情中,图片地址以逗号进行分割
spuInfoDescEntity.setDecript(StringUtils.join(spuVo.getSpuImages(), ","));
this.descMapper.insert(spuInfoDescEntity);

// 1.3. 保存spu的规格参数信息
List<SpuAttrValueVo> baseAttrs = spuVo.getBaseAttrs();
if (!CollectionUtils.isEmpty(baseAttrs)) {
List<SpuAttrValueEntity> spuAttrValueEntities = baseAttrs.stream().map(spuAttrValueVO -> {
spuAttrValueVO.setSpuId(spuId);
spuAttrValueVO.setSort(0);
return spuAttrValueVO;
}).collect(Collectors.toList());
this.baseService.saveBatch(spuAttrValueEntities);
}

/// 2. 保存sku相关信息
// 2.1. 保存sku基本信息

// 2.2. 保存sku图片信息

// 2.3. 保存sku的规格参数(销售属性)

// 3. 保存营销相关信息,需要远程调用gmall-sms
// 3.1. 积分优惠

// 3.2. 满减优惠

// 3.3. 数量折扣
}

注意:SpuDescEntity对象的主键需要设置为手动设置,无法手动设置。

1584722502507

测试效果:3张表的值均可正常插入

1584722548563

1584722595999

1584722625124

2.5.4. 完成SKU新增功能

继续完善SpuServiceImpl实现类新增方法:

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
@Autowired
private SpuDescMapper descMapper;

@Autowired
private SpuAttrValueService baseService;

@Autowired
private SkuMapper skuMapper;

@Autowired
private SkuImagesService skuImagesService;

@Autowired
private SkuAttrValueService skuAttrValueService;

@Override
public void bigSave(SpuVo spuVo) {
/// 1.保存spu相关
// 1.1. 保存spu基本信息 spu_info
spuVo.setPublishStatus(1); // 默认是已上架
spuVo.setCreateTime(new Date());
spuVo.setUpdateTime(spuVo.getCreateTime()); // 新增时,更新时间和创建时间一致
this.save(spuVo);
Long spuId = spuVo.getId(); // 获取新增后的spuId

// 1.2. 保存spu的描述信息 spu_info_desc
SpuDescEntity spuInfoDescEntity = new SpuDescEntity();
// 注意:spu_info_desc表的主键是spu_id,需要在实体类中配置该主键不是自增主键
spuInfoDescEntity.setSpuId(spuId);
// 把商品的图片描述,保存到spu详情中,图片地址以逗号进行分割
spuInfoDescEntity.setDecript(StringUtils.join(spuVo.getSpuImages(), ","));
this.descMapper.insert(spuInfoDescEntity);

// 1.3. 保存spu的规格参数信息
List<SpuAttrValueVo> baseAttrs = spuVo.getBaseAttrs();
if (!CollectionUtils.isEmpty(baseAttrs)) {
List<SpuAttrValueEntity> spuAttrValueEntities = baseAttrs.stream().map(spuAttrValueVO -> {
spuAttrValueVO.setSpuId(spuId);
spuAttrValueVO.setSort(0);
return spuAttrValueVO;
}).collect(Collectors.toList());
this.baseService.saveBatch(spuAttrValueEntities);
}

/// 2. 保存sku相关信息
List<SkuVo> skuVos = spuVo.getSkus();
if (CollectionUtils.isEmpty(skuVos)){
return;
}
skuVos.forEach(skuVo -> {
// 2.1. 保存sku基本信息
SkuEntity skuEntity = new SkuEntity();
BeanUtils.copyProperties(skuVo, skuEntity);
// 品牌和分类的id需要从spuInfo中获取
skuEntity.setBrandId(spuVo.getBrandId());
skuEntity.setCatagoryId(spuVo.getCategoryId());
// 获取图片列表
List<String> images = skuVo.getImages();
// 如果图片列表不为null,则设置默认图片
if (!CollectionUtils.isEmpty(images)){
// 设置第一张图片作为默认图片
skuEntity.setDefaultImage(skuEntity.getDefaultImage()==null ? images.get(0) : skuEntity.getDefaultImage());
}
skuEntity.setSpuId(spuId);
this.skuMapper.insert(skuEntity);
// 获取skuId
Long skuId = skuEntity.getId();

// 2.2. 保存sku图片信息
if (!CollectionUtils.isEmpty(images)){
String defaultImage = images.get(0);
List<SkuImagesEntity> skuImageses = images.stream().map(image -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setDefaultStatus(StringUtils.equals(defaultImage, image) ? 1 : 0);
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setSort(0);
skuImagesEntity.setUrl(image);
return skuImagesEntity;
}).collect(Collectors.toList());
this.skuImagesService.saveBatch(skuImageses);
}

// 2.3. 保存sku的规格参数(销售属性)
List<SkuAttrValueEntity> saleAttrs = skuVo.getSaleAttrs();
saleAttrs.forEach(saleAttr -> {
// 设置属性名,需要根据id查询AttrEntity
saleAttr.setSort(0);
saleAttr.setSkuId(skuId);
});
this.skuAttrValueService.saveBatch(saleAttrs);

// 3. 保存营销相关信息,需要远程调用gmall-sms
// 3.1. 积分优惠

// 3.2. 满减优惠

// 3.3. 数量折扣
});
}

测试:sku相关的3张表保存成功

1584723319043

1584723350642

1584723375965

2.5.5. sms提供营销保存接口

SkuVo中剩余没有保存的字段都是营销信息的字段,需要把这些数据传输给营销系统,接下来首先创建一个数据模型

在gmall-sms中添加VO对象

1584764077728

内容如下:营销信息 + skuId

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
@Data
public class SkuSaleVo {

private Long skuId;

// 积分活动
private BigDecimal growBounds;
private BigDecimal buyBounds;
/**
* 优惠生效情况[1111(四个状态位,从右到左);
* 0 - 无优惠,成长积分是否赠送;
* 1 - 无优惠,购物积分是否赠送;
* 2 - 有优惠,成长积分是否赠送;
* 3 - 有优惠,购物积分是否赠送【状态位0:不赠送,1:赠送】]
*/
private List<Integer> work;

// 满减活动
private BigDecimal fullPrice;
private BigDecimal reducePrice;
private Integer fullAddOther;

private Integer fullCount;
private BigDecimal discount;
/**
* 是否叠加其他优惠[0-不可叠加,1-可叠加]
*/
private Integer addOther;
}

在SkuBoundsController中添加方法:

1
2
3
4
5
6
7
@ApiOperation("新增sku的营销信息")
@PostMapping("/skusale/save")
public ResponseVo<Object> saveSkuSaleInfo(@RequestBody SkuSaleVo skuSaleVo){
this.skuBoundsService.saveSkuSaleInfo(skuSaleVo);

return ResponseVo.ok(null);
}

给SkuBoundsService接口添加方法:

1
void saveSkuSaleInfo(SkuSaleVo skuSaleVo);

给SkuBoundsServiceImpl实现类添加实现方法:

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
@Autowired
private SkuFullReductionMapper skuFullReductionMapper;

@Autowired
private SkuLadderMapper skuLadderMapper;

@Override
public void saveSkuSaleInfo(SkuSaleVo skuSaleVo) {
// 3.1. 积分优惠
SkuBoundsEntity skuBoundsEntity = new SkuBoundsEntity();
BeanUtils.copyProperties(skuSaleVo, skuBoundsEntity);
// 数据库保存的是整数0-15,页面绑定是0000-1111
List<Integer> work = skuSaleVo.getWork();
if (!CollectionUtils.isEmpty(work)){
skuBoundsEntity.setWork(work.get(0) * 8 + work.get(1) * 4 + work.get(2) * 2 + work.get(3));
}
this.save(skuBoundsEntity);

// 3.2. 满减优惠
SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
BeanUtils.copyProperties(skuSaleVo, skuFullReductionEntity);
skuFullReductionEntity.setAddOther(skuSaleVo.getFullAddOther());
this.skuFullReductionMapper.insert(skuFullReductionEntity);

// 3.3. 数量折扣
SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
BeanUtils.copyProperties(skuSaleVo, skuLadderEntity);
this.skuLadderMapper.insert(skuLadderEntity);
}

2.5.6. pms调用营销保存接口

feign的玩法分以下三步:

  1. 引入openfeign的启动器,已添加
  2. 在引导类上添加@EnableFeignClients
  3. 编写feign接口

在gmall-pms的引导类(GmallPmsApplication)上添加@EnableFeignClients注解

1584764490061

添加SkuSaleVo实体类和GmallSmsClient接口

1584766226032

SkuSaleVo的内容参照gmall-sms中的SkuSaleVo的内容

GmallSmsClient的内容:

1
2
3
4
5
6
@FeignClient("sms-service")
public interface GmallSmsClient {

@PostMapping("/sms/skubounds/skusale/save")
public ResponseVo<Object> saveSkuSaleInfo(@RequestBody SkuSaleVo skuSaleVo);
}

完成商品新增:

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
@Autowired
private SpuDescMapper descMapper;

@Autowired
private SpuAttrValueService baseService;

@Autowired
private SkuMapper skuMapper;

@Autowired
private SkuImagesService skuImagesService;

@Autowired
private SkuAttrValueService skuAttrValueService;

@Autowired
private GmallSmsClient smsClient;

@Override
public void bigSave(SpuVo spuVo) {
/// 1.保存spu相关
// 1.1. 保存spu基本信息 spu_info
Long spuId = saveSpu(spuVo);

// 1.2. 保存spu的描述信息 spu_info_desc
saveSpuDesc(spuVo, spuId);

// 1.3. 保存spu的规格参数信息
saveBaseAttr(spuVo, spuId);

/// 2. 保存sku相关信息
saveSku(spuVo, spuId);
}

private void saveSku(SpuVo spuVo, Long spuId) {
List<SkuVo> skuVos = spuVo.getSkus();
if (CollectionUtils.isEmpty(skuVos)){
return;
}
skuVos.forEach(skuVo -> {
// 2.1. 保存sku基本信息
SkuEntity skuEntity = new SkuEntity();
BeanUtils.copyProperties(skuVo, skuEntity);
// 品牌和分类的id需要从spuInfo中获取
skuEntity.setBrandId(spuVo.getBrandId());
skuEntity.setCatagoryId(spuVo.getCategoryId());
// 获取图片列表
List<String> images = skuVo.getImages();
// 如果图片列表不为null,则设置默认图片
if (!CollectionUtils.isEmpty(images)){
// 设置第一张图片作为默认图片
skuEntity.setDefaultImage(skuEntity.getDefaultImage()==null ? images.get(0) : skuEntity.getDefaultImage());
}
skuEntity.setSpuId(spuId);
this.skuMapper.insert(skuEntity);
// 获取skuId
Long skuId = skuEntity.getId();

// 2.2. 保存sku图片信息
if (!CollectionUtils.isEmpty(images)){
String defaultImage = images.get(0);
List<SkuImagesEntity> skuImageses = images.stream().map(image -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setDefaultStatus(StringUtils.equals(defaultImage, image) ? 1 : 0);
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setSort(0);
skuImagesEntity.setUrl(image);
return skuImagesEntity;
}).collect(Collectors.toList());
this.skuImagesService.saveBatch(skuImageses);
}

// 2.3. 保存sku的规格参数(销售属性)
List<SkuAttrValueEntity> saleAttrs = skuVo.getSaleAttrs();
saleAttrs.forEach(saleAttr -> {
// 设置属性名,需要根据id查询AttrEntity
saleAttr.setSort(0);
saleAttr.setSkuId(skuId);
});
this.skuAttrValueService.saveBatch(saleAttrs);

// 3. 保存营销相关信息,需要远程调用gmall-sms
SkuSaleVo skuSaleVo = new SkuSaleVo();
BeanUtils.copyProperties(skuVo, skuSaleVo);
skuSaleVo.setSkuId(skuId);
this.smsClient.saveSkuSaleInfo(skuSaleVo);
});
}

private void saveBaseAttr(SpuVo spuVo, Long spuId) {
List<SpuAttrValueVo> baseAttrs = spuVo.getBaseAttrs();
if (!CollectionUtils.isEmpty(baseAttrs)) {
List<SpuAttrValueEntity> spuAttrValueEntities = baseAttrs.stream().map(spuAttrValueVO -> {
spuAttrValueVO.setSpuId(spuId);
spuAttrValueVO.setSort(0);
return spuAttrValueVO;
}).collect(Collectors.toList());
this.baseService.saveBatch(spuAttrValueEntities);
}
}

private void saveSpuDesc(SpuVo spuVo, Long spuId) {
SpuDescEntity spuInfoDescEntity = new SpuDescEntity();
// 注意:spu_info_desc表的主键是spu_id,需要在实体类中配置该主键不是自增主键
spuInfoDescEntity.setSpuId(spuId);
// 把商品的图片描述,保存到spu详情中,图片地址以逗号进行分割
spuInfoDescEntity.setDecript(StringUtils.join(spuVo.getSpuImages(), ","));
this.descMapper.insert(spuInfoDescEntity);
}

private Long saveSpu(SpuVo spuVo) {
spuVo.setPublishStatus(1); // 默认是已上架
spuVo.setCreateTime(new Date());
spuVo.setUpdateTime(spuVo.getCreateTime()); // 新增时,更新时间和创建时间一致
this.save(spuVo);
return spuVo.getId();
}

3. feign的最佳实践

1584766480880

以上的这些代码直接从营销微服务中拷贝而来,完全一致。差别就是没有方法的具体实现。大家觉得这样有没有问题?

而FeignClient代码遵循SpringMVC的风格,因此与商品微服务的Controller完全一致。这样就存在一定的问题:

  • 代码冗余。尽管不用写实现,只是写接口,但服务调用方要写与服务controller一致的代码,有几个消费者就要写几次。另外DTO对象,在每个需要feign的工程里面都要维护一份。
  • 增加开发成本。调用方还得清楚知道接口的路径,才能编写正确的FeignClient。

解决方案:

  • 我们的服务提供方不仅提供实体类,还要提供api接口声明
  • 调用方不用自己编写接口方法声明,直接继承提供方给的Api接口即可

第一步:服务的提供方在gmall-sms-interface中提供API接口,并编写接口声明:

第二步:在调用方gmall-pms中编写FeignClient,但不要写方法声明了,直接继承gmall-sms-interface提供的api接口:

3.1. 服务提供方添加接口工程

服务提供方需要创建接口工程:

1567616497727

1567616540202

1567616575235

工程结构如下:

1584766903411

pom.xml中的内容:

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
<?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>gmall</artifactId>
<groupId>com.atguigu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>gmall-sms-interface</artifactId>

<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
</dependencies>

</project>

SkuSaleVo的内容跟之前没有变化,只是移动到接口工程了

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
@Data
public class SkuSaleVO {
private Long skuId;

// 积分活动
private BigDecimal growBounds;
private BigDecimal buyBounds;
/**
* 优惠生效情况[1111(四个状态位,从右到左);
* 0 - 无优惠,成长积分是否赠送;
* 1 - 无优惠,购物积分是否赠送;
* 2 - 有优惠,成长积分是否赠送;
* 3 - 有优惠,购物积分是否赠送【状态位0:不赠送,1:赠送】]
*/
private List<Integer> work;

// 满减活动
private BigDecimal fullPrice;
private BigDecimal reducePrice;
private Integer fullAddOther;

private Integer fullCount;
private BigDecimal discount;
/**
* 是否叠加其他优惠[0-不可叠加,1-可叠加]
*/
private Integer addOther;
}

SkuSaleApi接口:

1
2
3
4
5
public interface GmallSmsApi {

@PostMapping("/sms/skubounds/skusale/save")
public Resp<Object> saveSkuSaleInfo(@RequestBody SkuSaleVO skuSaleVO);
}

3.2. 服务提供方微服务

只要引入接口工程,重新到一下包即可

1
2
3
4
5
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-sms-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

之前微服务中定义的Vo可以删掉了:

1567617868566

3.3. 服务消费方

1584767441863

也需要依赖营销的接口工程即可:

1
2
3
4
5
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-sms-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

也不需要自己定义Vo了,另外GmallSmsClient内容变的及其简单:

1
2
3
4
@FeignClient("sms-service")
public interface GmallSmsClient extends GmallSmsApi {

}

3.4. 小结

1567618674250