谷粒商城笔记+踩坑(7)——新增商品,请求参数转vo类

本文涉及的产品
对象存储 OSS,20GB 3个月
.cn 域名,1个 12个月
对象存储 OSS,恶意文件检测 1000次 1年
简介: 效果展示、配置、启动会员模块、获取当前分类关联的品牌(不用分页)、获取当前分类下的分组及其关联的属性、新增商品、添加复合配置、限制内存、报错loadbalancer解决

 导航:

谷粒商城笔记+踩坑汇总篇

Java笔记汇总:

【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析-CSDN博客

目录

12、商品服务-新增商品

12.0、效果展示

12.1、配置、启动会员模块

12.1.1、用户模块添加到nacos注册中心

12.1.2、配置网关路由

12.1.3、添加“会员等级”数据

12.2、获取当前分类关联的品牌(不用分页)

12.2.1、分析

12.2.2、新建BrandVo

12.2.3、代码实现

12.2.4、测试

12.3、获取当前分类下的分组及其关联的属性

12.3.1、分析

12.3.2、代码实现

12.3.3、测试

12.4、新增商品

12.4.1、分析

12.4.2、填写表单

12.4.3、vo类封装表单json数据

12.4.4、新增业务流程分析

12.4.5、保存商品模块的商品信息

12.4.6、保存优惠券模块的商品信息,feign远程调用

12.5、添加复合配置、限制内存

12.6、报错loadbalancer解决

12.7、商品保存debug、解决其他报错


12、商品服务-新增商品

12.0、效果展示

todo。这节写后补上

12.1、配置、启动会员模块

进入“发布商品”页面会发获取会员等级的请求,所以第一步要先配置、启动会员模块。

image.gif

12.1.1、用户模块添加到nacos注册中心

修改gulimall-member配置文件,将用户模块添加到服务注册中心,然后启动gulimall-member服务

image.gif

启动成功:

image.gif

image.gif

“获取所有会员等级”功能,在逆向工程时已经自动生成了。url:/member/memberlevel/list

12.1.2、配置网关路由

