源碼解析:從部署到核心業(yè)務(wù)流程全攻略)
簡(jiǎn)介這是一套開箱即用的Java版WMS倉(cāng)庫(kù)管理系統(tǒng)企業(yè)級(jí)源碼面向Java后端開發(fā)者、MES/WMS系統(tǒng)實(shí)施工程師及高校物流信息化課程實(shí)踐者解決倉(cāng)儲(chǔ)作業(yè)數(shù)字化建模與快速部署難題。資源包含2030個(gè)文件主體為182個(gè)核心Java業(yè)務(wù)模塊、213個(gè)MyBatis映射XML、1569份Markdown格式技術(shù)文檔含接口說明、模塊設(shè)計(jì)與流程圖解輔以PDF部署手冊(cè)、SQL初始化腳本及Vue2前端頁面源碼壓縮包體積達(dá)262.43MB。已有203人下載學(xué)習(xí)配套提供圖文并茂的WMS部署文檔.docx與實(shí)操部署視頻覆蓋寶塔面板一鍵部署、SpringBootVue前后端聯(lián)調(diào)、MySQL5.7數(shù)據(jù)初始化等關(guān)鍵環(huán)節(jié)并完整實(shí)現(xiàn)入庫(kù)/出庫(kù)/調(diào)撥/退貨全鏈路業(yè)務(wù)及采購(gòu)、質(zhì)檢、生產(chǎn)、庫(kù)存等11大管理模塊結(jié)構(gòu)清晰、注釋完備適合二次開發(fā)與教學(xué)實(shí)訓(xùn)。 在倉(cāng)儲(chǔ)物流這個(gè)圈子里WMS系統(tǒng)倉(cāng)儲(chǔ)管理系統(tǒng)一直是企業(yè)信息化的核心環(huán)節(jié)。最近正好在整理一套Java版的WMS系統(tǒng)源碼包含了完整的部署文檔和部署視頻從數(shù)據(jù)庫(kù)初始化到項(xiàng)目啟動(dòng)、業(yè)務(wù)跑通全都有覆蓋。這篇文章我打算從源碼本身出發(fā)講講這套系統(tǒng)的業(yè)務(wù)鏈路、技術(shù)選型邏輯、部署環(huán)境準(zhǔn)備、典型業(yè)務(wù)流的實(shí)現(xiàn)方式以及我在實(shí)際部署和二次開發(fā)中踩過的幾個(gè)坑。不管你是想快速搭一套WMS用到實(shí)際業(yè)務(wù)中還是想通過企業(yè)級(jí)項(xiàng)目源碼來提升Java開發(fā)能力這篇文章應(yīng)該都能讓你少走不少?gòu)澛贰?. 為什么Java版WMS源碼值得研究從業(yè)務(wù)痛點(diǎn)到選型邏輯1.1 倉(cāng)儲(chǔ)管理系統(tǒng)的核心業(yè)務(wù)鏈路在拆解這套源碼之前得先明白WMS在整個(gè)供應(yīng)鏈里到底扮演什么角色。很多沒接觸過倉(cāng)儲(chǔ)業(yè)務(wù)的人會(huì)把WMS和進(jìn)銷存軟件混為一談實(shí)際上WMS管理的顆粒度要細(xì)得多——它管的不只是倉(cāng)庫(kù)里有什么而是每個(gè)貨架上有多少哪個(gè)批次的貨先到期揀貨員走哪條路線最省時(shí)這類具體執(zhí)行層面的問題。一套標(biāo)準(zhǔn)的WMS業(yè)務(wù)鏈路大致圍繞四個(gè)核心環(huán)節(jié)展開入庫(kù)采購(gòu)到貨、退貨入庫(kù)、調(diào)撥入庫(kù)核心動(dòng)作是收貨、驗(yàn)收、組托、上架。庫(kù)內(nèi)管理庫(kù)存查詢、盤點(diǎn)、移位、補(bǔ)貨、凍結(jié)/解凍核心目標(biāo)是保證賬實(shí)一致。出庫(kù)銷售出庫(kù)、調(diào)撥出庫(kù)、退供應(yīng)商出庫(kù)核心動(dòng)作是分配庫(kù)存、揀貨、復(fù)核、打包、發(fā)運(yùn)。庫(kù)存賬實(shí)時(shí)反映可用庫(kù)存、凍結(jié)庫(kù)存、在途庫(kù)存所有業(yè)務(wù)單據(jù)流轉(zhuǎn)的最終落點(diǎn)都是庫(kù)存賬。這套Java版WMS源碼把這幾個(gè)環(huán)節(jié)基本都覆蓋了。我在通讀源碼的時(shí)候感受很深的一點(diǎn)是它的模塊劃分不是隨意堆出來的而是嚴(yán)格按真實(shí)倉(cāng)庫(kù)作業(yè)流程來的。比如入庫(kù)單創(chuàng)建之后貨品不是直接進(jìn)庫(kù)存賬而是先走收貨狀態(tài)再到上架動(dòng)作完成后庫(kù)存才真正增加。這個(gè)設(shè)計(jì)邏輯和現(xiàn)實(shí)中貨沒放到貨架上就不算入庫(kù)的業(yè)務(wù)習(xí)慣完全一致對(duì)做二次開發(fā)的人來說非常友好。1.2 為什么是Java而不是其他技術(shù)?,F(xiàn)在市面上WMS系統(tǒng)用什么技術(shù)寫的都有Python、C#、甚至PHP都見過但企業(yè)級(jí)的WMS最終選Java的占比還是最高的。這套源碼選了Java技術(shù)棧我認(rèn)為有以下幾個(gè)原因。第一Java生態(tài)里以Spring Boot為核心的微服務(wù)/單體應(yīng)用方案非常成熟做權(quán)限、事務(wù)、緩存、消息隊(duì)列這些基礎(chǔ)設(shè)施時(shí)不需要從零造輪子。WMS這種業(yè)務(wù)涉及大量單據(jù)狀態(tài)流轉(zhuǎn)和庫(kù)存一致性校驗(yàn)正好是Spring聲明式事務(wù)最擅長(zhǎng)的場(chǎng)景。第二Java在并發(fā)處理上的表現(xiàn)穩(wěn)定。WMS是典型的多用戶高頻操作場(chǎng)景倉(cāng)庫(kù)里可能同時(shí)有十幾臺(tái)PDA在掃碼收貨、揀貨、盤點(diǎn)后端接口的并發(fā)壓力并不小。Java配合MyBatis的樂觀鎖、ConcurrentHashMap緩存熱點(diǎn)數(shù)據(jù)處理這類場(chǎng)景有大量現(xiàn)成經(jīng)驗(yàn)可循。第三從企業(yè)長(zhǎng)期維護(hù)角度看Java后端開發(fā)者的供給量最大出了問題找人接手容易。而且WMS基本都要和ERP、MES、TMS對(duì)接Java的對(duì)接生態(tài)也是所有語言里最完善的。提醒一句選擇什么語言寫的WMS有時(shí)候不是純技術(shù)問題而是誰在維護(hù)這套系統(tǒng)的問題。如果你所在團(tuán)隊(duì)全是PHP工程師那強(qiáng)行上Java版WMS后續(xù)維護(hù)會(huì)很吃力。這套源碼適合團(tuán)隊(duì)熟悉Java或者愿意學(xué)習(xí)Java的情況。2. WMS源碼的功能全景從入庫(kù)到出庫(kù)的完整閉環(huán)2.1 核心功能模塊拆解這套WMS源碼的功能模塊可以從菜單結(jié)構(gòu)上一眼看出來基本覆蓋了倉(cāng)儲(chǔ)日常作業(yè)面。我按業(yè)務(wù)維度梳理一下模塊核心功能關(guān)鍵業(yè)務(wù)對(duì)象基礎(chǔ)資料倉(cāng)庫(kù)、庫(kù)區(qū)、庫(kù)位、貨品、條碼、批次倉(cāng)庫(kù)、庫(kù)區(qū)、庫(kù)位、貨品檔案入庫(kù)管理采購(gòu)入庫(kù)、退貨入庫(kù)、調(diào)撥入庫(kù)、收貨確認(rèn)入庫(kù)單、入庫(kù)單行、上架記錄出庫(kù)管理銷售出庫(kù)、波次下發(fā)、揀貨、復(fù)核、打包出庫(kù)單、出庫(kù)單行、波次、揀貨任務(wù)庫(kù)內(nèi)管理盤點(diǎn)、移位、凍結(jié)/解凍、庫(kù)存調(diào)整盤點(diǎn)單、移位單、庫(kù)存凍結(jié)單庫(kù)存管理實(shí)時(shí)庫(kù)存、流水查詢、可用量/凍結(jié)量實(shí)時(shí)庫(kù)存、庫(kù)存流水報(bào)表中心出入庫(kù)報(bào)表、庫(kù)存臺(tái)賬、員工作業(yè)績(jī)效各維度統(tǒng)計(jì)報(bào)表從源碼工程結(jié)構(gòu)來看業(yè)務(wù)代碼集中在類似wms-server、wms-admin這樣的模塊里Controller層只做參數(shù)接收和數(shù)據(jù)返回核心業(yè)務(wù)邏輯放在Service層。這種分層方式即使沒接觸過這套源碼也能很快找到對(duì)應(yīng)的業(yè)務(wù)代碼位置?;A(chǔ)資料模塊有一個(gè)很容易忽略但很關(guān)鍵的細(xì)節(jié)貨品檔案里包含了雙單位設(shè)計(jì)同時(shí)支持基本單位和換算單位。舉個(gè)例子某商品按箱入庫(kù)、按瓶出庫(kù)系統(tǒng)在收貨時(shí)會(huì)自動(dòng)按換算比例轉(zhuǎn)換庫(kù)存單位。這個(gè)設(shè)計(jì)雖然增加了一點(diǎn)表結(jié)構(gòu)和代碼復(fù)雜度但現(xiàn)實(shí)中非常實(shí)用否則不同計(jì)量單位之間的庫(kù)存對(duì)賬會(huì)讓你崩潰。2.2 數(shù)據(jù)庫(kù)表設(shè)計(jì)的關(guān)鍵思路WMS系統(tǒng)的復(fù)雜程度很大程度上體現(xiàn)在數(shù)據(jù)庫(kù)表設(shè)計(jì)上。這套源碼的庫(kù)表結(jié)構(gòu)我認(rèn)為有三個(gè)設(shè)計(jì)特別值得借鑒。第一單據(jù)頭/行分離。不管是入庫(kù)單還是出庫(kù)單都拆成了主表和明細(xì)表。比如入庫(kù)單主表存單號(hào)、供應(yīng)商、倉(cāng)庫(kù)、狀態(tài)、制單人、審核人等公共信息明細(xì)表存貨品、數(shù)量、單價(jià)、批次、庫(kù)位等逐行信息。這種設(shè)計(jì)的直接好處是一個(gè)單據(jù)可以有幾十行明細(xì)查詢、統(tǒng)計(jì)、審核都靈活不會(huì)因?yàn)閱涡袛?shù)據(jù)過多導(dǎo)致主表字段冗余。第二實(shí)時(shí)庫(kù)存與庫(kù)存流水分離。這是我覺得整套庫(kù)表設(shè)計(jì)里最核心的一點(diǎn)。實(shí)時(shí)庫(kù)存表只保存當(dāng)前狀態(tài)記錄某個(gè)貨品在當(dāng)前庫(kù)位的可用量、凍結(jié)量、總量而庫(kù)存流水表則像流水賬一樣記錄每一次入庫(kù)、出庫(kù)、調(diào)整、盤點(diǎn)的增減明細(xì)。把實(shí)時(shí)數(shù)據(jù)和流水?dāng)?shù)據(jù)分開業(yè)務(wù)邏輯會(huì)清晰很多查詢庫(kù)存走實(shí)時(shí)表很快追溯歷史走流水表很全。我在很多企業(yè)級(jí)WMS里都看到過類似設(shè)計(jì)這算是一個(gè)標(biāo)準(zhǔn)答案。第三庫(kù)位維度的庫(kù)存記錄。庫(kù)存表的粒度不是貨品匯總而是貨品批次庫(kù)位。同一個(gè)商品存放在不同庫(kù)位會(huì)被記錄為多條庫(kù)存記錄。這樣設(shè)計(jì)的好處是支持先進(jìn)先出和指定批次出庫(kù)壞處是數(shù)據(jù)量大一些但如果庫(kù)位、批次維度不加進(jìn)去WMS的精細(xì)化管理能力就無從談起。2.3 權(quán)限體系與多倉(cāng)支持權(quán)限這塊這套源碼采用的是典型的RBAC模型用戶關(guān)聯(lián)角色角色關(guān)聯(lián)菜單權(quán)限和接口權(quán)限。前端根據(jù)權(quán)限碼控制按鈕顯隱后端在操作關(guān)鍵業(yè)務(wù)時(shí)校驗(yàn)permission雙端校驗(yàn)?zāi)苡行Х乐估@過前端直接調(diào)接口的越權(quán)行為。多倉(cāng)支持方面源碼在基礎(chǔ)資料里以倉(cāng)庫(kù)作為一級(jí)數(shù)據(jù)隔離維度。用戶登錄后通過上下文拿到當(dāng)前用戶所屬倉(cāng)庫(kù)或權(quán)限范圍內(nèi)的倉(cāng)庫(kù)集合所有庫(kù)存查詢、單據(jù)創(chuàng)建都帶上了倉(cāng)庫(kù)條件。這種設(shè)計(jì)在單倉(cāng)場(chǎng)景下感受不明顯一旦部署到多倉(cāng)環(huán)境數(shù)據(jù)隔離就非常關(guān)鍵了。注意多倉(cāng)數(shù)據(jù)的隔離這套源碼做的是邏輯隔離不是物理分庫(kù)分表。如果倉(cāng)庫(kù)數(shù)量非常多而且數(shù)據(jù)量爆炸可能需要改造為更復(fù)雜的按倉(cāng)庫(kù)維度分庫(kù)的方案但這對(duì)大部分中大型倉(cāng)庫(kù)其實(shí)并不是必要的。3. 部署前必須搞定的環(huán)境準(zhǔn)備JDK、MySQL、Redis等3.1 JDK版本與環(huán)境變量配置雖然部署文檔和視頻里已經(jīng)把步驟寫得很清楚了但我仍然建議你先對(duì)著文檔把環(huán)境準(zhǔn)備列表檢查一遍因?yàn)楹芏嗖渴饐栴}根子上都是環(huán)境不一致導(dǎo)致的。這套Java版WMS系統(tǒng)從源碼的pom.xml和編譯配置來看是基于JDK 1.8或更高版本來開發(fā)的。如果你用的是Java 17部分依賴可能需要升級(jí)版本所以最簡(jiǎn)單的方案是用JDK 8和大多數(shù)企業(yè)級(jí)Spring Boot項(xiàng)目保持一致。JDK配置最核心的是環(huán)境變量。在Windows上需要配置JAVA_HOME、PATH、CLASSPATH在Linux上通常配置在/etc/profile或用戶級(jí).bashrc中。Windows設(shè)置方式如下JAVA_HOME C:\Program Files\Java\jdk1.8.0_202 PATH %JAVA_HOME%\bin;%PATH% CLASSPATH .;%JAVA_HOME%\lib裝完之后在命令行執(zhí)行java -version和javac -version兩個(gè)命令都能正常輸出版本號(hào)才說明JDK環(huán)境沒問題。我見過很多部署卡在java能跑但mvn編譯報(bào)錯(cuò)的案例十有八九是JAVAC沒進(jìn)PATH。3.2 數(shù)據(jù)庫(kù)初始化與Redis配置要點(diǎn)這套源碼后端存儲(chǔ)用的是MySQL緩存用的是Redis另外可能還依賴了消息隊(duì)列或?qū)ο蟠鎯?chǔ)具體看源碼里的application.yml或application-prod.yml。數(shù)據(jù)庫(kù)初始化的思路是先在MySQL里創(chuàng)建一個(gè)獨(dú)立的庫(kù)比如wms_db然后把源碼包里的SQL腳本按順序?qū)?。?dǎo)入時(shí)需要注意幾點(diǎn)確保MySQL版本不低于5.7建議8.0以上字符集采用utf8mb4排序規(guī)則用utf8mb4_general_ci或utf8mb4_unicode_ci。如果SQL腳本有順序依賴一定要嚴(yán)格按文件名序號(hào)執(zhí)行先建表結(jié)構(gòu)再導(dǎo)初始數(shù)據(jù)。導(dǎo)入完成后至少確認(rèn)用戶表、菜單表、庫(kù)存表存在數(shù)據(jù)。有些源碼的初始數(shù)據(jù)里包含管理員賬號(hào)部署完要第一時(shí)間改密碼。Redis的配置也一樣重要。日志里常見的Caused by: redis.clients.jedis.exceptions.JedisConnectionException基本都是因?yàn)镽edis服務(wù)沒啟動(dòng)端口不是默認(rèn)的6379配置了密碼但代碼里沒填或填錯(cuò)Redis只綁定了127.0.0.1后端跨機(jī)器訪問連不上。把Redis配置調(diào)整為匹配本機(jī)環(huán)境的地址、端口、密碼然后再啟動(dòng)后端應(yīng)用。3.3 部署文檔和視頻的正確打開方式這套源碼附帶的部署文檔和部署視頻說實(shí)話是企業(yè)級(jí)項(xiàng)目里比較難得的交付物了。文檔的作用是知其然視頻的作用是知其所以然——文檔告訴你步驟是什么視頻能告訴你點(diǎn)每一步時(shí)屏幕上應(yīng)該出現(xiàn)什么界面、報(bào)什么錯(cuò)是正常的。我建議第一次部署時(shí)這么配合使用先完整看一遍部署視頻心里有個(gè)全局流程知道大概有哪些步驟、每步驟大概耗時(shí)多久。再打開部署文檔把環(huán)境要求那一節(jié)和自己電腦上的環(huán)境逐項(xiàng)對(duì)照。動(dòng)手操作時(shí)每完成一個(gè)階段就核對(duì)一下文檔里的驗(yàn)證點(diǎn)比如數(shù)據(jù)庫(kù)查詢正常、后端日志打印啟動(dòng)成功、前端頁面能登錄。如果卡住回到視頻對(duì)應(yīng)的時(shí)間節(jié)點(diǎn)看操作細(xì)節(jié)很多怪問題其實(shí)是漏了某一步。另外強(qiáng)調(diào)兩點(diǎn)一是部署文檔里的路徑、端口、賬號(hào)密碼一定要按自己的環(huán)境替換不要照抄二是部署視頻里可能是某個(gè)特定版本的界面如果你拿到的源碼版本稍新菜單或按鈕位置可能有細(xì)微差異這不代表你操作錯(cuò)了以實(shí)際源碼為準(zhǔn)。4. 源碼運(yùn)行后的核心業(yè)務(wù)流走讀用真實(shí)單據(jù)串起來4.1 采購(gòu)入庫(kù)單的完整流轉(zhuǎn)系統(tǒng)跑起來之后我建議不要直接去看報(bào)表而是走一遍真實(shí)的采購(gòu)入庫(kù)流程這樣能把源碼里的核心業(yè)務(wù)串聯(lián)起來。第一步在入庫(kù)管理模塊新建一張采購(gòu)入庫(kù)單選擇供應(yīng)商、倉(cāng)庫(kù)錄入貨品明細(xì)和數(shù)量。此時(shí)這張單的狀態(tài)是創(chuàng)建或待審核。你會(huì)在數(shù)據(jù)庫(kù)的入庫(kù)單主表里能看到一條H狀態(tài)的數(shù)據(jù)明細(xì)表里能看到對(duì)應(yīng)的入庫(kù)單行。第二步審核通過后單據(jù)流轉(zhuǎn)到收貨環(huán)節(jié)。現(xiàn)實(shí)中這個(gè)時(shí)候是倉(cāng)庫(kù)理貨員去核對(duì)實(shí)物和單據(jù)源碼里對(duì)應(yīng)一個(gè)收貨確認(rèn)動(dòng)作貨品數(shù)量會(huì)在入庫(kù)單行上被標(biāo)記為已收數(shù)量。第三步確認(rèn)收貨之后是上架動(dòng)作需要指定目標(biāo)庫(kù)位。這一步很關(guān)鍵——只有執(zhí)行了上架庫(kù)存賬里的可用量才會(huì)增加。在源碼里你會(huì)在庫(kù)存流水表里看到一條入庫(kù)類型的記錄實(shí)時(shí)庫(kù)存表里的對(duì)應(yīng)庫(kù)位上也多出了可用量。這個(gè)流程設(shè)計(jì)是合理的它嚴(yán)格區(qū)分了貨已到倉(cāng)庫(kù)收貨和貨已放到貨架上上架兩個(gè)業(yè)務(wù)節(jié)點(diǎn)。兩者之間單據(jù)狀態(tài)不同庫(kù)存狀態(tài)也不同這在WMS業(yè)務(wù)里非常重要因?yàn)楝F(xiàn)實(shí)中從收貨到上架通常有幾個(gè)小時(shí)的延遲。4.2 銷售出庫(kù)與波次策略出庫(kù)流程比入庫(kù)更復(fù)雜因?yàn)樯婕皫?kù)存分配和揀貨執(zhí)行。這套源碼里出庫(kù)單同樣走創(chuàng)建→審核→分配→揀貨→復(fù)核→出庫(kù)等一系列狀態(tài)。在庫(kù)存分配這一步系統(tǒng)要根據(jù)出庫(kù)單的貨品明細(xì)從實(shí)時(shí)庫(kù)存表中按指定的分配策略比如先進(jìn)先出、指定批次、最近庫(kù)位優(yōu)先找到滿足數(shù)量的庫(kù)位庫(kù)存生成一條分配明細(xì)。這個(gè)分配動(dòng)作不是直接扣減庫(kù)存而是先鎖住對(duì)應(yīng)的可用量將其轉(zhuǎn)為已分配量。波次則是把多張出庫(kù)單按照某些共同屬性比如同一承運(yùn)商、同一收貨區(qū)域、同一出庫(kù)庫(kù)區(qū)合并成一個(gè)揀貨批次。倉(cāng)庫(kù)揀貨員只需要按波次去揀貨效率會(huì)高不少。源碼里波次的核心邏輯是創(chuàng)建一個(gè)波次單 → 把符合條件的出庫(kù)單行關(guān)聯(lián)進(jìn)來 → 基于波次生成揀貨任務(wù) → 揀貨員完成揀貨后系統(tǒng)扣減庫(kù)存并推進(jìn)出庫(kù)單狀態(tài)。出庫(kù)流程里最值得看的是庫(kù)存扣減的時(shí)機(jī)。很多初級(jí)設(shè)計(jì)是在出庫(kù)單創(chuàng)建時(shí)就減庫(kù)存這在簡(jiǎn)單場(chǎng)景下能用但一到訂單取消部分發(fā)貨就會(huì)出問題。這套源碼把扣減動(dòng)作放在揀貨完成階段前面只是鎖定可用量等貨真的被揀出來了再轉(zhuǎn)成實(shí)際扣減。這樣既保證了庫(kù)存不被超賣也保留了取消單據(jù)的靈活性。4.3 庫(kù)存并發(fā)扣減的實(shí)現(xiàn)細(xì)節(jié)WMS最容易被問到的技術(shù)問題就是并發(fā)——多個(gè)PDA同時(shí)操作庫(kù)存怎么防超賣這套源碼在處理庫(kù)存扣減時(shí)用到了數(shù)據(jù)庫(kù)層面的鎖機(jī)制。具體來說在更新實(shí)時(shí)庫(kù)存表時(shí)SQL語句里通常會(huì)帶條件where stock needQty或者對(duì)庫(kù)存行加for update。判斷庫(kù)存充足和扣減庫(kù)存是一個(gè)原子操作如果庫(kù)存不夠更新行數(shù)為0業(yè)務(wù)層再拋出庫(kù)存不足異常前端就會(huì)提示操作失敗。除了數(shù)據(jù)庫(kù)鎖源碼里也用了Redis作為緩存層。熱點(diǎn)數(shù)據(jù)放到Redis后查詢很快但如果數(shù)據(jù)一致性控制不好很容易出現(xiàn)緩存與數(shù)據(jù)庫(kù)不一致。實(shí)戰(zhàn)中我不建議在WMS里做太復(fù)雜的緩存方案——庫(kù)存數(shù)據(jù)實(shí)時(shí)性要求太高緩存要么只做純查詢場(chǎng)景要么做完寫操作后立刻主動(dòng)失效并配合MQ或定時(shí)任務(wù)兜底刷新。5. 部署與運(yùn)行中的高頻問題排查5.1 環(huán)境問題JDK版本與內(nèi)存溢出部署階段最常見的報(bào)錯(cuò)第一類是JDK版本不匹配。Maven編譯時(shí)提示invalid target release或者source option 8 is no longer supported基本都是JDK版本和pom里的編譯版本不一致。解決辦法很簡(jiǎn)單把JDK切到1.8或者把pom里maven.compiler.source調(diào)整為當(dāng)前JDK版本。第二類是啟動(dòng)時(shí)內(nèi)存溢出。后端服務(wù)啟動(dòng)時(shí)報(bào)java.lang.OutOfMemoryError: Java heap space這時(shí)候需要調(diào)整JVM參數(shù)java -Xms512m -Xmx2048m -XX:MetaspaceSize256m -jar wms-server.jar-Xms 是初始堆內(nèi)存-Xmx 是最大堆內(nèi)存。單機(jī)部署時(shí)建議堆內(nèi)存至少給2G因?yàn)閃MS涉及大量庫(kù)存計(jì)算和報(bào)表統(tǒng)計(jì)內(nèi)存不夠很容易在跑批任務(wù)時(shí)掛掉。你在部署文檔里如果看到推薦的JVM參數(shù)直接按那個(gè)配別自己隨手填一個(gè)很小的值。5.2 數(shù)據(jù)庫(kù)連接與中文亂碼數(shù)據(jù)庫(kù)連接問題最多的就是啟動(dòng)日志里出現(xiàn)Access denied for user或Communications link failure。前者是賬號(hào)密碼錯(cuò)誤后者通常是MySQL端口沒對(duì)、防火墻擋了、或連接串地址寫錯(cuò)。MySQL 8.0 還要注意驅(qū)動(dòng)不能太舊依賴?yán)镆胼^新的mysql-connector-java版本。中文亂碼問題也很常見尤其是在導(dǎo)入初始化SQL之后。亂碼的根源基本是字符集不統(tǒng)一可以從三個(gè)地方排查數(shù)據(jù)庫(kù)表字符集確認(rèn)是utf8mb4。JDBC連接串一定要加characterEncodingutf8。前端頁面編譯編碼源碼里如果是HTML或JSPmeta charset要一致。示例JDBC配置jdbc:mysql://localhost:3306/wms_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai還有一個(gè)容易忽視的坑是時(shí)區(qū)問題。如果連接串不加serverTimezoneAsia/Shanghai用高版本MySQL驅(qū)動(dòng)連接時(shí)會(huì)報(bào)時(shí)區(qū)相關(guān)的異常或者日期字段比正常時(shí)間少8小時(shí)。5.3 并發(fā)場(chǎng)景下庫(kù)存不準(zhǔn)的處理系統(tǒng)已經(jīng)跑起來了但發(fā)現(xiàn)兩個(gè)用戶同時(shí)操作出庫(kù)時(shí)庫(kù)存偶爾會(huì)出現(xiàn)負(fù)數(shù)或?qū)Σ簧咸?hào)。這個(gè)問題我在部署和測(cè)試階段遇到過不止一次排查鏈路基本是這樣的第一步先看后端日志里有沒有鎖等待超時(shí)。如果出現(xiàn)Lock wait timeout exceeded說明業(yè)務(wù)事務(wù)時(shí)間過長(zhǎng)導(dǎo)致行鎖被長(zhǎng)時(shí)間持有。解決方案是給事務(wù)加索引盡量讓更新操作快速提交避免在事務(wù)里做耗時(shí)的外部調(diào)用。第二步檢查庫(kù)存扣減邏輯是否用了樂觀鎖。很多WMS在庫(kù)存表里加一個(gè)version字段更新時(shí)where version ?如果版本號(hào)匹配不上就放棄更新并重試。這套源碼如果沒有加version你可能需要自己補(bǔ)上。第三步看是不是多節(jié)點(diǎn)部署導(dǎo)致緩存不一致。如果負(fù)載均衡后面掛了多臺(tái)后端實(shí)例Redis雖然是共享的但本地進(jìn)程內(nèi)緩存比如Caffeine各節(jié)點(diǎn)各自維護(hù)一份數(shù)據(jù)就容易不一致。WMS這種實(shí)時(shí)性要求高的系統(tǒng)建議關(guān)掉本地緩存或者設(shè)置極短的過期時(shí)間。結(jié)尾這幾天下來的感受是一套好上手的WMS源碼真正值錢的不是那一堆CRUD代碼而是它把倉(cāng)儲(chǔ)業(yè)務(wù)中那些潛規(guī)則用代碼表達(dá)得清清楚楚——收貨和上架的區(qū)分、可用量和已分配量的鎖扣、庫(kù)存流水和實(shí)時(shí)庫(kù)存的雙寫、波次策略對(duì)出庫(kù)效率的影響。你把這套源碼部署起來、跑通核心業(yè)務(wù)流之后再去看其他WMS系統(tǒng)會(huì)發(fā)現(xiàn)很多東西是相通的。最后分享一個(gè)小技巧拿這套源碼做二次開發(fā)時(shí)先別急著加功能先把實(shí)時(shí)庫(kù)存表和歷史流水表的數(shù)據(jù)關(guān)系吃透很多看似復(fù)雜的需求最后都會(huì)落到當(dāng)前值與流水變更的計(jì)算上。如果這兩張表的數(shù)據(jù)邏輯理順了對(duì)接PDA、對(duì)接電子秤、對(duì)接AGV調(diào)度都只是時(shí)間問題。本文還有配套的精品資源點(diǎn)擊獲取