Java日志框架(二)
最流行的日志框架解决方案
按笔者理解,现在最流的日志框架解决方案莫过于SLF4J + LogBack。其有以下几个优点:
- LogBack 自身实现了 SLF4J 的日志接口,不需要 SLF4J 去做进一步的适配。
- LogBack 自身是在 Log4J 的基础上优化而成的,其运行速度和效率都比 LOG4J 高。
- SLF4J + LogBack 支持占位符,方便日志代码的阅读,而 LOG4J 则不支持。
从上面几点来看,SLF4J + LogBack是一个较好的选择。
LogBack 被分为3个组件:logback-core、logback-classic 和 logback-access。
- logback-core 提供了 LogBack 的核心功能,是另外两个组件的基础。
- logback-classic 则实现了 SLF4J 的API,所以当想配合 SLF4J 使用时,需要将 logback-classic 引入依赖中。
- logback-access 是为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。
了解 LogBack 日志的日志流向,对于我们后面学习日志框架的配置很有帮助。从下图可以看出 LogBack 的日志记录数据流是从 Class 或 Package 流到 Logger,再从Logger到Appender,最后从Appender到具体的输出终端。
LogBack配置文件可以分为几个节点,其中 Configuration 是根节点,Appender、Logger、Root是Configuration的子节点。
appender节点
<appender>是<configuration>的子节点,是负责写日志的组件。appender有两个必要属性name、class 。name指定appender的名称,class指定appender的全限定名
class,主要包括:
- ch.qos.logback.core.ConsoleAppender 控制台输出
- ch.qos.logback.core.FileAppender 文件输出
- ch.qos.logback.core.RollingFileAppender 文件滚动输出
<?xml version="1.0" encoding="utf-8"?>
<configuration debug="true" scan="true" scanPeriod="2">
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
</appender>
<!-- conf file out -->
<appender name="file_out" class="ch.qos.logback.core.FileAppender">
</appender>
<!-- conf file out -->
<appender name="file_out" class="ch.qos.logback.core.RollingFileAppender">
</appender>
<root></root>
<logger></logger>
</configuration>
ConsoleAppender
把日志添加到控制台,有如下节点:
<encoder>
: 对日志进行格式化。<target>
: 字符串System.out 或者 System.err, 默认 System.out;
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console_out" />
</root>
</configuration>
FileAppender
把日志添加到文件,有如下节点:
<file>
:被写入的文件名,可以是相对目录 , 也可以是绝对目录 , 如果目录不存在则会自动创建。<append>
:如果是true , 日志被追加到文件结尾 , 如果是false,清空现存文件 , 默认是true。<encoder>
:对日志进行格式化 [具体的转换符说明请参见官网.]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appender name="file_out" class="ch.qos.logback.core.FileAppender">
<file>logs/debug.log</file>
<encoder>
<pattern>%date [%thread] %-5level %logger - %message%newline</pattern>
</encoder>
</appender>
</configuration>
rollingFileAppender
滚动纪录文件,先将日志记录到指定文件,当符合某种条件时,将日志记录到其他文件,有如下节点:
<file>
:被写入的文件名,可以是相对目录,也可以解决目录,如果目录不存在则自动创建。<append>
:如果是true,日志被追加到文件结尾,如果是false,清空现存文件,默认是true。<encoder>
:对日志进行格式化。<rollingPolicy>
:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。
rollingPolicy
TimeBaseRollingPolicy :最常用的滚动策略,根据时间来制定滚动策略,即负责滚动也负责触发滚动。有如下节点;
<fileNamePattern>
:必要节点,包含文件及“%d” 转换符,“%d”可以包含一个java.text.SimpleDateFormat 制定的时间格式,如:%d{yyyy-MM},如果直接使用%d ,默认格式是 yyyy-MM-dd。<maxHistory>
:可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,假设设置每个月滚动,且<maxHistory> 是 6,则只保存最近6个月的文件,删除之前的旧文件,注意:删除旧文件是哪些为了归档而创建的目录也会被删除。<filenamePattern>
:必须包含“%i” 例如:设置最小值,和最大值分别为1和2,命名模式为 log%i.log,会产生归档文件log1.log和log2.log,还可以指定文件压缩选项,例如:log%i.log.gz 或者 log%i.log.zip
- triggeringPolicy:告知RollingFileAppender,激活RollingFileAppender滚动。
<!-- 03:conf errorAppender out -->
<appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
<file>logs/error.log</file>
<!-- 设置滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置日志命名模式-->
<fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--最多保留30天log-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 超过150MB时,触发滚动策略 -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>150</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
</encoder>
</appender>
logger节点
logger是<configuration>的子节点,来设置某一个包或者具体的某一个类的日志打印级别,以及指定<appender>。logger仅有一个name属性,两个可选属性 level/addtivity。
- name:用来指定受此loger约束的某一个包或者具体的某一个类。
- level:用来设置打印级别,大小写无关。可选值有TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。还有一个特俗值INHERITED 或者 同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别。
- addtivity:是否向上级logger传递打印信息,默认为true;
<logger>可以包含零个或多个<appender-ref>元素,表示这个appender将会添加到logger。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤掉非INFO级别 -->
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- conf infoAppender out -->
<appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
<file>logs/info.log</file>
<!-- 设置滚动策略 -->
<rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置日志命名模式-->
<fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--最多保留30天log-->
<maxHistory>30</maxHistory>
</rollingPoliy>
<!-- 超过150MB时,触发滚动策略 -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>150</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
</encoder>
</appender>
<!-- 添加两个appender节点 -->
<logger name="logback.olf.log" level="info">
<appender-ref ref = "console_out"/>
<appender-ref ref = "infoAppender"/>
</logger>
</configuration>
root节点
元素配置根logger。该元素有一个level属性,没有name属性,因为已经被命名 为root。Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、 WARN、ERROR、ALL 和 OFF。如果 root 元素没 有引用任何 appender,就会失去所有 appender。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤掉非INFO级别 -->
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 01:conf infoAppender out -->
<appender name="infoAppender" class="ch.qos.logback.core.RollingFileAppender">
<file>logs/info.log</file>
<!-- 设置滚动策略 -->
<rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置日志命名模式-->
<fileNamePattern>infoFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--最多保留30天log-->
<maxHistory>30</maxHistory>
</rollingPoliy>
<!-- 超过150MB时,触发滚动策略 -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>150</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
</encoder>
</appender>
<!-- 02:conf debugAppender out -->
<appender name="debugAppender" class="ch.qos.logback.core.RollingFileAppender">
<file>logs/debug.log</file>
<!-- 设置滚动策略 -->
<rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置日志命名模式-->
<fileNamePattern>debugFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--最多保留30天log-->
<maxHistory>30</maxHistory>
</rollingPoliy>
<!-- 超过150MB时,触发滚动策略 -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>150</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
</encoder>
</appender>
<!-- 03:conf errorAppender out -->
<appender name="errorAppender" class="ch.qos.logback.core.RollingFileAppender">
<file>logs/error.log</file>
<!-- 设置滚动策略 -->
<rollingPoliy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置日志命名模式-->
<fileNamePattern>errorFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!--最多保留30天log-->
<maxHistory>30</maxHistory>
</rollingPoliy>
<!-- 超过150MB时,触发滚动策略 -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>150</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d [%p] %-5level %logger - %msg%newline</pattern>
</encoder>
</appender>
<root level="ALL">
<appender-ref ref="infoAppender"/>
<appender-ref ref="debugAppender"/>
<appender-ref ref="errorAppender"/>
</root>
</configuration>
filter过滤节点
级别过滤器(LevelFilter)
LevelFilter 根据记录级别对记录事件进行过滤。如果事件的级别等于配置的级别,过滤 器会根据 onMatch 和 onMismatch 属性接受或拒绝事件。下面是个配置文件例子:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤掉非INFO级别 -->
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console_out" />
</root>
</configuration>
临界值过滤器(ThresholdFilter)
ThresholdFilter过滤掉低于指定临界值的事件。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤掉TRACE和DEBUG级别的日志 -->
<level>INFO</level>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console_out" />
</root>
</configuration>
求值过滤器(EvaluatorFilter)
评估是否符合指定的条件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.EvaluatorFilter">
<evaluator>
<!--过滤掉所有日志中不包含hello字符的日志-->
<expression>
message.contains("hello")
</expression>
<onMatch>NEUTRAL</onMatch>
<onMismatch>DENY</onMismatch>
</evaluator>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console_out" />
</root>
</configuration>
匹配器(Matchers)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- conf consoel out -->
<appender name ="console_out" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.EvaluatorFilter">
<evaluator>
<matcher>
<Name>odd</Name>
<!-- 过滤掉序号为奇数的语句-->
<regex>statement [13579]</regex>
</matcher>
<expression>odd.matches(formattedMessage)</expression>
<onMatch>NEUTRAL</onMatch>
<onMismatch>DENY</onMismatch>
</evaluator>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{30} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console_out" />
</root>
</configuration>
下面是一个我常用的logback.xml配置文件,供大家参考:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="30 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern>
<!-- 常用的Pattern变量,大家可打开该pattern进行输出观察 -->
<!--
<pattern>
%d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n
Logger: %logger
Class: %class
File: %file
Caller: %caller
Line: %line
Message: %m
Method: %M
Relative: %relative
Thread: %thread
Exception: %ex
xException: %xEx
nopException: %nopex
rException: %rEx
Marker: %marker
%n
</pattern>
-->
</encoder>
</appender>
<!-- 按日期区分的滚动日志 -->
<appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
</encoder>
<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">
<!-- daily rollover -->
<fileNamePattern>error.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 按文件大小区分的滚动日志 -->
<appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/info.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>info.%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
</appender>
<!-- 按日期和大小区分的滚动日志 -->
<appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/debug.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- 级别阀值过滤 -->
<appender name="SUM-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/sum.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern>
</encoder>
<!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="ERROR-OUT" />
<appender-ref ref="INFO-OUT" />
<appender-ref ref="DEBUG-OUT" />
<appender-ref ref="SUM-OUT" />
</root>
</configuration>
日志系统转换指南
在实际的日志转换过程中,SLF4J其实是充当了一个中介的角色。例如当我们一个项目原来是使用LOG4J进行日志记录,但是我们要换成LogBack进行日志记录。此时我们需要先将LOG4J转换成SLF4J日志系统,再从SLF4J日志系统转成LogBack日志系统。
从日志框架转向SLF4J
- jul-to-slf4j:jdk-logging到slf4j的桥梁
- log4j-over-slf4j:log4j1到slf4j的桥梁
- jcl-over-slf4j:commons-logging到slf4j的桥梁
从SLF4J转向具体的日志框架
- slf4j-jdk14:slf4j到jdk-logging的桥梁
- slf4j-log4j12:slf4j到log4j1的桥梁
- log4j-slf4j-impl:slf4j到log4j2的桥梁
- logback-classic:slf4j到logback的桥梁
- slf4j-jcl:slf4j到commons-logging的桥梁
日志技术框架一览
- JUL:JDK中的日志记录工具,也常称为JDKLog、jdk-logging。
- LOG4J1:一个具体的日志实现框架。
- LOG4J2:一个具体的日志实现框架,是LOG4J1的下一个版本。
- LOGBACK:一个具体的日志实现框架,但其性能更好。
- JCL:一个日志门面,提供统一的日志记录接口,也常称为commons-logging。
- SLF4J:一个日志门面,与JCL一样提供统一的日志记录接口,可以方便地切换看具体的实现框架。
JUL、LOG4J1、LOG4J2、LOGBACK是日志实现框架,而JCL、SLF4J是日志实现门面。
原文链接:https://www.imooc.com/article/21908
Java日志框架(二)的更多相关文章
- java日志框架系列(4):logback框架xml配置文件语法
1.xml配置文件语法 由于logback配置文件语法特别灵活,因此无法用DTD或schema进行定义. 1.配置文件基本结构 配置文件基本结构:以<configuration>标签开头, ...
- Java程序员最常用的8个Java日志框架
转自:http://www.codeceo.com/article/8-java-log-framework.html 作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用 ...
- 转:Java程序员最常用的8个Java日志框架
作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...
- Java 日志框架终极教程
概述 对于现代的 Java 应用程序来说,只要被部署到真实的生产环境,其日志的重要性就是不言而喻的,很难想象没有任何日志记录功能的应用程序被运行于生产环境中.日志 API 所能提供的功能是多种多样的, ...
- Java日志框架那些事儿
文章首发于[博客园-陈树义],点击跳转到原文Java日志框架那些事儿. 在项目开发过程中,我们可以通过 debug 查找问题.而在线上环境我们查找问题只能通过打印日志的方式查找问题.因此对于一个项目而 ...
- Java基础学习总结(40)——Java程序员最常用的8个Java日志框架
作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...
- Java日志框架总结
1. 前言 从写代码开始,就陆陆续续接触到了许多日志框架,较常用的属于LOG4J,LogBack等.每次自己写项目时,就copy前人的代码或网上的demo.配置log4j.properties或者lo ...
- Java-最常用的Java日志框架整理
Java-最常用的Java日志框架整理 前言 Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日 ...
- java日志框架slf4j与log4j
日志记录自然是非常重要的,但恐怕能记住slf4j与log4j等日志框架配置的人就很少了,这个东西不难,只是配置好后很少会去动它,开发新项目一般也是从其他项目拷贝,或者参照文档 废话不多说,先说log4 ...
随机推荐
- python之爬虫(四)之 Requests库的基本使用
什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...
- HangFire多集群切换及DashBoard登录验证
项目中是有多个集群的,现在存在一个是:在切换web集群时,如何切换HangFire的周期性任务. 先采取的解决办法是: 每个集群分一个队列,在周期性任务入队时分配当前web集群的集群id单做队列名称. ...
- 蒲公英 · JELLY技术周刊 Vol.14: Vue 3 新特性详解
2020 年真的是灾祸频发,但是在各类前端框架上,依旧是在稳步的推进.近日 Vue 团队更新了关于 Vue 3 的最新状态,尤大新增了三个语法糖特性,它们将用于优化 SFC 的开发体验,你会有兴趣尝鲜 ...
- 事件的event对象基本解释
事件流: 描述的是在页面中接受事件的顺序主要分为两种: 事件冒泡.事件捕获 事件event对象:1. type 获取事件类型2. target获取事件目标3. stopPropagation() 阻止 ...
- TX 1核4G2M云服务器,376/2年,可免费续1年
腾讯云个人开发者活动 https://cloud.tencent.com/act/developer
- Babel:下一代Javascript语法编译器
定义 Babel是一个Javascript的编译器,通过它你可以将一些新版本的ECMAScript语法转换成低版本的语法.以便能够在低版本的浏览器或者其它环境平稳运行. 截至目前笔者写这篇文章的时候, ...
- c# Winfrom-DataGridView实现筛选功能
//应对用户需求,需要在DataGridView中直接进行筛选功能,在网上找了一些代码加上自己修改整理过后的类,仅供参考! //上面代码可以直接创建类库项目生成DLL文件,下面代码为另外项目引用创 ...
- STL源码剖析:配接器
启 配接器就是适配器 STL中的适配器一共三种: 迭代器适配器 是一种观念上的改变,如将赋值操作变成插入,前进变成后退,等 函数适配器 STL中最广泛的配接器群体 可以实现连续配接 配接操作:bind ...
- u盘安装 osx 出现 “不能验证”
关于安装是出现关于出现“不能验证”错误: 解决办法 :打开终端 在"终端"里面修改时间 输入:date 032208102015.20
- Spring的SchedulingConfigurer实现定时任务
前提:在做业务平台的时候我们经常会遇到,某些跟时间打交道的需要修改状态,比如说在时间区间之前,属于未生效状态,区间之内属于有效期,区间之后,属于过期,或者需要每天 每周 每月,甚至是年为单位的做一些固 ...