文章目录
1 添加进注册中心
将ware模块添加进注册中心,配置application.yml
cloud:
nacos:
discovery:
server-addr: nacos地址:8848
application:
name: gulimall-ware
添加服务发现注解
@SpringBootApplication
@EnableDiscoveryClient
public class GulimallWareApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallWareApplication.class, args);
}
}
启动服务
2 配置网关
配置仓储服务的路由,重启网关
####################### 仓储服务路由 ########################
- id: ware_route
uri: lb://gulimall-ware
predicates:
- Path=/api/ware/**
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
3 仓库模糊查询
1、修改WareInfoController
里的queryPage
方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareInfoEntity> wareInfoEntityQueryWrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)) {
wareInfoEntityQueryWrapper.eq("id", key).or()
.like("name", key)
.or().like("address", key)
.or().like("areacode", key);
}
IPage<WareInfoEntity> page = this.page(
new Query<WareInfoEntity>().getPage(params),
wareInfoEntityQueryWrapper
);
return new PageUtils(page);
}
2、修改ware服务日志打印等级
logging:
level:
com.atguigu: debug
3、重启ware服务
坑:ware一直在报错[NACOS ConnectException httpPost] currentServerAddr: http://127.0.0.1:8848, err : Connection refused: connect
问题分析:
由于ware导入了nacos-config的依赖,而没有在配置文件中配置nacos-config的地址,从而去连接默认的nacos地址,也就是本地的8848端口。
解决方法:
在nacos新建ware的命名空间
在ware的resources目录下新建bootstrap.yml
spring:
application:
name: gulimall-ware
cloud:
nacos:
config:
server-addr: nacos的IP地址:8848
namespace: ware服务的命名空间id
4、测试
新增几条仓储数据,查看数据库是否有数据增加
模糊查询测试
4 查询库存
修改WareSkuServiceImpl
的queryPage方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
String skuId = (String) params.get("skuId");
if (!StringUtils.isEmpty(skuId)) {
queryWrapper.eq("sku_id", skuId);
}
String wareId = (String) params.get("wareId");
if (!StringUtils.isEmpty(wareId)) {
queryWrapper.eq("ware_id", wareId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
重启服务测试
5 查询采购需求
修改PurchaseDetailServiceImpl
的queryPage
方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<PurchaseDetailEntity> queryWrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)) {
//purchase_id sku_id
queryWrapper.and(w -> {
w.eq("purchase_id", key).or().eq("sku_id", key);
});
}
String status = (String) params.get("status");
if (!StringUtils.isEmpty(status)) {
//purchase_id sku_id
queryWrapper.eq("status", status);
}
String wareId = (String) params.get("wareId");
if (!StringUtils.isEmpty(wareId)) {
//purchase_id sku_id
queryWrapper.eq("ware_id", wareId);
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
重启服务测试
6 合并采购需求
6.1 采购流程图
6.2 创建采购单
创建采购单,分配采购人员
6.3 查询未领取的采购单
1、在PurchaseController
创建unReceiveList
方法
@RequestMapping("/unreceive/list")
public R unReceiveList(@RequestParam Map<String, Object> params) {
PageUtils page = purchaseService.queryPageUnReceivePurchase(params);
return R.ok().put("page", page);
}
2、实现queryPageUnReceivePurchase
方法
@Override
public PageUtils queryPageUnReceivePurchase(Map<String, Object> params) {
IPage<PurchaseEntity> page = this.page(
new Query<PurchaseEntity>().getPage(params),
new QueryWrapper<PurchaseEntity>().eq("status", 0).or().eq("status", 1)
);
return new PageUtils(page);
}
3、重启服务
6.4 合并采购需求
1、创建MergeVo
@Data
public class MergeVo {
private Long purchaseId; //整单id
private List<Long> items;//[1,2,3,4] //合并项集合
}
2、创建vo
3、创建ware常量类
package com.atguigu.common.constant;
public class WareConstant {
public enum PurchaseStatusEnum {
CREATED(0, "新建"), ASSIGNED(1, "已分配"),
RECEIVE(2, "已领取"), FINISH(3, "已完成"),
HASERROR(4, "有异常");
private int code;
private String msg;
PurchaseStatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
public enum PurchaseDetailStatusEnum {
CREATED(0, "新建"), ASSIGNED(1, "已分配"),
BUYING(2, "正在采购"), FINISH(3, "已完成"),
HASERROR(4, "采购失败");
private int code;
private String msg;
PurchaseDetailStatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
}
4、在PurchaseController
里创建merge
方法
@RequestMapping("/merge")
public R merge(@RequestBody MergeVo mergeVo) {
purchaseService.mergePurchase(mergeVo);
return R.ok();
}
3、实现mergePurchase
方法
@Autowired
PurchaseDetailService purchaseDetailService;
@Transactional
@Override
public void mergePurchase(MergeVo mergeVo) {
Long purchaseId = mergeVo.getPurchaseId(); // 采购单id
// 如果没有传递采购单id,则新建一个采购单
if (purchaseId == null) {
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
purchaseEntity.setCreateTime(new Date());
purchaseEntity.setUpdateTime(new Date());
this.save(purchaseEntity); // 保存采购单记录
purchaseId = purchaseEntity.getId(); // 获取保存后生成的id
}
// 获取所有采购需求的id
List<Long> items = mergeVo.getItems();
// 局部内部类里面使用外部变量的时候,这个变量需要是final类型的或者是没有被修改过值的变量,但是purchaseId判空时有可能会修改,所以另外赋值给finalPurchaseId
Long finalPurchaseId = purchaseId;
// 根据id更新所有的采购需求记录的purchase_id和状态
List<PurchaseDetailEntity> collect = items.stream().map(i -> {
PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
purchaseDetailEntity.setId(i);
purchaseDetailEntity.setPurchaseId(finalPurchaseId);
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
return purchaseDetailEntity;
}).collect(Collectors.toList());
purchaseDetailService.updateBatchById(collect);
}
4、修改PurchaseController
里的save
方法
@RequestMapping("/save")
public R save(@RequestBody PurchaseEntity purchase) {
purchase.setUpdateTime(new Date());
purchase.setCreateTime(new Date());
purchaseService.save(purchase);
return R.ok();
}
5、添加日期格式转换配置
jackson:
date-format: yyyy-MM-dd HH:mm:ss
6、重启服务测试
新增两个采购需求
点击批量合并,采购需求变化
采购单变化
7 领取采购单
1、在PurchaseController
里创建received
方法
@PostMapping("/received")
public R received(@RequestBody List<Long> ids) {
purchaseService.received(ids);
return R.ok();
}
2、实现received
方法
@Override
public void received(List<Long> ids) {
// 1、确认当前采购单是否是新建或者是已分配状态
List<PurchaseEntity> purchaseEntities = ids.stream().map(id -> {
// 1.1、根据id查询出purchaseEntity
PurchaseEntity purchaseEntity = this.getById(id);
return purchaseEntity;
}).filter(purchaseEntity -> {
// 1.2、过滤掉状态不是0和1的purchaseEntity
if (purchaseEntity.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
purchaseEntity.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
return true;
}
return false;
}).map(purchaseEntity -> {
// 设置purchaseEntity状态为已领取,并更新时间
purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
purchaseEntity.setUpdateTime(new Date());
return purchaseEntity;
}).collect(Collectors.toList());
// 2、改变采购单的状态
this.updateBatchById(purchaseEntities);
// 3、改变采购需求的状态
purchaseEntities.forEach(purchaseEntity -> {
// 3.1、查询到对应的所有采购需求
List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDetailService.listDetailByPurChaseId(purchaseEntity.getId());
// 3.2、修改所有采购需求的状态
purchaseDetailEntities.forEach(purchaseDetailEntity -> {
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
});
purchaseDetailService.updateBatchById(purchaseDetailEntities);
});
}
3、实现listDetailByPurChaseId
方法
@Override
public List<PurchaseDetailEntity> listDetailByPurChaseId(Long id) {
List<PurchaseDetailEntity> purchaseDetailEntities = this.list(new QueryWrapper<PurchaseDetailEntity>().eq("purchase_id", id));
return purchaseDetailEntities;
}
4、重启服务测试
postman发送请求
查看前端页面变化
8 完成采购
8.1 创建vo
1、创建PurchaseItemDoneVo
@Data
public class PurchaseItemDoneVo {
private Long itemId;
private Integer status;
private String reason;
}
2、创建PurchaseDoneVo
@Data
public class PurchaseDoneVo {
@NotNull
private Long id;//采购单id
private List<PurchaseItemDoneVo> items;
}
8.2 controller
1、在PurchaseController
创建finish
方法
@PostMapping("/done")
public R finish(@RequestBody PurchaseDoneVo doneVo) {
purchaseService.done(doneVo);
return R.ok();
}
8.3 实现done方法
@Transactional
@Autowired
WareSkuService wareSkuService;
@Override
public void done(PurchaseDoneVo doneVo) {
// 1、改变采购项的状态
AtomicBoolean flag = new AtomicBoolean(true);
List<PurchaseItemDoneVo> purchaseItemDoneVos = doneVo.getItems(); // 获取采购需求信息反馈
// 将purchaseItemDoneVos转变成purchaseDetailEntities
List<PurchaseDetailEntity> purchaseDetailEntities = purchaseItemDoneVos.stream().map(item -> {
// 根据id查询出采购需求记录实体类
PurchaseDetailEntity purchaseDetailEntity = purchaseDetailService.getById(item.getItemId());
if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()) {
flag.set(false);
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode());
} else {
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
// 2、将成功采购的进行入库
wareSkuService.addStock(purchaseDetailEntity.getSkuId(), purchaseDetailEntity.getWareId(), purchaseDetailEntity.getSkuNum());
}
return purchaseDetailEntity;
}).collect(Collectors.toList());
// 更新采购需求信息
purchaseDetailService.updateBatchById(purchaseDetailEntities);
// 2、改变采购单状态
PurchaseEntity purchaseEntity = this.getById(doneVo.getId());
purchaseEntity.setStatus(flag.get() ? WareConstant.PurchaseStatusEnum.FINISH.getCode() : WareConstant.PurchaseStatusEnum.HASERROR.getCode());
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
8.4 实现addStock方法
1、在WareSkuServiceImpl
里创建addStock
方法
@Autowired
WareSkuDao wareSkuDao;
@Autowired
ProductFeignService productFeignService;
@Override
public void addStock(Long skuId, Long wareId, Integer skuNum) {
// 1、判断是否存在这个库存的记录
List<WareSkuEntity> wareSkuEntities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
if (wareSkuEntities == null || wareSkuEntities.size() == 0) {
WareSkuEntity wareSkuEntity = new WareSkuEntity();
wareSkuEntity.setSkuId(skuId);
wareSkuEntity.setStock(skuNum);
wareSkuEntity.setWareId(wareId);
wareSkuEntity.setStockLocked(0);
//TODO 远程查询sku的名字,如果失败,整个事务无需回滚
//1、自己catch异常
//TODO 还可以用什么办法让异常出现以后不回滚?高级
try {
R info = productFeignService.info(skuId);
Map<String, Object> data = (Map<String, Object>) info.get("skuInfo");
if (info.getCode() == 0) {
wareSkuEntity.setSkuName((String) data.get("skuName"));
}
} catch (Exception ignored) {
}
wareSkuDao.insert(wareSkuEntity);
} else {
wareSkuDao.addStock(skuId, wareId, skuNum);
}
}
2、实现wareSkuDao.addStock
创建接口
@Mapper
public interface WareSkuDao extends BaseMapper<WareSkuEntity> {
void addStock(@Param("skuId") Long skuId, @Param("wareId") Long wareId, @Param("skuNum") Integer skuNum);
}
生成SQL语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.gulimall.ware.dao.WareSkuDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.atguigu.gulimall.ware.entity.WareSkuEntity" id="wareSkuMap">
<result property="id" column="id"/>
<result property="skuId" column="sku_id"/>
<result property="wareId" column="ware_id"/>
<result property="stock" column="stock"/>
<result property="skuName" column="sku_name"/>
<result property="stockLocked" column="stock_locked"/>
</resultMap>
<update id="addStock">
UPDATE `wms_ware_sku` SET stock=stock+#{skuNum} WHERE sku_id=#{skuId} AND ware_id=#{wareId}
</update>
</mapper>
8.5 远程调用服务
1、创建feign.ProductFeignService
@FeignClient("gulimall-product")
public interface ProductFeignService {
/**
* /product/skuinfo/info/{skuId}
* 1)、让所有请求过网关;
* 1、@FeignClient("gulimall-gateway"):给gulimall-gateway所在的机器发请求
* 2、/api/product/skuinfo/info/{skuId}
* 2)、直接让后台指定服务处理
* 1、@FeignClient("gulimall-product")
* 2、/product/skuinfo/info/{skuId}
*
* @return
*/
@RequestMapping("/product/skuinfo/info/{skuId}")
public R info(@PathVariable("skuId") Long skuId);
}
2、开启远程服务注解
@EnableFeignClients(basePackages = "com.atguigu.gulimall.ware.feign")
@SpringBootApplication
@EnableDiscoveryClient
public class GulimallWareApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallWareApplication.class, args);
}
}
8.6 MyBatis配置
创建config.MyBatis
@EnableTransactionManagement
@MapperScan("com.atguigu.gulimall.ware.dao")
@Configuration
public class MyBatisConfig {
//引入分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(true);
// // 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(1000);
return paginationInterceptor;
}
}
8.7 测试
postman发送请求
localhost:88/api/ware/purchase/done
注意id
与数据库wms_purchase
表中的id对应,itemId
与数据库wms_purchase_detail
表中的id对应
{
"id": 1, "items": [
{"itemId": 1, "status": 3, "reason": ""},
{"itemId": 2, "status": 4, "reason": "无货"}
]
}
采购单
采购需求
商品库存
数据表wms_ware_sku
如果sku_name是null,查看采购需求的sku_id是否和商品信息里的sku_id对应