以下規范僅代表個人觀點以及部分公司的規范,不一定適用於所有項目,具體如何准守以實際項目而定。
一.模型篇
請求入參
所有Controller
入參,一律使用 DTO結尾進行交互
所有 DTO 命名,前面采用駝峰命名,后面DTO大寫
所有DTO內參數,如果是一組,請用List<類型>進行接口,盡量不用分隔符隔開,然后字符串接收,
所有DTO放置在子模塊Model下,根據業務進行分組,例如:
com.wang.order.center.order.DTO,com.wang.order.center.pay.DTO
請求出參
所有Controller
出參,一律使用Result進行包裝返回
所有Controller
出參,Result泛型包裝對象,一律用VO結尾進行命名
所有 VO 命名,前面采用駝峰命名,后面VO大寫
所有VO放置在子模塊Model下,根據業務進行分組,例如
com.wang.order.center.order.VO
com.wang.order.center.order.VO
數據庫交互對象
跟數據庫打交道的對象,一律使用PO進行結尾
跟數據庫交互的對象,全部通過逆向生成工具進行生成
所有PO對象,放置在子模塊dao下
所有映射生成的xml文件,在子模塊dao的resources/mapper下
二.命名篇
Controller
必須根據業務進行命名,駝峰,Controller
結尾
Service
必須根據業務進行命名,駝峰,Service
結尾
implement必須根據業務進行命名,駝峰,業務+service+impl結尾
輔助類的命名,根據功能進行命名,如果是工具類,請使用final修飾,並且以utils或者util進行結尾
函數命名使用駝峰命名
輔助函數,例如構建對象,請用build開頭,表示只用於構建對象,並且返回
輔助函數,請使用 private修飾
DAO層函數命名
查詢單個盡量使用queryXX或者selectXX命名
查詢多個盡量使用queryXXs或者selectXXs復數形式進行命名
更新單個盡量使用modifyXX或者updateXX命名
更新多個盡量使用modifyXXs或者updateXX復數形式進行命名
插入單個盡量使用insert或者add命名
插入多個盡量使用insertXXs或者addXXs命名
DAO所有傳參如果是單個參數,請使用@param注解進行注明
所有XXMapper.xml獲取參數,請使用@param("XX") 命名, #{XX}獲取,${XX}會有SQL注入的風險,具體細節請參考Mysql手冊`跟'的區別
變量命名
-
使用駝峰
-
狀態類的變量,請使用int類型
-
boolean類型的變量,請使用has開頭,請勿使用is開頭,在某些序列化框架下,可能會導致反序列化失敗
-
枚舉類型使用全大寫,_進行分割
-
枚舉命名請使用業務+Enum進行命名
-
接口常量命名請使用業務+Constant進行命名(盡量使用枚舉來定義常量)
三.函數參數篇
接口參數
-
盡量使用對象進行傳遞,嚴禁使用MAP進行傳參
-
如果要進行單個參數傳遞,最好不要操作5個參數,參數太多,看起來太混亂
-
盡量使用對象進行傳參,嚴禁使用Map進行傳參
-
如果要進行單個參數傳遞,最好不要操作5個參數,參數太多,看起來太混亂
四.注釋篇
類注釋
/** * 項目名:wang-order-center * 創建人: XX * 創建時間:2018/8/13 15:45 * 類名:OrderController * 類描述: 訂單控制器 */
函數參數,一定要加上 @param 這樣,別人在調用的時候,ide會進行提示,如果涉及到枚舉 加上注解 @see 可以跳轉到枚舉
/** * 創建人:XXX * 創建時間:2018-08-20 20:46:04 * 描述: 購物車創建訂單 * @param userId 用戶ID * @param subUserId 用戶ID * @param addrId 地址ID * @param cartProductIds 購物車ID集合 * @param fahuoTimeLimitedMode 截單模式 0 立即截單, 1 根據活動時間截單 */
代碼注釋
代碼注釋,進行別使用/**/的形式,注釋不需要像寫作文那樣詳細,只需要介紹是做什么的就好
// 構建訂單對象
五.其它篇
代碼是邏輯的表現,一段代碼是否是好代碼,主要是要看邏輯是否清晰,因為業務代碼是給人看的,並不是框架或者開源代碼,寫的太高大上,各種設計模式,並非好事,有過度設計的嫌疑,盡量做到面向接口編程,提高內聚,降低耦合
代碼
-
Controller
盡量只做轉發,不做具體邏輯實現,所有邏輯實現交由service進行 -
service的接口函數,盡量功能單一,職責越小,越便於維護跟擴展
-
如果涉及到寫等動作,請在函數上加上@transaction注解/或者自己用事務塊包裹
-
service如果不需要捕獲異常,可以往上層拋,訂單中心已經在全局做了異常處理
-
盡量做到所有的check在入參就應該進行判斷
-
如果遇到需要構建對象,大量 set函數不應該放置主流程,抽離出來一個輔助函數,直接調用輔助函數即可,輔助函數注釋寫好,主流程調用輔助函數加上功能注釋
-
代碼內部盡量不使用多層for循環調用,在不注意的情況,多層for循環嵌套構建對象,很容易寫出內存泄漏的代碼
-
盡量不使用匿名內部類,使用lambda,因為現在jdk已經是1.8版本,支持Java8的特性
-
如果一段代碼,超過兩個地方調用,說明需要進行抽象,然后對抽象進行實現
-
函數跳轉層級盡量不要過深,因為是業務代碼,跳轉太深,很容易把人繞暈了
-
如果一個函數出現特別多的if else 考慮把if else建成枚舉,然后枚舉內進行判斷返回
-
所有service層可以直接拋出異常,不需要捕獲異常處理,已經配置好全局異常處理,只需要拋出錯誤信息就好
-
業務錯誤打印日志,盡量別打印error打印warning級別日志就好,所有拋出異常上面,盡量打印錯誤日志的參數
-
日志打印,盡量使用一下示例打印 // 正確打印 LOGGER.info("訂單ID錯誤,訂單ID:{}",order.getId()); // 錯誤打印 LOGGER.info("訂單ID錯誤,訂單ID:"+order.getId());
-
日志是常量,所以請使用以下定義 private static finale Logger LOGGER = LoggerFactory.get(XX.class);
-
日志引用,禁止引用具體實現,請引用 slf4j接口
請求路徑
-
盡量使用Restful風格
-
/liveId/productId URL參數,請使用 @PathVariable("liveId")String liveId 指定名稱綁定
-
查詢盡量使用Get請求方式,如果參數在URL傳遞過多,可以不使用Get請求,使用POST請求,請把參數寫進請求體內
-
所有寫的操作一律使用POST請求,參數放入請求體內,公共參數,以后會讓客戶端放入請求頭內
-
所有的核心寫接口,例如,創建訂單,支付,取消訂單等,一定一定要做冪等,冪等可以在所有的check后也可以在函數調用就進行判斷,但是一定是在邏輯進行前
-
冪等接口,一定要跟調用方統一狀態,達成共識
-
往往冪等會伴隨着並發同時進行,因為網絡傳輸,機器性能,請求處理,事務提交帶有太多的不確定性,所以要加以控制,所以redis盡量只做並發控制跟短時間內的冪等,請勿太依賴redis來進行做冪等,在redis鎖后,插入前請進行DB查詢操作,查看是否已經寫入過,如果已經寫入,拒絕請求
單機鎖,如果沒有競爭資源,不要使用鎖
盡量使用 Lock接口作為鎖,別使用Synchronize作為鎖,后者作為重量級鎖,太影響性能
對鎖的使用不清楚,嚴禁私自使用,盡量多請教會的人,避免寫出死鎖或者活鎖
分布式鎖,目前只是用了redis的setnx操作作為分布式鎖的實現,使用分布式鎖,一定一定要設置過期時間或者在鎖代碼塊執行完畢,手動移除鎖,否則出現鎖不能釋放,你就悲劇了……...
目前setnx操作,使用的是jedis連接池來實現的,沒有使用spring-data提供的redisTemplate是因為,后者的setnx操作並非一個原子操作,運氣不好的情況,極有可能出現setnx操作了,setexprie失敗,導致鎖不過期,但是jedis使用,切勿忘記,使用完畢,歸還連接,jedis是不會再你調用完畢主動歸還連接的
所有鎖,請在check完畢或者check之前進行鎖定資源,請勿在最后鎖定,進行無用的寫
鎖定的資源,必須是唯一的,例如,訂單ID,訂單編號等