Springboot整合日志一文全解

我们无法判断一个瞬间的价值,直至它成为回忆。

日志的分类 

首先,要知道,在项目中使用的日志分为两个大类。

一类是日志的门面,相当于Java中说的接口API,通过这个门面API去调用底层具体的日志实现。另一类就是日志的实现,即门面调用的日志具体实现。我们在项目中使用一般就是 日志门面 + 日志实现

1. 日志门面

- JCL

- slf4j

2. 日志实现

- JUL

- log4j

- logback

- log4j2

日志的使用

JUL(Java util logging)

jdk原生的日志框架,使用时不需要引入第三方类库,使用方便,一般用来自己写demo时打印测试日志。

使用示例:

import org.junit.jupiter.api.Test;

import java.util.logging.Level;
import java.util.logging.Logger;

public class AppTest 
{
    @Test
    public void testJUL() {
        // 1. 创建日志记录器对象
        Logger logger = Logger.getLogger("com.example.AppTest");
        // 2. 日志输出
        logger.info("test JUL");
        logger.log(Level.INFO, "选择日志的输出级别:test JUL");
        // 在日志输出中使用占位符
        String name = "li";
        Integer age = 18;
        logger.log(Level.INFO, "用户姓名:{0}, 用户年龄:{1}", new Object[]{name, age});
    }
}

输出:

三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: test JUL
三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: 选择日志的输出级别:test JUL
三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: 用户姓名:li, 用户年龄:18

搭配配置文件使用:

# Set root logger level to INFO and its only appender to ConsoleAppender.
log4j.rootLogger=INFO, ConsoleAppender

# Configure the console appender
log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c %x - %m%n\
  
# Configure the file appender
log4j.appender.FileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.FileAppender.File=mylog.log
log4j.appender.FileAppender.append=true
log4j.appender.FileAppender.MaxFileSize=10MB
log4j.appender.FileAppender.MaxBackupIndex=5
log4j.appender.FileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.FileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c %x - %m%n

解释:
- 这个配置文件定义了两种日志记录器:ConsoleAppender 和 FileAppender。ConsoleAppender 将日志输出到控制台,FileAppender 将日志输出到文件。
- log4j.rootLogger 定义了日志记录器的根级别为 INFO,这意味着只有 INFO、WARN、ERROR 和 FATAL 级别的日志信息才会被记录。
- og4j.appender.ConsoleAppender 定义了 ConsoleAppender 的布局,它使用了一个 PatternLayout,这个布局输出日志的时间、线程、日志级别、记录器名称和日志消息。
- log4j.appender.FileAppender 定义了 FileAppender 的布局和文件名,它使用了 RollingFileAppender,当日志文件大小超过 10MB 时,它将自动滚动文件。它还设置了最大备份数为 5,这意味着最多有五个备份日志文件。
- 最后,log4j.appender.FileAppender.layout.ConversionPattern 定义了日志记录的格式。

log4j

Apache下一款开源的日志框架。

使用示例

导入pom依赖:

<dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
   </dependency>

   <!-- log4j -->
   <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
   </dependency>
</dependencies>

编写测试类:

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.junit.Test;

public class AppTest
{
    @Test
    public void testLog4j() {
        // 1. 初始化配置信息
        BasicConfigurator.configure();
        // 2. 获取日志记录器对象
        Logger logger = Logger.getLogger(AppTest.class);
        // 3. 日志输出
        logger.info("hello log4j");
    }
}

搭配配置文件log4j.properties使用:

配置文件示例1:

#设置日志级别
log4j.rootLogger=INFO, Console, File

#输出到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#输出到文件
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.File=/var/log/myapp.log
log4j.appender.File.MaxFileSize=10MB
log4j.appender.File.MaxBackupIndex=10
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#设置包级别
log4j.logger.org.springframework=INFO
log4j.logger.com.example=DEBUG

配置文件示例2:

#设置日志级别
log4j.rootLogger = debug,Console,D,E
 
