1.整合ware服务,获取仓库列表
先把gulimall-ware注册进注册中心(nacos):
添加@EnableDiscoveryClient注解(开启服务发现)加在启动类前
添加@MapperScan("dao包的位置") 添加mybatis-plus的扫描
添加@EnableTransactionManagement注解(启用基于注解的事务管理功能)
然后就像之前一样,根据接口文档来写方法
serviceImpl类里写方法体:
2.商品库存
来到wareskucontroller类里:
添加上条件查询
来写方法体:
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
String wareId = (String) params.get("wareId");
if (StringUtils.hasLength(wareId)){
queryWrapper.eq("ware_id",wareId);
}
String skuId = (String) params.get("skuId");
if (StringUtils.hasLength(skuId)){
queryWrapper.eq("sku_id",skuId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
3.采购业务
1.业务逻辑:
B2C的商城的业务逻辑一般是由商家采购商品销售给消费者,所以我们就需要有采购的业务.
根据采购需求来购买商品,为商品添加库存.采购需求来源有两个:1.人工添加2.当商品低库存时发出警告,自动生成采购需求
2.先来实现采购需求的条件查询
来到controller
写方法体:
@Override
public PageUtils queryPage(Map<String, Object> params) {
/**
* key: '华为',//检索关键字
* status: 0,//状态
* wareId: 1,//仓库id
*/
QueryWrapper<PurchaseDetailEntity> queryWrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if (StringUtils.hasLength(key)){
queryWrapper.and(wrapper->{
wrapper.eq("purchase_id",key).or().eq("sku_id",key);
});
}
String status = (String) params.get("status");
if (StringUtils.hasLength(status)){
queryWrapper.eq("status",status);
}
String wareId = (String) params.get("wareId");
if (StringUtils.hasLength(wareId)){
queryWrapper.eq("ware_id",wareId);
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
3.合并采购需求
controller:
方法体:
先写一个vo
controller:
方法体:
4.采购人员领取采购单
属于员工手机上app的功能,我们用APIfox来模拟请求
方法体:
@Override
public void received(List<Long> ids) {
//1.确认当前采购单是新建或者已分配状态
List<PurchaseEntity> collect = ids.stream().map(id -> {
PurchaseEntity purchaseEntity = this.getById(id);
return purchaseEntity;
}).filter(item -> {
if (item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
return true;
}
return false;
}).map(item->{
item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
item.setUpdateTime(new Date());
return item;
}).collect(Collectors.toList());
//2.改变采购单的状态
this.updateBatchById(collect);
//3.改变采购需求的状态
collect.forEach((item)->{
List<PurchaseDetailEntity> entities= purchaseDetailService.listDetailByPurchaseId(item.getId());
List<PurchaseDetailEntity> detailEntities = entities.stream().map(entity -> {
PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
detailEntity.setId(entity.getId());
detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
return detailEntity;
}).collect(Collectors.toList());
purchaseDetailService.updateBatchById(detailEntities);
});
}
5.完成采购
先写vo:
来到controller来写方法:
实现类来写方法体
@Transactional
@Override
public void done(PurchaseDoneVo doneVo) {
Long id = doneVo.getId();//获取采购单id
//2.改变采购需求的状态
Boolean flag=true;
List<PurchaseItemDoneVo> items = doneVo.getItems();//把vo中的采购需求vo取出来组成 items
List<PurchaseDetailEntity> updateItems = new ArrayList<>();//新建一个采购需求数组,放我们完成的 采购需求
for (PurchaseItemDoneVo item:items) {//遍历采购需求vo
PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
if (item.getStatus()==WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()){//判断采购需求
flag=false;// 当没被完成时设置采购单状态标记为false
detailEntity.setStatus(item.getStatus());// 把采购需求标记为 采购失败
}else {//采购成功
detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());//先设置采购需求 状态为 已完成
//3.将成功采购的进行入库
PurchaseDetailEntity entity = purchaseDetailService.getById(item.getItemId());//通过采购需求id 获取到采购需求的实体类,方便拿到入库需要的skuid,wareid,数量
wareSkuService.addStock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum());//自定义方法入库(添加数据库记录,其中包括当采购需求是库里没有的时新建,已经有的更新)
}
detailEntity.setId(item.getItemId());//设置采购需求实体类的id
updateItems.add(detailEntity);//把上述完成入库或者采购失败的 采购需求 加入之前放完成采购需求的 数组 中
}
purchaseDetailService.updateBatchById(updateItems);//来执行更新 采购需求 操作
//1.改变采购单状态
PurchaseEntity entity = new PurchaseEntity();
entity.setId(id);
entity.setStatus(flag?WareConstant.PurchaseStatusEnum.FINISH.getCode():WareConstant.PurchaseStatusEnum.HASERROR.getCode());
entity.setUpdateTime(new Date());
this.updateById(entity);
}
其中自定义的加库存的方法:
自定义SQL:
细节完善(远程调用product服务的skuinfo功能给库存set上skuName):
先写远程调用:
1.写feign包,在启动类前加@EnableFeignClients开启远程调用
2.调用方法:
Tips:什么是"事务"
事务(Transaction)是数据库管理系统中的一个核心概念,它用于管理一组数据库操作,确保这些操作作为一个不可分割的工作单元来执行,要么全部成功执行,要么在遇到错误时全部回滚(撤销),从而保持数据库的一致性和完整性。
通俗点说把对数据库的操作打包成一个事务,这个事务里的操作都成功了,数据库才会真正被加上数据,如果有失败的操作,就会进行数据回滚,不对数据库执行任何操作.
四大特性:(ACID):
原子性(Atomicity):
- 事务是一个不可分割的工作单位,事务中包含的所有操作要么全部成功,要么全部失败回滚。因此,事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
- 例如,在银行转账中,从A账户转账到B账户的操作要么全部成功,要么全部失败,不能出现A账户扣款成功但B账户未收到款项的情况。
一致性(Consistency):
- 事务必须保证数据库的一致性,即事务的执行结果必须使数据库从一个一致性状态转换到另一个一致性状态。事务的执行不能破坏数据库数据的完整性和一致性。
- 例如,在转账过程中,无论转账是否成功,A账户和B账户的总金额应该保持不变。
隔离性(Isolation):
- 事务的隔离性确保了多个并发事务之间的隔离,即一个事务的执行不应被其他事务干扰。隔离性要求并发执行的事务之间互不干扰,以保证每个事务的独立性。
- 数据库事务隔离级别主要分为四种:读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。不同的隔离级别解决了不同程度的并发问题,但也会带来不同的性能开销。
持久性(Durability):
- 一旦事务被提交,它对数据库的更改就是永久的,即使系统崩溃也不会丢失。持久性确保了事务的结果在提交后能够永久保存在数据库中