java日誌規約及配置示例終極總結

来源:https://www.cnblogs.com/luao/archive/2019/03/17/10549610.html
-Advertisement-
Play Games

目錄 1、什麼是日誌? 簡單的說,日誌就是記錄程式的運行軌跡,方便查找關鍵信息,也方便快速定位解決問題。我們 Java 程式員在開發項目時都是依賴 Eclipse/ Idea 等開發工具的 Debug 調試功能來跟蹤解決 Bug,在開發環境可以這麼做,但項目發佈到了測試、生產環境呢?你有可能會說可以 ...


目錄

  1. 什麼是日誌
  2. 常用日誌框架
  3. 日誌級別詳解
  4. 日誌的記錄時機
  5. 日誌使用規約
  6. logback 配置示例
  7. loh4j2 配置示例

1、什麼是日誌?

  簡單的說,日誌就是記錄程式的運行軌跡,方便查找關鍵信息,也方便快速定位解決問題。我們 Java 程式員在開發項目時都是依賴 Eclipse/ Idea 等開發工具的 Debug 調試功能來跟蹤解決 Bug,在開發環境可以這麼做,但項目發佈到了測試、生產環境呢?你有可能會說可以使用遠程調試,但實際並不能允許讓你這麼做。所以,日誌的作用就是在測試、生產環境沒有 Debug 調試工具時開發、測試人員定位問題的手段。日誌打得好,就能根據日誌的軌跡快速定位並解決線上問題,反之,日誌輸出不好不能定位到問題不說反而會影響系統的性能。優秀的項目都是能根據日誌定位問題的,而不是線上調試,或者半天找不到有用的日誌。

2、常用日誌框架

  log4j、Logging、commons-logging、slf4j、logback,開發的同學對這幾個日誌相關的技術不陌生吧,為什麼有這麼多日誌技術,它們都是什麼區別和聯繫呢?相信大多數人搞不清楚它們的關係,下麵我將一一介紹一下,以後大家再也不用傻傻分不清楚了。

Logging 【java 自帶工具】

  這是 Java 自帶的日誌工具類,在 JDK 1.5 開始就已經有了,在java.util.logging 包下。

Log4j 【框架實現】

  Log4j 是 Apache 的一個開源日誌框架,也是市場占有率最多的一個框架。大多數沒用過 Java Logging, 但沒人敢說沒用過 Log4j 吧,反正從我接觸 Java 開始就是這種情況,做 Java 項目必有 Log4j 日誌框架。註意:log4j 在 2015/08/05 這一天被 Apache 宣佈停止維護了,用戶需要切換到 Log4j2上面去。

下麵是官方宣佈原文

On August 5, 2015 the Logging Services Project Management Committee announced that Log4j 1.x had reached end of life. For complete text of the announcement please see the Apache Blog. Users of Log4j 1 are recommended to upgrade to Apache Log4j 2.

Commons-logging 【日誌介面】

  上面介紹的 log4j 是一個具體的日誌框架的實現,而 commons-logging 就是日誌門面介面,它也是 apache 最早提供的日誌門面介面,用戶可以根據喜好選擇不同的日誌實現框架,而不必改動日誌定義,這就是日誌門面的好處,符合面向介面抽象編程。

Slf4j 【日誌介面】

  全稱:Simple Logging Facade for Java,即簡單日誌門面介面,和 Apache 的 commons-logging是一樣的概念,它們都不是具體的日誌框架,你可以指定其他主流的日誌實現框架。Slf4j也是現在主流的日誌門面框架,使用Slf4j可以很靈活的使用占位符進行參數占位,簡化代碼,擁有更好的可讀性,這個後面會講到。

Logback 【框架實現】

  Logback 是 Slf4j 的原生實現框架,同樣也是出自 Log4j一個人之手,但擁有比log4j更多的優點、特性和更做強的性能,現在基本都用來代替 log4j 成為主流。