#输出信息到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#输出DEBUG 级别以上的日志到=E://logs/error.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
 
#输出ERROR 级别以上的日志到=E://logs/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

JCL + LOG4J

全称Jakarta Commons Logging,是Apache提供的一个通用日志API。

使用示例:

导入依赖

 <dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.11</version>
         <scope>test</scope>
     </dependency>

     <!-- jcl日志门面 -->
     <dependency>
         <groupId>commons-logging</groupId>
         <artifactId>commons-logging</artifactId>
         <version>1.2</version>
     </dependency>

     <!-- log4j -->
     <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.17</version>
     </dependency>
 </dependencies>

编写测试代码

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;

public class AppTest
{
    @Test
    public void testJCL() {
        Log log = LogFactory.getLog(AppTest.class);

        log.info("hello jcl");
    }
}

输出

22:28:25.433 [main] INFO com.example.AppTest - hello jcl

slf4j + logback

springboot底层默认使用的日志框架。

- Simple Logging Facade For Java 简单日志门面,主要是为了给java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其它日志框架。

- 是由log4j创始人设计的另一个开源日志组件,性能比log4j要好。

使用示例:

导入依赖

<dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.11</version>
         <scope>test</scope>
     </dependency>

     <!-- slf4j -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.30</version>
     </dependency>

     <!-- logback -->
     <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
         <version>1.2.3</version>
     </dependency>
 </dependencies>

编写测试类

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AppTest
{
    private final static Logger LOGGER = LoggerFactory.getLogger(AppTest.class);

    @Test
    public void testLogback() {
        LOGGER.info("hello logback");
    }
}

输出

22:19:12.237 [main] INFO com.example.AppTest - hello logback

搭配logback.xml配置文件使用

<configuration>

  <!-- 定义日志输出格式 -->
  <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>

  <!-- 控制台输出 -->
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${PATTERN}</pattern>
    </encoder>
  </appender>

  <!-- 文件输出 -->
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/app.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logs/app-%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>${PATTERN}</pattern>
    </encoder>
  </appender>

  <!-- 日志级别 -->
  <root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
  </root>

</configuration>

- 以上配置文件定义了两个输出源,控制台和文件。控制台输出采用ConsoleAppender,文件输出采用RollingFileAppender,并且使用TimeBasedRollingPolicy来按时间轮换日志文件。
- <root>元素定义了日志级别为INFO,并将日志输出到控制台和文件中。可以通过在<root>元素中指定不同的级别来控制日志输出的详细程度。例如,将level属性设置为DEBUG可以在日志中包含更多的详细信息。

log4j2

Log4j2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
- 异常处理,在logback中,Appender中的异常不会被应用程序感知到,但是在log4j2中,提供了一些异常处理机制。
- 性能提升,log4j相较于logback都具有很明显的性能提升。
- 自动重载机制,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制,log4j在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。

使用示例:

导入依赖

<dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.1</version>
         <scope>test</scope>
     </dependency>

     <!-- 使用slf4j作为日志门面 -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.30</version>
     </dependency>

     <!-- 使用log4j2作为日志实现 -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>2.0.7</version>
     </dependency>
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-api</artifactId>
         <version>2.13.3</version>
     </dependency>
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>
         <version>2.20.0</version>
     </dependency>
 </dependencies>

编写测试类

import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AppTest
    extends TestCase
{
    private static final Logger logger = LoggerFactory.getLogger(AppTest.class);

    public void testLog4j2() {
        logger.info("This is an info message.");
        logger.error("This is an error message.");
    }
}

输出结果

20:30:16.428 [main] INFO com.example.AppTest - This is an info message.
20:30:16.431 [main] ERROR com.example.AppTest - This is an error message.

搭配配置文件使用

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/app-%d{yyyy-MM-dd}.log.gz">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
      <Policies>
        <TimeBasedTriggeringPolicy interval="1" modulate="true" />
        <SizeBasedTriggeringPolicy size="10MB" />
      </Policies>
      <DefaultRolloverStrategy max="10" />
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="Console" />
      <AppenderRef ref="RollingFile" />
    </Root>
  </Loggers>