网关模块修改yml,用户路由(/api/member/**)要放到人人管理后台路由(/api/**)前面,因为路由路径更具体。

#用户模块路由
        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
#/api/member/**重写成/menber/**
            - RewritePath=/api/(?<segment>.*),/$\{segment}

image.gif

当前网关模块的yml:

server:
  port: 88
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
#商品模块路由
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**  #http://localhost:88/api/product/category/list/tree转发http://localhost:10000/product/category/list/tree
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
# oss等第三方模块路由
        - id: third_party_route
          uri: lb://gulimall-third-party
          predicates:
            - Path=/api/thirdparty/**
          filters:
#            http://localhost:88/api/thirdparty/oss/policy--->http://localhost:30000/oss/policy
            - RewritePath=/api/thirdparty/(?<segment>.*),/$\{segment}
#用户模块路由
        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
#人人管理后台,路径路由。路由id,自定义,只要唯一即可
        - id: admin_route
          # uri路由的目标地址。lb就是负载均衡,后面跟服务名称。
          uri: lb://renren-fast
          #断言工厂的Path,请求路径必须符合指定规则,才能进行转发
          predicates:
            - Path=/api/**    # 把所有api开头的请求都转发给renren-fast
          #局部过滤器。回顾默认过滤器default-filters是与routes同级
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}
            # 默认规则, 请求过来:http://localhost:88/api/captcha.jpg   转发-->  http://renren-fast:8080/api/captcha.jpg
            # 但是真正的路径是http://renren-fast:8080/renren-fast/captcha.jpg
            # 所以使用路径重写把/api/* 改变成 /renren-fast/*
  application:
    name: gulimall-gateway
logging:
  level:
    com.vince.gulimall: debug
image.gif

重启网关模块,发现“会员列表”和“会员等级”请求已经不报错404:

image.gif

12.1.3、添加“会员等级”数据

点击 用户系统-会员等级

添加一些数据

image.gif

然后进入“发布商品”页面,就不用请求会员等级报错:

image.gif

12.2、获取当前分类关联的品牌(不用分页)

12.2.1、分析

需求:发布商品时,选择分类后,会发请求获取当前分类关联的品牌,所以需要编写这个业务,下面是完成后的效果:

image.gif

请求14:/product/categorybrandrelation/brands/list

  • 新增商品时,点击商品的分类,要获取与该分类关联的所有品牌id和name

image.gif

12.2.2、新建BrandVo

因为只需要品牌id和name,也可以不新建vo,使用CategoryBrandRelationEntity响应数据:

image.gif

CategoryBrandRelationController中一步到位:

/**
     * 获取当前分类关联的所有品牌id和name
     * @param catId
     * @return
     */
    @GetMapping("/brands/list")
    public R relationBrandsList(@RequestParam(value = "catId",required = true) Long catId){
        List<CategoryBrandRelationEntity> categoryBrandRelationEntities = categoryBrandRelationService.list(
                new LambdaQueryWrapper<CategoryBrandRelationEntity>().eq(CategoryBrandRelationEntity::getCatelogId, catId)
        );
        return R.ok().put("data",categoryBrandRelationEntities);
    }
image.gif
@Data
public class BrandVo {
    private Long brandId;
    private String brandName;
}

image.gif

12.2.3、代码实现

CategoryBrandRelationController

/**
    * 获取当前分类关联的所有品牌
     * 1、 Controller: 处理请求,接受和校验数据
     * 2、Service接受controller传来的数据,进行业务处理
     * 3、Controller接受Service处理完的数据,封装成页面指定的vo
    */
    @GetMapping("/brands/list")
    public R relationBrandsList(@RequestParam(value = "catId", required = true) Long catId){
        List<BrandEntity> vos = categoryBrandRelationService.getBrandsByCatId(catId);
//遍历拷贝vos到brandVo
        List<BrandVo> collect = vos.stream().map(item -> {
            BrandVo brandVo = new BrandVo();
            brandVo.setBrandId(item.getBrandId());
            brandVo.setBrandName(item.getName());
            return brandVo;
        }).collect(Collectors.toList());
        return R.ok().put("data", collect);
    }

image.gif

CategoryBrandRelationServiceImpl

@Autowired
BrandService brandService;
@Override
public List<BrandEntity> getBrandsByCatId(Long catId) {
    List<CategoryBrandRelationEntity> catelogId = this.baseMapper.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
    List<BrandEntity> collect = catelogId.stream().map(item -> {
        Long brandId = item.getBrandId();
        BrandEntity byId = brandService.getById(brandId);
        return byId;
    }).collect(Collectors.toList());
    return collect;
}

image.gif

如果报错:

image.gif

就把brandService.getById改成brandDao.selectById

也可以不新建vo,使用CategoryBrandRelationEntity响应数据:

image.gif

CategoryBrandRelationController中一步到位:

/**
     * 获取当前分类关联的所有品牌id和name
     * @param catId
     * @return
     */
    @GetMapping("/brands/list")
    public R relationBrandsList(@RequestParam(value = "catId",required = true) Long catId){
        List<CategoryBrandRelationEntity> categoryBrandRelationEntities = categoryBrandRelationService.list(
                new LambdaQueryWrapper<CategoryBrandRelationEntity>().eq(CategoryBrandRelationEntity::getCatelogId, catId)
        );
        return R.ok().put("data",categoryBrandRelationEntities);
    }
image.gif

12.2.4、测试

再次发布商品,选择分类后就能查到该分类下的品牌了:

image.gif

12.3、获取当前分类下的分组及其关联的属性

12.3.1、分析

需求:录入规格参数时要获取当前分类下所有分组和关联属性,进行选择分组、规格参数

image.gif

无法上传图片问题

如果在填写基本信息时候无法上传图片,开启第三方模块。

image.gif

检测bucket域名,参考下文7.3.10修改前端,替换成自己的Bucket域名

谷粒商城笔记+踩坑(4)——商品服务-品牌管理、云存储

image.gif

请求17:/product/attrgroup/{catelogId}/withattr

响应数据:

image.gif

12.3.2、代码实现

新建AttrGroupWithAttrsVo

@Data
public class AttrGroupWithAttrsVo extends AttrGroupEntity {
    private List<AttrEntity> attrs;
}

image.gif

AttrGroupController

@GetMapping("/{catelogId}/withattr")
public R getAttrGroupWithAttrs(@PathVariable("catelogId") Long catelogId){
    //1、查出当前分类下的所有属性分组
    //2、查出每个属性分组的所有属性
    List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrsByCatelogId(catelogId);
    return R.ok().put("data", vos);
}

image.gif

AttrGroupServiceImpl

/**
     * 获取当前分类下所有分组以及属性
     * @param catelogId
     * @return
     */
    @Override
    public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId) {
        //查询此分类下所有分组
        List<AttrGroupEntity> attrGroupEntities = this.list(new LambdaQueryWrapper<AttrGroupEntity>().eq(AttrGroupEntity::getCatelogId, catelogId));
        //每个分组查询规格属性
        List<AttrGroupWithAttrsVo> vos=attrGroupEntities.stream().map(item->{
            AttrGroupWithAttrsVo vo = new AttrGroupWithAttrsVo();
            BeanUtils.copyProperties(item,vo);
            //在关联表里查询此分组的规格属性
            Long groupId = item.getAttrGroupId();
            //有编写这个业务,获取分组关联的属性list
            vo.setAttrs(attrService.getRelationAttr(groupId));
            return vo;
        }).collect(Collectors.toList());
        return vos;
    }