日誌框架總結

  • commons-loggin、slf4j 只是一種日誌抽象門面,不是具體的日誌框架。
  • log4j、logback 是具體的日誌實現框架。
  • 一般首選強烈推薦使用 slf4j + logback。當然也可以使用slf4j + log4j、commons-logging + log4j 這兩種日誌組合框架。

3、日誌級別詳解

  日誌的輸出都是分級別的,不同的設置不同的場合列印不同的日誌。下麵拿最普遍用的 Log4j 日誌框架來做個日誌級別的說明,這個也比較全面,其他的日誌框架也都大同小異。Log4j 的級別類 org.apache.log4j.Level 裡面定義了日誌級別,日誌輸出優先順序由高到底分別為以下8種。

日誌級別及描述

  • ERROR:系統發生了錯誤事件,但仍然不影響系統的繼續運行。系統需要將錯誤或異常細節記錄ERROR日誌中,方便後續人工回溯解決。
  • WARN: 系統在業務處理時觸發了異常流程(參數驗證不過),但系統可恢復到正常態,下一次業務可以正常執行。如程式調用了一個舊版本的介面,可選參數不合法,非業務預期的狀態但仍可繼續處理等
  • INFO: 記錄系統關鍵信息,旨在保留系統正常工作期間關鍵運行指標,開發人員可以將初始化系統配置、業務狀態變化信息,或者用戶業務流程中的核心處理記錄到INFO日誌中,方便日常運維工作以及錯誤回溯時上下文場景復現
  • DEBUG: 可以將各類詳細信息記錄到DEBUG里,起到調試的作用,包括參數信息,調試細節信息,返回值信息等。

日誌優先順序別標準順序

  ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

設置級別和列印級別的關係

  如果日誌級別設置 INFO,只有輸出級別為 INFO、WARN,後面的日誌才會正常輸出。

4、日誌的記錄時機

系統初始化

  系統初始化時會依賴一些關鍵配置,根據參數不同會提供不一樣的服務。將系統的啟動參數記錄INFO日誌,列印出參數以及服務啟動完成狀態。

業務流程與預期不符

  系統中結果與期望不符,應當記錄日誌。常見的合適場景包括外部參數不正確,數據處理問題導致返回碼不在合理範圍內等等。

系統核心的關鍵動作

  系統中核心角色觸發的業務動作是需要多加關註的,是衡量系統正常運行的重要指標,建議記錄INFO級別日誌,比如微服務各服務節點交互等。

捕獲到異常時

  這類捕獲的異常是系統告知開發人員需要加以關註的,應當記錄日誌,根據實際情況使用warn或者error級別。

外部介面日誌

  這類日誌涉及到與外部系統的交互,事關責任問題,建議將原始數據文件內容寫入日誌或資料庫(如mongodb),核心處理邏輯關鍵業務數據也儘量寫入日誌。如果涉及到重發,建議將處理失敗的原始數據文件日誌寫入資料庫,以便重發執行。

5、日誌使用規約

  • 使用@SLF4J中的API進行日誌列印。
  • 日誌輸出必須採用UTF-8字元集,推薦列印日誌時輸出英文,防止中文不支持而列印出亂碼的情況。
  • 不允許記錄日誌後又拋出異常,因為這樣會多次記錄日誌,只允許記錄一次日誌,應拋出異常,頂層列印一次日誌。
try {
  // 錯誤 
} catch (Exception e) { 
  log.error("xxxxxx", e);
  throw e;
}
  • 輸出Exceptions的全部堆棧信息,但是不能使用e.printStackTrace()
// 錯誤例子, 丟失掉StackTrace信息 
log.error(e.getMessage()); 
// 錯誤例子,丟失掉StackTrace信息 
log.error(“Bad things : {}“, e.getMessage()); 
// 正確例子 
log.error(“Bad things : {}“,e); 

