此篇為萌新級別hzero 食用指南,記述了我學習過程中遇到的問題和心得,所記述不一定正確,僅供參考~
PS:有些圖很模糊,不曉得為什么從word或者Ty里拿出來的畫質壓縮得這么厲害,見諒。
1.版本號問題,當前應避免hzero企業版的 1.6.1和1.6.4版本服務組件(但是也不一定,有的人會出現的問題,別的人不一定會出現。很玄學,可能后續兼容性會加強吧)
2.前端頁面404問題:請查看package.json和hzerorc.json內是否添加了依賴,
然后看其workspace文件下(一般是/dist/packages/,如果是服務模塊,看routers.ts中的路徑)是否有對應組件,沒有則進行install並build,注意每次添加新的依賴后應當保存,然后運行的位置也要注意,比如子模塊單獨運行的話就不要在父模塊那個路徑下啟動,子模塊會無法及時刷新的,盡量在子模塊下編譯運行,如果想訪問父模塊(一般就是平台治理這些一級菜單模塊),可以單獨開一個命令行,在項目的根目錄運行就可以(因為子模塊運行無法向上訪問父模塊內容)
還有一種情況,因為平台和租戶兩個級別下 可以瀏覽的頁面是不一樣的,所以也有可能是沒有給用戶授予權限(去子賬戶管理->對應賬號->編輯),比如我以前遇到的(工作流練習中,未授權的賬戶無法訪問【我的待辦事項】,從消息中點擊【處理】會顯示404.)
3.如果安裝了某個組件,服務也啟動了,但是前端找不到顯示,這個恐怕不是前端的問題,因為h0組件是先基於數據庫進行渲染的,如果數據庫利用種子文件初始化有問題,在瀏覽器頁面可能會無法顯示對應的組件,可以考慮先查看數據庫,再決定是否刪掉對應庫然后重新建立並導入數據。
4.系統頁面提示【未安裝相關服務或者訪問的資源不存在】,可能是后台相關模塊未啟動,遇到這個問題可以先查看網頁控制台/審查元素,->network->請求狀態,若為200則ok(當然想必不會是200),40x 這類說不好,還是要排查一下依賴而且可能是其余關聯的模塊沒有成功加載導致的,根據后台報錯信息來判斷,比如401,就是無權限,看賬戶是否登錄,啟動類的相關權限注解是否添加, 資源注解沒有的話也是無法讀取或訪問資源的;
我曾遇到問題:swagger中可以看到對應模塊,但是系統工具刷新其權限缺失敗,最后服務都起了一遍然后前端也重啟了一遍就好了,中間還發現某些模塊顯示【訪問資源不存在】,后來也是刷新權限即可。
50x則是服務問題,先去后端看看是否日志里有報錯, 然后重新啟動一下,再看看路由id,路徑這些易錯的地方,如果都沒問題就去瀏覽器內hzero的頁面里看看,點擊服務管理
5.關於權限刷新問題:
刷新權限有很多種辦法,可以去swagger里刷新:admin->RefreshController,然后選擇serviceName,點擊Try it out,前四個都可以刷一下
也可以用平台刷新:平台管理員->【系統工具】,以及【服務管理】;
以及【缺失權限管理】,可以針對請求失敗的特定API進行權限添加。
6.通用調試思路:
報錯了,看報錯信息,判斷是前端還是后端問題,
->前端(前端一般都是直接導入,所以多半是依賴或版本問題)(單個組件問題可以用服務管理和系統工具刷一下,在超級管理員權限下)
->后端,查看模塊是否有日志報錯,
->若有則根據報錯信息和狀態碼去判斷
->若無報錯,先去swaggerUI界面查看一下相關服務是否啟動了
一般來說后台不報錯,邏輯也正確,前端頁面不報錯,那瀏覽器控制台的請求碼多半會有錯誤,如果都沒有報錯那就只能打斷點一點一點找了ORZ
具體調試方法仁者見仁智者見智,不多嘮叨了。
7.基礎服務:
hzero-register:注冊中心
hzero-admin:平台治理服務
hzero-gatway:網關服務
hzero-oauth:認證服務
hzero-swaggr:API測試服務(調試必備)
hzero-iam:用戶身份服務
Hzero-platform:平台服務
8.利用swagger測試API
響應體Response Body:
{"requestStatus":"PERMISSION_MISMATCH","requestCode":"error.permission.mismatch","requestMessage":"This request mismatch any permission","detailsMessage":"您訪問的資源不存在或者未安裝相關的服務"}
相應碼 為404
解決過程:
查看后台6組件+swagger,沒有報錯提示,再去看todo服務模塊,也沒報錯。
改了一下控制類的函數名和返回類型,無果
這下好了,還得啟動一下界面刷新權限;
刷新(todo和admin)后果然可以訪問了,狀態碼200
Unknown exception, Request: {URI=/v2/orderHeader/byId, method=NullMethod}, User: null
org.springframework.web.bind.MissingPathVariableException: Missing URI template variable 'companyId' for method parameter of type Long
更改請求:@GetMapping("/{companyId}")
這種基本上就是mapper注解里沒加{xxx}變量名xxx為要從路徑中獲取的變量
Unknown exception, Request: {URI=/v2/orderHeader/12, method=NullMethod}, User: null
java.lang.NullPointerException: null
空指針這個問題當時沒有解決,調用封裝好的API就不會空指針
后來發現空指針是因為我ddd開發不規范,使用@service注釋但是沒有調用對應的mapper,而是調用repository,(總之,自己寫的api 是控制層->repository的接口函數->repository的實現類->mapper接口->sql語句函數,開發要盡量規范)
9.引入前端后,問題變得多了起來,總之盡量先接口跑通后再去修改前端的url。
10.Mapper.xml里面sql語句盡量不要寫具體的數據庫名字(因為可以通過yaml配置文件確定是哪個庫)防止同名慘案
11.關於404,如果是h0頁面404,查看數據庫和部分組件依賴, 如果是前端url請求404,那么查看報錯信息,多半是permission _mismitch之類的權限問題,去系統工具或者swagger里面刷新”一下”權限就好了(怎么可能一次就好呢233)
12.接口測試的話,注意一下請求方法和response body
客戶端接口測試的話需要用post
13.前端可以直接傳遞對象給后端控制層,只不過其對象必然被包含在List數組內傳給后端:
后端參數內需添加注解@RequestBody
14.遇到寫完api后運行服務,發現swagge里沒有對應的api接口,只有其他接口。
看看基礎組件是否正常運行,刷新swagger,重啟所寫的服務類。
這個不是大問題,基本上基礎服務都跑起來,多刷幾次就好了
15.接口傳參報錯(狀態碼200)
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.util.List<com.hand.Test.domain.entity.OrderAll> com.hand.Test.api.controller.v1.OrderController.queryById(com.hand.Test.domain.entity.OrderAll,io.choerodon.mybatis.pagehelper.domain.PageRequest,int,int)
此處我使用了get方法訪問@RequestBody修飾的接口,應使用post方法訪問
16.傳參報錯 (狀態碼200)
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'zoey': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'zoey': was expecting ('true', 'false' or 'null')
經查詢,這種錯誤一般是由於返回的數據格式和接收返回結果的格式不同,比如我明明規定createdBy是long類型,但是自己卻輸入了zoey 這種字符串,就會報錯。
17.時間類型的報錯:
date format error java.text.ParseException: Unparseable date: "2019-08-14T07:22:33.117Z"
仔細看,發現這個date 不符合規范,應該yy-mm-dd:hh:mm:ss(好像是,反正沒有那個117z)
接口傳個正常的就可以了
18.org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'item_id' in 'class com.hand.Test.domain.entity.OrderAll'
這個就是字段問題,仔細查看set/get方法內的字段是否正確, 以及實體類內的,sql語句中的,這個問題並不復雜,主要是粗心導致。
19.當控制層返回參數以及SQL語句正常時 卻發現swagger接口查詢后的responsebody內缺少自己想要的字段,此時應該查看對應實體類,看看是不是少了什么字段
20.Error attempting to get column 'company_name' from result set.
查看數據庫和實體類,二者的字段類型不一致
21.我算是發現了,幾乎每次新寫一個api,用swagger測試基本都是404未授權,建議去動態刷新里一個個都把 todo服務刷新一遍
22.java.lang.IllegalStateException: Type handler was null on parameter mapping for property '__frch_soHeaderId_0'. It was either not specified and/or could not be found for the javaType (com.hand.Test.domain.entity.OrderHeader) : jdbcType (INTEGER) combination.]
這個錯是映射問題,仔細查看一下result映射和實體類的數據類型是否相符。
23.h0后端問題:遍歷查詢要注意判空,api應當添加校驗
寫導入客戶端的時候,點擊導入報了個錯:
發現idea后台報錯了,說沒有找到himp_import數據庫, 去數據庫一看,果然沒有,通過種子文件或者從別的庫導入即可,注意,用種子文件會覆蓋相關的import原表.
另外:
一直處於數據校驗狀態,有人遇到過,他的是由於版本問題,建議改為1.6.3,不幸的是,我也是,換了版本就可以了。
還有:
空指針異常:
其在importServiceImpl,也就是導入的實現類中,可能是由於導入的repository對象沒有加注解,所以找不到,另外,從邏輯上講,service應當調用repository的對象而不是mapper,其實如果你用private XXXMapper xxx也通常會提示無法autowire,沒有bean。
加注解后再導入有新的錯誤:
我用的是豬齒魚的插入函數,可能是其引用了sql解析工具jsqlparser.jar,是工具包拋出的異常,既然是封裝的sql,所以不是sql語句問題,可能是我數據源引用錯誤或者字段問題:
然后用debug打斷點,
注意,執行到4的時候才能看出3的值,例如此刻執行到4,就會顯示orderline為空
另外,點1執行當前頁面運行語句的下一行語句,2為當前函數的深層調用,會跳出本類頁面。
言歸正傳,我debug發現接收后對象都是空,是我接口平台寫的【維護模板列】有問題,應當和實體類對應,其字段要寫成駝峰的形式才可以。
23.如果報錯空指針空方法,重點在於空,可能是順着路徑找不到對象,屬於對象空,或者是路徑不對,也找不到對象,這種我理解為方法空。最近一次遇到的空指針是我引用了某個類的mapper,但是沒加@Autowire注解,導致找不到bean(有的時候它是會提示缺少bean的,有的時候就沒什么有用的報錯信息,孤零零一個空指針,就很難受了)
24.log打印輸出信息是個好習慣,偷懶寫法:給類上加@Sl4j注解( 有兩個,用這個:import lombok.extern.slf4j.Slf4j ),然后直接log.xxx即可
25工作流審批,審批人點 消息 -> 處理 ,會遇到404,這是由於審批人這個賬戶沒有分配租戶管理員權限,沒有租戶管理員就沒有 【我的待辦事項】,自然就無法審批處理了。
26.這次的問題依然是工作流:
我需要:流程審批通過后需要修改訂單頭狀態為【已審批】,拒絕操作后修改訂單狀態為【已拒絕】,通過節點事件觸發。
現在的問題是:工作流中審批人審批后無法觸發【服務節點】
甚至都沒進入工作流的控制類:
主服務打了斷點,但是壓根兒就沒進去這個控制類;
問題在哪呢?我有理由懷疑我規定的這個 【工作流事件】根本沒執行,於是去流程監控里看了一眼,果然:停在這里了
也不能說沒有執行,只能說,好像是卡在這里了,流程狀態【異常暫掛】
Workflow內的報錯信息如上
然后呢,在審批人未提交審批意見時,workflow有報錯但是沒有影響運行(大概):
提交后:
可能是因為我沒添加流程變量,
運行:
如果測接口時顯示【PERMISSION_NOT_PASS】就去平台的【缺失權限管理】里添加權限即可,主要是添加【客戶端授權】等
正常運行:
Swagger測試有問題,但是用平台的發布模擬是可以的,很奇怪
27.復測批量刪除
關於批量操作可以有兩種,一種是把遍歷放在sql里,一種是放在service里,此處為service里;
測試數據:
展開下方可查看 測試用例

