java开发WMS仓库商品预警
Hi梅 人气:01.预警需求
为了更好的管理商品日期,需要对仓库的商品进行预警管理,对商品的保质期控制在一个范围内提示出来,也可以通过该功能间接的展示出一个商品的的销量程度和对下次进货做个考量!
1. 预警需求分析
- 前端界面需要设置商品的预警天数
- 后端保存预警天数
- 数据库有字段存放商品需要预警的天数
- 通过定时器运行指点方法算出对应那些商品的批次存低于设置的预警天数
- 查询出来在wms首页展出
2.数据库表
对于前端界面的开发不做过多的代码分析,本次重点展示商品预警实现思路!!
数据库用到到字段会截取出来,便于理解!
商品表数据:
预警表数据:
商品批次表:
商品批次表中添加预警字段:后续查询对应的预警信息作为标志
Mysql使用到的函数
//查询当前时间 select now(); //获取时间相减 获取到天数 参数是前面-后面 select DATEDIFF("2022-9-10", now()) as day
如:
由此我们就可以通过函数算出商品距离过期的天数
查询语句:
SELECT bb.id as batchId, bb.product_id as productId, DATEDIFF(bb.ed, now()) as warnDate FROM `商品批次表` bb
需要注意: 查询或者修改表数据我们如果只要使用某个字段去修改,尽量查询下该表更新的字段数据是否有重复的数据并且其他字段可能跟我们预想不一致,必须要修改的,我们就应该使用多字段去查询修改
查询重复数据
select * from 表 GROUP BY 字段 HAVING count(*)>1
查询预警批次数量: 因为需要展示出来在前端可以给用户点击查看货物存放的地方,所以查询出来的数据库存数量要大于0
select IFNULL(count(*),0) from basic_batch bb LEFT JOIN handle_stock hs on bb.id=hs.batch_id where bb.is_warn_date=1 and hs.reality_number>0
2.后端代码实现:
1. 定时器任务
使用Scheduled作为定时器,通过cron语法指定运行时间,每3小时运行一次表达式如下
代码详情注释写的也比较清楚
/** * 每3小时运行一次 */ @Scheduled(cron = "0 0 0/3 * * ?") public void goodsWarn(){ BasicProductGpExample basicProductGpExample = new BasicProductGpExample(); List<String> warnBatchIds=new ArrayList<>(); //查询商品预警表信息 商品的货号是唯一的 (所以现在是全表查询出来) // 这里把商品预警信息都查询出来为了以后扩展做库存预警设置 List<BasicProductGp> basicProductGps = productGpMapper.selectByExample(basicProductGpExample); //查询商品批次表:商品批次和天数 商品的批次是唯一的,存在多个商品货号(所以现在是全表查询出来) // 以后扩展商品库存预警只要在这个查询里面添加关联库存数量查询出来,然后在过滤里面添加预警数量判断 List<BasicProductWarn> warnGoodsDay = basicBatchMapper.selectWarnGoodsDay(); Long start=System.currentTimeMillis(); for (BasicProductGp basicProductGp : basicProductGps) { //商品预警日期 Integer warnDate = basicProductGp.getWarnDate(); //商品货号编码 Integer productId = basicProductGp.getProductId(); //查询出符合预警的商品批次 List<String> warnBatchId = warnGoodsDay.stream().filter(warnGood -> warnGood.getProductId().equals(productId) && warnGood.getWarnDate() <= warnDate) .map(BasicProductWarn::getBatchId).collect(Collectors.toList()); warnBatchIds.addAll(warnBatchId); } Long end=System.currentTimeMillis(); log.info("消耗时长:"+(end-start)/1000+"秒"); //获取出所有需要提醒的批次号 log.info(Arrays.toString(warnBatchIds.toArray())); //数组为空时不更新 if (CollectionUtils.isEmpty(warnBatchIds)){ log.info("没有需要预警的商品批次!"); return; } //修改批次状态为1标识预警日期已经到达 //使用boolean类型保存数据库会自动把true转换成1 int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true); log.info("更新预警数量:{}",count); }
这里面还存在一个问题,如果批次被打上预警标识,此时客户更改了商品的预警日期,那么商品的预警可能就没有到达,但是页面查询预警也能被查询出来,解决方案,使用mq来做处理,当客户更改了商品编码预警信息,那么程序就把更改的商品编码存到mq中我们在写个消费方法来消费更改后的商品编码单独走波预警方法
2.优化加入队列
先不考虑全局预警设置,只对勾选多个商品进行添加队列
使用了springBoot的rabbitMq模板类RabbitTemplate
pom.xml引入:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
生产者添加消息到队列中
//存入队列 routingkey名称 存入的数据 rabbitTemplate.convertAndSend("warnGoodsQueue",ids);
消费者:
/** * 消费预警队列信息 */ @Configuration @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "warnGoodsQueue", durable = "true"), exchange = @Exchange(value = "warnGoodsExchange", ignoreDeclarationExceptions = "true", type = ExchangeTypes.TOPIC), key = {"warnGoodsQueue"})) public class WarnGoodsQueue { @RabbitHandler public void process(List<String> ids) { if (ids == null) { System.out.println("空"); } System.out.println(ids); } }
3.注意:关于Mq
生产者,生产的数据类型一定要要和消费者获取的类型要一致,否则会无限循环报错
Listener threw exception No method found for class [B
4.测试是否成功
生产者存入队列:
消费者获取数据:
如果消费方法报错不try/catch的话,队列就会一直重试该条数据
可以看出已经获取到修改预警商品的商品编号,这个时候我们只要写方法做相应的处理就行了
我们也可以去RabbitMq管理界面查看队列信息
消费方法代码:
public void updateWarnGoods(List<Integer> ids){ if (CollectionUtils.isEmpty(ids)){ return; } BasicProductGpExample example = new BasicProductGpExample(); example.createCriteria().andProductIdIn(ids); //查询商品信息 商品的货号是唯一的 (查询变动的商品货号) List<BasicProductGp> basicProductGps = productGpMapper.selectByExample(example); //商品批次和天数 商品的批次是唯一的,存在多个商品货号(查询变动的商品货号) List<BasicProductWarn> warnGoodsDay = basicBatchMapper.selectWarnGoodsDayList(ids); //需要预警的集合 List<String> warnBatchIds=new ArrayList<>(); //不需要预警的集合 List<String> notWarnBatchIds=new ArrayList<>(); Long start=System.currentTimeMillis(); for (BasicProductGp basicProductGp : basicProductGps) { //商品预警日期 Integer warnDate = basicProductGp.getWarnDate(); //商品货号编码 Integer productId = basicProductGp.getProductId(); //查询出符合预警的商品批次 List<String> warnBatchId = warnGoodsDay.stream().filter(warnGood -> { if (warnGood.getProductId().equals(productId)){ //匹配到的商品数据 //2种情况:一种要预警另外一种不要预警 if (warnGood.getWarnDate() <= warnDate){ //预警的返回 return true; } //不要预警的添加到不预警集合用于更新 notWarnBatchIds.add(warnGood.getBatchId()); } return false; }).map(BasicProductWarn::getBatchId).collect(Collectors.toList()); //把预警集合添加到预警大集合中 warnBatchIds.addAll(warnBatchId); } long end=System.currentTimeMillis(); log.info("更新预警商品耗时:{}秒",(end-start)/1000); //结束后会得到2种集合:不预警和要预警集合 //更新未预警商品 if (!CollectionUtils.isEmpty(notWarnBatchIds)){ int count = basicBatchMapper.updateByBatchWarn(notWarnBatchIds, false); log.info("更新预警数量:{}",count); } //更新预警商品 if (!CollectionUtils.isEmpty(warnBatchIds)){ int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true); log.info("更新预警数量:{}",count); } }
关于一些代码存在冗余我们可以提取成一个公共方法进行调用,后续也对全局修改预警Mq队列走波运算预警的商品
重载方法:
/*** * 重载方法 * 用于运算全局商品类型 * 用于更新商品预警时间 */ public void updateWarnGoods(){ BasicProductGpExample example = new BasicProductGpExample(); //查询商品信息 商品的货号是唯一的 (查询变动的商品货号) List<BasicProductGp> basicProductGps = productGpMapper.selectByExample(example); //商品批次和天数 商品的批次是唯一的,存在多个商品货号(查询变动的商品货号) List<BasicProductWarn> warnGoodsDay = basicBatchMapper.selectWarnGoodsDay(); //需要预警的集合 List<String> warnBatchIds=new ArrayList<>(); //不需要预警的集合 List<String> notWarnBatchIds=new ArrayList<>(); Long start=System.currentTimeMillis(); for (BasicProductGp basicProductGp : basicProductGps) { //商品预警日期 Integer warnDate = basicProductGp.getWarnDate(); //商品货号编码 Integer productId = basicProductGp.getProductId(); //查询出符合预警的商品批次 List<String> warnBatchId = warnGoodsDay.stream().filter(warnGood -> { if (warnGood.getProductId().equals(productId)){ //匹配到的商品数据 //2种情况:一种要预警另外一种不要预警 if (warnGood.getWarnDate() <= warnDate){ //预警的返回 return true; } //不要预警的添加到不预警集合用于更新 notWarnBatchIds.add(warnGood.getBatchId()); } return false; }).map(BasicProductWarn::getBatchId).collect(Collectors.toList()); //把预警集合添加到预警大集合中 warnBatchIds.addAll(warnBatchId); } long end=System.currentTimeMillis(); log.info("更新预警商品耗时:{}秒",(end-start)/1000); //结束后会得到2种集合:不预警和要预警集合 //更新未预警商品 if (!CollectionUtils.isEmpty(notWarnBatchIds)){ int count = basicBatchMapper.updateByBatchWarn(notWarnBatchIds, false); log.info("更新预警数量:{}",count); } //更新预警商品 if (!CollectionUtils.isEmpty(warnBatchIds)){ int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true); log.info("更新预警数量:{}",count); } }
3.前端提一嘴
给商品添加预警日期,需要用户提些数据,为了避免出现英文空格等我们需要,对输入的数据进行正则,只能输入数字
效果:
英文:
但是可以输入0,如果预警日期设置成了0你们就意味着废弃该商品预警提示功能
前端展示:
首页:
预警商品列表:
加载全部内容