这里借鉴了很多大牛们的观点和资料,参考网址:

1、http://www.cnblogs.com/ywlaker/p/6124067.html

2、http://www.cnblogs.com/xing901022/p/4149524.html

3、http://www.cnblogs.com/olmlo/p/3143468.html

4、http://www.open-open.com/lib/view/open1418652677495.html

5、http://www.cnblogs.com/eflylab/archive/2007/01/11/618001.html

一、slf4j介绍

SLF4J是为各种loging APIs提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的loging APIs实现。Logging API实现既可以选择直接实现SLF4J接口的loging APIs如: logback、SimpleLogger。也可以通过开发相应的适配器来使用已有的API实现如Log4jLoggerAdapter、JDK14LoggerAdapter。

SLF4J 不依赖任何特殊的class loader机制,实际上,SLF4J 和已有日志实现的绑定是在编译时静态执行的,具体绑定工作是通过一个jar包实现的,使用时只要把相应的jar包(只有一个)放到类路径上即可.

在 SLF4J发行版本中包含了几个jar包,如slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-log4j13.jar, slf4j-jdk14.jar and slf4j-jcl.jar等.SLF4J支持多个日志系统,比如NOP, Simple, log4j version 1.2, log4j version 1.3, JDK 1.4 logging, JCL and logback。

使用slf4j尽管很方便,但是让很多人搞不明白slf4j那么多包怎么用。其实slf4j原理很简单,他只提供一个核心slf4j api(就是slf4j-api.jar包),这个包只有日志的接口,并没有实现,所以如果要使用就得再给它提供一个实现了些接口的日志包,比 如:log4j,common logging,jdk log日志实现包等,但是这些日志实现又不能通过接口直接调用,实现上他们根本就和slf4j-api不一致,因此slf4j又增加了一层来转换各日志实 现包的使用,当然slf4j-simple除外。其结构如下:

slf4j-api(接口层)|
各日志实现包的连接层( slf4j-jdk14, slf4j-log4j)|
各日志实现包

下面这个图更能说明其原理:

在这里还需要注意的是,连接层的jar包和实现的jar的版本要一致。

slf4j的构造是通过工厂类生存,我们调用接口时,接口的工厂会自动寻找恰当的实现,返回一个实现的实例给我服务。这些过程都是透明化的,用户不需要进行任何操作。

loging APIs的接口,

关于上述所述的“实现查找符合自己接口的实现类”,对于slf4j其实同通过加载器的方式自动来实现。具体的详细实现可以参考:http://www.cnblogs.com/xing901022/p/4149524.html

关于JVM加载器,可以参考下图理解:

二、slf4j具体使用

Logger logger = LoggerFactory.getLogger(name);

或者

Logger logger = LoggerFactory.getLogger(calss.class);

这样就可使用logger对象进行日志输出。

slf4j只提供了debug、warn、info、error等几个简单的接口,但由于slf4j只是接口,其具体实现是有对应的实现类完成。所以在在使用slf4j时都是和相应日志实现一起使用。

常用的使用有:slf4j+log4j、slf4j+Logback等

三、log4j介绍

Log4J是Apache的一个开放源代码的项目。通过使用Log4J,程序员可以控制日志信息输送的目的地,包括控制台,文件,GUI组件和NT事件记录器,也可以控制每一条日志的输出格式,或通过定义每一条日志信息的级别,更加细致地控制日志的生成过程。

Log4j的组成:
Log4j由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。
Logger:控制要启用或禁用哪些日志记录语句,并对日志信息进行级别限制:Appenders指定了日志将打印到控制台还是文件中;而Layout则控制日志信息的显示格式。

A).Logger对象的获得或创建
Logger被指定为实体,由一个String类的名字识别。Logger的名字是大小写敏感的,且名字之间具有继承关系,子名用父名作为前缀,用点“.”分隔,例如x.y是x.y.z的父亲。
root Logger(根Logger)是所有Logger的祖先,它有如下属性:
1.它总是存在的。
2.它不可以通过名字获得。
root Logger可以通过以下语句获得:

public static Logger Logger.getRootLogger();

或:

public static Logger Logger.getLogger(Class clazz)

其中调用Logger.getLogger(Class clazz)是目前ogger对象最理想的方法。