</Configuration>

- 该配置文件定义了两个Appenders(Console和RollingFile)以及一个Root Logger。
- Console Appender将日志输出到控制台,RollingFile Appender将日志输出到一个滚动的日志文件。
- RollingFile Appender使用了时间和大小两种触发策略,每天生成一个新的日志文件,并且日志文件最多保留10个。

log4j2异步日志实现的三种方式

在高并发的情况下,或者业务处理复杂的情况下,使用异步日志实现。

1. 使用AsyncLogger

AsyncLogger是log4j2中提供的异步日志实现方式之一。使用AsyncLogger需要在log4j2.xml配置文件中指定使用AsyncLogger。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
    </Loggers>
    <AsyncLogger name="async" level="info" additivity="false">
        <AppenderRef ref="Console"/>
    </AsyncLogger>
</Configuration>

在上面的配置中,我们定义了一个名为async的Logger,并将其级别设置为info。然后,我们使用AsyncLogger来实现异步日志记录,将日志输出到Console Appender中。

2. 使用AsyncAppender

AsyncAppender是log4j2另一个提供的异步日志实现方式。使用AsyncAppender需要在log4j2.xml配置文件中指定使用AsyncAppender,并同时指定要使用的Appender。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <Async name="Async">
            <AppenderRef ref="Console"/>
        </Async>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Async"/>
        </Logger>
    </Loggers>
</Configuration>

在上面的配置中,我们定义了一个名为Async的AsyncAppender,并将其Appender设置为Console Appender。然后,我们将async的Logger的Appender设置为Async Appender,实现异步日志记录。

3. 使用Disruptor等其它类似框架

Disruptor是一个高性能的并发框架,可以在log4j2中用来实现异步日志记录。

使用Disruptor需要在log4j2.xml配置文件中指定使用Disruptor,并同时指定要使用的Appender。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <Disruptor name="Disruptor" bufferSize="1024">
            <AppenderRef ref="Console"/>
        </Disruptor>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Disruptor"/>
        </Logger>
    </Loggers>
</Configuration>

在上面的配置中,我们定义了一个名为Disruptor的Disruptor Appender,并将其Appender设置为Console Appender。然后,我们将async的Logger的Appender设置为Disruptor Appender,实现异步日志记录。

效率 3 > 2 > 1

springboot使用slf4j + log4j2 

1. 排除springboot内部默认的logback依赖,导入log4j依赖

2. 在src/main/resources目录下新建log4j2.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
 
  <Appenders>
    <Console name="console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %highlight{%-5level} %logger{36} - %msg%n"/>
    </Console>
 
    <RollingFile name="file" fileName="logs/myapp.log"
                 filePattern="logs/myapp-%d{yyyy-MM-dd}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Pattern>
      </PatternLayout>
      <Policies>
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
      <DefaultRolloverStrategy max="20"/>
    </RollingFile>
  </Appenders>
 
  <Loggers>
    <Root level="info">
      <AppenderRef ref="console"/>
      <AppenderRef ref="file"/>
    </Root>
  </Loggers>
 
</Configuration>

以上配置文件中,定义了两个Appender,一个是Console Appender,用于将日志输出到控制台;另一个是RollingFile Appender,用于将日志输出到文件中,并支持文件滚动。其中,RollingFile Appender使用了SizeBasedTriggeringPolicy来控制文件大小,以及DefaultRolloverStrategy来控制文件滚动。最后,在Loggers中配置了Root Logger,将日志输出到Console和RollingFile Appender中。

3. 在Spring Boot的application.properties文件中,配置日志级别:

logging.level.root=info

以上配置将Root Logger的日志级别设置为info,也可以根据需要设置其他Logger的日志级别。