// e.printStackTrace()的源碼
public void printStackTrace() { 
    printStackTrace(System.err); 
}
  • 禁止system.out 用於日誌記錄。
  • 線上必須關閉 DEBUG 級別日誌。
  • 非正常的情況,需要根據情況選擇列印warn 或 error 日誌,不能使用錯誤的日誌級別。
try { 
// ... 
} catch (Exception e) { 
// 錯誤LOG.info("XX 發生異常...", e); 
}
// 用 info 記錄 error 日誌,日誌輸出到了 info 日誌文件中了,同事拼命地在 error 錯誤日誌文件里 面找怎麼能找到呢?
  • 日誌輸出,必須使用占位符的方式,因為即使信息不列印,也會執行字元串拼接,造成資源浪費。
  • 日誌中不允許出現計算或方法調用,防止在列印日誌的時候報錯。
  • 輸出的POJO類必須重寫toString方法,否則只輸出對象的hashCode值,沒有參考意義。
  • 不記錄對於排查故障毫無意義的日誌信息,日誌信息一定要帶有業務信息。
//錯誤 
log.error(“handle failed“); 
//正確
log.error(“handle failed,id= {}“, id); 
  • 禁止大量無效重覆的日誌輸出,通常情況下在程式日誌只記錄一些有意義的狀態數據,參考日誌記錄時機。
  • 不可以講敏感業務信息記錄入日誌文件。
  • 嚴防日誌占滿磁碟,定期檢查磁碟(確定是否有磁碟告警)。
  • 不要在千層迴圈中列印日誌
for(int i=0; i<2000; i++){
LOG.info("XX");
}
// 這個是什麼意思,如果你的框架使用了性能不高的 Log4j 框架,那就不要在上千個 for 迴圈中列印日誌,
// 這樣可能會拖垮你的應用程式,如果你的程式響應時間變慢,那要考慮是不是日誌列印的過多了。

6、logback配置參考

配置說明

  • 統一使用logback.xml配置,logback.xml 文件放在 classpath 目錄下。
  • 所有的jar包中不建議包含logback.xml文件,避免干擾實際的業務系統。
  • 通過在文件logback.xml中引入資源文件log.properties定義logback屬性信息,log.properties根據不同的profile放置在不同位置;
<property resource="log.properties"/>
  • log.properties文件
  • 屬性命名推薦使用統一使用大寫,以下劃線分隔,參考
APP_NAME = yourAppName
LOG_DIR = /export/home/logs/yourSystem/yourAppName
LOG_PATTERN = [%date{yyyy-MM-dd HH:mm:ss.SSS}] %level [%mdc{invokeNo}] %C{0}:%line - %message%n
  • 註意Logger間的繼承關係,推薦additivity設置false;
  1. 子logger會預設繼承父logger的appender,將它們加入到自己的Appender中;除非加上了additivity="false",則不再繼承父logger的appender。
  2. 子logger只在自己未定義輸出級別的情況下,才會繼承父logger的輸出級別。
  • 將日誌輸出到文件當中,禁止使用FileAppender,推薦使用提供自動切換功能的RollingFileAppender Log文件位置和命名,目前Log文件的位置統一放在相同目錄下麵。
 
文件名 描述
/export/home/logs 預設日誌路徑(所有日誌的根路徑)
/export/home/logs/${SYSTEM_NAME}/${APP_NAME} log.properties中配置的日誌全路徑LOG_DIR
${LOG_DIR}/all.log 必選
${LOG_DIR}/ all-%d{yyyy-MM-dd}.log All歷史文件命名
${LOG_DIR}/all_error.log 必選
${LOG_DIR}/sql.log 可選

 

  • 日誌按天記錄,單個日誌文件最大不超過2000MB,考慮到有些bug按月規律出現,推薦歷史日誌保留30天。
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <fileNamePattern>${LOG_DIR}/all-%d{yyyy-MM-dd}.log</fileNamePattern>
  <maxHistory>30</maxHistory>
  <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  <maxFileSize>2000MB</maxFileSize>
  </timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
  • 在出現問題之後,需要立即根據日誌定位問題。對於INFO及以上級別的日誌,要求按照一定順序,輸出以下必要的信息。參考日誌格式定義