image.gif

12.3.3、测试

重启商品模块,可以看到当前分类下的分组和规格参数已显示:

image.gif

无法上传图片问题

如果在填写基本信息时候无法上传图片,开启第三方模块。

image.gif

检测bucket域名,参考下文7.3.10修改前端,替换成自己的Bucket域名

谷粒商城笔记+踩坑(4)——商品服务-品牌管理、云存储

image.gif

12.4、新增商品

12.4.1、分析

url:/product/spuinfo/save

12.4.2、填写表单

参考商品:【AppleiPhone 14 Pro】Apple iPhone 14 Pro (A2892) 256GB 暗紫色 支持移动联通电信5G 双卡双待手机【行情 报价 价格 评测】-京东

图片地址:D:\download\尚硅谷谷粒商城电商项目等1个文件\尚硅谷谷粒商城电商项目\资料源码\docs\pics

基本信息

image.gif

规格参数

image.gif 销售属性

image.gif

销售属性展示的是“可选值”。这里自定义“+” 号,可以新加销售属性的可选值,仅针对于这个商品,不会改动销售属性的数据库。

sku信息

根据笛卡尔积计算销售属性,得出相应数量的sku信息。一个sku决定了一个价格。

image.gif

image.gif

12.4.3、vo类封装表单json数据

点击下一步“保存商品信息” ,然后点击取消,复制控制台的json数据。

image.gif

json格式化工具:

https://www.bejson.com/

image.gif

json生成java类:

https://www.bejson.com/json2javapojo/new/

image.gif

1.生成vo类并下载,复制到自己项目的vo包下

image.gif

2.把所有id字段改成Long类型,把所有金额相关字段的类型由String或Double改成BigDecimal类型,把get和set方法改成@Data

  1. SpuSaveVo的brandId和catelogId改成Long,weight改成BigDecimal。
  2. Bounds都改成BigDecimal
  3. BaseAttrs的attrId改成Long;price,discount,fullPrice,reducePrice改成BigDecimal ;
  4. Attr的attrId改成Long
  5. MemberPrice的id改成Long,price改成BigDecimal;

BigDecimal

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

 

12.4.4、新增业务流程分析

  1. 保存spu基本信息pms_spu_info
  2. 保存spu的描述图片pms_spu_info_desc
  3. 保存spu的图片集pms_spu_images
  4. 保存spu的规格参数pms_product_attr_value
  5. 保存spu的积分信息gulimall_sms->sms_spu_bounds
  6. 保存spu对应的所有sku信息
  1. sku的基本信息pms_sku_info
  2. sku的图片信息pms_sku_images
  3. sku的销售属性信息pms_sku_sale_attr_value
  4. sku的优惠、满减等信息gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price

12.4.5、保存商品模块的商品信息

SpuInfoController

