1. 程式人生 > >使用spring boot+logback的一些編碼問題整理

使用spring boot+logback的一些編碼問題整理

本文主要講述在spring boot中使用logback時出現的一些中文亂碼問題,在springMVC中基本也是適用的。

輸出到檔案中,配置如下:

 <appender name="STDOUT" class="ch.qos.logback.core.FileAppender">
     <file>D:\firstLog.log</file>
     <layout class="ch.qos.logback.classic.PatternLayout">
         <Pattern>%d{HH:mm:ss.SSS} [%thread] %-2level %logger{36} [%method][%line] -                     %msg%n</Pattern
>
</layout> </appender> <root level="ERROR"> <appender-ref ref="STDOUT"/> </root>

這個配置可以成功輸出日誌到指定的檔案,但當輸出中文時,出現了亂碼,有些同學可能沒有發現亂碼的情況,是因為開啟文字的工具預設編碼有區別,直接用windows記事本開啟可能沒有亂碼,但用Nodepad++等其他文字工具開啟可能就是亂碼。重要的是我們得明白logback輸出的是什麼編碼。

新增的appender,如果沒有指定編碼,那預設編碼是什麼呢,預設就是Null,最後在輸出的地方會取當前呼叫當前執行環境的預設編碼。

    private byte[] convertToBytes(String s) {
        if(this.charset == null) {
            return s.getBytes();
        } else {
            try {
                return s.getBytes(this.charset.name());
            } catch (UnsupportedEncodingException var3) {
                throw new IllegalStateException("An existing charset cannot possibly be unsupported."
); } } }

由於charset==null

    //String.getBytes()
   public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }

    //StringCoding.encode(char[] ca, int off, int len)
    static byte[] encode(char[] ca, int off, int len) {
        String csn = Charset.defaultCharset().name();
        try {
            // use charset name encode() variant which provides caching.
            return encode(csn, ca, off, len);
        } catch (UnsupportedEncodingException x) {
            warnUnsupportedCharset(csn);
        }
        try {
            return encode("ISO-8859-1", ca, off, len);
        } catch (UnsupportedEncodingException x) {
            // If this code is hit during VM initialization, MessageUtils is
            // the only way we will be able to get any kind of error message.
            MessageUtils.err("ISO-8859-1 charset not available: "
                             + x.toString());
            // If we can not find ISO-8859-1 (a required encoding) then things
            // are seriously wrong with the installation.
            System.exit(1);
            return null;
        }
    }

這個預設編碼是哪裡的預設編碼呢?是tomcat的預設編碼,那我們可以去修改tomcat的預設編碼:
有人提供了簡便的設定tomcat charset的方式:

在tomcat/bin目錄下建一個檔案,檔名為 setenv.bat ,並將下面程式碼寫入檔案,重啟tomcat,預設編碼就變為UTF-8了,用Logback輸出就沒有中文亂碼情況了。

set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF8"

這是一種處理方式,但個人不太支援這種做法,因為很多預設輸出用的是GBK的,將tomcat編碼設定為UTF-8只是方便了自己輸出日誌,但有可能導致其他編碼的輸出會變成亂碼,所以最好不要去動tomcat的預設編碼。

解決方法當然是設定logback本身的輸出編碼,我們可以參見spring boot提供的console-appender.xml

<included>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
</included>

設定編碼一定要在encoder節點下設定,有些人說可以直接在appender節點下新增charset,略翻原始碼發現最後的輸出是在類ch.qos.logback.core.encoder.LayoutWrappingEncoder下完成的,這個類有個Charset成員變數,最終輸出編碼獲取的就是這個變數,如果沒有則取當前執行環境的預設編碼。

設定編碼可以如下:

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{10} [%file:%line] -                  %msg%n</pattern>
    </layout>
    <charset>UTF-8</charset>
</encoder>

如果沒有特殊要求可以引用spring boot寫好的base.xml

<?xml version="1.0" encoding="UTF-8"?>

<!--
Base logback configuration provided for compatibility with Spring Boot 1.1
-->

<included>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</included>

我們可以看到base.xml引入了兩個appender,他的預設輸出編碼都是UTF-8的,但是執行環境不預設編碼為GBK,編碼有衝突,所以在console中輸出的又是亂碼,我們可以把他的預設配置copy到我們自定義的logback-spring.xml下,修改下預設的名稱為CONSOLE的appender預設編碼為GBK。

總結下來logback輸出中文的亂碼情況我們要考慮兩個因素:

  • 位元組流的編碼 byte[],通常為 s.getBytes(this.charset.name());
  • 當前執行環境的預設編碼,這個基本上可以確定是伺服器的編碼,這個我們可以通過Charset.defaultCharset().name()檢視。值得注意的是通過spring boot內建的tomcat執行時,他的預設編碼是UTF-8,所以無需任何設定,但當打包成war包時就會出現亂碼情況了,所以最好在logback中明確設定好編碼,以免受到驚嚇。。

歡迎關注我的個人公眾號:逍遙的心。主推程式設計師寫的生活類文章,有興趣的朋友可以共同探討下:這裡寫圖片描述