电商项目——CG
- 为何使用分布式ID
- 项目中如何使用分布式ID
- 搞清SPU和SKU的区别
- 商品的CRUD
-
- 增加商品
- 根据id查询商品
- 修改商品
- 审核商品
- 商品上下架
- 删除商品
- 全局异常处理
为何使用分布式ID
- 我们学过UUID是唯一的,但是它是字符串,
。查询效率低。无法保证递增的趋势,不可读
- 也可用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现,但是
。网络传输会造成性能下降
- 而雪花算法(snowflake)的其核心思想是:使用前41bit作为毫秒数,中间10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),后12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最前还有一个符号位,永远是0(二进制1为负数)。几乎完美解决了上述的问题。
项目中如何使用分布式ID
- 首先引入工具包IdWorker.java
- changgou_service_goods中yml配置:
这两值只能在0~31之间
workerId: 0
datacenterId: 0
- 在启动类配置一个idWorker的Bean,以@Value将两个属性注进来。
搞清SPU和SKU的区别
-
概念
SPU:一个统称
SKU:对SPU的细化,比如有颜色,内存大小等等
-
就搞一个SKU不行吗?
答案是:不行,因为对于单个商品(如小米10)的详情,图片,友情链接是一样的。SPU更加便于维护。
商品的CRUD
增加商品
- 商品Goods由spu和sku组成,所以在…-api中先创建Goods实体类
-
spu业务层新增方法add(Goods goods),先存spu,再存sku。具体逻辑:
- 生成分布式ID,重新封装spu(审核状态,删除状态,上架状态全为0),再调用方法spuMapper.insertSelective(spu)进行保存。
- 存sku的时候注意两点,第一:分类与品牌的关联,如未建立则需在tb_category_brand添加数据,方便数据的维护。第二:skuList中拿到的spec是个json字符串,需要将其拿出来转成map取value的值再与name组合生成最终的name。再重新封装sku,向表中添加数据。sku所需数据如下:
private String sn;//商品条码
private String name;//SKU名称
private Integer price;//价格(分)
private Integer num;//库存数量
private Integer alertNum;//库存预警数量
private String image;//商品图片
private String images;//商品图片列表
private Integer weight;//重量(克)
private java.util.Date createTime;//创建时间
private java.util.Date updateTime;//更新时间
private String spuId;//SPUID
private Integer categoryId;//类目ID
private String categoryName;//类目名称
private String brandName;//品牌名称
private String spec;//规格
private Integer saleNum;//销量
private Integer commentNum;//评论数
private String status;//商品状态 1-正常,2-下架,3-删除
根据id查询商品
- 根据id查询spu。
- 封装Example对象,然后根据id查询出所有的skuList。
- 创建Goods对象,将spu和skuList一起放进对象中并返回。
修改商品
- 首先从goods中拿到spu,对spu进行修改
- 根据spu的id删除所有的sku,再重新增加(调用新增方法)
审核商品
-
分析:
先通过id查询到spu,如果spu为空或者删除状态为1,则抛一个
,否则就将spu的status和isMarketable设为1。系统异常(本篇的最后)
- 代码如下:
@Transactional
@Override
public void audit(String id) {
Spu spu = spuMapper.selectByPrimaryKey(id);
if (spu==null || "1".equals(spu.getIsDelete())){
throw new BusinessException(new Result(false, StatusCode.ERROR,"无此商品信息或处于删除状态"));
}
//审核
spu.setStatus("1");
//上架
spu.setIsMarketable("1");
spuMapper.updateByPrimaryKeySelective(spu);
}
商品上下架
-
分析:
无论上下架都要先进行判断,根据id查询spu,若spu为空或者处于删除状态,或status为0都不可操作,抛一个系统异常。否则直接更改上架状态,代码简单,不做赘述。
删除商品
-
逻辑删除(可还原)
先做一个判断,未下架商品不能逻辑删除,下架后可直接更改删除状态为1。
还原商品:当status为0或删除状态为0都不可操作,否则直接修改删除状态为0。
-
物理删除
根据id直接删除数据即可。
全局异常处理
主要利用了Aop思想,做了异常捕获类,代码如下:
/**
* 统一异常处理类
*/
@ControllerAdvice
public class BaseExceptionHandler {
//BusinessException继承了RuntimeExcption
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public Result otherError(BusinessException e){
e.printStackTrace();
return e.getResult();
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return new Result(false, StatusCode.ERROR, "执行出错");
}
}