B)日志级别
每个Logger都被了一个日志级别(log level),用来控制日志信息的输出。日志级别从高到低分为:
A:off         最高等级,用于关闭所有日志记录。
B:fatal       指出每个严重的错误事件将会导致应用程序的退出。
C:error      指出虽然发生错误事件,但仍然不影响系统的继续运行。
D:warm     表明会出现潜在的错误情形。
E:info         一般和在粗粒度级别上,强调应用程序的运行全程。
F:debug     一般用于细粒度级别上,对调试应用程序非常有帮助。
G:all           最低等级,用于打开所有日志记录。

上面这些级别是定义在org.apache.log4j.Level类中。Log4j只建议使用4个级别,优先级从高到低分别是error,warn,info和debug。通过使用日志级别,可以控制应用程序中相应级别日志信息的输出。例如,如果使用b了info级别,则应用程序中所有低于info级别的日志信息(如debug)将不会被打印出来。

package log4j;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class Log4jTest {
    public static void main(String[] args) {   
        Logger logger = Logger.getLogger(Log4jTest.class);        
        //使用默认的配置信息,不需要写log4j.properties
        BasicConfigurator.configure();
        //设置日志输出级别为info,这将覆盖配置文件中设置的级别
        logger.setLevel(Level.INFO);
        //下面的消息将被输出
        logger.info("this is an info");
        logger.warn("this is a warn");
        logger.error("this is an error");
        logger.fatal("this is a fatal");
    }
}

C)输出端Appender
Appender用来指定日志信息输出到哪个地方,可以同时指定多个输出目的地。Log4j允许将信息输出到许多不同的输出设备中,一个log信息输出目的地就叫做一个Appender。
每个Logger都可以拥有一个或多个Appender,每个Appender表示一个日志的输出目的地。可以使用Logger.addAppender(Appender app)为Logger增加一个Appender,也可以使用Logger.removeAppender(Appender app)为Logger删除一个Appender。
以下为Log4j几种常用的输出目的地。
a:org.apache.log4j.ConsoleAppender:将日志信息输出到控制台。
b:org.apache.log4j.FileAppender:将日志信息输出到一个文件。
c:org.apache.log4j.DailyRollingFileAppender:将日志信息输出到一个日志文件,并且每天输出到一个新的日志文件。
d:org.apache.log4j.RollingFileAppender:将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件。
e:org.apache.log4j.WriteAppender:将日志信息以流格式发送到任意指定地方。
f::org.apache.log4j.jdbc.JDBCAppender:通过JDBC把日志信息输出到数据库中。

日志输出器,指定logger的输出位置

1
log4j.appender.appenderName=className

每种appender都有若干配置项,下面逐一介绍

  ConsoleAppender(常用)

1
2
3
Threshold=WARN:指定日志信息的最低输出级别,默认DEBUG
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true
Target=System.err:默认值是System.out

  FileAppender

1
2
3
4
Threshold=WARN:指定日志信息的最低输出级别,默认DEBUG
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认true
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认true
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件

  DailyRollingFileAppender(常用)

1
2
3
4
5
6
7
8
9
10
11
12
Threshold=WARN:指定日志信息的最低输出级别,默认DEBUG
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认true
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认true
File=D:/logs/logging.log4j:指定当前消息输出到logging.log4j文件
DatePattern='.'yyyy-MM:每月滚动一次日志文件,即每月产生一个新的日志文件。当前月的日志文件名为logging.log4j,前一个月的日志文件名为logging.log4j.yyyy-MM
另外,也可以指定按周、天、时、分等来滚动日志文件,对应的格式如下:
1)'.'yyyy-MM:每月
2)'.'yyyy-ww:每周
3)'.'yyyy-MM-dd:每天
4)'.'yyyy-MM-dd-a:每天两次
5)'.'yyyy-MM-dd-HH:每小时
6)'.'yyyy-MM-dd-HH-mm:每分钟

  RollingFileAppender

1
2
3
4
5
6
Threshold=WARN:指定日志信息的最低输出级别,默认DEBUG
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认true
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认true
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件
MaxFileSize=100KB:后缀可以是KB,MB或者GB。在日志文件到达该大小时,将会自动滚动,即将原来的内容移到logging.log4j.1文件
MaxBackupIndex=2:指定可以产生的滚动文件的最大数,例如,设为2则可以产生logging.log4j.1,logging.log4j.2两个滚动文件和一个logging.log4j文件

日志格式化器Layout
有三种:
HTMLLayout:格式化日志输出为HTML表格形式:如下
SimpleLayout:以一种非常简单的方式格式化日志输出,它打印三项内容:级别-信息

