開發項目中,調試是必不可少的。
本篇博客的代碼舉例均為該系列博客涉及的項目:社交網站后端項目開發日記(一)
本篇博客從以下4個方面介紹項目調試技巧:
- 響應狀態碼的含義
- 服務端斷點調試技巧
- 客戶端斷點調試技巧
- 設置日志級別,並將日志輸出到不同的終端
以及,最后簡單的介紹了一下git的使用。
1. 項目調試技巧
項目調試過程中,web項目首先看HTTP狀態響應碼,找是客戶端還是服務端的錯誤,看看日志信息有沒有錯誤信息,如果沒有找到,進行斷點調試,這是一個大概的流程。
1.1 響應狀態碼的含義
接下來介紹幾個最常見的響應狀態碼,參考網址:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
HTTP 響應狀態代碼指示特定 HTTP 請求是否已成功完成。響應分為五類:信息響應(100
–199
),成功響應(200
–299
),重定向(300
–399
),客戶端錯誤(400
–499
)和服務器錯誤 (500
–599
)。狀態代碼由 section 10 of RFC 2616定義
打開任意一個網址,都會有如下信息:
200 OK
(成功響應)
請求成功。成功的含義取決於HTTP方法:
- GET:資源已被提取並在消息正文中傳輸。
- HEAD:實體標頭位於消息正文中。
- POST:描述動作結果的資源在消息體中傳輸。
- TRACE:消息正文包含服務器收到的請求消息
302 Found
(重定向)
請求的資源現在臨時從不同的 URI 響應請求。由於這樣的重定向是臨時的,客戶端應當繼續向原有地址發送以后的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應才是可緩存的。
介紹一下重定向:假如說網頁上進行刪除功能,這個時候刪除完畢,是不需要返回一個html的,但是生活中常見的會發生什么?一般刪除之后,網頁會回到一個地址,比如說首頁或者說回到查詢頁面。這個就是重新進行定位。另外一個例子:我們注冊之后,一般直接會跳轉到登錄頁面。