/**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody SpuSaveVo spuSaveVo){
    spuInfoService.saveSpuInfo(spuSaveVo);
        return R.ok();
    }

image.gif

SpuInfoServiceImpl

注意:

  • 保存sku的优惠、满减信息时,需要用到gulimall-coupon模块的服务,所以这里要用open-feign远程调用
@Autowired
SkuInfoService skuInfoService;
@Autowired
SkuImagesService skuImagesService;
@Autowired
SkuSaleAttrValueService skuSaleAttrValueService;
@Autowired
CouponFeignService couponFeignService;
    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {
        //1、保存spu基本信息`pms_spu_info`
        SpuInfoEntity infoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo, infoEntity);
        infoEntity.setCreateTime(new Date());
        infoEntity.setUpdateTime(new Date());
        this.save(infoEntity);
        //2、保存spu的描述图片`pms_spu_info_desc`
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(infoEntity.getId());
        //String.join方法可以快速拼接list里的字符串
        descEntity.setDecript(String.join(",", decript));
        spuInfoDescService.save(descEntity);
        //3、保存spu的图片集`pms_spu_images`
        List<String> images = vo.getImages();
        if (images != null && images.size() != 0) {
            List<SpuImagesEntity> collect = images.stream().map(image -> {
                SpuImagesEntity imagesEntity = new SpuImagesEntity();
                imagesEntity.setSpuId(infoEntity.getId());
                imagesEntity.setImgUrl(image);
                return imagesEntity;
            }).collect(Collectors.toList());
            imagesService.saveBatch(collect);
        }
        //4、保存spu的规格参数`pms_product_attr_value`
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> productAttrValueEntityList = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(attr.getAttrId());
            AttrEntity byId = attrService.getById(attr.getAttrId());
            valueEntity.setAttrName(byId.getAttrName());
            valueEntity.setAttrValue(attr.getAttrValues());
            valueEntity.setQuickShow(attr.getShowDesc());
            valueEntity.setSpuId(infoEntity.getId());
            return valueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveBatch(productAttrValueEntityList);
        //5、保存spu的积分信息`gulimall_sms`->`sms_spu_bounds`
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, spuBoundTo);
        spuBoundTo.setSpuId(infoEntity.getId());
        R r = couponFeignService.saveSpuBounds(spuBoundTo);
        if (r.getCode() != 0){
            log.error("远程保存spu积分信息失败");
        }
        //6、保存spu对应的所有sku信息
        List<Skus> skus = vo.getSkus();
        if (skus != null && skus.size() > 0) {
            skus.forEach(item -> {
                String defaultImg = "";
                //查找出默认图片
                for (Images image : item.getImages()) {
                    if (image.getDefaultImg() == 1) {
                        defaultImg = image.getImgUrl();
                    }
                }
                //6.1、sku的基本信息`pms_sku_info`
                //skus列表里的每个item赋值给sku_info实体类
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(item, skuInfoEntity);
                skuInfoEntity.setSpuId(infoEntity.getId());
                skuInfoEntity.setBrandId(infoEntity.getBrandId());
                skuInfoEntity.setCatalogId(infoEntity.getCatalogId());
                skuInfoEntity.setSaleCount(0L); //销量
                skuInfoEntity.setSkuDefaultImg(defaultImg);
                skuInfoService.save(skuInfoEntity);
                //6.2、sku的图片信息`pms_sku_images`
                Long skuId = skuInfoEntity.getSkuId();
                List<SkuImagesEntity> skuImagesEntities = item.getImages().stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).collect(Collectors.toList());
                skuImagesService.saveBatch(skuImagesEntities);
                //6.3、sku的销售属性信息`pms_sku_sale_attr_value`
                List<Attr> attr = item.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(a -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    BeanUtils.copyProperties(a, skuSaleAttrValueEntity);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
                //6.4、sku的优惠、满减等信息`gulimall_sms`->`sms_sku_ladder`/`sms_sku_full_reduction`/`sms_member_price`
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(item, skuReductionTo);
                skuReductionTo.setSkuId(infoEntity.getId());
                R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
                if (r1.getCode() != 0){
                    log.error("远程保存优惠信息失败");
                }
            });
        }
    }

image.gif

12.4.6、保存优惠券模块的商品信息,feign远程调用

1.common模块创建to,用于不同服务间传数据

TO:Transfer Object 数据传输对象

在应用程序不同关系之间传输的对象。

common模块中新建common.to.SpuBoundTo用来做远程调用积分数据传输

@Data
public class SpuBoundTo {
    private Long spuId;
    private BigDecimal buyBounds;
    private BigDecimal growBounds;
}

image.gif

common模块中新建common.to.SkuReductionTo用来做远程调用满减数据传输

@Data
public class SkuReductionTo {
    private Long skuId;
    private int fullCount;
    private BigDecimal discount;
    private int countStatus;
    private BigDecimal fullPrice;
    private BigDecimal reducePrice;
    private int priceStatus;
    private List<MemberPrice> memberPrice;
}

image.gif

common中新建MemberPrice

@Data
public class MemberPrice {
    private Long id;
    private String name;
    private BigDecimal price;
    
}

image.gif

2.引导类注解扫描远程调用的包

在GulimallProductApplication中注解feign包扫描

也可以不注解,默认也能扫描到。因为目前引导类和feign同级,都在product包下,可以扫描到。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.vince.gulimall.product.feign")
@EnableTransactionManagement
public class GulimallProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
        System.err.println("商品模块已启动");
    }
}

image.gif

3.product远程调用coupon服务保存积分和满减信息

SpuInfoServiceImpl中保存coupon模块的信息:

//5、保存spu的积分信息;gulimall_sms->sms_spu_bounds
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds,spuBoundTo);
        spuBoundTo.setSpuId(infoEntity.getId());
        R r = couponFeignService.saveSpuBounds(spuBoundTo);
        if(r.getCode() != 0){
            log.error("远程保存spu积分信息失败");
        }
image.gif
// //6.4)、sku的优惠、满减等信息;gulimall_sms->sms_sku_ladder\sms_sku_full_reduction\sms_member_price
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(item,skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                if(skuReductionTo.getFullCount() >0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1){
                    R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
                    if(r1.getCode() != 0){
                        log.error("远程保存sku优惠信息失败");
                    }
                }
image.gif

product模块的product.feign包新建CouponFeignService接口,用来远程调用Coupon服务。

一共调用了两个服务"coupon/spubounds/save""coupon/skufullreduction/saveInfo",即保存积分和满减:

@FeignClient("gulimall-coupon")
public interface CouponFeignService {
    /**
    *1、CouponFeginService.saveSpuBounds(spuBoudnTo);
     *  1)、@RequestBody 将这个对象转化为json
     *  2)、找到gulimall-coupon服务,给coupon/spubounds/save发送请求
     *      将上一步转的json放在请求体位置,发送数据
     *  3)、对方服务接受请求,请求体里面有json数据
     *      public R save(@RequestBody SpuBoundsEntity spuBounds);
     *      将请求体的json转化为SpuBoundsEntity;
     * 只要json数据模型是兼容的。双方无需使用同一个to
    *@param:[spuBoundTo]
    *@return:com.xmh.common.utils.R
    *@date: 2021/8/18 1:28
    */
    @PostMapping("coupon/spubounds/save")
    R saveSpuBounds(@RequestBody SpuBoundTo spuBoundTo);
    @PostMapping("coupon/skufullreduction/saveInfo")
    R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}

