爲何你學了n遍《1天精通Spring Boot》,至今仍是不精通Spring Boot,甚至仍是停留在學生項目?真正要作項目就應該一步到位,半吊子半桶水是不行的。一個實戰項目須要充分考慮狀態碼、異常處理、日誌處理、性能監控、數據安全、部署等等因素,而不是急於求成,爲了達到1天精通的目標而糊弄過去。前端
筆者在大學時也經歷過學了不少Spring Boot的教材,可是比起外包(哪怕是個小程序),總以爲比真實項目缺了點什麼,項目跑起來也是分分鐘解體。本篇適合有必定後端開發基礎(不涉及中間件,會在Spring Cloud講),可是又停留於學生項目的讀者(不一樣語言均有借鑑意義)。java
問題分析:程序員
項目監控spring
項目能跑就行!管他什麼項目監控,項目問題統統等用戶反饋,掛了就重啓!SQL慢用戶就等着,我怎麼知道哪裏執行慢?項目訪問不了就是用戶網絡問題!用戶遇到問題就是一清緩存、二換瀏覽器、三重啓大法好!你怕是沒通過社會的毒打,KPI分分鐘墊底,再過2個月就能夠實現家裏蹲的願望了。sql
這裏拿alibaba的druid作個例子,druid能夠監控如下幾個部分:小程序
集成完druid,項目立刻提升一個檔次,能夠在boss面前打開頁面吹噓一把。最最關鍵的是,集成druid是分分鐘的事情,幾乎沒有代碼的侵入性,要改造也只需添加個bean,改下配置文件。詳細可參考springboot集成druid,絕對是排查慢SQL、優化性能、監控項目居家必備良藥!後端
日誌瀏覽器
日誌記錄操做軌跡、監控系統運行狀態、回溯系統故障,保留系統故障現場,方便程序員快定位問題。生產環境不一樣於學生項目,隨時有問題就重啓debug,在公司裏,開發人員你碰服務器的資格都沒有,因此保留日誌成了排查Bug惟一的方法。這裏就談談容易被忽視的幾點:緩存
狀態碼安全
對比一下上圖有什麼區別?很簡單,就是多了個狀態碼。有沒有這個狀態碼彷佛對前端請求的數據也沒什麼影響,不加狀態碼前端仍是能夠正常顯示。確實,在覈心數據上是不會有任何影響的,可是一旦出現一些業務異常,返回的數據就會以下圖所示:
{ "timestamp": "2020-04-25T03:55:26.179+0000", "status": 500, "error": "Internal Server Error", "message": "\n### Error querying database. Cause: java.sql.SQLException: sql injection violation, syntax error: syntax error, error in :\u0027 asd from product_info where produc\u0027, expect IDENTIFIER, actual IDENTIFIER pos 12, line 1, column 13, token IDENTIFIER null : select * asd from ...}
若是前端沒有能經過狀態碼進行不一樣返回請求的處理,返回異常數據時,前端代碼仍舊直接獲取data數據,那誰知道前端會出現什麼樣子的異常呢?
若是能與前端妹子好好商量一下狀態碼的規則,那麼前端就能夠經過不一樣的狀態碼,判斷不一樣的請求響應等級,例如:
否則你就爲所欲爲拋異常,想怎麼返回就怎麼返回,前端妹子提刀就來找你了。想一想本身爲何仍是單身?或許就是由於沒跟前端妹子在大明湖畔約定好狀態碼吧。
異常處理
學生項目每每就是不到IDE報沒法編譯,不到萬不得已堅定不進行異常處理!而異常處理又相當重要!那就大體來了解一下吧。
全部異常都是Throwable的子類,分爲Error致命異常和Exception非致命異常。
而咱們關心的是RuntimeException,這類,這類異常每每是業務異常,正常的作法是封裝一個AppException繼承自RuntimeException,在發現業務異常時,配合狀態碼拋出對應異常:
@Getterpublic class APIException extends RuntimeException { private int code; private String msg; // 手動設置異常 public APIException(StatusCode statusCode, String message) { // message用於用戶設置拋出錯誤詳情,例如:當前價格-5,小於0 super(message); // 狀態碼 this.code = statusCode.getCode(); // 狀態碼配套的msg this.msg = statusCode.getMsg(); } // 默認異常使用APP_ERROR狀態碼 public APIException(String message) { super(message); this.code = AppCode.APP_ERROR.getCode(); this.msg = AppCode.APP_ERROR.getMsg(); }}
那麼誰來拋出異常,誰又來處理異常呢?
一般來講,通常拋出業務異常的是在service層或者相關的邏輯業務層進行,而且配合狀態碼進行拋出:
throw new APIException(AppCode.PRODUCT_NOT_EXIST, "上架商品中沒法查詢到:" + orderDetail.getProductId());
而後在調用者層進行處理,這裏的調用者通常指最上層的controller層也就是控制層,進行處理,固然springboot有統一處理的功能,本質是經過AOP對controller層進行攔截異常。有想深刻了解的能夠參考:《正規軍springboot如何處理:參數校驗、統一異常、統一響應》。
@RestControllerAdvice@Slf4jpublic class ControllerExceptionAdvice { @ExceptionHandler({BindException.class}) public ResultVo MethodArgumentNotValidExceptionHandler(BindException e) { // 從異常對象中拿到ObjectError對象 ObjectError objectError = e.getBindingResult().getAllErrors().get(0); return new ResultVo(ResultCode.VALIDATE_ERROR, objectError.getDefaultMessage()); } @ExceptionHandler(APIException.class) public ResultVo APIExceptionHandler(APIException e) { log.error(e.getMessage(), e); return new ResultVo(e.getCode(), e.getMsg(), e.getMessage()); }}
單元測試
單元測試的意義並不只僅在於發現現有代碼Bug。一個好的單元測試能夠做爲測試用例固化在項目中,方便程序員進行重構和修改。如上圖,本身均可能出現不敢刪掉冗餘代碼的狀況,更況且是重構代碼?修改代碼?甚至是接手別人的代碼?在公司中,正常一套代碼會有AB角之分,保證其中一方跑路跳槽,項目也不會出現人員斷層,確保項目能正常進行:
若是說,公司某個A角邀請你籤他的AB角生死狀,請先看一下他的單元測試覆蓋率等指標,若是一個單元測試都不寫的,打死都不籤!否則改完代碼一上線極可能又是解體操做!
服務器
這點筆者深有體會,在大學期間,老是聽人說服務器就是一臺電腦。可是你說任你說,我仍是以爲服務器是一個高端大氣又特別神祕的東西!本身的代碼永遠都運行在IDEA上,哪怕我知道部署項目的全部步驟,卻一直止步不前,總以爲少了點什麼。直到第一次接觸到服務器,才發現本來覺得這貨真的是個電腦!這貨真的就是個Linux!並且經過公網IP、域名真的能夠訪問到本身的項目!
原做者:bugpool
原文連接: 爲何你學了N遍Springboot,至今仍是學生項目?你的問題都在這裏!_前端_bugpool的博客-CSDN博客
原出處:CSDN