<encoder charset="UTF-8">
  <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] %level 
  [%mdc{invokeNo}] %C{0}:%line - %message%n</pattern>
</encoder>
  • 一個完整的Appender配置如下
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <property resource="log.properties"/>    
  <contextName>${APP_NAME}</contextName>    
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">     <encoder charset="UTF-8">       <pattern>${LOG_PATTERN}</pattern>     </encoder>   </appender> <appender name="all" class="ch.qos.logback.core.rolling.RollingFileAppender">   <file>${LOG_DIR}/all.log</file>   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">     <fileNamePattern>${LOG_DIR}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>     <maxHistory>30</maxHistory>     <timeBasedFileNamingAndTriggeringPolicy
      
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">       <maxFileSize>2000MB</maxFileSize> <!-- 每個日誌文件大小不超過2GB -->     </timeBasedFileNamingAndTriggeringPolicy>   </rollingPolicy>   <encoder charset="UTF-8">     <pattern>${LOG_PATTERN}</pattern>   </encoder>   <filter class="ch.qos.logback.classic.filter.ThresholdFilter">     <level>info</level>   </filter> </appender> <appender name="all-error" class="ch.qos.logback.core.rolling.RollingFileAppender">   <file>${LOG_DIR}/all-error.log</file>   <filter class="ch.qos.logback.classic.filter.LevelFilter">     <level>ERROR</level>     <onMatch>ACCEPT</onMatch>     <onMismatch>DENY</onMismatch>   </filter>   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">     <fileNamePattern>       ${LOG_DIR}/all-error-%d{yyyy-MM-dd}.%i.log     </fileNamePattern>     <maxHistory>30</maxHistory>     <timeBasedFileNamingAndTriggeringPolicy
     
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">       <!-- 每個日誌文件大小不超過2GB -->       <maxFileSize>2000MB</maxFileSize>     </timeBasedFileNamingAndTriggeringPolicy>   </rollingPolicy>   <encoder charset="UTF-8">     <pattern>
      
[%date{yyyy-MM-dd HH:mm:ss.SSS}] %level [%mdc{invokeNo}] %C{0}:%line - %message%n     </pattern>   </encoder> </appender>
<root level="debug">   <appender-ref ref="all"/>   <appender-ref ref="all-error"/>   <appender-ref ref="console"/> </root> </configuration>

7、Log4j2配置參考

配置說明

  • 統一使用log4j2.xml配置,log4j2.xml 文件放在 resource目錄下。
  • 註意Logger間的繼承關係,推薦additivity設置false:
  1. 子logger會預設繼承父logger的appender,將它們加入到自己的Appender中;除非加上了additivity="false",則不再繼承父logger的appender。
  2. 子logger只在自己未定義輸出級別的情況下,才會繼承父logger的輸出級別。
  • 將日誌輸出到文件當中,考慮到RollingRandomAccessFile比RollingFile更靈活,推薦統一使用RollingRandomAccessFile。
  • Log文件位置和命名,目前Log文件的位置統一放在相同目錄下麵。
 
