java開發(fā)WMS倉庫商品預警需求示例解析
1.預警需求
為了更好的管理商品日期,需要對倉庫的商品進行預警管理,對商品的保質(zhì)期控制在一個范圍內(nèi)提示出來,也可以通過該功能間接的展示出一個商品的的銷量程度和對下次進貨做個考量!
1. 預警需求分析
- 前端界面需要設置商品的預警天數(shù)
- 后端保存預警天數(shù)
- 數(shù)據(jù)庫有字段存放商品需要預警的天數(shù)
- 通過定時器運行指點方法算出對應那些商品的批次存低于設置的預警天數(shù)
- 查詢出來在wms首頁展出
2.數(shù)據(jù)庫表
對于前端界面的開發(fā)不做過多的代碼分析,本次重點展示商品預警實現(xiàn)思路!!
數(shù)據(jù)庫用到到字段會截取出來,便于理解!
商品表數(shù)據(jù):

預警表數(shù)據(jù):

商品批次表:

商品批次表中添加預警字段:后續(xù)查詢對應的預警信息作為標志

Mysql使用到的函數(shù)
//查詢當前時間
select now();
//獲取時間相減 獲取到天數(shù) 參數(shù)是前面-后面
select DATEDIFF("2022-9-10", now()) as day
如:

由此我們就可以通過函數(shù)算出商品距離過期的天數(shù)

查詢語句:
SELECT bb.id as batchId, bb.product_id as productId, DATEDIFF(bb.ed, now()) as warnDate
FROM `商品批次表` bb需要注意: 查詢或者修改表數(shù)據(jù)我們?nèi)绻灰褂媚硞€字段去修改,盡量查詢下該表更新的字段數(shù)據(jù)是否有重復的數(shù)據(jù)并且其他字段可能跟我們預想不一致,必須要修改的,我們就應該使用多字段去查詢修改
查詢重復數(shù)據(jù)
select * from 表 GROUP BY 字段 HAVING count(*)>1
查詢預警批次數(shù)量: 因為需要展示出來在前端可以給用戶點擊查看貨物存放的地方,所以查詢出來的數(shù)據(jù)庫存數(shù)量要大于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.后端代碼實現(xiàn):
1. 定時器任務
使用Scheduled作為定時器,通過cron語法指定運行時間,每3小時運行一次表達式如下

代碼詳情注釋寫的也比較清楚
/**
* 每3小時運行一次
*/
@Scheduled(cron = "0 0 0/3 * * ?")
public void goodsWarn(){
BasicProductGpExample basicProductGpExample = new BasicProductGpExample();
List<String> warnBatchIds=new ArrayList<>();
//查詢商品預警表信息 商品的貨號是唯一的 (所以現(xiàn)在是全表查詢出來)
// 這里把商品預警信息都查詢出來為了以后擴展做庫存預警設置
List<BasicProductGp> basicProductGps = productGpMapper.selectByExample(basicProductGpExample);
//查詢商品批次表:商品批次和天數(shù) 商品的批次是唯一的,存在多個商品貨號(所以現(xiàn)在是全表查詢出來)
// 以后擴展商品庫存預警只要在這個查詢里面添加關聯(lián)庫存數(shù)量查詢出來,然后在過濾里面添加預警數(shù)量判斷
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()));
//數(shù)組為空時不更新
if (CollectionUtils.isEmpty(warnBatchIds)){
log.info("沒有需要預警的商品批次!");
return;
}
//修改批次狀態(tài)為1標識預警日期已經(jīng)到達
//使用boolean類型保存數(shù)據(jù)庫會自動把true轉(zhuǎn)換成1
int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true);
log.info("更新預警數(shù)量:{}",count);
}
這里面還存在一個問題,如果批次被打上預警標識,此時客戶更改了商品的預警日期,那么商品的預警可能就沒有到達,但是頁面查詢預警也能被查詢出來,解決方案,使用mq來做處理,當客戶更改了商品編碼預警信息,那么程序就把更改的商品編碼存到mq中我們在寫個消費方法來消費更改后的商品編碼單獨走波預警方法
2.優(yōu)化加入隊列
先不考慮全局預警設置,只對勾選多個商品進行添加隊列

