商品微服务--后半部分:
注: 由于商品微服务内容太多,所以做了优化,拆分成两部分写。地址:商品微服务–前半部分
4.6 商品规格数据结构与商品表结构分析
内容偏多,重新写了一篇商品规格数据结构与商品表结构分析
4.7 实现商品规格参数管理
4.7.1 规格组查询
4.7.1.1 SpecGroup数据表
由于在商品规格数据结构与商品表结构分析中SpecGroup数据表已给出,这里就不再附一遍了。
4.7.1.2 SpecGroup实体类
@Data
@Table(name = "tb_spec_group")
public class SpecGroup {
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
private Long cid;
private String name;
@Transient //数据库表中没有params这一字段,因此要加上@Transient注解
private List<SpecParam> params;
}
- @Transient注解
-
serialization
会忽略掉
Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。
为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient -
不跟数据库表做映射 就是表中没有这个字段
@Transient
表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.
-
4.7.1.3 业务
4.7.1.3.1 web
4.7.1.3.1.1 页面分析
- 请求方式:get
- 请求路径:/spec/groups/cid
- 请求参数:cid
- 返回结果:group集合
4.7.1.3.1.2 实现业务
@RestController
@RequestMapping("spec")
public class SpecificationController {
@Autowired
private SpecificationService specificationService;
// 根据分类id查询规格组
@GetMapping("groups/{cid}")
public ResponseEntity<List<SpecGroup>> queryGroupByCid(@PathVariable("cid")Long cid){
return ResponseEntity.ok(specificationService.queryGroupByCid(cid));
}
4.7.1.3.2 service
@Service
public class SpecificationService {
@Autowired
private SpecGroupMapper groupMapper;
@Autowired
private SpecParamMapper paramMapper;
// 根据分类id查询规格组
public List<SpecGroup> queryGroupByCid(Long cid) {
SpecGroup group = new SpecGroup();
group.setCid(cid);
//根据非空字段进行查询
List<SpecGroup> list = groupMapper.select(group);
if(CollectionUtils.isEmpty(list)){
throw new LyException(ExceptionEnum.SPEC_GROUP_NOT_FOUND);
}
return list;
}
}
4.7.1.3.3 mapper
public interface SpecGroupMapper extends Mapper<SpecGroup> {
}
4.7.2 规格参数查询
当我们点击规格组,切换到规格参数显示
4.7.2.1 SpecParam数据表
表结构见商品规格数据结构与商品表结构分析
4.7.2.2 SpecParam实体类
@Data
@Table(name = "tb_spec_param")
public class SpecParam {
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
private Long cid;
private Long groupId;
private String name;
//通用mapper生成sql语句时,不要直接拼接numeric,而要拼接`numeric`,反引号是转义为字符串,numeric是一个关键字
@Column(name = "`numeric`")
private Boolean numeric;
private String unit;
private Boolean generic;
private Boolean searching;
private String segments;
}
4.7.2.3 业务
4.7.2.3.1 web
4.7.2.3.1.1 页面分析
- 请求方式:get
- 请求路径:/spec/params
- 请求参数:gid,分组id
- 返回结果:当前组下的所有规格参数
4.7.2.3.1.2 实现业务
// 根据组id查询规格参数
@GetMapping("/params")
public ResponseEntity<List<SpecParam>> querySpecParams(@RequestParam("gid")Long gid){
return ResponseEntity.ok(specificationService.querySpecParams(gid));
}
4.7.2.3.1 service
// 根据组id查询规格参数
public List<SpecParam> querySpecParams(Long gid) {
SpecParam param = new SpecParam();
param.setGroupId(gid);
List<SpecParam> params = paramMapper.select(param);
if(CollectionUtils.isEmpty(params)){
throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOUND);
}
return params;
}
4.7.2.3.1 mapper
public interface SpecParamMapper extends Mapper<SpecParam> {
}
4.8 商品查询
4.8.1 spu与spuDetail数据表
表结构见商品规格数据结构与商品表结构分析
4.8.1 spu与spuDetail实体类
@Data
@Table(name = "tb_spu")
public class Spu {
@Id
@KeySql(useGeneratedKeys=true)
private Long id;
private Long brandId;
private Long cid1;// 1级类目
private Long cid2;// 2级类目
private Long cid3;// 3级类目
private String title;// 标题
private String subTitle;// 子标题
private Boolean saleable;// 是否上架
@JsonIgnore //在json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。
private Boolean valid;// 是否有效,逻辑删除用
private Date createTime;// 创建时间
@JsonIgnore
private Date lastUpdateTime;// 最后修改时间
@Transient
private String cname;
@Transient
private String bname;
@Transient
private List<Sku> skus;
@Transient
private SpuDetail spuDetail;
}
注:
- po:persisent object,持久对象;它的字段必须和数据库字段完全一致
- 由于数据库里没有商品分类和品牌的name字段,应该写成专门的vo对象(专门返回页面上的)
- 查出来的是spu po,应该转成vo。但将来从页面接收到vo转成spu po才能往数据库传,可能会有各种对象转换的错误
- 为了方便,我们把 商品分类和品牌的name字段 等字段添加到spu里去,由于这些字段数据库中没有,因此都应逐个添加
@Transient
注解(javax.persistence包下的) - 不想返回到界面的字段 可以加一个
@JsonIgnore
注解
@Data
@Table(name="tb_spu_detail")
public class SpuDetail {
@Id // id没有加上自增主键,因为这张表id不是自增的,而是和spu表的id关联的
private Long spuId;// 对应的SPU的id
private String description;// 商品描述
private String genericSpec;// 商品特殊规格的名称及可选值模板
private String specialSpec;// 商品的全局规格属性
private String packingList;// 包装清单
private String afterService;// 售后服务
}
4.8.1 业务
4.8.3.1 web
4.8.3.1.1 页面分析
效果预览:
注:这的id为spu_id,标题为spu的title字段。
多个sku有大量的共享数据,因此商品管理的单位应该为spu。
- 请求方式:GET
- 请求路径:/spu/page
- 请求参数:
- page:当前页
- rows:每页大小
- key:过滤条件
- saleable:上架或下架
- 返回结果:商品SPU的分页信息。
4.8.3.1.1 实现业务
@RestController
public class GoodsController {
@Autowired
private GoodsService goodsService;
// 分页查询spu
@GetMapping("/spu/page")
public ResponseEntity<PageResult<Spu>> querySpuByPage(
@RequestParam(value = "page",defaultValue = "1")Integer page,
@RequestParam(value = "rows",defaultValue = "5")Integer rows,
@RequestParam(value = "saleable",required = false)Boolean saleable,
@RequestParam(value = "key",required = false)String key
){
return ResponseEntity.ok(goodsService.querySpuByPage(page,rows,saleable,key));
}
}
4.8.3.1 service
@Service
public class GoodsService {
@Autowired
private SpuMapper spuMapper;
@Autowired
private SpuDetailMapper spuDetailMapper;
// 分页查询spu
public PageResult<Spu> querySpuByPage(Integer page, Integer rows, Boolean saleable, String key) {
//分页
PageHelper.startPage(page,rows);
//过滤
Example example = new Example(Spu.class);
Example.Criteria criteria = example.createCriteria();
//搜索字段过滤
if(StringUtils.isNotBlank(key))
criteria.andLike("title","%"+key+"%");
//上下架过滤
if(saleable!=null)
criteria.andEqualTo("saleable",saleable);
//默认排序
example.setOrderByClause("last_update_time DESC");
//查询
List<Spu> spus = spuMapper.selectByExample(example);
if(CollectionUtils.isEmpty(spus))
throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
//解析分类和品牌名称
for (Spu spu : spus) {
//处理分类名称
List<String> names = categoryService.queryByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()))
.stream().map(Category::getName).collect(Collectors.toList());
spu.setCname(StringUtils.join(names,"/"));
//处理品牌名称
spu.setBname(brandService.queryById(spu.getBrandId()).getName());
}
//解析分页结果
PageInfo<Spu> pageInfo = new PageInfo<>(spus);
return new PageResult<>(pageInfo.getTotal(),spus);
}
}
注:
- 这里用到了
categoryService.queryByIds(cids)
, // 根据商品分类cid列表查询分类集合,因此应在categoryService写出该方法 - 用户同时输入根据 名称(title)过滤 和 上下架(saleable)过滤,因此采用
and
连接 - 由于spu数据库表中 商品和品牌存的是id,因此需要解析分类和品牌名称
@Service
public class CategoryService {
@Autowired
private CategoryMapper categoryMapper;
// 根据商品分类cid列表查询分类集合
public List<Category> queryByIds(List<Long> cids){
List<Category> idList = categoryMapper.selectByIdList(cids);
if(CollectionUtils.isEmpty(idList)){
throw new LyException(ExceptionEnum.CATEGORY_NOT_FOUND);
}
return idList;
}
}
public interface CategoryMapper extends Mapper<Category> , IdListMapper<Category,Long>{
}
注:
- 由于根据一堆id查询,因此需要在 CategoryMapper 中添加
IdListMapper
。
IdListMapper中继承了SelectByIdListMapper<T, PK>
和DeleteByIdListMapper<T, PK>
4.8.3.1 mapper
public interface SpuMapper extends Mapper<Spu>{
}
public interface SpuDetailMapper extends BaseMapper<SpuDetail> {
}
4.9 商品新增
4.9.1 基本数据
当我们点击新增商品按钮时:
会出现一个弹框:
里面把商品的数据分为了4部分来填写:
- 基本信息:主要是一些简单的文本数据,包含了SPU和SpuDetail的部分数据,如
- 商品分类:是SPU中的cid1,cid2,cid3属性
- 品牌:是spu中的brandId属性
- 标题:是spu中的title属性
- 子标题:是spu中的subTitle属性
- 售后服务:是SpuDetail中的afterService属性
- 包装列表:是SpuDetail中的packingList属性
- 商品描述:是SpuDetail中的description属性,数据较多,所以单独放一个页面
- 规格参数:商品规格信息,对应SpuDetail中的genericSpec属性
- SKU属性:spu下的所有Sku信息
4.9.1.2 根据商品分类id查询品牌
商品分类信息查询我们之前已经做过,品牌也是一个下拉选框,不过其选项是不确定的,只有当用户选择了商品分类,才会把这个分类下的所有品牌展示出来。
(页面编写了watch函数,监控商品分类的变化,每当商品分类值有变化,就会发起请求,查询品牌列表)
因此我们只要编写后台接口,根据商品分类id查询对应品牌即可。
4.9.1.2.1 web
@RestController
@RequestMapping("brand")
public class BrandController {
// 根据cid查询品牌
@GetMapping("cid/{cid}")
public ResponseEntity<List<Brand>> queryBrandByCid(@PathVariable("cid")Long cid){
return ResponseEntity.ok(brandService.queryBrandByCid(cid));
}
}
4.9.1.2.2 service
@Service
public class BrandService {
// 根据cid查到所有的品牌
public List<Brand> queryBrandByCid(Long cid) {
List<Brand> brands = brandMapper.queryByCategoryId(cid);
if(CollectionUtils.isEmpty(brands)){
throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
}
return brands;
}
}
- cid 和 tb_category,tb_category_brand表都有关系,要自己写sql语句
4.9.1.2.3 mapper
public interface BrandMapper extends BaseMapper<Brand> {
@Select("SELECT b.* FROM tb_brand b LEFT JOIN tb_category_brand cb ON b.id = cb.brand_id WHERE cb.category_id = #{cid}")
List<Brand> queryByCategoryId(@Param("cid")Long cid);
}
4.9.2 商品描述
商品描述信息比较复杂,而且图文并茂,甚至包括视频。
这样的内容,一般都会使用富文本编辑器。
4.9.2.1 什么是富文本编辑器
百度百科:
通俗来说:富文本,就是比较丰富的文本编辑器。普通的框只能输入文字,而富文本还能给文字加颜色样式等。
富文本编辑器有很多,例如:KindEditor、Ueditor。但并不原生支持vue
但我们用的是一款支持Vue的富文本编辑器:vue-quill-editor
4.9.2.2 Vue-Quill-Editor
GitHub的主页:https://github.com/surmon-china/vue-quill-editor
Vue-Quill-Editor是一个基于Quill的富文本编辑器:Quill官网
4.9.3 商品规格参数
-
规格参数的查询我们之前也已经编写过接口,因为商品规格参数也是与商品分类绑定,所以需要在商品分类变化后去查询(通过watch监控来实现)
-
因此我们一样实现根据商品分类id查询规格参数。我们之前写过一个根据gid(分组id)来查询规格参数的接口,若如果再编写一个新的接口(根据分类id查询规格参数)由于和 根据gid来查询规格参数的接口 的路径一模一样,会发生冲突(路径都是/spec/params,参数不一样,但SpringMVC不会因为参数不同就会认定是两次请求)
-
最终:我们在 根据gid来查询规格参数的接口上 对其进行扩展
4.9.3.1 web
@RestController
@RequestMapping("spec")
public class SpecificationController {
// 查询规格参数集合
@GetMapping("/params")
public ResponseEntity<List<SpecParam>> querySpecParams(@RequestParam(value = "gid",required = false)Long gid,
@RequestParam(value = "cid",required = false)Long cid,
@RequestParam(value = "searching",required = false)Boolean searching){
return ResponseEntity.ok(specificationService.querySpecParams(gid,cid,searching));
}
}
- 因为两个参数传一个就好,因此应加上
required = false
- 现在我们想要的功能实现了,但从长远角度来看,以后可能会有 根据搜索字段来查规格参数 需求(搜索微服务,做索引库新增),因此应再请求参数里再加一个参数
value = "searching"
4.9.3.2 service
@Service
public class SpecificationService {
// 查询规格参数集合
public List<SpecParam> querySpecParams(Long gid, Long cid, Boolean searching) {
SpecParam param = new SpecParam();
param.setGroupId(gid);
param.setCid(cid);
param.setSearching(searching);
List<SpecParam> params = paramMapper.select(param);
if(CollectionUtils.isEmpty(params)){
throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOUND);
}
return params;
}
}
4.9.4 SKU信息
Sku属性是SPU下的每个商品的不同特征,如图:
当我们填写一些属性后,会在页面下方生成一个sku表格(不同属性的Sku)
当我们选择了上图中的这些选项时:
- 颜色共2种:夜空黑,绚丽红
- 内存共2种:4GB,6GB
- 机身存储1种:64GB
此时会产生 2 * 2 * 1 = 4种,这其实就是在求笛卡尔积。
我们会在页面下方生成一个sku的表格:
4.9.5 提交
整体是一个json格式数据,包含Spu表所有数据:
- brandId:品牌id
- cid1、cid2、cid3:商品分类id
- subTitle:副标题
- title:标题
- spuDetail:是一个json对象,代表商品详情表数据
- afterService:售后服务
- description:商品描述
- packingList:包装列表
- specialSpec:sku规格属性模板
- genericSpec:通用规格参数
- skus:spu下的所有sku数组,元素是每个sku对象:
- title:标题
- images:图片
- price:价格
- stock:库存
- ownSpec:特有规格参数
- indexes:特有规格参数的下标
4.9.5.1 Sku和Stock表结构
Spu、SpuDetail和 Sku表结构 见商品规格数据结构与商品表结构分析
CREATE TABLE `tb_stock` (
`sku_id` bigint(20) NOT NULL COMMENT '库存对应的商品sku id',
`seckill_stock` int(9) DEFAULT '0' COMMENT '可秒杀库存',
`seckill_total` int(9) DEFAULT '0' COMMENT '秒杀总数量',
`stock` int(9) NOT NULL COMMENT '库存数量',
PRIMARY KEY (`sku_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存表,代表库存,秒杀库存等信息'
4.9.5.2 Sku和Stock实体类
@Data
@Table(name = "tb_sku")
public class Sku {
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
private Long spuId;
private String title;
private String images;
private Long price;
private String ownSpec;// 商品特殊规格的键值对
private String indexes;// 商品特殊规格的下标
private Boolean enable;// 是否有效,逻辑删除用
private Date createTime;// 创建时间
private Date lastUpdateTime;// 最后修改时间
@Transient //和数据库无关
private Integer stock;// 库存
}
@Data
@Table(name = "tb_stock")
public class Stock {
@Id
private Long skuId;
private Integer seckillStock;// 秒杀可用库存
private Integer seckillTotal;// 已秒杀数量
private Integer stock;// 正常库存
}
4.9.5.3 业务
4.9.5.3.1 web
4.9.5.3.1.1 页面分析
- 请求方式:PUT
- 请求路径:/
- 请求参数:Spu对象
- 返回结果:无
4.9.5.3.1.1 实现业务
@RestController
public class GoodsController {
//商品新增
@PostMapping("goods")
public ResponseEntity<Void> saveGoods(@RequestBody Spu spu){ //json结构,加上@RequestBody注解
goodsService.saveGoods(spu);
return ResponseEntity.status(HttpStatus.CREATED).build();//没有返回值
}
}
4.9.5.3.2 service
@Service
public class GoodsService {
//商品新增
@Transactional
public void saveGoods(Spu spu) {
//新增spu
spu.setId(null);
spu.setSaleable(true);
spu.setValid(false);
spu.setCreateTime(new Date());
spu.setLastUpdateTime(spu.getCreateTime());
int count = spuMapper.insert(spu);
if (count != 1) {
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
}
//新增detail
SpuDetail spuDetail = spu.getSpuDetail();
spuDetail.setSpuId(spu.getId());
spuDetailMapper.insert(spuDetail);
//新增sku和库存
saveSkuAndStock(spu);
//发送mq消息(这一步后边用到,可忽略)
//amqpTemplate.convertAndSend("item.insert",spu.getId());
}
}
在这里,我们把 新增sku和库存 单独抽取成一个方法了
// 新增sku和库存
private void saveSkuAndStock(Spu spu) {
int count;//新增sku
List<Sku> skus = spu.getSkus();
List<Stock> stockList = new ArrayList<>();
for (Sku sku : skus) {
sku.setCreateTime(new Date());
sku.setLastUpdateTime(sku.getCreateTime());
sku.setSpuId(spu.getId());
count = skuMapper.insert(sku);
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
//新增库存
Stock stock = new Stock();
stock.setSkuId(sku.getId());
stock.setStock(sku.getStock());
stockList.add(stock);
}
//批量新增库存
count = stockMapper.insertList(stockList);
if(count!=stockList.size())
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
}
4.9.5.3.3 mapper
public interface SkuMapper extends BaseMapper<Sku>{
}
public interface StockMapper extends BaseMapper<Stock> {
}
注:
- 为了以后Mapper实现的功能更加全面,简单起见,我们自己定义一个
BaseMapper<>
,泛型为要传递的 类 - BaseMapper继承
Mapper<T>,IdListMapper<T,Long>,InsertListMapper<T>
,可实现 从数据库中批量查询与添加数据 - 将BaseMapper放在ly-common 工具包中,供其他mapper继承
- 同时,InsertListMapper要导 tk.mybatis.mapper.additional.insert.InsertListMapper包下的;(另外一个包下的InsertListMapper接口限制实体中必须包含‘Id’属性且必须为自增列)
@RegisterMapper
public interface BaseMapper<T> extends Mapper<T>,IdListMapper<T,Long>,InsertListMapper<T> {
}
@RegisterMapper
注解可以避免 mappers 参数配置,通用 Mapper 检测到该接口被继承时,会自动注册。
即使不增加该接口,如果只用到了通用 Mapper 提供的方法,也可以自动注册,通用 Mapper 会自动向上查找带有该注解的父接口。如果是自己开发的通用方法,建议加上该注解,否则还需要自己配置 mappers 参数
4.10. 商品修改
因为在商品列表页面,只有spu的基本信息:id、标题、品牌、商品分类等。比较复杂的商品详情(spuDetail)和sku信息都没有,编辑页面要回显数据,就需要查询这些内容。
因此,接下来我们就编写后台接口,提供查询服务接口。
4.10.1 查询SpuDetail接口
4.10.1.1 web
4.10.1.1.1 页面分析
- 请求方式:GET
- 请求路径:/spu/detail/{id}
- 请求参数:id,应该是spu的id
- 返回结果:SpuDetail对象
4.10.1.1.2 实现业务
@RestController
public class GoodsController {
//根据spu的id查询详情detail
@GetMapping("/spu/detail/{id}")
public ResponseEntity<SpuDetail> querySpuDetailById(@PathVariable("id")Long id){
return ResponseEntity.ok(goodsService.queryDetailById(id));
}
}
4.10.1.2 service
@Service
public class GoodsService {
public SpuDetail queryDetailById(Long spuId) {
SpuDetail spuDetail = spuDetailMapper.selectByPrimaryKey(spuId);
if(spuDetail==null)
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
return spuDetail;
}
}
4.10.2 查询sku
4.10.2.1 web
4.10.2.1.1 页面分析
- 请求方式:Get
- 请求路径:/sku/list
- 请求参数:id,应该是spu的id
- 返回结果:sku的集合
4.10.2.1.2 实现业务
@RestController
public class GoodsController {
//根据spu查询下面所有的sku
@GetMapping("/sku/list")
public ResponseEntity<List<Sku>> querySkuBySpuId(@RequestParam("id") Long spuId){
return ResponseEntity.ok(goodsService.querySkuBySpuId(spuId));
}
}
4.10.2.1 service
@Service
public class GoodsService {
//根据spu查询下面所有的sku
public List<Sku> querySkuBySpuId(Long spuId) {
//查询sku
Sku sku = new Sku();
sku.setSpuId(spuId);
List<Sku> skuList = skuMapper.select(sku);
if(CollectionUtils.isEmpty(skuList))
throw new LyException(ExceptionEnum.GOODS_SKU_NOT_FOUND);
List<Long> ids = skuList.stream().map(Sku::getId).collect(Collectors.toList());
//将库存放到相应的sku中
//查询库存
List<Stock> stockList = stockMapper.selectByIdList(ids);
if(CollectionUtils.isEmpty(stockList))
throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
//把stock变成一个map,其key:skuId,值:库存值
Map<Long, Integer> stockMap = stockList.stream().collect(Collectors.toMap(Stock::getSkuId, Stock::getStock));
skus.forEach(s ->s.setStock(stockMap.get(s.getId())));
return skuList;
}
}
4.10.3 提交业务
4.10.3.1 web
4.10.3.1.1 页面分析
- 请求方式:PUT
- 请求路径:/
- 请求参数:Spu对象
- 返回结果:无
4.10.3.1.1 实现业务
@RestController
public class GoodsController {
//商品修改
@PutMapping("goods")
public ResponseEntity<Void> updateGoods(@RequestBody Spu spu){
goodsService.updateGoods(spu);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
4.10.3.1 service
spu数据可以修改,但是SKU数据无法修改,因为有可能之前存在的SKU现在已经不存在了,或者以前的sku属性都不存在了。比如以前内存有4G,现在没了。
因此这里直接删除以前的SKU,然后新增即可
@Service
public class GoodsService {
@Transactional
public void updateGoods(Spu spu) {
if(spu.getId() == null)
throw new LyException(ExceptionEnum.GOODS_ID_CANNOT_BE_NULL);
Sku sku = new Sku();
sku.setSpuId(spu.getId());
//查询sku
List<Sku> skuList = skuMapper.select(sku);
if(!CollectionUtils.isEmpty(skuList)){
//删除sku
skuMapper.delete(sku);
//删除库存
List<Long> ids = skuList.stream().map(Sku::getId).collect(Collectors.toList());
stockMapper.deleteByIdList(ids);
}
//修改spu
spu.setValid(null);
spu.setSaleable(null);
spu.setCreateTime(null);
spu.setLastUpdateTime(new Date());
int count = spuMapper.updateByPrimaryKeySelective(spu);
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_UPDATE_ERROR);
//修改detail
spuDetailMapper.updateByPrimaryKeySelective(spu.getSpuDetail());
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_UPDATE_ERROR);
//新增sku和库存stock(单独提取成一个方法了,上边已经写过了)
saveSkuAndStock(spu);
//发送mq消息(以后会用到)
amqpTemplate.convertAndSend("item.update",spu.getId());
}
}
以上,商品微服务可以先告一段落了!