image.gif

在coupon模块的SkuFullReductionController中新建方法

@PostMapping("/saveInfo")
    public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
        skuFullReductionService.saveSkuReduction(skuReductionTo);
        return R.ok();
    }

image.gif

SkuFullReductionServiceImpl中实现

public void saveSkuReduction(SkuReductionTo reductionTo) {
        //1、// //5.4)、sku的优惠、满减等信息;gulimall_sms->sms_sku_ladder\sms_sku_full_reduction\sms_member_price
        //sms_sku_ladder
        SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
        skuLadderEntity.setSkuId(reductionTo.getSkuId());
        skuLadderEntity.setFullCount(reductionTo.getFullCount());
        skuLadderEntity.setDiscount(reductionTo.getDiscount());
        skuLadderEntity.setAddOther(reductionTo.getCountStatus());
        if(reductionTo.getFullCount() > 0){
            skuLadderService.save(skuLadderEntity);
        }
        //2、sms_sku_full_reduction
        SkuFullReductionEntity reductionEntity = new SkuFullReductionEntity();
        BeanUtils.copyProperties(reductionTo,reductionEntity);
        if(reductionEntity.getFullPrice().compareTo(new BigDecimal("0"))==1){
            this.save(reductionEntity);
        }
        //3、sms_member_price
        List<MemberPrice> memberPrice = reductionTo.getMemberPrice();
        List<MemberPriceEntity> collect=null;
        //坑点,空指针异常
        if(memberPrice!=null){
            collect = memberPrice.stream().map(item -> {
                MemberPriceEntity priceEntity = new MemberPriceEntity();
                priceEntity.setSkuId(reductionTo.getSkuId());
                priceEntity.setMemberLevelId(item.getId());
                priceEntity.setMemberLevelName(item.getName());
                priceEntity.setMemberPrice(item.getPrice());
                priceEntity.setAddOther(1);
                return priceEntity;
            }).filter(item->{
                return item.getMemberPrice().compareTo(new BigDecimal("0")) == 1;
            }).collect(Collectors.toList());
        }
        memberPriceService.saveBatch(collect);
    }