文件名 描述 
/export/home/logs` 預設日誌路徑(所有日誌的根路徑)
/export/home/logs/${SYSTEM_NAME}/${APP_NAME}  log.properties中配置的日誌全路徑LOG_DIR
${LOG_DIR}/all.log 必選 
${LOG_DIR}/ all-%d{yyyy-MM-dd}.log All歷史文件命名
${LOG_DIR}/all_error.log 必選
${LOG_DIR}/sql.log 可選 

 

  • 日誌按天記錄,單個日誌文件最大不超過3000MB,考慮到有些bug按周規律出現,推薦歷史日誌保留14天。
<RollingRandomAccessFile name="all-append" immediateFlush="true" 
    fileName
="${LOG_DIR}/all.log" filePattern="${LOG_DIR}/all-%d{yyyy-MM-dd}-%i.log"> <Policies> <SizeBasedTriggeringPolicy size="3GB" /> <TimeBasedTriggeringPolicy interval="8" modulate="true" /> <!-- 最多備份14天以內||日誌文件大小達到50GB的日誌||文件數量超過20此處為策略限制,
    Delete中可以按自己需要用正則表達式編寫
--> <DefaultRolloverStrategy>   <Delete basePath="${filePath}" maxDepth="1">     <IfLastModified age="14d" />     <IfAccumulatedFileSize exceeds="50 GB" />     <IfAccumulatedFileCount exceeds="20" />   </Delete> </DefaultRolloverStrategy>
  • 在出現問題之後,需要立即根據日誌定位問題。對於INFO及以上級別的日誌,要求按照一定順序,輸出以下必要的信息。參考日誌格式定義
<PatternLayout>
  <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%mdc{invokeNo}] %C{2}:%L %M - %msg%n
  </Pattern>
</PatternLayout>
  • 一個完整的Appender配置如下
<?xml version="1.0" encoding="UTF-8"?>
<!-- Configuration後面的status,這個用於設置log4j2自身內部的信息輸出,可以不設置,當設置成trace時,
  你會看到log4j2內部各種詳細輸出。monitorInterval:Log4j能夠自動檢測修改配置文件和重新配置本身,
  設置間隔秒數。
--> <configuration status="OFF" monitorInterval=”600″> <properties>   <property name="LOG_PATH">/export/home/logs/yourSystem/yourAppName</property>   <property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%mdc{invokeNo}]
         %C{2}:%L %M - %msg%n </property>   <property name="EVERY_FILE_SIZE">3GB</property>   <property name="OUTPUT_LOG_LEVEL">info</property>   <property name="FILE_COUNT">20</property>   <property name="ERROR_FILE_COUNT">3</property> </properties> <!--先定義所有的appender--> <appenders>
  <!--輸出控制台的配置-->   <Console name="console" target="SYSTEM_OUT">     <!--控制台只輸出level及以上級別的信息(onMatch),其他的直接拒絕(onMismatch)-->     <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>     <!--輸出日誌的格式-->     <PatternLayout pattern="${LOG_PATTERN}"/>   </Console> <!-- 列印信息,每次大小超過size,則這size大小的日誌會自動存入按年份-月份建立的文件夾下麵併進行壓縮,
  作為存檔
--> <RollingRandomAccessFile   name="all"   immediateFlush="true"   fileName="${LOG_DIR}/all.log"   filePattern="${LOG_DIR}/all-%d{yyyy-MM-dd}-%i.log">   <Filters>     <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="NEUTRAL"/>     <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="NEUTRAL"/>     <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="NEUTRAL"/>     <ThresholdFilter level="trace" onMatch="DENY" onMismatch="DENY"/>   </Filters> <PatternLayout>   <Pattern>${LOG_PATTERN}</Pattern> </PatternLayout> <Policies>   <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />   <TimeBasedTriggeringPolicy interval="1" modulate="true" /> </Policies> <!-- DefaultRolloverStrategy屬性如不設置,則預設為最多同一文件夾下7個文件,這裡設置了20 --> <DefaultRolloverStrategy>   <!-- 最多備14 天以內||日誌文件大小達到50GB的日誌||文件數量超過20此處為策略限制,Delete中可以按自
     己需要用正則表達式編寫
-->   <Delete basePath="${LOG_DIR}" maxDepth="1">     <IfLastModified age="14d" />     <IfAccumulatedFileSize exceeds="50 GB" />     <IfAccumulatedFileCount exceeds="20" />   </Delete> </DefaultRolloverStrategy>
</RollingRandomAccessFile> <RollingRandomAccessFile   name="all-error"   immediateFlush="true"   fileName="${LOG_DIR}/all-error.log"   filePattern="${LOG_DIR}/all-error-%d{yyyy-MM-dd}-%i.log">   <Filters>     <ThresholdFilter level="error" onMatch="ACCEPT"onMismatch="NEUTRAL"/>     <ThresholdFilter level="warn" onMatch="ACCEPT"onMismatch="DENY"/>   </Filters>   <PatternLayout>     <Pattern>${LOG_PATTERN}</Pattern>   </PatternLayout>   <Policies>     <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}" />     <TimeBasedTriggeringPolicy interval="1" modulate="true" />   </Policies>   <!-- DefaultRolloverStrategy屬性如不設置,則預設為最多同一文件夾下7個文件,這裡設置了20 --> <DefaultRolloverStrategy max="${ERROR_FILE_COUNT}"/> </RollingRandomAccessFile>
</appenders>

<!--然後定義logger,只有定義了logger並引入的appender,appender才會生效--> <loggers>   <!--預設的root的logger-->   <Logger name="all" level="info" additivity="false">     <AppenderRef ref="all" />   </Logger>   <Logger name="all-error" level="error" additivity="false">     <AppenderRef ref="all-error" />   </Logger>   <root level="${OUTPUT_LOG_LEVEL}">     <appender-ref ref="console"/>   </root> </loggers>
</configuration>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • π的計算 一、π的簡介 π的介紹 圓周率用希臘字母 π(讀作pài)表示,是一個常數(約等於3.141592654),是代表圓周長和直徑的比值。它是一個即無限不迴圈小數,在日常生活中,通常都用3.14代表圓周率去進行近似計算。 π的求解歷程 1965年,英國數學家約翰·沃利斯(John Wallis ...
  • python中的猴子補丁Monkey Patch 什麼是猴子補丁 the term monkey patch only refers to dynamic modifications of a class or module at runtime, motivated by the intent t ...
  • Java數據結構-HashMap 1. HashMap數據結構 沒有哈希衝突時,為數組,支持動態擴容 哈希衝突時,分為兩種情況: 1. 當衝突長度小於8或數組長度小於64(MIN_TREEIFY_CAPACITY預設值為64)時,為數組+鏈表(Node) 2. 當衝突長度大於8時,為數組+紅黑樹/鏈 ...
  • 作為一個有多年PHP開發經驗的碼農,我也是前段時間才發現PHP處理數組有這麼好用的函數, 至此之前,我處理數組的數據基本都是使用迴圈,記錄一下兩個函數的用法: array_column() 函數 返回輸入數組中某個單一列的值。 語法: array_column(array,column_key,in ...
  • 基於Cmake、QT Creator、Visual Studio的C++項目構建、開發、編譯是初學者必要的工具,本文主要介紹這些工具的下載與安裝,以及C++及Qt項目構建,主要包括 1.基於VS構建Qt項目;2.基於Qt Creater構建,在VS中開發Qt Creater生成的項目;3.基於Cma... ...
  • 概述 在PHP中有一種代碼復用的技術, 因為單繼承的問題, 有些公共方法無法在父類中寫出, 而 Trait可以應對這種情況, 它可以定義一些復用的方法, 然後在你需要使用的類中將其引入即可. 剛開始的時候給我的感覺就是將trait代碼塊直接拿到類中的意思, 但後來我發現, 我太天真了. PHP中的T ...
  • / 【例11 10】建立一個學生成績信息(包括學號、姓名、成績)的單向鏈表,學生數據按學號由小到大順序排列,要求實現對成績信息的插入、修改、刪除和遍歷操作。 / / 用鏈表實現學生成績信息的管理 / include include include struct stud_node{ int num; ...
  • 6 2 遞歸求階乘和 (10 分) 本題要求實現一個計算非負整數階乘的簡單函數,並利用該函數求 1!+2!+3!+...+n! 的值。 函數介面定義: double fact( int n ); double factsum( int n ); 函數fact應返回n的階乘,建議用遞歸實現。函數fac ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...