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
 
 
 
 
public  interface  SpuInfoService  extends  IService < SpuInfoEntity > { PageUtils  queryPage ( Map < String ,  Object > ) ; public  void  saveSpuInfo ( SpuSaveVO  spuSaveVO) ; 
} 
    @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) ; } 
    @RequestMapping ( "/save" ) public  R  save ( @RequestBody  SpuSaveVO  spuSaveVO)  { spuInfoService. saveSpuInfo ( spuSaveVO) ; return  R . ok ( ) ; } 
 
 
 
 
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; 
 
 
 
    @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 > =  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) ; } 
 
 
 
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; 
 
    @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 > =  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 > =  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 > =  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) ; } } 
 
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; 
 
    void  saveProductAttrValue ( List < ProductAttrValueEntity > ) ; 
    @Override public  void  saveProductAttrValue ( List < ProductAttrValueEntity > )  { this . saveBatch ( productAttrValueEntities) ; } 
        List < BaseAttrs > =  spuSaveVO. getBaseAttrs ( ) ; List < ProductAttrValueEntity > =  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) ; 
 
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;    void  saveBatch ( List < SkuInfoEntity > ) ; 
    @Override public  void  saveBatch ( List < SkuInfoEntity > )  { this . saveBatch ( skuInfoEntities) ; } 
        List < Skus > =  spuSaveVO. getSkus ( ) ; List < SkuInfoEntity > =  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 > =  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) ; 
 
这里只报了这一个StackOverflowError,没有任何其他的提示信息 栈溢出,只可能是无限递归,debug查看数据没问题,在调用saveBatch报错 检查一下saveBatch发现,我自定义的名字跟IService接口的saveBatch相同,这样就相当于重写了IService接口中的方法,然后不断递归,所以出现了栈溢出 解决方式:修改一下自定义方法的名字即可 
 
 
 
 
 
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
 
    void  saveSkuImages ( List < SkuImagesEntity > ) ; 
    @Override public  void  saveSkuImages ( List < SkuImagesEntity > )  { this . saveBatch ( skuImagesEntity) ; } 
        List < 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 > =  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 > =  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) ; } ) ; 
 
 
 
 
 
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; 
 
    void  saveSkuSaleAttrValues ( List < SkuSaleAttrValueEntity > ) ; 
    @Override public  void  saveSkuSaleAttrValues ( List < SkuSaleAttrValueEntity > )  { this . saveBatch ( skuSaleAttrValueEntities) ; }             List < Attr > =  sku. getAttr ( ) ; List < SkuSaleAttrValueEntity > =  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) ; 
 
 
首先,一定是在Controller层,接收到一个完整的VO 将这个VO的基本属性,转换为一个主entity 将每个特殊属性再单独转为一个entity,需要与主entity的id关联,当然也可以关联其他属性 关于List类型的特殊属性,有两种选择,一种是将里面的内容,比如是String类型的图片url放到一个entity中使用逗号间隔,第二种是将每一个String都放到一个entity中,都是可以的 
 
可以看到一个SpuSaveVO中不仅有List类型的Skus,而且每个Skus中还有List类型的Attr 虽然看上去复杂,不过确实也复杂。 但是,关于List类型的属性,只需要记住一点,遍历出每一个元素,将其转化为entity,这个entity至少需要与上一层的entity的id关联