image.gif

common模块的R结果类加上获取状态码方法,方便判断远程调用是否成功

public Integer getCode(){
   return Integer.parseInt((String) this.get("code"));
}

image.gif

12.5、添加复合配置、限制内存

1、新建复合Compound

image.gif

image.gif

2、把服务添加到新建的compound里

image.gif

3、设置每个项目最大占用内存为100M

-Xmx100m

image.gif

image.gif

image.gif

4.设置compound命名后,点确定:

image.gif

5、启动或重启复合配置

image.gif

启动后此复合包含的六个模块就都会启动成功,如果有报错请看下一节报错解决。

image.gif

12.6、报错loadbalancer解决

如果product模块启动报错

No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?

image.gif

原因:SpringCloud Feign在Hoxton.M2 RELEASED版本之后抛弃了Ribbon,使用了spring-cloud-loadbalancer,所以我们这里还需要引入spring-cloud-loadbalancer的依赖,否则就会报错。

解决:

common模块的pom引入依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
            <version>3.1.4</version>
        </dependency>

image.gif

nacos里排除ribbon:

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

image.gif

12.7、商品保存debug、解决其他报错

如果自己网页没出意外,就重新点击保存商品,否则就重新发请求。

POST

http://localhost:88/api/product/spuinfo/save
image.gif

请求参数样式:

{
  "spuName": "Apple XR",
  "spuDescription": "Apple XR",
  "catalogId": 225,
  "brandId": 12,
  "weight": 0.048,
  "publishStatus": 0,
  "decript": ["https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-22//66d30b3f-e02f-48b1-8574-e18fdf454a32_f205d9c99a2b4b01.jpg"],
  "images": ["https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-22//dcfcaec3-06d8-459b-8759-dbefc247845e_5b5e74d0978360a1.jpg", "https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-22//5b15e90a-a161-44ff-8e1c-9e2e09929803_749d8efdff062fb0.jpg"],
  "bounds": {
    "buyBounds": 500,
    "growBounds": 6000
  },
  "baseAttrs": [{
    "attrId": 7,
    "attrValues": "aaa;bb",
    "showDesc": 1
  }, {
    "attrId": 8,
    "attrValues": "2019",
    "showDesc": 0
  }],
  "skus": [{
    "attr": [{
      "attrId": 9,
      "attrName": "颜色",
      "attrValue": "黑色"
    }, {
      "attrId": 10,
      "attrName": "内存",
      "attrValue": "6GB"
    }],
    "skuName": "Apple XR 黑色 6GB",
    "price": "1999",
    "skuTitle": "Apple XR 黑色 6GB",
    "skuSubtitle": "Apple XR 黑色 6GB",
    "images": [{
      "imgUrl": "https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-22//dcfcaec3-06d8-459b-8759-dbefc247845e_5b5e74d0978360a1.jpg",
      "defaultImg": 1
      }, {
      "imgUrl": "https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-22//5b15e90a-a161-44ff-8e1c-9e2e09929803_749d8efdff062fb0.jpg",
      "defaultImg": 0
    }],
    "descar": ["黑色", "6GB"],
    "fullCount": 5,
    "discount": 0.98,
    "countStatus": 1,
    "fullPrice": 1000,
    "reducePrice": 10,
    "priceStatus": 0,
    "memberPrice": [{
      "id": 1,
      "name": "aaa",
      "price": 1998.99
    }]
    }, {
    "attr": [{
      "attrId": 9,
      "attrName": "颜色",
      "attrValue": "黑色"
    }, {
      "attrId": 10,
      "attrName": "内存",
      "attrValue": "12GB"
    }],
    "skuName": "Apple XR 黑色 12GB",
    "price": "2999",
    "skuTitle": "Apple XR 黑色 12GB",
    "skuSubtitle": "Apple XR 黑色 6GB",
    "images": [{
      "imgUrl": "",
      "defaultImg": 0
    }, {
      "imgUrl": "",
      "defaultImg": 0
    }],
    "descar": ["黑色", "12GB"],
    "fullCount": 0,
    "discount": 0,
    "countStatus": 0,
    "fullPrice": 0,
    "reducePrice": 0,
    "priceStatus": 0,
    "memberPrice": [{
      "id": 1,
      "name": "aaa",
      "price": 1998.99
    }]
  }, {
    "attr": [{
      "attrId": 9,
      "attrName": "颜色",
      "attrValue": "白色"
    }, {
      "attrId": 10,
      "attrName": "内存",
      "attrValue": "6GB"
    }],
    "skuName": "Apple XR 白色 6GB",
    "price": "1998",
    "skuTitle": "Apple XR 白色 6GB",
    "skuSubtitle": "Apple XR 黑色 6GB",
    "images": [{
      "imgUrl": "",
      "defaultImg": 0
    }, {
      "imgUrl": "",
      "defaultImg": 0
    }],
    "descar": ["白色", "6GB"],
    "fullCount": 0,
    "discount": 0,
    "countStatus": 0,
    "fullPrice": 0,
    "reducePrice": 0,
    "priceStatus": 0,
    "memberPrice": [{
      "id": 1,
      "name": "aaa",
      "price": 1998.99
    }]
  }, {
    "attr": [{
      "attrId": 9,
      "attrName": "颜色",
      "attrValue": "白色"
    }, {
      "attrId": 10,
      "attrName": "内存",
      "attrValue": "12GB"
    }],
    "skuName": "Apple XR 白色 12GB",
    "price": "2998",
    "skuTitle": "Apple XR 白色 12GB",
    "skuSubtitle": "Apple XR 黑色 6GB",
    "images": [{
      "imgUrl": "",
      "defaultImg": 0
    }, {
      "imgUrl": "",
      "defaultImg": 0
    }],
    "descar": ["白色", "12GB"],
    "fullCount": 0,
    "discount": 0,
    "countStatus": 0,
    "fullPrice": 0,
    "reducePrice": 0,
    "priceStatus": 0,
    "memberPrice": [{
      "id": 1,
      "name": "aaa",
      "price": 1998.99
    }]
  }]
}
image.gif

