1.分析前端保存商品发布信息的json数据
1.分析commoditylaunch.vue的submitSkus
1.将后面的都注销,只保留查看数据的部分
2.填写基本信息
3.保存信息,得到json
4.使用工具格式化一下
2.使用工具将json转为model
3.根据业务修改vo,放到vo包下
2.保存spu基本信息
1.创建表commodity_spu_info
1.用这个表来存储json的前六条信息
2.sql
use sunliving_commodity; CREATE TABLE commodity_spu_info
( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '商品 id' , spu_name VARCHAR ( 200 ) COMMENT '商品名称' , spu_description VARCHAR ( 1000 ) COMMENT '商品描述' , catalog_id BIGINT COMMENT '所属分类 id' , brand_id BIGINT COMMENT '品牌 id' , weight DECIMAL ( 18 , 4 ) , publish_status TINYINT COMMENT '上架状态[0 - 下架,1 - 上架]' , create_time DATETIME , update_time DATETIME , PRIMARY KEY ( id)
) CHARSET = utf8mb4 COMMENT = '商品 spu 信息' ; SELECT * FROM commodity_spu_info
2.生成基本的CRUD
1.启动项目,访问localhost:81,点击生成
2.将生成的main目录覆盖sunliving-commodity的main目录
3.注释掉SpuInfoController.java中跟shiro相关的
4.重启测试接口
1.访问 http://localhost:5050/api/sunliving-commodity/commodity/spuinfo/list
2.注意,如果提示VO不识别之类的就先刷新maven然后build一下即可
3.完成基本信息的保存
1.后端 sunliving-commodity模块
1.SpuInfoService.java 接受SpuSaveVO,保存到数据库
public interface SpuInfoService extends IService < SpuInfoEntity > { PageUtils queryPage ( Map < String , Object > params) ; public void saveSpuInfo ( SpuSaveVO spuSaveVO) ;
}
2.SpuInfoServiceImpl.java 实现方法
@Override public void saveSpuInfo ( SpuSaveVO spuSaveVO) { SpuInfoEntity spuInfoEntity = new SpuInfoEntity ( ) ; BeanUtils . copyProperties ( spuSaveVO, spuInfoEntity) ; spuInfoEntity. setCreateTime ( new Date ( ) ) ; spuInfoEntity. setUpdateTime ( new Date ( ) ) ; this . save ( spuInfoEntity) ; }
3.SpuInfoController.java 编写保存信息的接口
@RequestMapping ( "/save" ) public R save ( @RequestBody SpuSaveVO spuSaveVO) { spuInfoService. saveSpuInfo ( spuSaveVO) ; return R . ok ( ) ; }
4.前端 commoditylaunch.vue的submitSkus方法
1.修改url为环境变量+资源路径的方式
2.解掉下面的注释
5.前后端联调
1.前端输入信息
2.后端查看数据库
3.保存spu图片描述url
1.数据库表设计
use sunliving_commodity; CREATE TABLE commodity_spu_info_desc
( spu_id BIGINT NOT NULL COMMENT '商品 id' , decript LONGTEXT COMMENT '商品介绍图片' , PRIMARY KEY ( spu_id)
) CHARSET = utf8mb4 COMMENT = '商品 spu 信息介绍' ; select * from commodity_spu_info_desc;
2.生成基本CRUD
1.将生成的main目录覆盖sunliving-commodity的main目录
2.注释掉SpuInfoDescController.java的与shiro有关的部分
3.重启测试
3.完成保存spu的图片描述url
1.后端 sunliving-commodity模块
1.将SpuInfoDescEntity.java的id修改为不是自增的
2.修改SpuInfoServiceImpl.java的saveSpuInfo方法即可,注意需要添加@Transactional进行事务管理
@Transactional @Override public void saveSpuInfo ( SpuSaveVO spuSaveVO) { SpuInfoEntity spuInfoEntity = new SpuInfoEntity ( ) ; BeanUtils . copyProperties ( spuSaveVO, spuInfoEntity) ; spuInfoEntity. setCreateTime ( new Date ( ) ) ; spuInfoEntity. setUpdateTime ( new Date ( ) ) ; List < String > decript = spuSaveVO. getDecript ( ) ; SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity ( ) ; if ( decript != null && ! decript. isEmpty ( ) ) { spuInfoDescEntity. setDecript ( String . join ( "," , decript) ) ; } else { spuInfoDescEntity. setDecript ( "暂无描述" ) ; } spuInfoDescEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; spuInfoDescService. save ( spuInfoDescEntity) ; this . save ( spuInfoEntity) ; }
3.前后端联调
1.前端保存信息
2.后端在保存图片描述url的时候发现是空,原因是在将spuInfoEntity的id保存到db之前的确是空的,更改一下执行顺序即可
3.将spuInfoEntity的保存提前
4.再次测试,成功保存信息
4.保存SPU图片集信息
1.数据库表设计
use sunliving_commodity; CREATE TABLE commodity_spu_images
( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'id' , spu_id BIGINT COMMENT 'spu_id' , img_name VARCHAR ( 200 ) COMMENT '图片名' , img_url VARCHAR ( 255 ) COMMENT '图片地址' , img_sort INT COMMENT '顺序' , default_img TINYINT COMMENT '是否默认图' , PRIMARY KEY ( id)
) CHARSET = utf8mb4 COMMENT = 'spu 图片集' ; SELECT *
FROM commodity_spu_images;
2.生成基本CRUD(不再赘述)
3.完成保存图片集信息
1.后端 sunliving-commodity 模块
1.修改SpuInfoServiceImpl.java的saveSpuInfo即可
@Transactional @Override public void saveSpuInfo ( SpuSaveVO spuSaveVO) { SpuInfoEntity spuInfoEntity = new SpuInfoEntity ( ) ; BeanUtils . copyProperties ( spuSaveVO, spuInfoEntity) ; spuInfoEntity. setCreateTime ( new Date ( ) ) ; spuInfoEntity. setUpdateTime ( new Date ( ) ) ; List < String > decript = spuSaveVO. getDecript ( ) ; SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity ( ) ; if ( decript != null && ! decript. isEmpty ( ) ) { spuInfoDescEntity. setDecript ( String . join ( "," , decript) ) ; } else { spuInfoDescEntity. setDecript ( "暂无描述" ) ; } this . save ( spuInfoEntity) ; spuInfoDescEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; spuInfoDescService. save ( spuInfoDescEntity) ; List < String > images = spuSaveVO. getImages ( ) ; if ( images == null || images. isEmpty ( ) ) { SpuImagesEntity spuImagesEntity = new SpuImagesEntity ( ) ; spuImagesEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; spuImagesEntity. setDefaultImg ( 0 ) ; spuImagesEntity. setImgUrl ( "暂无图片" ) ; spuImagesEntity. setImgSort ( 0 ) ; spuImagesService. save ( spuImagesEntity) ; } else { List < SpuImagesEntity > collect = images. stream ( ) . map ( img -> { SpuImagesEntity spuImagesEntity = new SpuImagesEntity ( ) ; spuImagesEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; spuImagesEntity. setDefaultImg ( 0 ) ; spuImagesEntity. setImgUrl ( img) ; spuImagesEntity. setImgSort ( 0 ) ; return spuImagesEntity; } ) . collect ( Collectors . toList ( ) ) ; spuImagesService. saveBatch ( collect) ; } }
2.前后端联调
1.前端保存信息
2.后端查看数据库
5.保存SPU的基本属性
1.数据库表创建
use sunliving_commodity; CREATE TABLE commodity_product_attr_value
( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'id' , spu_id BIGINT COMMENT '商品 id' , attr_id BIGINT COMMENT '属性 id' , attr_name VARCHAR ( 200 ) COMMENT '属性名' , attr_value VARCHAR ( 200 ) COMMENT '属性值' , attr_sort INT COMMENT '顺序' , quick_show TINYINT COMMENT '快速展示【是否展示在介绍上;0-否 1-是】' , PRIMARY KEY ( id)
) CHARSET = utf8mb4 COMMENT = 'spu 基本属性值' ; select * from commodity_product_attr_value;
2.生成基本CRUD(不再赘述)
3.保存SPU的基本属性
1.后端 sunliving-commodity模块
1.ProductAttrValueService.java 新增方法,批量保存
void saveProductAttrValue ( List < ProductAttrValueEntity > productAttrValueEntities) ;
2.ProductAttrValueServiceImpl.java 实现方法
@Override public void saveProductAttrValue ( List < ProductAttrValueEntity > productAttrValueEntities) { this . saveBatch ( productAttrValueEntities) ; }
3.修改SpuInfoServiceImpl.java 的saveSpuInfo方法,新增代码
List < BaseAttrs > baseAttrs = spuSaveVO. getBaseAttrs ( ) ; List < ProductAttrValueEntity > collect = baseAttrs. stream ( ) . map ( baseAttr -> { ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity ( ) ; productAttrValueEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; productAttrValueEntity. setAttrId ( baseAttr. getAttrId ( ) ) ; productAttrValueEntity. setQuickShow ( baseAttr. getShowDesc ( ) ) ; productAttrValueEntity. setAttrSort ( 0 ) ; productAttrValueEntity. setAttrValue ( baseAttr. getAttrValues ( ) ) ; productAttrValueEntity. setAttrName ( attrService. getById ( baseAttr. getAttrId ( ) ) . getAttrName ( ) ) ; return productAttrValueEntity; } ) . collect ( Collectors . toList ( ) ) ; productAttrValueService. saveProductAttrValue ( collect) ;
2.前后端联调
1.前端保存基本属性
2.后端查看数据库
6.保存SKU的基本信息
1.数据库表设计
use sunliving_commodity;CREATE TABLE commodity_sku_info
(sku_id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'skuId',spu_id BIGINT COMMENT 'spuId',sku_name VARCHAR(255) COMMENT 'sku 名称',sku_desc VARCHAR(2000) COMMENT 'sku 介绍描述',catalog_id BIGINT COMMENT '所属分类 id',brand_id BIGINT COMMENT '品牌 id',sku_default_img VARCHAR(255) COMMENT '默认图片',sku_title VARCHAR(255) COMMENT '标题',sku_subtitle VARCHAR(2000) COMMENT '副标题',price DECIMAL(18, 4) COMMENT '价格',sale_count BIGINT COMMENT '销量',PRIMARY KEY (sku_id)
) CHARSET = utf8mb4 COMMENT ='sku 信息';SELECT *
FROM commodity_sku_info;
2.生成基本CRUD(不再赘述)
3.保存SKU基本信息 sunliving-commodity模块
1.SkuInfoService.java 新增批量添加的方法
void saveBatch ( List < SkuInfoEntity > skuInfoEntities) ;
2.SkuInfoServiceImpl.java 实现方法
@Override public void saveBatch ( List < SkuInfoEntity > skuInfoEntities) { this . saveBatch ( skuInfoEntities) ; }
3.SpuInfoServiceImpl.java 修改saveSpuInfo方法,新增代码
List < Skus > skus = spuSaveVO. getSkus ( ) ; List < SkuInfoEntity > skusCollect = skus. stream ( ) . map ( sku -> { SkuInfoEntity skuInfoEntity = new SkuInfoEntity ( ) ; skuInfoEntity. setBrandId ( spuInfoEntity. getBrandId ( ) ) ; skuInfoEntity. setSkuDesc ( "" ) ; skuInfoEntity. setSkuName ( sku. getSkuName ( ) ) ; skuInfoEntity. setPrice ( sku. getPrice ( ) ) ; skuInfoEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; List < Images > skuImages = sku. getImages ( ) ; for ( Images image : skuImages) { if ( image. getDefaultImg ( ) == 1 ) { skuInfoEntity. setSkuDefaultImg ( image. getImgUrl ( ) ) ; } else { skuInfoEntity. setSkuDefaultImg ( "暂无默认图片" ) ; } } skuInfoEntity. setSkuSubtitle ( sku. getSkuSubtitle ( ) ) ; skuInfoEntity. setSkuTitle ( sku. getSkuTitle ( ) ) ; skuInfoEntity. setCatalogId ( spuInfoEntity. getCatalogId ( ) ) ; skuInfoEntity. setSaleCount ( 0L ) ; return skuInfoEntity; } ) . collect ( Collectors . toList ( ) ) ; skuInfoService. saveSkuInfoEntitys ( skusCollect) ;
4.前后端联调
1.后端报错,java.lang.StackOverflowError
2.问题分析
这里只报了这一个StackOverflowError,没有任何其他的提示信息 栈溢出,只可能是无限递归,debug查看数据没问题,在调用saveBatch报错 检查一下saveBatch发现,我自定义的名字跟IService接口的saveBatch相同,这样就相当于重写了IService接口中的方法,然后不断递归,所以出现了栈溢出 解决方式:修改一下自定义方法的名字即可
3.问题解决
1.修改自定义方法的名字
2.修改SpuInfoServiceImpl.java调用的方法
3.重启测试,保存成功!
7.保存SPU和SKU图片信息
1.数据库表创建
use sunliving_commodity; CREATE TABLE commodity_sku_images
( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'id' , sku_id BIGINT COMMENT 'sku_id' , img_url VARCHAR ( 255 ) COMMENT '图片地址' , img_sort INT COMMENT '排序' , default_img INT COMMENT '默认图[0 - 不是默认图,1 - 是默认图]' , PRIMARY KEY ( id)
) CHARSET = utf8mb4 COMMENT = 'sku 图片' ; SELECT *
FROM commodity_sku_images
2.生成基本CRUD(不再赘述)
3.完成保存SPU和SKU图片信息 sunliving-commodity模块
1.SkuImagesService.java 新增方法,批量保存sku图片
void saveSkuImages ( List < SkuImagesEntity > skuImagesEntity) ;
2.SkuImagesServiceImpl.java 实现方法
@Override public void saveSkuImages ( List < SkuImagesEntity > skuImagesEntity) { this . saveBatch ( skuImagesEntity) ; }
3.修改 SpuInfoServiceImpl.java,修改代码
List < Skus > skus = spuSaveVO. getSkus ( ) ; skus. forEach ( sku -> { SkuInfoEntity skuInfoEntity = new SkuInfoEntity ( ) ; skuInfoEntity. setBrandId ( spuInfoEntity. getBrandId ( ) ) ; skuInfoEntity. setSkuDesc ( "" ) ; skuInfoEntity. setSkuName ( sku. getSkuName ( ) ) ; skuInfoEntity. setPrice ( sku. getPrice ( ) ) ; skuInfoEntity. setSpuId ( spuInfoEntity. getId ( ) ) ; List < Images > skuImages = sku. getImages ( ) ; for ( Images image : skuImages) { if ( image. getDefaultImg ( ) == 1 ) { skuInfoEntity. setSkuDefaultImg ( image. getImgUrl ( ) ) ; } else { skuInfoEntity. setSkuDefaultImg ( "暂无默认图片" ) ; } } skuInfoEntity. setSkuSubtitle ( sku. getSkuSubtitle ( ) ) ; skuInfoEntity. setSkuTitle ( sku. getSkuTitle ( ) ) ; skuInfoEntity. setCatalogId ( spuInfoEntity. getCatalogId ( ) ) ; skuInfoEntity. setSaleCount ( 0L ) ; skuInfoService. save ( skuInfoEntity) ; List < SkuImagesEntity > skuImagesEntities = skuImages. stream ( ) . map ( image -> { SkuImagesEntity skuImagesEntity = new SkuImagesEntity ( ) ; skuImagesEntity. setSkuId ( skuInfoEntity. getSkuId ( ) ) ; skuImagesEntity. setDefaultImg ( image. getDefaultImg ( ) ) ; skuImagesEntity. setImgUrl ( image. getImgUrl ( ) ) ; skuImagesEntity. setImgSort ( 0 ) ; return skuImagesEntity; } ) . collect ( Collectors . toList ( ) ) ; skuImagesService. saveSkuImages ( skuImagesEntities) ; } ) ;
4.前后端联调
1.前端保存信息
2.后端测试,发现commodity_sku_images表插入了两条空的字段
3.debug分析
1.第一个sku有两张图片,第二个sku没有图片,在遍历第二个sku时发现,即使第二个没有图片,前端会传一个url为空的数组,包含两个元素
2.在保存sku图片信息的时候,就会将这个图片的信息保存到数据库中
3.解决方式:在保存sku图片信息时加一个过滤即可,把url为空的过滤掉
4.重启测试,再添加一次,没有空值了
8.保存SKU销售属性
1.数据库表设计
use sunliving_commodity; CREATE TABLE commodity_sku_sale_attr_value
( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'id' , sku_id BIGINT COMMENT 'sku_id' , attr_id BIGINT COMMENT 'attr_id' , attr_name VARCHAR ( 200 ) COMMENT '销售属性名' , attr_value VARCHAR ( 200 ) COMMENT '销售属性值' , attr_sort INT COMMENT '顺序' , PRIMARY KEY ( id)
) CHARSET = utf8mb4 COMMENT = 'sku 的销售属性/值表' ; SELECT *
FROM commodity_sku_sale_attr_value;
2.生成基本CRUD(不再赘述)
3.完成保存SKU销售属性 sunliving-commodity模块
1.SkuSaleAttrValueService.java 新增方法批量保存sku销售属性
void saveSkuSaleAttrValues ( List < SkuSaleAttrValueEntity > skuSaleAttrValueEntities) ;
2.SkuSaleAttrValueServiceImpl.java 实现方法
@Override public void saveSkuSaleAttrValues ( List < SkuSaleAttrValueEntity > skuSaleAttrValueEntities) { this . saveBatch ( skuSaleAttrValueEntities) ; }
3.SpuInfoServiceImpl.java 新增代码保存sku的销售属性信息
List < Attr > attr = sku. getAttr ( ) ; List < SkuSaleAttrValueEntity > skuSaleAttrValueEntities = attr. stream ( ) . map ( a -> { SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity ( ) ; BeanUtils . copyProperties ( a, skuSaleAttrValueEntity) ; skuSaleAttrValueEntity. setSkuId ( skuInfoEntity. getSkuId ( ) ) ; skuSaleAttrValueEntity. setAttrSort ( 0 ) ; return skuSaleAttrValueEntity; } ) . collect ( Collectors . toList ( ) ) ; skuSaleAttrValueService. saveSkuSaleAttrValues ( skuSaleAttrValueEntities) ;
4.重启测试
9.将vo转化为entity的总结
1.整体的 SpuSaveVO预览
2.转换结构
3.转换规则
首先,一定是在Controller层,接收到一个完整的VO 将这个VO的基本属性,转换为一个主entity 将每个特殊属性再单独转为一个entity,需要与主entity的id关联,当然也可以关联其他属性
4.List类型的特殊属性细节说明
关于List类型的特殊属性,有两种选择,一种是将里面的内容,比如是String类型的图片url放到一个entity中使用逗号间隔,第二种是将每一个String都放到一个entity中,都是可以的
5.关于List里面还有多个特殊属性的处理
1.查看这里的 List
2.分析
可以看到一个SpuSaveVO中不仅有List类型的Skus,而且每个Skus中还有List类型的Attr 虽然看上去复杂,不过确实也复杂。 但是,关于List类型的属性,只需要记住一点,遍历出每一个元素,将其转化为entity,这个entity至少需要与上一层的entity的id关联