[
{
"companyId": 1007,
"createdBy": 2,
"customerId": 100,
"itemId": 78,
"lineList": [
{
"_innerMap": {},
"addition1": "無",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "備注:廣受貓咪好評的貓罐頭",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 100,
"soLineId": 35,
"unitSellingPrice": 0
},
{
"_innerMap": {},
"addition1": "貓罐頭",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "備注:廣受貓咪好評的貓罐頭",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 100,
"soLineId": 36,
"unitSellingPrice": 0
}
],
"orderDate": "2021-08-13 15:03:48",
"orderHeader": {
"_innerMap": {},
"companyId": 1007,
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"customerId": 100,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"objectVersionNumber": 0,
"orderDate": "2021-08-13 15:03:48",
"orderNumber": "NEW",
"orderStatus": "NEW",
"soHeaderId": 100
},
"orderNumber": "100",
"orderStatus": "NEW",
"price": 110,
"soHeaderId": 100,
"soLineId": 36
},
{
"companyId": 1007,
"createdBy": 2,
"customerId": 100,
"itemId": 78,
"lineList": [
{
"_innerMap": {},
"addition1": "無",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "備注:廣受貓咪好評的貓罐頭",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 101,
"soLineId": 37,
"unitSellingPrice": 0
}
],
"orderDate": "2021-08-13 15:03:48",
"orderHeader": {
"_innerMap": {},
"companyId": 1007,
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"customerId": 100,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"objectVersionNumber": 0,
"orderDate": "2021-08-13 15:03:48",
"orderNumber": "NEW",
"orderStatus": "NEW",
"soHeaderId": 101
},
"orderNumber": "100",
"orderStatus": "NEW",
"price": 110,
"soHeaderId": 101,
"soLineId": 37
}
]
中間遇到了一個小問題, 輸入訂單狀態無論是NEW還是REJECTED,都會拋出異常,后來發現是邏輯問題,如下圖,應當使用邏輯與而不是邏輯或進行判斷。
頭表與行表: 執行后刪除了訂單頭id 100和101兩個和對應的行表
28.編碼規則與保存
保存分為插入和更新兩部分,其中插入時希望訂單編號(OrderNumber)為編碼規則生成 ,
編碼規則代碼:HZERO.xxxxx.ORDER.NUMBER
(租戶管理員->系統管理->編碼規則->編碼規則)
SO+YYYYMMDD+6位流水號
根據文檔中描述:
關鍵代碼如下:
String code = codeRuleBuilder.generateCode(CodeConstants.Level.TENANT, 0L, "HZERO.xxxxx.ORDER.NUMBER", CodeConstants.CodeRuleLevelCode.CUSTOM, "DEMO", map);
至於這些參數對應什么,可以看下圖:
TENANT(tenant為租戶),
RuleCode: HZERO.xxxxx.ORDER.NUMBER:(規則代碼)
CUSTOM: leavelCode (層級),這里CUSTOM代表自定義參數
“DEMO” : leavel values 層級值
Map: 一個S-S的map變量
平台設置如下:
其實一開始流水號想用UUID的,但是UUID沒有6位,所以只能用序列了,序列是自增的(每調用一次加1),也很好用;
相關代碼:
這樣插入so_header_id 為102 的數據,且主要目標OrderNumber 符合 編碼命名 要求。
最后:要注意代碼規范,比如url路徑不要用駝峰:PostMapping(value=”/delete/page-mapping/batch”)