1、保存基本信息断点调试通过

由于函数是个事务,而数据库默认读出已经提交了的数据,所以用如下命令设置隔离级别,以方便查看数据库变化

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

image.gif

image.gif

第一步保存基本信息成功。

2、SpuInfoDesc报错

image.gif

报错原因:表的id设计不是自增的,保存SpuInfoDesc时mybatisplus默认主键策略自增,这里要改变主键策略为input:

image.gif

image.gif

报错解决:mybatis默认主键为自增的,而SpuInfoDescEntity中的主键为自己输入的,所以修改主键注释

@TableId(type = IdType.INPUT)
  private Long spuId;

image.gif

image.gif

3、结果类R响应码类型报错

抛出异常,修改R中的getCode方法

按我博客上面一节里设置R的getCode方法不会此步报错。

image.gif

public Integer getCode(){
    return (Integer) this.get("code");
  }

image.gif

4、保存空图片问题

image.gif

image.gif

出现问题,保存sku图片时,有些图片是没有路径的,没有路径的图片,无需保存。

在6.2图片map处理后、收集前进行filter过滤

List<SkuImagesEntity> skuImagesEntities = item.getImages().stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).filter(entity -> {
                    //返回true是需要,返回false是过滤掉
                    return !StringUtils.isNullOrEmpty(entity.getImgUrl());
                }).collect(Collectors.toList());
                skuImagesService.saveBatch(skuImagesEntities);

image.gif

//6.2、sku的图片信息`pms_sku_images`。skus列表里的每个item的图片列表赋值给pms_sku_images实体类列表
                Long skuId = skuInfoEntity.getSkuId();
                List<SkuImagesEntity> skuImagesEntities = item.getImages().stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).filter(entity -> {
                    //返回true是需要,返回false是过滤掉
                    return !StringUtils.isNullOrEmpty(entity.getImgUrl());
                }).collect(Collectors.toList());
                skuImagesService.saveBatch(skuImagesEntities);

image.gif

