zoukankan      html  css  js  c++  java
  • 三、SpringBoot 日志篇

    日志级别

    几种常见的日志级别由低到高分为: TRACE < DEBUG < INFO < WARN < ERROR <FATAL 。

    如何理解这个日志级别呢?很简单,如果项目中的日志级别设置为 INFO ,那么比它更低级别的日志信息就看不到了,即是 TRACE 、 DEBUG 日志将会不显示。


    日志框架有哪些?

    常见的日志框架有 log4j 、 logback 、 log4j2

    log4j 这个日志框架显示是耳熟能详了,在 Spring 开发中是经常使用,但是据说log4j官方已经不再更新了,而且在性能上比logback 、 log4j2 差了很多。

    logback 是由 log4j 创始人设计的另外一个开源日志框架,logback相比之于log4j性能提升了10%以上,初始化内存加载也更小了。作为的Spring Boot默认的日志框架肯定是有着不小的优势。

    log4j2 晚于 logback 推出,官网介绍性能比 logback 高,但谁知道是不是王婆卖瓜自卖自夸,坊间流传,log4j2在很多思想理念上都是照抄logback,因此即便log4j2是Apache官方项目,Spring等许多框架项目没有将它纳入主流。

    日志框架很多,究竟如何选择能够适应现在的项目开发,当然不是普通程序员考虑的,但是为了更高的追求,至少应该了解一下,哈哈。

    Spring Boot 日志框架

    Spring Boot默认的日志框架是 logback ,既然Spring Boot能够将其纳入的默认的日志系统,肯定是有一定的考量的,因此实际开发过程中还是不要更换。

    原则上需要使用logback,需要添加以下依赖,但是既然是默认的日志框架,当然不用重新引入依赖了。

    <groupId>org.springframework.boot</groupId>
    
    <artifactId>spring-boot-starter-logging</artifactId>

    Spring Boot中默认的日志级别是 INFO ,启动项目日志打印如下:

    控制台日志
    控制台日志

    从上图可以看出,输出的日志的默认元素如下:

    1. 时间日期:精确到毫秒
    
    2. 日志级别:ERROR, WARN, INFO, DEBUG , TRACE
    
    3. 进程ID
    
    4. 分隔符:— 标识实际日志的开始
    
    5. 线程名:方括号括起来(可能会截断控制台输出)
    
    6. Logger名:通常使用源代码的类名
    
    7. 日志内容

    代码中如何使用日志?

    在业务中肯定需要追溯日志,那么如何在自己的业务中输出日志呢?其实常用的有两种方式,下面一一介绍。

    第一种其实也是很早之前常用的一种方式,只需要在代码添加如下:

    private final Logger logger= 
    
    LoggerFactory.getLogger(DemoApplicationTests.class);

    这种方式显然比较鸡肋,如果每个类中都添加一下岂不是很low。别着急,lombok为我们解决了这个难题。第二种:要想使用lombok,需要添加如下依赖:

    <dependency>
    
    <groupId>org.projectlombok</groupId>
    
    <artifactId>lombok</artifactId>
    
    </dependency>

    使用也是很简单,只需要在类上标注一个注解 @Slf4j 即可,如下:

    @Slf4j
    
    class DemoApplicationTests {
    
    @Test
    
    public void test(){
    
    log.debug("输出DEBUG日志.......");
    
     }
    
    }
    如何定制日志级别?

    Spring Boot中默认的日志级别是INFO,但是可以自己定制日志级别,如下:

    logging.level.root=DEBUG

    上面是将所有的日志的级别都改成了 DEBUG ,Spring Boot还支持 package 级别的日志级别调整,格式为: logging.level.xxx=xxx ,如下:

    logging.level.com.example.demo=INFO

    那么完整的配置如下:

    logging.level.root=DEBUG
    
    logging.level.com.example.demo=INFO
    日志如何输出到文件中?

    Spring Boot中日志默认是输出到控制台的,但是在生产环境中显示不可行的,因此需要配置日志输出到日志文件中。

    其中有两个重要配置如下:

    1.  logging.file.path  :指定日志文件的路径
    
    2.  logging.file.name  :日志的文件名,默认为  spring.log
    
    注意:官方文档说这两个属性不能同时配置,否则不生效,因此只需要配置一个即可。

    指定输出的文件为当前项目路径的 logs 文件下,默认生成的日志文件为spring.log ,如下:

    logging.file.path=./logs

    日志文件中还有一些其他的属性,比如日志文件的最大size,保留几天的日志等等,下面会介绍到。

    如何定制日志格式?

    默认的日志格式在第一张图已经看到了,有时我们需要定制自己需要的日志输出格式,这样在排查日志的时候能够一目了然。

    定制日志格式有两个配置,分别是控制台的输出格式和文件中的日志输出格式,如下:

    1.  logging.pattern.console  :控制台的输出格式
    2.  logging.pattern.file  :日志文件的输出格式

    例如配置如下:

    logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
    
    logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

    上面的配置编码的含义如下:

    %d{HH:mm:ss.SSS}——日志输出时间
    
    %thread——输出日志的进程名字,这在Web应用以及异步任务处理中很有用
    
    %-5level——日志级别,并且使用5个字符靠左对齐
    
    %logger- ——日志输出者的名字
    
    %msg——日志消息
    
    %n——平台的换行符

    如何自定义日志配置文件?

    Spring Boot官方文档指出,根据不同的日志系统,可以按照如下的日志配置文件名就能够被正确加载,如下:

    1. Logback :logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
    2. Log4j :log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
    3. Log4j2 :log4j2-spring.xml, log4j2.xml
    4. JDK (Java Util Logging) :logging.properties

    Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置。因此只需要在 src/resources 文件夹下创建 logback-spring.xml 即可,配置文件内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="60 seconds" debug="false">
    
        <property name="logPath" value="spring-boot-03-loging/logs"/><!-- 定义日志存放目录 -->
        <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-
    %L] %-5level %logger{36} %L %M - %msg%xEx%n"/><!--   日志输出的格式-->
        <contextName>logback</contextName>
    
        <!--输出到控制台 ConsoleAppender-->
        <appender name="consoleLog"
                  class="ch.qos.logback.core.ConsoleAppender">
    
            <!--展示格式 layout-->
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${PATTERN}</pattern>
            </layout>
            <!--过滤器,只有过滤到指定级别的日志信息才会输出,如果level为ERROR,那么控制台只会输出ERROR日志-->
            <!--
             <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
              </filter>
             -->
        </appender>
    
        <!--正常的日志文件,输出到文件中-->
        <appender name="fileDEBUGLog"
                  class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
            所以我们使用下面的策略,可以避免输出 Error 的日志-->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>Error</level><!--过滤 Error-->
                <onMatch>DENY</onMatch><!--匹配到就禁止-->
                <onMismatch>ACCEPT</onMismatch><!--没有匹配到就允许-->
            </filter>
            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件
            路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天
            会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。
            -->
            <File>${logPath}/log_demo.log</File>
    
            <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
                <FileNamePattern>${logPath}/log_demo_%d{yyyy-MM- dd}.log</FileNamePattern>
                <!--只保留最近90天的日志-->
                <maxHistory>90</maxHistory>
                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>
    
            <!--日志输出编码格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>${PATTERN}</pattern>
            </encoder>
        </appender>
    
        <!--指定最基础的日志输出级别-->
        <root level="DEBUG">
            <!--appender将会添加到这个loger-->
            <appender-ref ref="consoleLog"/>
            <appender-ref ref="fileDEBUGLog"/>
            <appender-ref ref="fileErrorLog"/>
        </root>
        <!--   定义指定package的日志级别-->
        <logger name="org.springframework" level="DEBUG"></logger>
        <logger name="org.mybatis" level="DEBUG"></logger>
        <logger name="java.sql.Connection" level="DEBUG"></logger>
        <logger name="java.sql.Statement" level="DEBUG"></logger>
        <logger name="java.sql.PreparedStatement" level="DEBUG"></logger>
        <logger name="io.lettuce.*" level="INFO"></logger>
        <logger name="io.netty.*" level="ERROR"></logger>
        <logger name="com.rabbitmq.*" level="DEBUG"></logger>
        <logger name="org.springframework.amqp.*" level="DEBUG"></logger>
        <logger name="org.springframework.scheduling.*" level="DEBUG"></logger>
        <!--定义com.xxx..xx..xx包下的日志信息不上传,直接输出到fileDEBUGLog和fileErrorLog这个两个appender中,
        日志级别为DEBUG-->
        <logger name="com.xxx.xxx.xx" additivity="false" level="DEBUG">
            <appender-ref ref="fileDEBUGLog"/>
            <appender-ref ref="fileErrorLog"/>
        </logger>
    </configuration>

    当然,如果就不想用SpringBoot推荐的名字,想自己定制也行,只需要在配置文件中指定配置文件名即可,如下:

    logging.config=classpath:logging-config.xml

    懵逼了,一堆配置什么意思?别着急,下面一一介绍。

    日志配置文件节点属性介绍
    configuration节点

    这是一个根节点,其中的各个属性如下:

    1.  scan  :当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    
    2.  scanPeriod  :设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    
    3.  debug  :当此属性设置为true时,将打印出logback内部日志信息,
    实时查看logback运行状态。默认值为false。
    root节点

    这是一个必须节点,用来指定基础的日志级别,只有一个 level 属性,默认值是 DEBUG 该节点可以包含零个或者多个元素,子节点是 appender-ref ,标记这个 appender 将会添加到这个 logger 中。

    contextName节点

    标识一个上下文名称,默认为 default,一般用不到

    property节点

    标记一个上下文变量,属性有name和value,定义变量之后可以使用 ${} 来获取。

    appender节点

    用来格式化日志输出节点,有两个属性 name 和 class ,class用来指定哪种输出策略,常用就是控制台输出策略文件输出策略

    这个节点很重要,通常的日志文件需要定义三个appender,分别是控制台输出常规日志文件输出异常日志文件输出

    该节点有几个重要的子节点,如下:

    1.  filter  :日志输出拦截器,没有特殊定制一般使用系统自带的即可,但是如果要将日志分开,比如将ERROR级别的日志输出到一个文件中,将除了  ERROR  级别的日志输出到另外一个文件中,此时就要拦截  ERROR  级别的日志了。
    
    2.  encoder  : 和pattern节点组合用于具体输出的日志格式和编码方式。
    
    3.  file  : 节点用来指明日志文件的输出位置,可以是绝对路径也可以是相对路径
    
    4.  rollingPolicy  : 日志回滚策略,在这里我们用了TimeBasedRollingPolicy,基于时间的回滚策略,有以下子节点fileNamePattern,必要节点,可以用来设置指定时间的日志归档。
    
    5.  maxHistory  : 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,,例如设置为30的话,则30天之后,旧的日志就会被删除
    
    6.  totalSizeCap  : 可选节点,用来指定日志文件的上限大小,例如设置为3GB的话,那么到了这个值,就会删除旧的日志
    logger节点

    可选节点,用来具体指明包的日志输出级别,它将会覆盖root的输出级别。 该节点有几个重要的属性如下:

    1.  name  :指定的包名
    
    2.  level  :可选,日志的级别
    
    3.  addtivity  :可选,默认为true,将此logger的信息向上级传递,将有root节点定义日志打印。如果设置为false,将不会上传,此时需要定义一个  appender-ref  节点才会输出。

    日志框架切换

    什么是日志门面?

    前面介绍的日志框架都是基于日志门面 SLF4j 即简单日志门面(Simple Logging Facade for Java),SLF4j 并不是一个真正的日志实现,而是一个抽象层,它允许你在后台使用任意一个日志实现。

    使用了 slf4j 后,对于应用程序来说,无论底层的日志框架如何变,应用程序不需要修改任意一行代码,就可以直接上线了。如果对 SLF4j 比较感兴趣的可以去官网看看:SLF4j 官网

    如何做到无感知切换?

    SLF4j 是日志门面,无论什么日志框架都是基于 SLF4j 的 API 实现,因此无论是代码打印日志还是 Lombok 注解形式打印日志,都要使用的 SLF4j 的 API,而 API ,这样才能解耦,做到无感知。因为最终切换的框架只是对 SLF4j的实现,并不是切换SLF4j。其实这一条在阿里开发手册中也是明确指出了,如下:


    Spring Boot默认是Logback日志框架,如果需要切换到其他的日志框架应该如何做?

    首先我们先看官网的一张图,一切都在图中,如下:

    日志框架
    日志框架

    SLF4j 只是一个门面,共有两大特性。一是静态绑定、二是桥接。

    什么是静态绑定?:我们以 log4j 为例。首先我们的 application 中会使用 slf4j 的 api 进行日志记录。我们引入适配层的 jar 包 slf4j-log412.jar 及底层日志框架实现 log4j.jar 。简单的说适配层做的事情就是把 slf4j 的 api 转化成 log4j 的 api。通过这样的方式来屏蔽底层框架实现细节。

    什么是桥接?:比如你的 application 中使用了 slf4j ,并绑定了 logback 。但是项目中引入了一个 A.jar , A.jar 使用的日志框架是 log4j 。那么有没有方法让 slf4j 来接管这个 A.jar 包中使用 log4j 输出的日志呢?这就用到了桥接包。你只需要引入 log4j-over-slf4j.jar 并删除 log4j.jar 就可以实现 slf4j 对 A.jar 中 log4j 的接管.听起来有些不可思议。你可能会想如果删除 log4j.jar 那 A.jar 不会报编译错误嘛?答案是不会。因为 log4j-over-slf4j.jar 实现了 log4j 几乎所有 public 的 API 。但关键方法都被改写了。不再是简单的输出日志,而是将日志输出指令委托给 slf4j 。

    下面就以 log4j2 为例,切换 Spring Boot 的日志框架为 log4j2 ,替换默认日志框架 Logback 。

    引入依赖

    Spring Boot 默认是 Logback 日志框架,如果想要切换 log4j2 肯定是要将 Logback 的依赖移除,只需要排除 web 模块中的日志场景启动器即可,如下:

    <dependencies>
    
    <dependency>
    
    <groupId>org.springframework.boot</groupId>
    
    <artifactId>spring-boot-starter-web</artifactId>
    
    <!-- 去掉springboot默认日志框架logback -->
    
    <exclusions>
    
    <exclusion>
    
    <groupId>org.springframework.boot</groupId>
    
    <artifactId>spring-boot-starter-logging</artifactId>
    
    </exclusion>
    
    </exclusions>
    
    </dependency>
    排除默认的 logback 依赖

    肯定是需要引入 log4j2 的依赖,其实 log4j2 为了与 Spring Boot 适配也做了个启动器,不需要在引入其他的jar包了,只需要添加如下依赖即可:

    <!-- 引入log4j2依赖 -->
    
    <dependency> 
    
        <groupId>org.springframework.boot</groupId>
    
        <artifactId>spring-boot-starter-log4j2</artifactId>
    
    </dependency>
    指定配置文件

    Spring Boot 官方文档已经给出了默认两个 log4j2 的配置的名称,分别为:log4j2-spring.xml , log4j2.xml ,但是建议使用 log4j2-spring.xml ,因为 Spring Boot 会做一些扩展,行吧,就整这个放在 src/resources 文件夹下即可。

    另外如果不使用默认的配置名称,则需要在 application.properties 指定配置文件,如下:

    logging.config=classpath:logging-config.xml
    日志配置文件如何配置?

    其实 log4j2 的一些配置和 logback 很相似,这里就不再一一介绍,有兴趣的可以去官网查查,直接贴出一些即用的配置,如下:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--Configuration 后面的 status,这个用于设置 log4j2 自身内部的信息输出,可以不设置,当设置成 trace 时,你会看到 log4j2 内部各种详细输出-->
    
    <!--monitorInterval:Log4j 能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
    <configuration monitorInterval="5">
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    
    
    <!--变量配置-->
    <Properties>
    
        <!-- 格式化输出:%date 表示日期,%thread 表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
    
        <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS}[%thread] %-5level %logger{36} - %msg%n" />
    
        <!-- 定义日志存储的路径 -->
    
        <property name="FILE_PATH" value="更换为你的日志路径" />
    
        <property name="FILE_NAME" value="更换为你的项目名" />
    
    </Properties>
    
    <appenders>
    
    <console name="Console" target="SYSTEM_OUT">
    
    <!--输出日志的格式-->
    
    <PatternLayout pattern="${LOG_PATTERN}"/>
    
    <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接
    
    拒绝(onMismatch)-->
    
    <ThresholdFilter level="info" onMatch="ACCEPT" 
    
    onMismatch="DENY"/>
    
    </console>
    
    <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由
    
    append属性决定,适合临时测试用-->
    
    <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
    
    <PatternLayout pattern="${LOG_PATTERN}"/>
    
    </File>
    <!-- 这个会打印出所有的 info 及以下级别的信息,每次大小超过 size,则这 size 大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
    
    <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" 
    
    filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-
    
    dd}_%i.log.gz">
    
    <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒
    
    绝(onMismatch)-->
    
    <ThresholdFilter level="info" onMatch="ACCEPT" 
    
    onMismatch="DENY"/>
    
    <PatternLayout pattern="${LOG_PATTERN}"/>
    
    <Policies>
    
    <!--interval属性用来指定多久滚动一次,默认是1 hour-->
    
    <TimeBasedTriggeringPolicy interval="1"/>
    
    <SizeBasedTriggeringPolicy size="10MB"/>
    
    </Policies>
    
    <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹
    
    下7个文件开始覆盖-->
    
    <DefaultRolloverStrategy max="15"/>
    
    </RollingFile>
    
    <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则
    
    这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为
    
    存档-->
    
    <RollingFile name="RollingFileWarn" 
    
    fileName="${FILE_PATH}/warn.log" 
    
    filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-
    
    dd}_%i.log.gz">
    
    <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒
    
    绝(onMismatch)-->
    
    <ThresholdFilter level="warn" onMatch="ACCEPT" 
    
    onMismatch="DENY"/>
    
    <PatternLayout pattern="${LOG_PATTERN}"/>
    
    <Policies>
    
    <!--interval属性用来指定多久滚动一次,默认是1 hour-->
    
    <TimeBasedTriggeringPolicy interval="1"/>
    
    <SizeBasedTriggeringPolicy size="10MB"/>
    
    </Policies>
    
    <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹
    
    下7个文件开始覆盖-->
    
    <DefaultRolloverStrategy max="15"/>
    
    </RollingFile>
    
    <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则
    
    这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为
    
    存档-->
    
     
    
    <RollingFile name="RollingFileError" 
    
    fileName="${FILE_PATH}/error.log" 
    
    filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-
    
    dd}_%i.log.gz">
    
    <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒
    
    绝(onMismatch)-->
    
    <ThresholdFilter level="error" onMatch="ACCEPT" 
    
    onMismatch="DENY"/>
    
    <PatternLayout pattern="${LOG_PATTERN}"/>
    
    <Policies>
    
    <!--interval属性用来指定多久滚动一次,默认是1 hour-->
    
    <TimeBasedTriggeringPolicy interval="1"/>
    
    <SizeBasedTriggeringPolicy size="10MB"/>
    
    </Policies>
    
    <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹
    
    下7个文件开始覆盖-->
    
    <DefaultRolloverStrategy max="15"/>
    
    </RollingFile>
    
    </appenders>
    
    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不
    
    同的日志级别等。-->
    
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会
    
    生效-->
    
    <loggers>
    
    <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
    
    <logger name="org.mybatis" level="info" additivity="false">
    
    <AppenderRef ref="Console"/>
    
    </logger>
    
    <!--监控系统信息-->
    
    <!--若是additivity设为false,则 子Logger 只会在自己的appender里输
    
    出,而不会在 父Logger 的appender里输出。-->
    
    <Logger name="org.springframework" level="info" additivity="false">
    
    <AppenderRef ref="Console"/>
    
    </Logger>
    
    <root level="info">
    
    <appender-ref ref="Console"/>
    
    <appender-ref ref="Filelog"/>
    
    <appender-ref ref="RollingFileInfo"/>
    
    <appender-ref ref="RollingFileWarn"/>
    
    <appender-ref ref="RollingFileError"/>
    
    </root>
    
    </loggers>
    
    </configuration>
    
     
    
    上面的配置中如果需要使用的话,需要改掉全局变量中的日志路径和项目名
    
    称,如下部分:
    
    <property name="FILE_PATH" value="更换为你的日志路径" />
    
    <property name="FILE_NAME" value="更换为你的项目名" />
  • 相关阅读:
    Javascript定义类(class)的三种方法
    npm命令ionic安装失败cordova安装失败解决方法
    解决类似 Requires: libstdc++.so.6(GLIBCXX_3.4.15)(64bit)的问题
    log_format为Nginx设置日志格式
    Nginx设置日志分割方法
    java和h5 canvas德州扑克开发中(二)
    java和h5 canvas德州扑克开发中(一)
    使用Reaver破解开启了WPS功能的wifi密码(wpa/wpa2)
    在Wifi网络中嗅探明文密码(HTTP POST请求、POP等)
    创建假的wifi热点
  • 原文地址:https://www.cnblogs.com/pengguozhen/p/14082763.html
Copyright © 2011-2022 走看看