Java項目調試技巧及版本控制

開發項目中,調試是必不可少的。

本篇部落格的程式碼舉例均為該系列部落格涉及的項目:社交網站後端項目開發日記(一)

本篇部落格從以下4個方面介紹項目調試技巧:

  • 響應狀態碼的含義
  • 服務端斷點調試技巧
  • 客戶端斷點調試技巧
  • 設置日誌級別,並將日誌輸出到不同的終端

以及,最後簡單的介紹了一下git的使用。

1. 項目調試技巧

項目調試過程中,web項目首先看HTTP狀態響應碼,找是客戶端還是服務端的錯誤,看看日誌資訊有沒有錯誤資訊,如果沒有找到,進行斷點調試,這是一個大概的流程。

1.1 響應狀態碼的含義

接下來介紹幾個最常見的響應狀態碼,參考網址://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status

HTTP 響應狀態程式碼指示特定 HTTP 請求是否已成功完成。響應分為五類:資訊響應(100199),成功響應(200299),重定向(300399),客戶端錯誤(400499)和伺服器錯誤 (500599)。狀態程式碼由 section 10 of RFC 2616定義

打開任意一個網址,都會有如下資訊:

image-20210720002539703

200 OK (成功響應)

請求成功。成功的含義取決於HTTP方法:

  • GET:資源已被提取並在消息正文中傳輸。
  • HEAD:實體標頭位於消息正文中。
  • POST:描述動作結果的資源在消息體中傳輸。
  • TRACE:消息正文包含伺服器收到的請求消息

302 Found (重定向)

請求的資源現在臨時從不同的 URI 響應請求。由於這樣的重定向是臨時的,客戶端應當繼續向原有地址發送以後的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應才是可快取的。

介紹一下重定向:假如說網頁上進行刪除功能,這個時候刪除完畢,是不需要返回一個html的,但是生活中常見的會發生什麼?一般刪除之後,網頁會回到一個地址,比如說首頁或者說回到查詢頁面。這個就是重新進行定位。另外一個例子:我們註冊之後,一般直接會跳轉到登錄頁面。

image-20210720001717638

伺服器進行刪除功能之後,返回302狀態碼,以及一個新的路徑。至於為什麼刪除之後沒有直接進行查詢功能呢?項目中不同功能之間要保持松耦合,不能形成依賴。

404 Not Found (客戶端響應)

請求失敗,請求所希望得到的資源未被在伺服器上發現。沒有資訊能夠告訴用戶這個狀況到底是暫時的還是永久的。假如伺服器知道情況的話,應當使用410狀態碼來告知舊資源因為某些內部的配置機制問題,已經永久的不可用,而且沒有任何可以跳轉的地址。404這個狀態碼被廣泛應用於當伺服器不想揭示到底為何請求被拒絕或者沒有其他適合的響應可用的情況下。

500 Internal Server Error (服務端響應)

伺服器遇到了不知道如何處理的情況。這時候應該去檢查服務端的程式。

1.2 服務端斷點調試技巧

以本人部落格的後端項目開發程式碼為例,介紹IDEA的調試技巧。

image-20210720005218639

    1. 設置斷點,進入debug模式

    2. 訪問URL,瀏覽器會一直處理,因為服務端程式停留在斷點那一步image-20210720005310828

    3. 調試介面如下(step over只直接跳轉到程式的下一行,不進入方法,step into則是進入方法進行跳轉下一行):

      image-20210720005441254

      如果想跳過循環條件,畢竟循環可能會循環很多次。可以進行Resume Program恢復程式,比如,你在第20行和25行有兩個斷點,當前運行至第20行,按F9,則運行到下一個斷點(即第25行),再按F9,則運行完整個流程,因為後面已經沒有斷點了。

其中,debug部分,View Breakpoints可以進行斷點管理,可以看到所有斷點,進行是否使用的設置。

image-20210720010356448

1.3 客戶端斷點調試技巧

image-20210720010639855

瀏覽器F12進入開發者模式,其中

Elements調試的是頁面,前端部分會用到。Console可以看到JS輸出的結果。Source可以看客戶端執行的程式碼。

image-20210720010900931

其實這裡設置斷點和IDEA相同,點擊程式碼行左側設置斷點,當使用該部分功能時,會呈現如下效果:

image-20210720010951887

在Source右側,和IDEA相同,還是有step over和step into等操作。邏輯都是相同的。

image-20210720011143468

1.4 設置日誌級別

SpringBoot的日誌工具是logback,官網為://logback.qos.ch/

image-20210720011830431

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級別下進行的測試:

image-20210720013318371

更高級別的log都有顯示。

級別改為warn後:

image-20210720013548956

一般來說,項目開發過程中採用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 等,客戶端並不只提取最新版本的文件快照, 而是把程式碼倉庫完整地鏡像下來,包括完整的歷史記錄。 這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢復。 因為每一次的克隆操作,實際上都是一次對程式碼倉庫的完整備份。

image-20210723005512820

這部分介紹git相關。便於備份程式碼,或者在開發流程中共享程式碼。是團隊開發中非常重要的工具。

首先介紹相關命令(windows命令):個人建議使用git.bash,使用linux命令,畢竟linux在將來的開發中還會有應用。

image-20210723004647485

參考網址:Git官網

如果想詳細了解git知識,建議閱讀(中文版)://git-scm.com/book/zh/v2

具體原理及應用可見:B站尚矽谷教學影片

我個人的操作一般是:

    1. 在github上創建倉庫,因為一般倉庫中都有readme這些資訊文件,所以將倉庫克隆到本地(你需要上傳的倉庫地址)命令:git clone url
    2. 將需要上傳的文件複製進克隆的文件夾里
    3. cd 文件地址,輸入命令
    git add .  //添加所有文件
    git commit -m "需要提交的資訊" //提交到本地倉庫
    git push -u origin main //將本地倉庫push到遠程的main分支,也可以push到master分支
    

    因為我個人使用了兩個github,所以一個採用ssh密鑰,上述方式介紹的是http協議上傳方式,使用帳號密碼即可。

    除此之外的方式還有利用fetch和push等等,我介紹的方式比較適用於初學者。

IDEA配置git:

image-20210723015439977

改為自己的git路徑。

IDEA的VCS中有git的各個操作,首先如圖Create Git Repository,

image-20210723015504904

然後Git中有commit,選中要提交的文件,不用選中全部,比如maven那些包其實沒必要提交。

commit之後,Git中有push,填上遠程倉庫的url以及登錄倉庫即可。