4. 在代码中使用Log4j2输出日志:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class MyApp {
 
    private static final Logger logger = LoggerFactory.getLogger(MyApp.class);
 
    public static void main(String[] args) {
        logger.debug("Debug message");
        logger.info("Info message");
        logger.warn("Warn message");
        logger.error("Error message");
    }
 
}

使用上述配置后,日志将会按照配置输出到控制台和文件中。如果需要更改日志输出的路径,可以在log4j2.xml文件中修改RollingFile Appender中的fileName属性。如果需要更改日志文件的格式,可以修改PatternLayout中的pattern属性。如果需要设置其他的Appender和Logger,可以在log4j2.xml文件中进行配置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot是一个开源的Java开发框架,它使得开发者能够快速、方便地构建独立的、基于Spring的应用程序。Jenkins是一个流行的自动化构建工具,它可以帮助开发团队实现持续集成和持续交付。Jenkins与SpringBoot结合使用可以实现自动化构建和部署SpringBoot应用程序的流程。JUnit是一个Java的单元测试框架,它提供了一种方便的方式来编写和运行单元测试。在SpringBoot中使用Jenkins和JUnit可以实现对应用程序进行自动化的单元测试和集成测试。 在Jenkins中,你可以使用Pipeline语法编写流水线脚本来定义构建过程。使用Jenkins的JUnit插件,你可以在构建过程中运行JUnit测试,并生成测试报告。测试报告可以帮助开发团队及时发现和修复代码中的问题。 关于SpringBoot、Jenkins和JUnit的详细学习资料,你可以参考以下资源: - 《JUnit5学习》系列文章可以提升在SpringBoot环境下的单元测试技能。 - Jenkins官方文档提供了关于流水线、测试和构件的详细说明。 - Jacoco官方文档介绍了Jacoco代码覆盖率工具的使用方法。 - 有关Jenkins单元测试的两篇文章提供了实际操作的指导。 - 《Jenkins 2.X Script Pipeline语法基础》一文介绍了Jenkins流水线脚本的基本语法。 如果你在使用Jenkins进行SpringBoot应用程序的单元测试时遇到了问题,你可以参考以下一些常见问题和解决方法: - "Jenkins mvn not found"错误可能是由于Jenkins环境变量中未添加Maven路径导致的。你可以在Jenkins配置中添加Maven路径以解决该问题。 - "NullPointerException in Jenkins"错误可能是由于流水线脚本中的wrap{}语法不支持所导致的。你可以尝试使用其他语法解决该问题。 - "Error cloning remote repo 'origin'"错误可能是由于流水线脚本书写错误所导致的。你可以检查脚本中的语法错误并进行修正。 - "There is insufficient memory for the Java Runtime Environment to continue"错误可能是由于服务器资源不足导致的。你可以整理服务器资源,关闭不常用的Docker容器来释放内存。 - "Could not initialize class jackson.databind.deser.std.JdkDeserializers"错误可能是由于依赖问题导致的。你可以尝试删除某些依赖或更换JDK版本来解决该问题。 - "java.lang.ArrayIndexOutOfBoundsException"错误可能是由于代码中的错误导致的。你可以尝试排查代码中的问题并进行修复。 - "Step 'Publish JUnit test result report' failed: No test report files were found"错误可能是由于测试报告文件未找到所导致的。你可以检查测试报告文件是否正确生成并配置正确的路径。 - "Failed to read test report file"错误可能是由于测试报告文件读取失败所导致的。你可以尝试重新生成测试报告文件或检查文件读取权限。 希望以上信息对你有帮助。祝你在SpringBoot、Jenkins和JUnit的学习和实践中取得成功!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [blog_demos:CSDN博客专家程序员欣宸的github,这里有四百多篇原创文章的详细分类和汇总,以及对应的源码,...](https://download.csdn.net/download/weixin_42116847/14986863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Jenkins实战先看这:Jenkins 集成Junit单元测试+Jacoco统计覆盖率](https://blog.csdn.net/l_mloveforever/article/details/121603703)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值