指定logger输出内容及格式

1
log4j.appender.appenderName.layout=className

  layout有4种选择

1
2
3
4
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)

  layout也有配置项,下面具体介绍

  HTMLLayout

1
2
LocationInfo=true:输出java文件名称和行号,默认false
Title=My Logging: 默认值是Log4J Log Messages

  PatternLayout(最常用的配置)

1
ConversionPattern=%m%n:设定以怎样的格式显示消息

  设置格式的参数说明如下

1
2
3
4
5
6
7
8
9
10
11
12
13
%p:输出日志信息的优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%d:输出日志时间点的日期或时间,默认格式为ISO8601,可以指定格式如:%d{yyyy/MM/dd HH:mm:ss,SSS}
%r:输出自应用程序启动到输出该log信息耗费的毫秒数
%t:输出产生该日志事件的线程名
%l:输出日志事件的发生位置,相当于%c.%M(%F:%L)的组合,包括类全名、方法、文件名以及在代码中的行数
%c:输出日志信息所属的类目,通常就是类全名
%M:输出产生日志信息的方法名
%F:输出日志消息产生时所在的文件名
%L:输出代码中的行号
%m:输出代码中指定的具体日志信息
%n:输出一个回车换行符,Windows平台为"rn",Unix平台为"n"
%x:输出和当前线程相关联的NDC(嵌套诊断环境)
%%:输出一个"%"字符

例:INFO - info
PatternLayout::根据指定的转换模式格式化日志输出,或者如果没有指定任何转换模式,就使用默认的转化模式格式。
下面的代码实现了SimpleLayout和FileAppender的程序

public static void main(String[] args) {
        
        Logger logger = Logger.getLogger(Log4jTest.class);        
        SimpleLayout layout = new SimpleLayout();
        //HTMLLayout  layout = new HTMLLayout();
        FileAppender appender = null;
        try{
            //把输出端配置到out.txt
            appender = new FileAppender(layout,"out.txt",false);
        }catch(Exception e){            
        }
        logger.addAppender(appender);//添加输出端
        logger.setLevel((Level)Level.DEBUG);//覆盖配置文件中的级别
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
        logger.fatal("fatal");
    }

Log4j的配置
配置Log4j环境就是指配置root Logger,包括把Logger为哪个级别,为它增加哪些Appender,以及为这些Appender设置Layout,等等。因为所有其他的Logger都是root Logger的后代,所以它们都继承了root Logger的性质。这些可以通过设置系统属性的方法来隐式地完成,也可以在程序中调用XXXConfigurator.configure()方法来显式地完成。有以下几种方式来配置Log4j。
A:配置放在文件里,通过环境变量传递文件名等信息,利用Log4j默认的初始化过程解析并配置。
B:配置放在文件里,通过应用服务器配置传递文件甸等信息,利用一个特定的Servlet来完成配置。
C:在程序中调用BasicConfigor.configure()方法。
D:配置放在文件里,通过命令行PropertyConfigurator.configure(args[])解析log4j.properties文件并配置Log4j。
下面对BasicConfigurator.configure()方法和PropertyConfigurator.config()方法分别进行介绍。
BasicConfigurator.configure()方法:
它使用简单的方法配置Log4j环境。这个方法完成的任务是:
1:用默认的方式创建PatternLayout对象p:
  PatternLayout p = new PatternLayout("%-4r[%t]%-5p%c%x-%m%n");
2:用p创建ConsoleAppender对象a,目标是System.out,标准输出设备:
 ConsoleAppender a = new CpnsoleAppender(p,ConsoleAppender.SYSTEM_OUT);
3:为root Logger增加一个ConsoleAppender p;
 rootLogger.addAppender(p);
4:把rootLogger的log level设置为DUBUG级别;
 rootLogger.setLevel(Level.DEBUG);

PropertyConfigurator.configure()方法:
当使用以下语句生成Logger对象时:

 static Logger logger = Logger.getLogger(mycalss.class);

如果没有调用BasicConfigurator.configure(),PropertyConfigurator.configure()或DOMConfigurator.configure()方法,Log4j会自动加载CLASSPATH下名为log4j.properties的配置文件。如果把此配置文件改为其他名字,例如my.properties,程序虽然仍能运行,但会报出不能正确初始化Log4j系统的提示。这时可以在程序中加上:

PropertyConfigurator.configure("classes/my.properties");

