一、发布商品
1.1 获取所有会员等级
配置gateway的路由转发规则,这里我设置了gateway直接从nacos中动态获取配置,以免每次加个路由规则,每次都要重启网关。(路由规则也同步加在了本地application.yml中,nacos中配置文件为route.yaml)
- id: member_route
uri: lb://gulimall-member
predicates:
- Path=/api/gulimallmember/**
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
*解决点击发布商品—不发送请求问题
点击发布商品菜单时,前端应该向后台发送如下请求:
但我这里没有。
解决方法:npm install --save pubsub-js
然后在src下的main.js中导入
import PubSub from 'pubsub-js'
Vue.prototype.PubSub = PubSub
1.2 获取分类关联的品牌
在添加SPU信息时,选择分类后会发送请求,查询当前分类下的品牌信息。
http://localhost:88/api/gulimallproduct/categorybrandrelation/brands/list?t=1646998496895&catId=225
Controller只用于处理请求、接收和校验数据
Service接收Controller传来的数据,进行业务处理
Controller接收Service处理完的数据,封装成页面指定VO
package com.atguigu.gulimall.gulimallproduct.vo;
import lombok.Data;
@Data
public class BrandVo {
private Long brandId;
private String brandName;
}
/**
* 获取当前分类对应的所有品牌
*/
// /product/categorybrandrelation/brands/list
@GetMapping("/brands/list")
public R relationBrandsList(@RequestParam(value = "catId") Long catId) {
List<BrandEntity> brands = categoryBrandRelationService.getBrands(catId);
List<BrandVo> collect = brands.stream().map((brandEntity -> {
BrandVo brandVo = new BrandVo();
brandVo.setBrandId(brandEntity.getBrandId());
brandVo.setBrandName(brandEntity.getName());
return brandVo;
})).collect(Collectors.toList());
return R.ok().put("data", collect);
}
声明&实现
@Autowired
CategoryBrandRelationDao categoryBrandRelationDao;
@Autowired
BrandService brandService;
/**
* 获取指定分类对应的所有品牌
* @param catId
*/
@Override
public List<BrandEntity> getBrands(Long catId) {
// 1 通过分类id取出当前分类与品牌关联的所有记录 查`pms_category_brand_relation`表
List<CategoryBrandRelationEntity> categoryBrandRelationEntities = categoryBrandRelationDao.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
// 2 通过查出来的关联记录,获取每条记录的品牌id,再通过品牌id查询品牌
List<BrandEntity> brandEntityList = categoryBrandRelationEntities.stream().map((item) -> {
Long brandId = item.getBrandId();
BrandEntity brand = brandService.getById(brandId);
return brand;
}).collect(Collectors.toList());
return brandEntityList;
}
1.3 获取分类下所有属性分组&关联属性
发布商品在设置规格参数的时候,会向后台发送请求,查询当前分类下对应的所有属性分组以及关联属性。
https://easydoc.net/s/78237135/ZUqEdvA4/6JM6txHf
1、查出当前catelogId对应分类下的所有属性分组
2、查出每个分组的所有关联属性
新建一个vo类,存放需要返回的数据
package com.atguigu.gulimall.gulimallproduct.vo;
import com.atguigu.gulimall.gulimallproduct.entity.AttrEntity;
import lombok.Data;
import java.util.List;
@Data
public class AttrGroupWithAttrsVo {
/**
* 分组id
*/
private Long attrGroupId;
/**
* 组名
*/
private String attrGroupName;
/**
* 排序
*/
private Integer sort;
/**
* 描述
*/
private String descript;
/**
* 组图标
*/
private String icon;
/**
* 所属分类id
*/
private Long catelogId;
/**
* 所关联的所有属性
*/
private List<AttrEntity> attrs;
}
/**
* 获取当前分类下所有的属性分组&关联属性
*/
// /product/attrgroup/{catelogId}/withattr
@GetMapping("/{catelogId}/withattr")
public R getAttrGroupWithAttr(@PathVariable("catelogId") Long catelogId) {
// 1、查出当前catelogId对应分类下的所有属性分组
// 2、查出每个分组的所有关联属性
List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrByCatelogId(catelogId);
return R.ok().put("data", vos);
}
声明&实现
/**
* 根据分类id(catelogId)查询当前分类下所有的属性分组&关联属性
* @param catelogId
* @return
*/
@Override
public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrByCatelogId(Long catelogId) {
// 1、查询分组信息
// 根据catelogId在`pms_attr_group`中查到分组信息
List<AttrGroupEntity> attrGroupEntities = this.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
// 将查到的分组基本信息放到AttrGroupWithAttrsVo对象中
List<AttrGroupWithAttrsVo> groupWithAttrsVos = attrGroupEntities.stream().map((item) -> {
AttrGroupWithAttrsVo attrGroupWithAttrsVo = new AttrGroupWithAttrsVo();
BeanUtils.copyProperties(item, attrGroupWithAttrsVo);
// 2、查询分组关联所有属性
// 之前在AttrService中写过通过attrGroupId查询关联的全部属性,直接调用
List<AttrEntity> relationAttr = attrService.getRelationAttr(item.getAttrGroupId());
attrGroupWithAttrsVo.setAttrs(relationAttr);
return attrGroupWithAttrsVo;
}).collect(Collectors.toList());
return groupWithAttrsVos;
}
1.4 新增商品
设置销售属性
在设置好规格销售属性和SKU信息后,点击下一步。
可以发现浏览器控制台打印了一长串JSON数据,这个就是我们提交给后台需要保存的数据。
1.4.1 JSON生成JAVA实体类
浏览器控制台打印了一长串json数据,复制,使用在线JSON生成JAVA实体类。在线JSON生成JAVA实体类
修改实体类,将id有关属性设置为Long类型,价格有关属性设置为BigDecimal类型;删除get/set方法使用@Data注解。
1.4.2 实现业务逻辑
这里的逻辑比较复杂,涉及到gulimall_pms(product)和gulimall_sms(coupon)中多张表的保存。获取到的SpuSaveVo包含了许多信息,通过以下6步将其信息保存到数据库中(这里强烈建议好好看看每张表里面到底有什么属性)
- 保存spu基本信息 pms_spu_info
- 保存spu的描述图片 pms_spu_info_desc
- 保存spu的图片集 pms_spu_images
- 保存spu的规格参数 pms_product_attr_value
- 保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
- 保存当前spu对应的所有sku信息
- 保存sku的基本信息 pms_sku_info
- 保存sku的图片信息 pms_sku_images
- 保存sku的销售属性信息 pms_sku_sale_attr_value
- 保存sku的优惠、满减等信息 gulimall_sms(sms_sku_ladder/sms_sku_full_reduction/sms_member_price)
其中保存积分信息和优惠满减信息都需要远程调用coupon服务。
/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("gulimallproduct:spuinfo:save")
public R save(@RequestBody SpuSaveVo vo){
// spuInfoService.save(spuInfo);
spuInfoService.saveSpuInfo(vo);
return R.ok();
}
service声明&实现(没有实现远程调用)。
@Autowired
SpuInfoDescService infoDescService;
@Autowired
SpuImagesService spuImagesService;
@Autowired
ProductAttrValueService attrValueService;
@Autowired
AttrService attrService;
@Autowired
SkuInfoService skuInfoService;
@Autowired
SkuImagesService skuImagesService;
@Autowired
SkuSaleAttrValueService skuSaleAttrValueService;
@Autowired
CouponFeignService couponFeignService;
@Transactional
@Override
public void saveSpuInfo(SpuSaveVo vo) {
@Transactional
@Override
public void saveSpuInfo(SpuSaveVo vo) {
//1、保存spu基本信息 pms_spu_info
SpuInfoEntity spuInfo = new SpuInfoEntity();
BeanUtils.copyProperties(vo, spuInfo);
spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
//this.save(spuInfo); // 为啥不直接使用自带的save方法?
this.saveBaseInfo(spuInfo);
//2、保存spu的描述图片 pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
descEntity.setDecript(String.join(",", decript));
// infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
infoDescService.saveSpuInfoDesc(descEntity);
//3、保存spu的图片集 pms_spu_images
List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
//4、保存spu的规格参数 pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
productAttrValueEntity.setAttrId(item.getAttrId());
AttrEntity attrEntity = attrService.getById(item.getAttrId());
productAttrValueEntity.setAttrName(attrEntity.getAttrName());
productAttrValueEntity.setAttrValue(item.getAttrValues());
productAttrValueEntity.setQuickShow(item.getShowDesc());
productAttrValueEntity.setSpuId(spuInfo.getId());
return productAttrValueEntity;
}).collect(Collectors.toList());
// attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
//5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
// coupon有一个SpuBoundsController
// 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
//6、保存当前spu对应的所有sku信息
// 从vo中获取提交的所有sku
List<Skus> skus = vo.getSkus();
if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
//6.1 保存sku的基本信息 pms_sku_info
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
// 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
BeanUtils.copyProperties(item, skuInfoEntity);
skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
skuInfoEntity.setSaleCount(0L); // saleCount
skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
// 寻找每个sku的默认图片
String defaultImag = "";
for (Images image : item.getImages()) {
// 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
if (image.getDefaultImg() == 1) {
defaultImag = image.getImgUrl();
}
}
skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
//skuInfoService.save(skuInfoEntity);
skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
//6.2 保存sku的图片信息 pms_sku_images
// sku_id img_url default_img
Long skuId = skuInfoEntity.getSkuId();
// 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
// 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(im.getImgUrl());
skuImagesEntity.setDefaultImg(im.getDefaultImg());
return skuImagesEntity;
}).collect(Collectors.toList());
skuImagesService.saveBatch(skuImagesEntityList);
//6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
// sku_id attr_id attr_name attr_value attr_sort
List<Attr> attr = item.getAttr();
List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(a, saleAttrValue);
saleAttrValue.setSkuId(skuId);
return saleAttrValue;
}).collect(Collectors.toList());
skuSaleAttrValueService.saveBatch(attrValueEntities);
//6.4 保存sku的优惠、满减等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 这里需要远程调用 gulimall-coupon服务
});
}
}
/**
* 保存spu的基本信息
*
* @param spuInfo
*/
@Override
public void saveBaseInfo(SpuInfoEntity spuInfo) {
this.baseMapper.insert(spuInfo);
}
}
/**
* 保存spu的描述信息
* @param descEntity
*/
@Override
public void saveSpuInfoDesc(SpuInfoDescEntity descEntity) {
this.baseMapper.insert(descEntity);
}
/**
* 保存spu的图片信息
* @param id
* @param images
*/
@Override
public void saveImages(Long id, List<String> images) {
if (!CollectionUtils.isEmpty(images)) {
List<SpuImagesEntity> spuImagesEntityList = images.stream().map((image) -> {
SpuImagesEntity spuImagesEntity = new SpuImagesEntity();
spuImagesEntity.setSpuId(id);
spuImagesEntity.setImgName(image);
return spuImagesEntity;
}).collect(Collectors.toList());
this.saveBatch(spuImagesEntityList);
}
}
@Override
public void saveProductAttr(List<ProductAttrValueEntity> attrValueEntityList) {
this.saveBatch(attrValueEntityList);
}
@Override
public void saveSkuInfo(SkuInfoEntity skuInfoEntity) {
this.baseMapper.insert(skuInfoEntity);
}
远程调用回顾
可以回看之前远程调用的笔记:https://www.yuque.com/mrlinxi/pxvr4g/rdcgap#ijC15
- 调用方Service编写一个接口,告诉SpringCloud这个接口需要调用远程服务(一般会放在feign这个包下),会使用到@FeignClient(“需要调用的微服务名”)注解
- 这里定义方法接口的方法签名一定要(不一样也可以)和微服务提供者的Controller中调用的方法签名(最好直接复制controller里面的方法)一致。
- 如果需要传递参数,那么
@RequestParam
和@RequestBody
@PathVariable
等不能省略,必需加。
- Controller层定义一个与Service层对应的方法
- 调用方在主启动类开启远程调用功能 @EnableFeignClient(basePackages=”包路径”)—默认扫描默认会扫描注解所在包的当前包以及子包下的@FeignCilent。
将所有需要远程调用的Service接口都写在feign包下。
product主启动类加上@EnableFeignClients注解,并指明包路径
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(value = "com.atguigu.gulimall.gulimallproduct.dao")
@EnableFeignClients(basePackages = "com.atguigu.gulimall.gulimallproduct.feign")
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
保存spu积分信息远程调用
我们需要将spu_id grow_bounds buy_bounds 传输到gulimall-coupon服务,让其存储到gulimall_sms->sms_spu_bounds表中。
现在product服务要给coupon传输数据,我们可以将这些数据封装成一个对象。在SpringCloud中,会默认把封装的这个对象转成JSON数据进行传输,那么coupon服务会收到一个JSON数据。
那么我们可以在common的to包下中定义一个TO(数据传输对象——用于不同的应用程序之间传输)
@Data
public class SpuBoundsTo {
private Long spuId;
/**
* 成长积分
*/
private BigDecimal growBounds;
/**
* 购物积分
*/
private BigDecimal buyBounds;
}
修改gulimall-coupon的SpuBoundsController,将/save请求对应的方法改成@PostMapping
/**
* 保存
*/
@PostMapping("/save")
//@RequiresPermissions("gulimallcoupon:spubounds:save")
public R save(@RequestBody SpuBoundsEntity spuBounds){
spuBoundsService.save(spuBounds);
return R.ok();
}
gulimall-product的feign包下,创建一个Service接口,用于远程调用coupon服务。
注意:@PostMapping注解中一定要写完整的请求路径(SpuBoundsController的类路径+方法路径)
package com.atguigu.gulimall.gulimallproduct.feign;
import com.atguigu.common.to.SpuBoundsTo;
import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
/**
* CouponFeignService.saveSpuBounds(spuBoundsTo) 调用方法,传了一个对象
* 1)有@RequestBody注解 会将这个对象转为Json
* 2)找到gulimall-coupon服务,给服务发送/gulimallcoupon/spubounds/save,将上一步转的Json放在请求体位置,发送请求
* 3)对方服务收到请求,收到了请求体中的Json数据
* (@RequestBody SpuBoundsEntity spuBounds) :将请求体中的Json转成SpuBoundsEntity
* 前提是spuBoundsTo中的属性名与SpuBoundsEntity中属性名能对应(spuBoundsTo的属性名是SpuBoundsEntity属性名的子集)
* 只要Json数据模型时兼容的,双方服务无需使用同一个to入参
* @param spuBoundsTo
* @return
*/
@PostMapping("/gulimallcoupon/spubounds/save")
R saveSpuBounds(@RequestBody SpuBoundsTo spuBoundsTo);
}
这里我们发现CouponFeignService中方法的入参与SpuBoundsController中对应的方法名以及入参不一致。
方法名不一致其实并不影响调用,只是平时为了方便,直接将需要调用的额方法签名复制过来。
这里着重讲一下,为什么入参可以不同:
CouponFeignService.saveSpuBounds(spuBoundsTo) 调用方法,传了一个对象,这个对象是SpuBoundsTo类,传输流程:
- 有@RequestBody注解 会将这个对象转为Json
- 找到gulimall-coupon服务,给服务发送/gulimallcoupon/spubounds/save,将上一步转的Json放在请求体位置,发送请求
- 对方服务收到请求,收到了请求体中的Json数据
- (@RequestBody SpuBoundsEntity spuBounds) :将请求体中的Json转成SpuBoundsEntity
- a的前提是spuBoundsTo中的属性名与SpuBoundsEntity中属性名能对应(spuBoundsTo的属性名是SpuBoundsEntity属性名的子集)
总结:只要Json数据模型时兼容的,双方服务无需使用同一个to入参
SpuInfoServiceImpl中调用(这里只展示了代码片段,完整版看后面)
//5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
// coupon有一个SpuBoundsController
// 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
BeanUtils.copyProperties(bounds, spuBoundsTo);
spuBoundsTo.setSpuId(spuInfo.getId());
couponFeignService.saveSpuBounds(spuBoundsTo);
保存sku的优惠、满减等信息
common中新建一个SkuReductionTo to类
@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;
}
CouponFeignService,声明调用gulimall-coupon的方法
@PostMapping("/gulimallcoupon/skufullreduction/saveinfo")
R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
gulimall-coupon SkuFullReductionController中创建对应方法
@PostMapping("/saveinfo")
//@RequiresPermissions("gulimallcoupon:skufullreduction:list")
public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
skuFullReductionService.saveSkuReduction(skuReductionTo);
return R.ok();
}
声明&实现
@Autowired
SkuLadderService skuLadderService;
@Autowired
MemberPriceService memberPriceService;
@Override
public void saveSkuReduction(SkuReductionTo skuReductionTo) {
// 6.4 保存sku的优惠、满减、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 1、保存数量满减打折优惠信息 sms_sku_ladder (sku_id full_count discount price add_other)
SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
skuLadderEntity.setSkuId(skuReductionTo.getSkuId()); // skuId
skuLadderEntity.setFullCount(skuReductionTo.getFullCount()); //满几件
skuLadderEntity.setDiscount(skuReductionTo.getDiscount()); // 打几折
skuLadderEntity.setAddOther(skuReductionTo.getCountStatus()); // 是否与其他优惠叠加
skuLadderService.save(skuLadderEntity);
// 2、保存 满多少金额,减多少钱 优惠信息
// sms_sku_full_reduction (sku_id full_price reduce_price add_other)
SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
BeanUtils.copyProperties(skuReductionTo, skuFullReductionEntity); // 传过来的对象包含了金额满减的信息,且属性名对应直接copy
this.save(skuFullReductionEntity);
// 3、保存 会员价格
// sms_member_price (sku_id member_level_id member_level_name member_price add_other)
List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice(); // 获取当前sku不同会员价格信息
List<MemberPriceEntity> memberPriceEntities = memberPrice.stream().map(member -> {
MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
memberPriceEntity.setSkuId(skuReductionTo.getSkuId()); // 获取skuId
memberPriceEntity.setMemberLevelId(member.getId()); // 获取会员等级Id
memberPriceEntity.setMemberLevelName(member.getName()); // 获取会员等级名
memberPriceEntity.setMemberPrice(member.getPrice()); // 会员价格
memberPriceEntity.setAddOther(1); // 是否可与其他优惠叠加
return memberPriceEntity;
}).collect(Collectors.toList());
memberPriceService.saveBatch(memberPriceEntities);
}
在SpuInfoServiceImpl中调用,这里只展示了针对当前业务的代码片段,最终完整代码看后面
//6.4 保存sku的优惠、满减会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 这里需要远程调用 gulimall-coupon服务
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
couponFeignService.saveSkuReduction(skuReductionTo);
其他改动
远程调用之后我们需要验证一下是否成功。在R中新增一个获得code的方法(R继承了HashMap)
public Integer getCode() {
return Integer.parseInt((String) this.get("code"));
}
分别在SpuInfoServiceImpl里两个远程调用的地方判断一下是否成功。
SpuInfoServiceImpl全部实现
@Transactional
@Override
public void saveSpuInfo(SpuSaveVo vo) {
//1、保存spu基本信息 pms_spu_info
SpuInfoEntity spuInfo = new SpuInfoEntity();
BeanUtils.copyProperties(vo, spuInfo);
spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
//this.save(spuInfo); // 为啥不直接使用自带的save方法?
this.saveBaseInfo(spuInfo);
//2、保存spu的描述图片 pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
descEntity.setDecript(String.join(",", decript));
// infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
infoDescService.saveSpuInfoDesc(descEntity);
//3、保存spu的图片集 pms_spu_images
List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
//4、保存spu的规格参数 pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
productAttrValueEntity.setAttrId(item.getAttrId());
AttrEntity attrEntity = attrService.getById(item.getAttrId());
productAttrValueEntity.setAttrName(attrEntity.getAttrName());
productAttrValueEntity.setAttrValue(item.getAttrValues());
productAttrValueEntity.setQuickShow(item.getShowDesc());
productAttrValueEntity.setSpuId(spuInfo.getId());
return productAttrValueEntity;
}).collect(Collectors.toList());
// attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
//5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
// coupon有一个SpuBoundsController
// 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
BeanUtils.copyProperties(bounds, spuBoundsTo);
spuBoundsTo.setSpuId(spuInfo.getId());
R r = couponFeignService.saveSpuBounds(spuBoundsTo);
if (r.getCode() != 0) {
log.error("远程调用gulimall-coupon保存spu的积分信息失败...............");
}
//6、保存当前spu对应的所有sku信息
// 从vo中获取提交的所有sku
List<Skus> skus = vo.getSkus();
if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
//6.1 保存sku的基本信息 pms_sku_info
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
// 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
BeanUtils.copyProperties(item, skuInfoEntity);
skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
skuInfoEntity.setSaleCount(0L); // saleCount
skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
// 寻找每个sku的默认图片
String defaultImag = "";
for (Images image : item.getImages()) {
// 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
if (image.getDefaultImg() == 1) {
defaultImag = image.getImgUrl();
}
}
skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
//skuInfoService.save(skuInfoEntity);
skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
//6.2 保存sku的图片信息 pms_sku_images
// sku_id img_url default_img
Long skuId = skuInfoEntity.getSkuId();
// 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
// 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(im.getImgUrl());
skuImagesEntity.setDefaultImg(im.getDefaultImg());
return skuImagesEntity;
}).collect(Collectors.toList());
skuImagesService.saveBatch(skuImagesEntityList);
//6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
// sku_id attr_id attr_name attr_value attr_sort
List<Attr> attr = item.getAttr();
List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(a, saleAttrValue);
saleAttrValue.setSkuId(skuId);
return saleAttrValue;
}).collect(Collectors.toList());
skuSaleAttrValueService.saveBatch(attrValueEntities);
//6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 这里需要远程调用 gulimall-coupon服务
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if (r1.getCode() != 0) {
log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
}
});
}
}
1.4.3 测试
因为微服务很多,所以可以设置一下每个服务的内存占用。创建一个Compound,将需要频繁重启的服务加进去,就可以批量重启。再设置每个微服务最大占用内存
以debug模式启动product服务,前端提交数据
先报存spu的基本信息,查看数据库,发现并没有保存。这是因为我们开启了事务,而Mysql的默认事务隔离级别是可重复读。
我们设置一下mysql的隔离界别为读未提交:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
现在pms_spu_info表中可以看到spu的信息
视频里在pms_spu_info_desc表中新建记录的时候报错(我实操没有报错),因为pms_spu_info_desc表中的spuId不是自增主键,而是手动进行输入的,所以需要修改SpuInfoDescEntity的spuId属性:
因为我用的nacos2.0.3,注册跟配置都没有问题,结果在远程调用的时候报错。这个没有找到解决方法(重启nacos就好了。。。。)
ERROR 24636 —- [t.remote.worker] c.a.n.c.remote.client.grpc.GrpcClient : Server check fail, please check server localhost ,port 9848 is available , error ={}
远程超时问题:在product设置一下超时时间
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接后从服务器读取到可用资源所用的时间 ms
ReadTimeout: 5000
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ms
ConnectTimeout: 5000
sku_images中保存了没有选中的图片:(TODO没有图片路径的无须保存)
同样,满减信息里面满0元减0元,满0件不打折也都不需要存储。
出现这个错误是因为我们在后台debug的时间太长,超时了。
spu_bounds表没有回滚
sku_images不保存没有图片路径的信息
通过filter函数式接口过滤
//6.2 保存sku的图片信息 pms_sku_images
// sku_id img_url default_img
Long skuId = skuInfoEntity.getSkuId();
// 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
// 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(im.getImgUrl());
skuImagesEntity.setDefaultImg(im.getDefaultImg());
return skuImagesEntity;
}).filter(emtity -> {
// filter中,返回true就是保留,返回false就是剔除
return !StringUtils.isEmpty(emtity.getImgUrl());
}).collect(Collectors.toList());
skuImagesService.saveBatch(skuImagesEntityList);
满减信息过滤
在保存sku优惠信息的时候,只需要保存存在的件数折扣、金额满减、会员价格。所以需要一个判断。(视频里面没有hashMemberPrice,会导致当没有件数折扣和金额满减时无法保存会员信息)
最开是我给hashMemberPrice传的是skuReductionTo.getMemberPrice() 但是一直报类型转换异常,没办法只能传Item的MemberPrice了。
//6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 这里需要远程调用 gulimall-coupon服务
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
// 当存在多件打折信息或者金额满减信息时,满减信息才会保存,同时需要考虑没有满减信息但存在会员价格的情况
if (hasMemberPrice(item.getMemberPrice()) || skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) {
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if (r1.getCode() != 0) {
log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
}
}
/**
* 判断会员价格是否存在
* @param memberPrices
* @return
*/
private boolean hasMemberPrice(List<com.atguigu.gulimall.gulimallproduct.vo.spu.MemberPrice> memberPrices) {
for (com.atguigu.gulimall.gulimallproduct.vo.spu.MemberPrice memberPrice : memberPrices) {
if (memberPrice.getPrice().compareTo(BigDecimal.ZERO) > 0) return true;
}
return false;
}
修改后的代码
这里修改主要是针对优惠信息的bug进行修改。
@Transactional
@Override
public void saveSpuInfo(SpuSaveVo vo) {
//1、保存spu基本信息 pms_spu_info
SpuInfoEntity spuInfo = new SpuInfoEntity();
BeanUtils.copyProperties(vo, spuInfo);
spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
//this.save(spuInfo); // 为啥不直接使用自带的save方法?
this.saveBaseInfo(spuInfo);
//2、保存spu的描述图片 pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
descEntity.setDecript(String.join(",", decript));
// infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
infoDescService.saveSpuInfoDesc(descEntity);
//3、保存spu的图片集 pms_spu_images
List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
//4、保存spu的规格参数 pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
productAttrValueEntity.setAttrId(item.getAttrId());
AttrEntity attrEntity = attrService.getById(item.getAttrId());
productAttrValueEntity.setAttrName(attrEntity.getAttrName());
productAttrValueEntity.setAttrValue(item.getAttrValues());
productAttrValueEntity.setQuickShow(item.getShowDesc());
productAttrValueEntity.setSpuId(spuInfo.getId());
return productAttrValueEntity;
}).collect(Collectors.toList());
// attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
//5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
// coupon有一个SpuBoundsController
// 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
BeanUtils.copyProperties(bounds, spuBoundsTo);
spuBoundsTo.setSpuId(spuInfo.getId());
R r = couponFeignService.saveSpuBounds(spuBoundsTo);
if (r.getCode() != 0) {
log.error("远程调用gulimall-coupon保存spu的积分信息失败...............");
}
//6、保存当前spu对应的所有sku信息
// 从vo中获取提交的所有sku
List<Skus> skus = vo.getSkus();
if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
//6.1 保存sku的基本信息 pms_sku_info
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
// 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
BeanUtils.copyProperties(item, skuInfoEntity);
skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
skuInfoEntity.setSaleCount(0L); // saleCount
skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
// 寻找每个sku的默认图片
String defaultImag = "";
for (Images image : item.getImages()) {
// 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
if (image.getDefaultImg() == 1) {
defaultImag = image.getImgUrl();
}
}
skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
//skuInfoService.save(skuInfoEntity);
skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
//6.2 保存sku的图片信息 pms_sku_images
// sku_id img_url default_img
Long skuId = skuInfoEntity.getSkuId();
// 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
// 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(im.getImgUrl());
skuImagesEntity.setDefaultImg(im.getDefaultImg());
return skuImagesEntity;
}).filter(emtity -> {
// filter中,返回true就是保留,返回false就是剔除
return !StringUtils.isEmpty(emtity.getImgUrl());
}).collect(Collectors.toList());
skuImagesService.saveBatch(skuImagesEntityList);
//6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
// sku_id attr_id attr_name attr_value attr_sort
List<Attr> attr = item.getAttr();
List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(a, saleAttrValue);
saleAttrValue.setSkuId(skuId);
return saleAttrValue;
}).collect(Collectors.toList());
skuSaleAttrValueService.saveBatch(attrValueEntities);
//6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 这里需要远程调用 gulimall-coupon服务
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
// 当存在多件打折信息或者金额满减信息时,满减信息才会保存,同时需要考虑没有满减信息但存在会员价格的情况
if (hasMemberPrice(item.getMemberPrice()) || skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) {
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if (r1.getCode() != 0) {
log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
}
}
});
}
}
@Override
public void saveSkuReduction(SkuReductionTo skuReductionTo) {
// 6.4 保存sku的优惠、满减、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 1、保存数量满减打折优惠信息 sms_sku_ladder (sku_id full_count discount price add_other)
SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
if (skuReductionTo.getFullCount() > 0) { // 存在数量满减才保存
skuLadderEntity.setSkuId(skuReductionTo.getSkuId()); // skuId
skuLadderEntity.setFullCount(skuReductionTo.getFullCount()); //满几件
skuLadderEntity.setDiscount(skuReductionTo.getDiscount());
skuLadderEntity.setAddOther(skuReductionTo.getCountStatus()); // 是否与其他优惠叠加
skuLadderService.save(skuLadderEntity);
}
// 2、保存 满多少金额,减多少钱 优惠信息
// sms_sku_full_reduction (sku_id full_price reduce_price add_other)
SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
if (skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) { // 存在金额满减才保存
BeanUtils.copyProperties(skuReductionTo, skuFullReductionEntity); // 传过来的对象包含了金额满减的信息,且属性名对应直接copy
this.save(skuFullReductionEntity);
}
// 3、保存 会员价格
// sms_member_price (sku_id member_level_id member_level_name member_price add_other)
List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice(); // 获取当前sku不同会员价格信息
List<MemberPriceEntity> memberPriceEntities = memberPrice.stream().map(member -> {
MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
memberPriceEntity.setSkuId(skuReductionTo.getSkuId()); // 获取skuId
memberPriceEntity.setMemberLevelId(member.getId()); // 获取会员等级Id
memberPriceEntity.setMemberLevelName(member.getName()); // 获取会员等级名
memberPriceEntity.setMemberPrice(member.getPrice()); // 会员价格
memberPriceEntity.setAddOther(1); // 是否可与其他优惠叠加
return memberPriceEntity;
}).filter(memberPriceEntity -> memberPriceEntity.getMemberPrice().compareTo(BigDecimal.ZERO) == 1).collect(Collectors.toList());
memberPriceService.saveBatch(memberPriceEntities);
}
暂未解决的问题
sms_spu_bounds表无法回滚,分布式事务的问题有待解决。// 高级部分完善
视频中没有判断MemberPrice,导致当没有件数折扣和金额满减时无法保存会员信息(我这里修复了这个bug)
二、spu管理
2.1 spu检索
https://easydoc.net/s/78237135/ZUqEdvA4/9LISLvy7 spu检索接口文档
/**
* 列表
*/
@RequestMapping("/list")
//@RequiresPermissions("gulimallproduct:spuinfo:list")
public R list(@RequestParam Map<String, Object> params){
// PageUtils page = spuInfoService.queryPage(params);
PageUtils page = spuInfoService.queryPageByCondition(params);
return R.ok().put("page", page);
}
声明&实现
@Override
public PageUtils queryPageByCondition(Map<String, Object> params) {
QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
String key = (String) params.get("key");
// SELECT * FROM pms_spu_info WHERE
if (!StringUtils.isEmpty(key)) {
wrapper.and((w) -> {
w.eq("id", key).or().like("spu_name", key);
});
}
// status = 1 and (id = 1 or spu_name like xxx)
String status = (String) params.get("status");
if (!StringUtils.isEmpty(status)) {
wrapper.eq("publish_status", status);
}
String brandId = (String) params.get("brandId");
if (!StringUtils.isEmpty(key) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
wrapper.eq("brand_id", brandId);
}
String catelogId = (String) params.get("catelogId");
if (!StringUtils.isEmpty(key) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
wrapper.eq("catalog_id", catelogId); // 这里数据库是catalog_id 可能是打错了
}
IPage<SpuInfoEntity> page = this.page(
new Query<SpuInfoEntity>().getPage(params), wrapper);
return new PageUtils(page);
}
检索成功实现,但是可以发现时间戳的格式不符合规范。
想要符合规范,可以通过配置文件中配置spring.jackson.date-format,这样我们写出的日期数据,均会按照指定的格式进行格式化
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
2.2 spu规格维护
这里视频P100才讲 跳转:https://www.yuque.com/mrlinxi/pxvr4g/zsn9l9#aKisn
三、商品管理
https://easydoc.net/s/78237135/ZUqEdvA4/ucirLq1D 商品管理检索的是sku的信息
/**
* 列表 按照检索条件对sku进行分页查询
*/
@RequestMapping("/list")
//@RequiresPermissions("gulimallproduct:skuinfo:list")
public R list(@RequestParam Map<String, Object> params){
// PageUtils page = skuInfoService.queryPage(params);
PageUtils page = skuInfoService.queryPageByCondition(params);
return R.ok().put("page", page);
}
/**
* 按照检索条件对sku进行分页查询
*
* @param params
* @return
*/
@Override
public PageUtils queryPageByCondition(Map<String, Object> params) {
QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
/**
* key: 华为
* catelogId: 225
* brandId: 9
* min: 500
* max: 10000
*/
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)) {
wrapper.and(w -> {
w.eq("sku_id", key).or().like("sku_name", key);
});
}
String catelogId = (String) params.get("catelogId");
if (!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)) { // 判断不为0,为保证初始化状态下能查到所有数据
wrapper.eq("catalog_id", catelogId);
}
String brandId = (String) params.get("brandId");
if (!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
wrapper.eq("brand_id", brandId);
}
String min = (String) params.get("min");
if (!StringUtils.isEmpty(min)) {
wrapper.ge("price", min); // ge表示大于等于
}
String max = (String) params.get("max");
if (!StringUtils.isEmpty(max)) {
try {
BigDecimal maxPrice = new BigDecimal(max);
if (maxPrice.compareTo(BigDecimal.ZERO) > 0) {
wrapper.le("price", max); // le表示小于等于
}
} catch (Exception e) {
e.printStackTrace();
}
}
IPage<SkuInfoEntity> page = this.page(
new Query<SkuInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}