使用了springBoot的rabbitMq模板類RabbitTemplate
pom.xml引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
生產(chǎn)者添加消息到隊列中
//存入隊列 routingkey名稱 存入的數(shù)據(jù)
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
生產(chǎn)者,生產(chǎn)的數(shù)據(jù)類型一定要要和消費者獲取的類型要一致,否則會無限循環(huán)報錯
Listener threw exception No method found for class [B

4.測試是否成功
生產(chǎn)者存入隊列:

消費者獲取數(shù)據(jù):

如果消費方法報錯不try/catch的話,隊列就會一直重試該條數(shù)據(jù)
可以看出已經(jīng)獲取到修改預警商品的商品編號,這個時候我們只要寫方法做相應的處理就行了
我們也可以去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);
//商品批次和天數(shù) 商品的批次是唯一的,存在多個商品貨號(查詢變動的商品貨號)
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)){
//匹配到的商品數(shù)據(jù)
//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("更新預警數(shù)量:{}",count);
}
//更新預警商品
if (!CollectionUtils.isEmpty(warnBatchIds)){
int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true);
log.info("更新預警數(shù)量:{}",count);
}
}
關于一些代碼存在冗余我們可以提取成一個公共方法進行調(diào)用,后續(xù)也對全局修改預警Mq隊列走波運算預警的商品

重載方法:
/***
* 重載方法
* 用于運算全局商品類型
* 用于更新商品預警時間
*/
public void updateWarnGoods(){
BasicProductGpExample example = new BasicProductGpExample();
//查詢商品信息 商品的貨號是唯一的 (查詢變動的商品貨號)
List<BasicProductGp> basicProductGps = productGpMapper.selectByExample(example);
//商品批次和天數(shù) 商品的批次是唯一的,存在多個商品貨號(查詢變動的商品貨號)
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)){
//匹配到的商品數(shù)據(jù)
//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("更新預警數(shù)量:{}",count);
}
//更新預警商品
if (!CollectionUtils.isEmpty(warnBatchIds)){
int count = basicBatchMapper.updateByBatchWarn(warnBatchIds, true);
log.info("更新預警數(shù)量:{}",count);
}
}
3.前端提一嘴
給商品添加預警日期,需要用戶提些數(shù)據(jù),為了避免出現(xiàn)英文空格等我們需要,對輸入的數(shù)據(jù)進行正則,只能輸入數(shù)字


效果:

英文:

但是可以輸入0,如果預警日期設置成了0你們就意味著廢棄該商品預警提示功能
前端展示:
首頁:

預警商品列表:

以上就是java開發(fā)WMS倉庫商品預警需求示例解析的詳細內(nèi)容,更多關于java開發(fā)WMS倉庫商品預警的資料請關注腳本之家其它相關文章!
相關文章
IDEA搭建SpringBoot多模塊聚合工程過程詳解(多模塊聚合工程)
這篇文章主要是介紹一下,如何在IDEA開發(fā)工具下,搭建一個基于SpringBoot的多模塊聚合工程項目,本篇文章,將項目模塊細分為幾個子工程模塊,在文中給大家詳細介紹過,對IDEA搭建SpringBoot多模塊聚合工程感興趣的朋友一起看看吧2022-04-04
Zuul 實現(xiàn)網(wǎng)關轉(zhuǎn)發(fā)的五種方式小結
這篇文章主要介紹了Zuul 實現(xiàn)網(wǎng)關轉(zhuǎn)發(fā)的五種方式小結,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
springboot2.1.3配置sftp自定義sftp連接池的詳細過程
這篇文章主要介紹了springboot2.1.3配置sftp自定義sftp連接池的詳細過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08
基于Spring AMQP實現(xiàn)消息隊列的示例代碼
Spring AMQP作為Spring框架的一部分,是一套用于支持高級消息隊列協(xié)議(AMQP)的工具,AMQP是一種強大的消息協(xié)議,旨在支持可靠的消息傳遞,本文給大家介紹了如何基于Spring AMQP實現(xiàn)消息隊列,需要的朋友可以參考下2024-03-03