服務器進行刪除功能之后,返回302狀態碼,以及一個新的路徑。至於為什么刪除之后沒有直接進行查詢功能呢?項目中不同功能之間要保持松耦合,不能形成依賴。
404 Not Found
(客戶端響應)
請求失敗,請求所希望得到的資源未被在服務器上發現。沒有信息能夠告訴用戶這個狀況到底是暫時的還是永久的。假如服務器知道情況的話,應當使用410狀態碼來告知舊資源因為某些內部的配置機制問題,已經永久的不可用,而且沒有任何可以跳轉的地址。404這個狀態碼被廣泛應用於當服務器不想揭示到底為何請求被拒絕或者沒有其他適合的響應可用的情況下。
500 Internal Server Error
(服務端響應)
服務器遇到了不知道如何處理的情況。這時候應該去檢查服務端的程序。
1.2 服務端斷點調試技巧
以本人博客的后端項目開發代碼為例,介紹IDEA的調試技巧。
-
-
設置斷點,進入debug模式
-
訪問URL,瀏覽器會一直處理,因為服務端程序停留在斷點那一步
-
調試界面如下(step over只直接跳轉到程序的下一行,不進入方法,step into則是進入方法進行跳轉下一行):
如果想跳過循環條件,畢竟循環可能會循環很多次。可以進行Resume Program恢復程序,比如,你在第20行和25行有兩個斷點,當前運行至第20行,按F9,則運行到下一個斷點(即第25行),再按F9,則運行完整個流程,因為后面已經沒有斷點了。
-
其中,debug部分,View Breakpoints可以進行斷點管理,可以看到所有斷點,進行是否使用的設置。
1.3 客戶端斷點調試技巧
瀏覽器F12進入開發者模式,其中
Elements調試的是頁面,前端部分會用到。Console可以看到JS輸出的結果。Source可以看客戶端執行的代碼。
其實這里設置斷點和IDEA相同,點擊代碼行左側設置斷點,當使用該部分功能時,會呈現如下效果:
在Source右側,和IDEA相同,還是有step over和step into等操作。邏輯都是相同的。
1.4 設置日志級別
SpringBoot的日志工具是logback,官網為:http://logback.qos.ch/
logger中不同的日志級別:
- trace跟蹤級別
- debug調試級別
- info普通級別
- warn警告級別
- error錯誤級別
這五個級別從低到高順序排列。例:開啟Info級別,則trace和debug不會打印出來,只有更高級別的日志會打印出來。級別設置是為了提高性能。
接下來舉個例子:(SpringBoot中在application.properties設置Logger級別即可)
logging.level.com.nowcoder.community=debug
舉測試類:
public class LoggerTests {
//為了便於所有的方法去調用,一般設置為靜態,不可改變的,注意使用org.slf4j包下的
//傳入的類即logger的名字,一般傳入當前類,這樣便於區別不同的Logger
private static final Logger logger = LoggerFactory.getLogger(LoggerTests.class);
@Test
public void testLogger() {
System.out.println(logger.getName());
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
}
}
這是在logger為debug級別下進行的測試:
更高級別的log都有顯示。
級別改為warn后:
一般來說,項目開發過程中采用debug級日志,方便調試。上線后一般采用更高級別。並且上線后都不會有控制台了,這就需要我們把日志文件給打印出來。
1.4.1. 直接在application.properties中配置
過程:在properties進行配置
logging.file.path=sp.log
該配置會在同級目錄下生成sp.log文件夾,里面存儲spring.log
(不知為何,logging.file這句配置在我這里失效了,暫未找到原因,SpringBoot2.5.1)
這種方式會混雜各種類型的日志,而且可能文件比較大,建議將各種級別的日志放在不同的文件中,介紹第二種配置方式。
1.4.2 logback-spring.xml配置
在resources目錄下,SpringBoot會自動識別該命名的.xml文件並進行配置,注意如果命名不同則不會識別。
以error級別log文件配置為例:(已加注釋,請閱讀源碼)
<contextName>community</contextName>
<!-- log文件存放地址,這里相當於一個string -->
<property name="LOG_PATH" value="D:/javawork/data"/>
<property name="APPDIR" value="community"/>
<!-- error file -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 聲明地址 -->
<file>${LOG_PATH}/${APPDIR}/log_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 命名格式,%d為日期, %i是一個變量,如0,1,2等 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 一個Log最大為5MB,如果存不下再存新的 -->
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 最長存儲時間30天 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 以追加的方式存儲而不是覆蓋 -->
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 定義日志輸出格式%d日期,%level級別, [%thread]哪個線程執行,%logger{10}logger所處的類,[%file:%line] 所處哪個文件多少行 -->
<!-- %msg%n消息內容 -->
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 過濾器,過濾error級日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<!-- 這里的意思是匹配到就接收,不匹配就拒絕 -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
其他級別的Log文件配置類似,可自行配置。
其中,也可以配置如何打印控制台Log信息,例:
<!-- console -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
</appender>
在.xml文件末尾需要聲明:
<logger name="com.nowcoder.community" level="debug"/>
<root level="info">
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_WARN"/>
<appender-ref ref="FILE_INFO"/>
<appender-ref ref="STDOUT"/>
</root>
root代表項目根目錄,因為項目中包含着非常多的包,所以級別為info即可,debug級將會多出許多不必要的log。其中,logger會將日志信息傳給root,root再根據appender進行打印。具體信息可參考官方網站,沒有細說。
中間4行代表啟用上述的error等各個級別的文件配置。
項目中的日志配置參考該模板即可。
2. 版本控制
分布式版本控制系統,在這類系統中,像 Git、Mercurial、Bazaar 以及 Darcs 等,客戶端並不只提取最新版本的文件快照, 而是把代碼倉庫完整地鏡像下來,包括完整的歷史記錄。 這么一來,任何一處協同工作用的服務器發生故障,事后都可以用任何一個鏡像出來的本地倉庫恢復。 因為每一次的克隆操作,實際上都是一次對代碼倉庫的完整備份。

這部分介紹git相關。便於備份代碼,或者在開發流程中共享代碼。是團隊開發中非常重要的工具。
首先介紹相關命令(windows命令):個人建議使用git.bash,使用linux命令,畢竟linux在將來的開發中還會有應用。
參考網址:Git官網
如果想詳細了解git知識,建議閱讀(中文版):https://git-scm.com/book/zh/v2
具體原理及應用可見:B站尚硅谷教學視頻
我個人的操作一般是:
-
- 在github上創建倉庫,因為一般倉庫中都有readme這些信息文件,所以將倉庫克隆到本地(你需要上傳的倉庫地址)命令:git clone url
- 將需要上傳的文件復制進克隆的文件夾里
- cd 文件地址,輸入命令
git add . //添加所有文件 git commit -m "需要提交的信息" //提交到本地倉庫 git push -u origin main //將本地倉庫push到遠程的main分支,也可以push到master分支
因為我個人使用了兩個github,所以一個采用ssh密鑰,上述方式介紹的是http協議上傳方式,使用賬號密碼即可。
除此之外的方式還有利用fetch和push等等,我介紹的方式比較適用於初學者。
IDEA配置git:
改為自己的git路徑。
IDEA的VCS中有git的各個操作,首先如圖Create Git Repository,
然后Git中有commit,選中要提交的文件,不用選中全部,比如maven那些包其實沒必要提交。
commit之后,Git中有push,填上遠程倉庫的url以及登錄倉庫即可。