四 log4j完整配置示例

  介绍完了log4j.properties内容,我们来配置一些常用的日志输出吧

1
2
log4j.rootLogger=DEBUG,console,dailyFile,rollingFile,logFile
log4j.additivity.org.apache=true

  控制台console日志输出器

1
2
3
4
5
6
7
# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

  文件logFile日志输出器

1
2
3
4
5
6
7
8
# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.appender.logFile.ImmediateFlush=true
log4j.appender.logFile.Append=true
log4j.appender.logFile.File=D:/logs/log.log4j
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

  滚动文件rollingFile日志输出器

1
2
3
4
5
6
7
8
9
10
# 滚动文件(rollingFile)
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=DEBUG
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.Append=true
log4j.appender.rollingFile.File=D:/logs/log.log4j
log4j.appender.rollingFile.MaxFileSize=200KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

  定期滚动文件dailyFile日志输出器

1
2
3
4
5
6
7
8
9
# 定期滚动日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold=DEBUG
log4j.appender.dailyFile.ImmediateFlush=true
log4j.appender.dailyFile.Append=true
log4j.appender.dailyFile.File=D:/logs/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

五、log4j局部日志配置

  以上介绍的配置都是全局的,整个工程的代码使用同一套配置,意味着所有的日志都输出在了相同的地方,你无法直接了当的去看数据库访问日志、用户登录日志、操作日志,它们都混在一起,因此,需要为包甚至是类配置单独的日志输出,下面给出一个例子,为“com.demo.test”包指定日志输出器“test”,“com.demo.test”包下所有类的日志都将输出到/log/test.log文件

1
2
3
4
5
log4j.logger.com.demo.test=DEBUG,test
log4j.appender.test=org.apache.log4j.FileAppender
log4j.appender.test.File=/log/test.log
log4j.appender.test.layout=org.apache.log4j.PatternLayout
log4j.appender.test.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

  也可以让同一个类输出不同的日志,为达到这个目的,需要在这个类中实例化两个logger

1
2
private static Log logger1 = LogFactory.getLog("myTest1");
private static Log logger2 = LogFactory.getLog("myTest2");

  然后分别配置

1
2
3
4
5
6
7
8
9
10
11
12
log4j.logger.myTest1= DEBUG,test1
log4j.additivity.myTest1=false
log4j.appender.test1=org.apache.log4j.FileAppender
log4j.appender.test1.File=/log/test1.log
log4j.appender.test1.layout=org.apache.log4j.PatternLayout
log4j.appender.test1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n
  
log4j.logger.myTest2=DEBUG,test2
log4j.appender.test2=org.apache.log4j.FileAppender
log4j.appender.test2.File=/log/test2.log
log4j.appender.test2.layout=org.apache.log4j.PatternLayout
log4j.appender.test2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n

六、slf4j与log4j联合使用

  slf4j是什么?slf4j只是定义了一组日志接口,但并未提供任何实现,既然这样,为什么要用slf4j呢?log4j不是已经满足要求了吗?

  是的,log4j满足了要求,但是,日志框架并不只有log4j一个,你喜欢用log4j,有的人可能更喜欢logback,有的人甚至用jdk自带的日志框架,这种情况下,如果你要依赖别人的jar,整个系统就用了两个日志框架,如果你依赖10个jar,每个jar用的日志框架都不同,岂不是一个工程用了10个日志框架,那就乱了!

  如果你的代码使用slf4j的接口,具体日志实现框架你喜欢用log4j,其他人的代码也用slf4j的接口,具体实现未知,那你依赖其他人jar包时,整个工程就只会用到log4j日志框架,这是一种典型的门面模式应用,与jvm思想相同,我们面向slf4j写日志代码,slf4j处理具体日志实现框架之间的差异,正如我们面向jvm写java代码,jvm处理操作系统之间的差异,结果就是,一处编写,到处运行。况且,现在越来越多的开源工具都在用slf4j了

  那么,怎么用slf4j呢?

  首先,得弄到slf4j的jar包,maven依赖如下,log4j配置过程完全不变

1
2
3
4
5
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.21</version>
</dependency>

  然后,弄到slf4j与log4j的关联jar包,通过这个东西,将对slf4j接口的调用转换为对log4j的调用,不同的日志实现框架,这个转换工具不同

1
2
3
4
5
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.21</version>
</dependency>

  当然了,slf4j-log4j12这个包肯定依赖了slf4j和log4j,所以使用slf4j+log4j的组合只要配置上面这一个依赖就够了

  最后,代码里声明logger要改一下,原来使用log4j是这样的

