java開發(fā)WMS倉庫商品預警需求示例解析
1.預警需求
為了更好的管理商品日期,需要對倉庫的商品進行預警管理,對商品的保質期控制在一個范圍內提示出來,也可以通過該功能間接的展示出一個商品的的銷量程度和對下次進貨做個考量!
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ù)我們如果只要使用某個字段去修改,盡量查詢下該表更新的字段數(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標識預警日期已經到達 //使用boolean類型保存數(shù)據(jù)庫會自動把true轉換成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>
生產者添加消息到隊列中
//存入隊列 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
生產者,生產的數(shù)據(jù)類型一定要要和消費者獲取的類型要一致,否則會無限循環(huán)報錯
Listener threw exception No method found for class [B
4.測試是否成功
生產者存入隊列:
消費者獲取數(shù)據(jù):
如果消費方法報錯不try/catch的話,隊列就會一直重試該條數(shù)據(jù)
可以看出已經獲取到修改預警商品的商品編號,這個時候我們只要寫方法做相應的處理就行了
我們也可以去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); } }
關于一些代碼存在冗余我們可以提取成一個公共方法進行調用,后續(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倉庫商品預警需求示例解析的詳細內容,更多關于java開發(fā)WMS倉庫商品預警的資料請關注腳本之家其它相關文章!
相關文章
springmvc+shiro+maven 實現(xiàn)登錄認證與權限授權管理
Shiro 是一個 Apache 下的一開源項目項目,旨在簡化身份驗證和授權,下面通過實例代碼給大家分享springmvc+shiro+maven 實現(xiàn)登錄認證與權限授權管理,感興趣的朋友一起看看吧2017-09-09基于自定義BufferedReader中的read和readLine方法
下面小編就為大家分享一篇基于自定義BufferedReader中的read和readLine方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12Javaweb EL自定義函數(shù)開發(fā)及代碼實例
這篇文章主要介紹了Javaweb EL自定義函數(shù)開發(fā)及代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06Java8中 LocalDate和java.sql.Date的相互轉換操作
這篇文章主要介紹了Java8中 LocalDate和java.sql.Date的相互轉換操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12