5、保存折扣信息的时候,满0元打0折这种都是无意义的,要过滤掉

image.gif

解决方法:在保存之前做判断,过滤掉小于等于0的无意义信息(不贴代码了),要注意的是判断BigDecimal进行判断时,要用compareTo函数。

例:

if (skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1){
                    R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
                    if (r1.getCode() != 0){
                        log.error("远程保存优惠信息失败");
                    }
                }

image.gif

6、保存满减时product模块远程调用报错500,coupon模块报错空指针异常

image.gif


相关文章
|
4月前
|
XML JSON API
怎样获取抖音店铺的所有商品 API 返回值说明
1688` 是阿里巴巴旗下的一个 B2B(Business-to-Business)电商平台,专注于为企业提供批发和采购服务。`1688` 商品详情 API 是指从阿里巴巴中国站获取商品详细信息的接口。这个 API 通常需要开发者在阿里巴巴开放平台上注册并获取相应的 API 密钥(AppKey 和 AppSecret)才能使用。
|
XML JSON 缓存
Json实现根据商品ID请求微店商品详情数据方法,微店商品详情API接口,微店API接口申请指南
Json实现根据商品ID请求微店商品详情数据方法,微店商品详情API接口,微店API接口申请指南
|
4天前
|
SQL 设计模式 开发框架
谷粒商城笔记+踩坑(6)——商品服务-属性及其关联分组
商品规格属性和销售属性的增删改查、属性分组中查询新增关联的属性
谷粒商城笔记+踩坑(6)——商品服务-属性及其关联分组
|
4天前
|
存储 自然语言处理 关系型数据库
谷粒商城笔记+踩坑(9)——上架商品spu到ES索引库
ES回顾、【查询模块】保存ES文档、【库存模块】库存量查询、【商品模块】上架单个spu
谷粒商城笔记+踩坑(9)——上架商品spu到ES索引库
|
4天前
|
XML 前端开发 Java
谷粒商城笔记+踩坑(5)——商品服务-属性分组、品牌关联分类,spu+sku+分页拦截器
SPU和SKU、属性分组的增删改查、QueryWrapper的and和or用法、获取当前品牌关联的所有分类
谷粒商城笔记+踩坑(5)——商品服务-属性分组、品牌关联分类,spu+sku+分页拦截器
|
4天前
|
存储 前端开发 Java
谷粒商城笔记+踩坑(4)——商品服务-品牌管理,阿里云云存储+JSR303数字校验+统一异常处理
商品服务-品牌管理、添加“品牌管理”到人人后台管理系统、前端显示状态开关、阿里云云存储实现文件上传、异常处理类、JSR303数字校验、分组校验、自定义校验
谷粒商城笔记+踩坑(4)——商品服务-品牌管理,阿里云云存储+JSR303数字校验+统一异常处理
|
4天前
|
存储 前端开发 Java
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
首先搭建页面环境,然后介绍整合Spring Session的相关内容,并将用户信息放到session里,多线程优化,完成订单模块的功能、登录拦截等功能的实现
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
|
3月前
|
前端开发 JavaScript Python
Django项目之电商购物商城 -- 新增收货地址
Django项目之电商购物商城 -- 新增收货地址
|
1月前
|
供应链 数据挖掘 Java
微店商品列表接口详解与实战应用
微店商品列表数据接口是专为开发者设计的API,允许调用微店店铺所有商品数据。接口(如micro.item_search_shop,具体名称需确认)提供商品ID、标题、价格等信息,支持商品展示、数据分析及库存管理等功能。开发者须在微店开放平台注册并创建应用获取API凭证,构建HTTP请求调用接口,处理返回的商品数据。此接口有助于优化购物体验,提供数据支持。[体验API:b.mrw.so/2Pv6Qu]
|
2月前
|
XML JSON API
开发者必备:淘宝商品列表接口集成全攻略
淘宝开放平台提供的商品列表数据接口让开发者编程获取商品列表数据。接口支持按关键词、类目等查询条件获取商品详情,包括标题、价格等信息。具备灵活性高、数据丰富及操作便捷等特点。使用流程包括注册账号、构建并发送HTTP请求及处理响应数据。可用于电商数据分析、商品推荐等场景。开发者需遵守规定确保数据安全合法。[体验API](c0b.cc/R4rbK2)