1
2
3
4
5
6
7
import org.apache.log4j.Logger;
class Test {
    final Logger log = Logger.getLogger(Test.class);
    public void test() {
        log.info("hello this is log4j info log");
    }
}

  现在要改成这样

1
2
3
4
5
6
7
8
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class Test {
    Logger log = LoggerFactory.getLogger(Test.class);
    public void test() {
        log.info("hello, my name is {}""chengyi");
    }
}

  依赖的Logger变了,而且,slf4j的api还能使用占位符,很方便。

slf4j+log4j结合使用相关推荐

  1. [转]slf4j + log4j原理实现及源码分析

    slf4j + log4j原理实现及源码分析 转载于:https://www.cnblogs.com/jasonzeng888/p/6051080.html

  2. slf4j+log4j打印日志,控制台无日志输出

    slf4j+log4j 实现日志打印 项目场景: 今天看以前的项目,运行起来报错,项目日志对于项目是很重要的,但是控制台没有打印出来日志,运行起来报错的问题先放一放,先把日志的问题解决了,我项目中有l ...

  3. SLF4J log4j 学习笔记一

    SLF4J log4j 一.介绍: 简单日记门面(simple logging Facade for java)SLF4J是为各种loging APIs提供一个简单统一的 接口,从而使得最终用户能够在 ...

  4. java ndc_通过slf4j/log4j的MDC/NDC 实现日志追踪

    在分布式系统或者较为复杂的系统中,我们希望可以看到一个客户请求的处理过程所涉及到的所有子系统\模块的处理日志. 由于slf4j/log4j基本是日志记录的标准组件,所以slf4j/log4j成为了我的 ...

  5. slf4j + log4j原理实现及源码分析

    2019独角兽企业重金招聘Python工程师标准>>> #0 系列目录# 2种日志接口框架,4种日志实现框架 jdk-logging.log4j.logback日志介绍及原理 jcl ...

  6. slf4j+log4j在Java中实现日志记录

    小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...

  7. slf4j log4j logback关系详解和相关用法 【by Sinte-Beuve】

    slf4j log4j logback关系详解和相关用法 slf4j log4j logback的关系 The Simple Logging Facade for Java是什么? log4j和log ...

  8. SLF4j+LOG4j

    工作笔记:在myeclipse 中创建一个java project 创建一个 TestSlf4J 类 import org.slf4j.Logger; import org.slf4j.LoggerF ...

  9. Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

最新文章

  1. 慎重使用volatile关键字
  2. numpy函数中的linspace
  3. Java中的LongAdder和AtomicLong有什么区别?
  4. webpack和vue的按需加载组件、console、抓包
  5. cocos2d-x游戏开发(十四)用shader使图片背景透明
  6. 手机热点总是正在连接服务器,手机热点用不了?可以尝试这个方法。
  7. oracle不空顺序输出,Oracle应用笔记
  8. CentOS7安装VPP(FD.io)
  9. 蓝桥杯 ADV-89 算法提高 输出九九乘法表
  10. 用DIB位图显示图像
  11. 科研热点|官宣!2022年JCR分区和影响因子发布时间确定!
  12. 一篇文章带你登顶 MacBook高效工作环境配置
  13. Verilog实现按键消抖
  14. 不要奇怪 XP震网病毒缺陷或为2014最大软件漏洞
  15. 在vue项目中使用webp图片心得
  16. android one a2,小米第二代 Android One 机种小米 A2 与平价版小米 A2 Lite 于西班牙发表...
  17. mac 笔记本 终端使用管理员权限
  18. 11月开展消防宣传活动
  19. Java程序实现Word文档转为pdf以及出现的问题解决
  20. 企业在产品同质化的今天如何提高竞争力

热门文章

  1. CentOS7 linux ifconfig 没有ens33网卡 连不上网
  2. 傅里叶变换家族的关系
  3. 批处理命令set /p是什么意思
  4. WuThreat身份安全云-TVD每日漏洞情报-2023-03-28
  5. 2020年10款实用的电脑软件大盘点,强烈推荐!
  6. Hotmail无法登陆暂时解决办法
  7. 从流量分析看20几个购物网,很好很强大
  8. 我的第二次找工作之旅
  9. leaflet离线地图(开发总结)
  10. 大数据4 - 分布式计算