java开发WMS仓库商品预警需求示例解析
作者:Hi梅 发布时间:2023-10-03 11:07:30
1.预警需求
为了更好的管理商品日期,需要对仓库的商品进行预警管理,对商品的保质期控制在一个范围内提示出来,也可以通过该功能间接的展示出一个商品的的销量程度和对下次进货做个考量!
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你们就意味着废弃该商品预警提示功能
前端展示:
首页:
预警商品列表:
来源:https://blog.csdn.net/qq_45502336/article/details/124123045
猜你喜欢
- 1,获取当前线程信息Thread.CurrentThread 是一个 静态的 Thread 类,Thread 的CurrentTh
- 配置Servlet的方法有俩种,分别是传统web.xml文档中部署servlet和注解方式部署servlet,下面就先一起来学习 * 解方式部
- 在软件开发过程中经常需要知道程序运行的大概时间,或者需要在规定时间内取数据,这是可以使用下面的方法获取时间段,还可以用在限时循环方法一:/*
- 在android开发中,当不满足触发条件就按返回键的时候,就要对此进行检测。尤其是当前Activity需要往前一个Activity传送消息时
- 配置基础的定时任务最基本的配置方法,而且这样配置定时任务是单线程串行执行的,也就是说每次只能有一个定时任务可以执行,可以试着声明两个方法,在
- 域对象共享数据使用ServletAPI向request域对象共享数据@RequestMapping("/testServletAP
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个
- 本文实例为大家分享了Android实现闪屏页效果的具体代码,供大家参考,具体内容如下1.效果图2.闪屏页逻辑及布局2.1 activity_
- 如论实施敏捷的团队,或者实施 DevOps 的团队,通过自动化测试提高测试效率和软件质量都是其共同的选择。UI 自动化测试是自动化化测试当中
- 开发设计搞了一个带圆形进度的进度条,在GitHub上逛了一圈,发现没有,自己撸吧。先看界面效果:主要思路是写一个继承ProgressBar的
- 本文实例汇总了DevExpress SplitContainerControl的用法,希望对大家进行C#项目开发能起到一定的帮助作用。具体用
- 题目要求思路一:模拟迭代依次判断每个节点是否合法:左子树判断是否>low,合法就向左下走,不合法往右下;右子树判断是否<high
- 对HDFS上的文件进行上传和下载是对集群的基本操作,在《HADOOP权威指南》一书中,对文件的上传和下载都有代码的实例,但是对如何配置HAD
- AI 平台:http://ai.baidu.com/开发工具:vs 2017准备工作1、注册百度账号2、登录百度 AI 开发平台,http:
- 有时候如果想让我们的应用在桌面上创建多个快捷方式,我们可以在Manifest.xml文件中对相应的activity进行声明。<appl
- 单例模式大概是所有设计模式中最简单的一种,如果在面试时被问及熟悉哪些设计模式,你可能第一个答的就是单例模式。单例模式的实现分为两种:饿汉式和
- 本文实例为大家分享了java实现多个文件压缩的具体代码,供大家参考,具体内容如下需要用到的ant.jarpackage util;impor
- Mybatis与Ibatis的区别: 1、Mybatis实现了接口绑定,使用更加方便 在ibatis2.x中我们需要在DAO的实现类中指定具
- 在Word插入分页符可以在指定段落后插入,也可以在特定文本位置处插入。本文,将以Java代码来操作以上两种文档分页需求。下面是详细方法及步骤
- 引言热修复技术如今已经不是一个新颖的技术,很多公司都在用,而且像阿里、腾讯等互联网巨头都有自己的热修复框架,像阿里的AndFix采用的是ho