Logback的使用
1、基本认识
logback官方文档:http://logback.qos.ch
具体样例:https://www.baeldung.com/logback
从下面依赖关系图可以看见,Springboot的核心启动器spring-boot-stater依赖了spring-boot-starter-looging,而这个就是日志的启动器。
Springboot项目整合了日志框架,它默认使用Slf4j作为日志门面,默认的日志实现使用Logback。用JAVA来理解的话,Slf4j就是接口,而logback就是它的具体实现类。
如果你使用的日志实现不是logback。比如,使用的日志实现是log4j2,在Springboot启动的时候,也会自动通过桥接包《log4j-to-slf4j》,将log4j2切换到slf4j的门面,然后使用logback输出日志到控制台。
2、实际演示
pom文件中引入SpringBoot的Web启动依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.7.RELEASE</version> </dependency>
需要注意,需要导入的Logger类是在【org.slf4j】下,不要错误。
①日志工具的logger对象应当用private static final修饰,private保证不会被其他类调用,static final保证在类加载时就被初始化,并且其值不会改变,减少内存消耗。
②打印日志时,尽量不要使用“+”进行拼接,这会额外消耗内存,尽量使用{}占位符。
package com.travel.logback.study.web;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.PostConstruct;@RestController
public class DemoController {private static final Logger logger = LoggerFactory.getLogger(DemoController.class);//该注解的作用是让Springboot启动时,自动执行该方法@PostConstructpublic void testLogback(){logger.trace("---trace 级别的日志 ---");logger.debug("---debug 级别的日志 ---");logger.info("---info 级别的日志 ---");logger.warn("---warn 级别的日志 ---");logger.error("---error 级别的日志 ---");}
}
启动项目,控制台打印效果如下:
可以发现一个问题,trace级别 和 debug级别的日志并没有出现在控制台。这是因为Springboot启动时,控制台打印的日志级别默认是info级别,低于info级别的日志,就不会打印在控制台上。如果需要打印低级别的日志,就需要修改配置文件内容,指定控制台打印的日志级别。
logback的日志级别
从低到高:TRACE < DEBUG < INFO < WARN < ERROR < FATAL
可以在yml文件中设置日志级别
logging:level:root: debug
3、配置文件的学习
由于springboot默认使用logback作为日志实现,因此可以在resources目录下直接创建一个【logback.xml】配置文件进行一些个性化的配置。
3.1 完整配置文件内容 和 展示效果
完整配置文件
<configuration scan="true" scanPeriod="60 seconds" debug="false"><!-- property指定日志输出格式,他有两个属性:name定义property节点的名称,value属性设置具体的日志输出格式property节点定义之后,下面的节点可以直接使用“${}”来引用value中定义的日志输出格式--><!--日志输出格式:%-5level %level表示日志级别,-5表示占5个字符,如果不足,就向左对齐%d{yyyy-mm-dd H:mm:ss.sss} %d表示日期,后面是日期的格式%c 表示 类的完整名称%M 表示 method%L 表示 行号%thread 表示 线程名称%m或者%msg 表示 信息%X{key} %X表示输出MDC中特定键的值,key为具体的键名称,值不存在,则不会输出%logger{36} 表示 使用哪个日志记录器,就会打印那个日志记录器的name,最多显示36个字符%n 表示 换行被[]中括号括起来,只是为了方便区分,也可以将中括号去掉,不会有影响--><!--%X{key} %X表示输出MDC中特定键的值,key为具体的键名称,值不存在,则不会输出--><property name="NEW_LOG_STYLE"value="[%-5level] [%thread] [%logger] [%X{traceId-UMR}] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n"/><!--定义日志文件的保存路径--><property name="BASE_LOG_HOME" value="/opt/applog"/><property name="MAX_FILE_SIZE" value="1MB"/><property name="MAX_HISTORY" value="3"/><!--项目的名称--><property name="SERVICE_NAME" value="ACCOUNT_MANAGE_SYSTEM"/><!-- 控制台输出设置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><!--encoder指定日志格式,class属性可以不写,默认会将值映射到PatternLayoutEncoder的变量中--><!-- <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> --><encoder><!--使用上文定义的,全局的property配置--><pattern>${NEW_LOG_STYLE}</pattern><charset>UTF-8</charset></encoder></appender><!--定义一个日志文件输出的appender,RollingFileAppender 可以实现日志拆分、和归档压缩 --><appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--file标签指定日志文件保存路径--><file>${BASE_LOG_HOME}/${SERVICE_NAME}_rollback.log</file><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志文件的最大限制 --><maxFileSize>${MAX_FILE_SIZE}</maxFileSize><!-- 日志文件保留时间,默认以天为单位 --><maxHistory>${MAX_HISTORY}</maxHistory><!-- 日志每超过一次最大限制,则按时间压缩一次,%i是一个计数,从0开始,往上递增--><fileNamePattern>${BASE_LOG_HOME}/${SERVICE_NAME}/%d{yyyy-MM-dd}.log%i.log.zip</fileNamePattern></rollingPolicy><encoder><!--指定log文件中的日志格式--><pattern>${NEW_LOG_STYLE}</pattern></encoder></appender><!--日志记录器,additivity默认也是true,如果为true,则使用父节点的appender进行输出--><logger name="com.travel.logback.study.web" level="INFO" additivity="true" /><logger name="Wechat-UMR" level="debug" additivity="false"><appender-ref ref="CONSOLE"/></logger><!--调整某一个类的日志输出级别,name写入类的全限定名称,level设置日志级别--><logger name="org.hibernate.XXXX" level="ERROR" additivity="false"><appender-ref ref="CONSOLE"/></logger><root level="info"><!--匹配到当前日志记录器之后,会执行下面两个appender标签--><appender-ref ref="LOG_FILE"/><appender-ref ref="CONSOLE"/></root>
</configuration>
3.2 各节点介绍
<configuration>根节点
包含的属性如下所示:
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
<property> 标签
property定义全局的变量,他有两个属性:name属性定义property节点的名称,value属性设置具体的日志输出格式 property标签定义之后,能够方便其他标签通过“${name}”来获取value中的值value可配置的日志输出格式: %-5level %level表示日志级别,-5表示占5个字符,如果不足,就向左对齐 %d{yyyy-mm-dd H:mm:ss.sss} %d表示日期,后面是日期的格式 %c 表示 类的完整名称 %M 表示 method %L 表示 行号 %thread 表示 线程名称 %m或者%msg 表示 信息 %X{key} %X表示输出MDC中特定键的值,key为具体的键名称,值不存在,则不会输出 %logger{36} 表示使用哪个日志记录器,就会打印那个日志记录器的name,最多显示36个字符 %n 表示 换行
<property name="UMR_LOG_STYLE" value="[%-5level] [%thread] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n"/>
用 “ 中括号[ ] ” 括起来,只是为了方便查看,可以将中括号去掉,不会有任何影响
<appender>标签
appender用来指定日志输出方式,有两个属性name和class。由class决定使用哪种输出策略,常用就是控制台输出策略和文件输出策略。ConsoleAppender是将日志输出到控制台。FileAppender是将日志输出到一个文件中。
使用控制台输出策略
<property name="UMR_LOG_STYLE" value="[%-5level] [%thread] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n"/><!-- 控制台输出设置 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><!--encoder标签指定日志的格式--><encoder><!--引用指定property配置,获取它的value值--><pattern>${UMR_LOG_STYLE}</pattern><charset>UTF-8</charset></encoder>
</appender><!--日志记录器,使用类的全限定名称进行匹配,表示只捕获这一个类的日志-->
<logger name ="com.travel.logback.study.web.DemoController" level="INFO" additivity="false"><appender-ref ref="CONSOLE"/>
</logger>
使用文件输出策略
将日志输出到文件比较麻烦,需要考虑输出到哪里,一个log文件最大是多少,保存多少天,文件超过最大又该如何处理。
针对这些问题,可以使用RollingFileAppender,它里面的属性能够帮助我们控制文件大小、根据时间将日志信息进行压缩等等。
ch.qos.logback.core.rolling.RollingFileAppender这个类有一个rollingPolicy成员变量
而RollingPolicy只是一个接口,所以我们使用SizeAndTimeBasedRollingPolicy这个实现类,这个实现类的源码如下:
类图如下
观察类图可以发现TimeBasedRollingPolicy继承于RollingPolicyBase。RollingPolicyBase有个fileNamePattern变量,能够帮助我们按照某种规则拆分日志。
<!--项目存放路径--><property name="BASE_LOG_HOME" value="/opt/applog" /><property name="MAX_FILE_SIZE" value="1MB" /><property name="MAX_HISTORY" value="3" /><!--项目的名称--><property name="SERVICE_NAME" value="ACCOUNT_MANAGE_SYSTEM" /><property name="NEW_LOG_STYLE"value="[%-5level] [%thread] [%logger] [%X{traceId-UMR}] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n"/><!-- 定义一个日志文件输出的appender,RollingFileAppender 可以实现日志拆分、和归档压缩 --><appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--会根据给定的路径创建对应文件夹以及log文件【/opt/applog】会从根路径创建文件夹。如果是windows系统,会默认从当前项目所在磁盘的根路径开始,如果处于D盘,则会创建 D:/opt/applog目录【opt/applog】是在当前项目下创建一个opt/applog目录--><!--file标签指定日志文件保存路径--><file>${BASE_LOG_HOME}/${SERVICE_NAME}_rollback.log</file><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志文件的最大限制 --><maxFileSize>${MAX_FILE_SIZE}</maxFileSize><!-- 日志文件保留时间,默认以天为单位 --><maxHistory>${MAX_HISTORY}</maxHistory><!-- 日志文件每超过一次最大限制,则按时间压缩一次,%i是一个计数,从0开始,往上递增--><fileNamePattern>${BASE_LOG_HOME}/${SERVICE_NAME}/%d{yyyy-MM-dd}.log%i.log.zip</fileNamePattern></rollingPolicy><encoder><!--指定log文件中的日志格式--><pattern>${NEW_LOG_STYLE}</pattern></encoder></appender><root level="info"><appender-ref ref="LOG_FILE" /><appender-ref ref="CONSOLE" /></root>
我在logback文件中写的是超过1M就进行压缩,通过for循环模拟1w次请求。(生产环境,日志文件肯定不要限制这么小,这里只是为了方便测试)
@RestController
public class DemoController {private Logger logger = LoggerFactory.getLogger(DemoController.class);@PostConstructpublic void testLogback() {for (int i = 0; i < 10000; i++) {logger.info("---info 级别的日志 ---");logger.warn("---warn 级别的日志 ---");logger.error("---error 级别的日志 ---");}}
}
最外层的log,因为我们限制文件大小为1MB,所以肯定不会超过
压缩包是经过压缩之后形成的,肯定没有1M,但解压之后,他的文件大小就是1M左右了
为什么有些appender节点下面存在<file>、<rollingPolicy>等子节点,有些又不存在?
这取决于class属性中定义的是什么类型。项目启动的时候,会创建class指定类型的对象,并且子节点的名称并不是随便起的,是class中定义的这个类的变量名。子节点设置的值会通过类的set()方法进行属性的赋值。
能够看见,项目启动时调用了set方法,并将配置文件中的值赋值给指定对象。
<logger>标签
一个logger标签就表示一个日志记录器,在同一个配置文件中可以有多个。他有三个属性 name、level 和 additivity,以及一个子节点<appender-ref>。
一、level可以设置日志级别。
二、additivity默认为true,当logger匹配成功后,调用父logger的appender进行日志输出;
如果为false,则使用当前logger的appender进行日志输出。当additivity为true的时候,不要在当前logger引用<appender-ref>标签,否则会输出2次一样的日志。
三、name的值可以是类的全限定名称,也可以是包名,也可以是自定义的名称。
①上面的例子就是使用类的全限定名称。
②使用包名,这个包下所有类的日志都会被这个logger记录,并输出到控制台或者文件中。
③name使用自定义的名称,这个也是我工作中经常使用的。
定义一个客户端,并打印日志
package com.travel.logback.study.web;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class WechatTerminalDemo {private Logger wechatLogger = LoggerFactory.getLogger("Wechat-UMR");@PostConstructpublic void payAmount(){wechatLogger.debug("---远程接口调用成功--");}
}
添加日志记录器
<logger name ="Wechat-UMR" level="debug" additivity="false"><appender-ref ref="CONSOLE"/></logger>
<root>标签
root标签也可以指定日志的级别,它是特殊的<logger>标签,是所有<logger>的祖先节点,等于<logger name="ROOT">。
一个配置文件中只能有一个root标签,且root标签只有一个属性level。因为name已经被命名为root,而且他是所有logger的祖先节点,所以也就没有additivity。
一个配置文件需要用<root>标签来进行兜底,避免日志出现丢失的情况。JAVA中定义的一个Logger对象,会向上遍历,直到在配置文件中找到合适的logger。如果一个logger都没找到,最终都会达到根logger,也就是root标签,所以,如果配置文件中没有声明root标签,那这个日志就会出现丢失。
比如,定义一个PayService,并且在一个方法中打印日志信息
package com.travel.logback.study.web;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;@Service
public class PayService {private final Logger logger = LoggerFactory.getLogger(PayService.class);//该注解的作用是让Springboot启动时,自动执行该方法@PostConstructprivate void pay() {logger.info("----支付成功----");}
}
logback.xml配置文件如下,logger日志记录器只配置了一个,使用全限定名称,没有root标签。
<configuration scan="true" scanPeriod="60 seconds" debug="false"><property name="UMR_LOG_STYLE" value="[%-5level] [%thread] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n" /><!-- 控制台输出设置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--使用上文定义的,全局的property配置--><pattern>${UMR_LOG_STYLE}</pattern><charset>UTF-8</charset></encoder></appender><logger name ="com.travel.logback.study.web.DemoController" level="INFO" additivity="false"><appender-ref ref="CONSOLE"/></logger></configuration>
启动就会发现,没有root标签进行兜底,少了非常多的日志,只保留了 DemoController的日志。
3.3 排除某些依赖包中的日志
有些第三方的依赖包会打出许多我们不需要知道的INFO日志,不方便我们排查问题。
说是排除,实际就是使用类的全限定名称,创建一个日志记录器,将日志级别提高,不让他打印INFO级别的日志。
<!--name写入类的全限定名称,level调整日志级别,additivity默认为true--><logger name ="org.hibernate.boot.internal.SessionFactoryOptionsBuilder" level="ERROR" />
4、MDC的使用
MDC是 logback 提供的,用于日志跟踪的工具。多线程或者是并发量很大的情况下,请求没有唯一标识的话,不好排查问题,不清楚哪些日志对应的是哪一次请求,这个时候就需要用到MDC。
MDC 内部使用的是 ThreadLocal ,只有本线程才有效,如果在当前线程中,又开启了一个异步线程,那么异步线程的MDC就会丢失,异步线程获取指定key的时候就会是null。通常这种情况,都是请求传来的时候,携带一个requestId,用来表示唯一的请求,当前线程和异步线程就使用这唯一的requestId。
一般MDC是定义在拦截器中,等到一次完整的请求结束之后,再去清除掉,这里只是做一个Demo,所以我就不创建拦截器了。
package com.travel.logback.study.web;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.PostConstruct;
import java.util.Date;@RestController
public class DemoController {private Logger logger = LoggerFactory.getLogger(DemoController.class);//该注解的作用是让Springboot启动时,自动执行该方法@PostConstructpublic void testLogback() {//往当前线程存入一个键值对MDC.put("traceId-UMR", "traceId" + new Date().getTime());logger.info("当前线程的traceId为:" + MDC.get("traceId-UMR"));logger.info("---info 级别的日志 ---");logger.warn("---warn 级别的日志 ---");//清除当前线程的traceIdlogger.warn("---清除当前线程的MDC ---");MDC.clear();logger.error("---error 级别的日志 ---");}
}
logback中,使用%X{key}来接收MDC中的值,key为存入MDC中的键
<!--%X{key} %X表示输出MDC中特定键的值,key为具体的键名称,值不存在,则不会输出--> <property name="NEW_LOG_STYLE" value="[%-5level] [%thread] [%logger] [%X{traceId-UMR}] [%d{yyyy-mm-dd H:mm:ss.sss}] [%c] [%M] [%L] %m%n" /><!-- 控制台输出设置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--使用上文定义的,全局的property配置--><pattern>${NEW_LOG_STYLE}</pattern><charset>UTF-8</charset></encoder></appender><logger name ="com.travel.logback.study.web" level="INFO" additivity="false"><appender-ref ref="CONSOLE"/></logger>
由于打印error级别日志之前,我在代码中已经执行了clear()方法,将当前线程的所有key给清除掉了,所以,输出error日志到控制台的时候,显示是空白的。
5、注意事项
①logback单独使用,也可以通过logback.xml文件来完成一些个性化的配置,并不一定需要是Springboot项目。单独使用时,只需要引入slf4j和logback的包就可以了。
②日志工具的logger对象应当用private static final修饰,private保证不会被其他类调用,static final保证在类加载时就被初始化,并且其值不会改变,减少内存消耗。
③打印日志时,尽量不要使用“+”进行拼接,这会额外消耗内存,尽量使用{}占位符。
相关文章:
Logback的使用
1、基本认识 logback官方文档:http://logback.qos.ch 具体样例:https://www.baeldung.com/logback 从下面依赖关系图可以看见,Springboot的核心启动器spring-boot-stater依赖了spring-boot-starter-looging,而这个就是日志的启动器…...
沙箱模拟支付宝支付3--支付的实现
1 支付流程实现 演示案例 主要参考程序员青戈的视频【支付宝沙箱支付快速集成版】支付宝沙箱支付快速集成版_哔哩哔哩_bilibili 对应的源码在 alipay-demo: 使用支付宝沙箱实现支付功能 - Gitee.com 以下是完整的实现步骤 1.首先导入相关的依赖 <?xml version"1…...
微信小程序滑动解锁、滑动验证
微信小程序简单滑动解锁 效果 通过 movable-view (可移动的视图容器,在页面中可以拖拽滑动)实现的简单微信小程序滑动验证 movable-view 官方说明:https://developers.weixin.qq.com/miniprogram/dev/component/movable-view.ht…...
Redis的常用命令
Redis中文字典网站 redis 命令手册https://redis.com.cn/commands.html Keys * 查看当前库所有的key exists ke 判断某个key是否存在 type key查看你的key是什么类型 Del key删除执行的key数据 unlink key非阻塞删除,仅仅将keys从keyspace元数据中删除…...
国内Ubuntu环境Docker部署 ComfyUI
国内Ubuntu环境Docker部署 ComfyUI 趁着这两天用docker部署了 Stable Diffusion,顺手也安排上 ComfyUI。 ComfyUI相比 Stable Diffusion 原生的 WEB UI,更容易让人了解其出图的过程,极其适合学习与研究。拼接其强大的插件节点、不仅能够实现文…...
Meta 的新策略,将 AI 生成的角色整合到其社交媒体平台
一、Meta新年规划及引人注目的举措 多元规划背景:在新的一年,Meta制定了多维度的战略规划,旨在巩固并拓展其在科技领域的影响力。增强现实与元宇宙是其长期布局的重点方向,期望借此塑造未来互联网的交互形态;面对TikTo…...
玩转OCR | 腾讯云智能结构化OCR初次体验
目录 一、什么是OCR(需要了解) 二、产品概述与核心优势 产品概述 智能结构化能做什么 举例说明(选看) 1、物流单据识别 2、常见证件识别 3、票据单据识别 4、行业材料识别 三、产品特性 高精度 泛化性 易用性 四、…...
蓝桥杯JAVA--003
需求 2.代码 public class RegularExpressionMatching {public boolean isMatch(String s, String p) {if (p.isEmpty()) {return s.isEmpty();}boolean firstMatch !s.isEmpty() && (s.charAt(0) p.charAt(0) || p.charAt(0) .);if (p.length() > 2 && p…...
STC51和STM32单片机烧录引脚的完整名称
STC51 和 STM32 单片机烧录引脚的完整名称 1. STC51 单片机的烧录引脚 STC51 单片机通过 串口(UART) 进行程序下载,主要引脚如下: 引脚名称完整英文名称说明TXDTransmit Data串口发送引脚,用于发送数据。RXDReceive…...
阿里云大模型ACP高级工程师认证模拟试题
阿里云大模型ACP高级工程师认证模拟试题 0. 引言1. 模拟试题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题多选题单选题单选题单选题多选题多选题单选题多选题单…...
深入理解计算机中的补码、反码、原码
问题: 我们每天用的钟表,其实只有1~12这12个数字,但我们日常会说13点、17点之类的。 问:13点在钟表上哪个位置? 答:很简单嘛,1点的位置。 你不觉得奇怪吗,为啥13点会和1点在同一个位…...
调试:用电脑开发移动端网页,然后用手机真机调试
一、背景 电脑开发移动端,然后想真机调试... 二、实现 2.1、电脑和手机链接相同局域网 2.2、pnpm run dev 启动项目 2.3、浏览器访问 localhost:3001/login 2.4、Windowsr 输入cmd,在cmd输入 ipconfig 2.5、浏览器访问 ip地址加/login 2.6、手机端…...
深入浅出:Spring Boot 自定义消息转换器的实现与应用
Spring Boot 作为当前最流行的 Java Web 开发框架之一,广泛应用于微服务架构、企业级应用等多个场景。Spring Boot 提供了灵活且易于扩展的架构,其中消息转换器(Message Converter)是其重要组成部分。消息转换器在 Spring Boot 中…...
基于AI大模型的医院SOP优化:架构、实践与展望
一、引言 1.1 研究背景与意义 近年来,人工智能(AI)技术取得了迅猛发展,尤其是大模型的出现,为各个领域带来了革命性的变化。在医疗领域,AI 医疗大模型正逐渐崭露头角,展现出巨大的应用潜力。随着医疗数据的海量积累以及计算能力的大幅提升,AI 医疗大模型能够对复杂的…...
Maven项目集成SQL Server的完整教程:从驱动配置到封装优化
前言 在最近的系统对接过程中,由于对方团队不熟悉技术,最终选择直接提供 SQL Server 视图。本文详细记录了使用 Maven 集成 SQL Server 驱动的过程,以及从配置到查询的各个关键步骤,还包括注意事项与常见问题,希望对需…...
Java 21 优雅和安全地处理 null
在 Java 21 中,判断 null 依然是开发中常见的需求。通过使用现代 Java 提供的工具和特性,可以更加优雅和安全地处理 null。 1. 使用 Objects.requireNonNull Objects.requireNonNull 是标准的工具方法,用于快速判断并抛出异常。 示例 import java.util.Objects;public c…...
Java(四十四)file
Java中的file类:代表文件或者文件夹(目录)类,也就是说将文件或者文件夹通过File类来封装成对象。 一:常用的构造方法: 使用file类,需要通过构造方法创建一个file对象。 1:public File(String pathname) public static void main(String[] args) {File fl = new File(&…...
【51项目】51单片机自制小霸王游戏机
视频演示效果: 纳新作品——小霸王游戏机 目录: 目录 视频演示效果: 目录: 前言:...
【ArcGISPro/GeoScenePro】检查多光谱影像的属性并优化其外观
数据 https://arcgis.com/sharing/rest/content/items/535efce0e3a04c8790ed7cc7ea96d02d/data 操作 其他数据 检查影像的属性 熟悉检查您正在使用的栅格属性非常重要。...
《新概念模拟电路》-三极管
三极管 本系列文章主要学习《新概念模拟电路》中的知识点。在工作过程中,碰到一些问题,于是又翻阅了模电这本书。我翻阅的是ADI出版的,西安交通大学电工中心杨建国老师编写的模电书。 <模电>和《数电》这两本书是电子学的专业基础课&…...
K 近邻算法入门指南:明氏距离与皮尔森距离的基础讲解
1、K近邻算法介绍 K近邻(k-Nearest Neighbor,KNN)分类算法的思路是:在特征空间中,如果一个样本附近的k个最近样本的大多数属于某一个类别,则该样本也属于这个类别。K近邻算法中,所选择的邻居都是已经正确分类的对象。…...
如何验证imap是否生效
要验证您的 Outlook 邮箱是否启用了 IMAP 并且正常工作,可以按照以下步骤进行操作: 1. 确认 Outlook 邮箱是否启用 IMAP 步骤: 登录到您的 Outlook Web 账户: 打开浏览器,访问 Outlook.com 或 Microsoft 365 Outlook…...
MySQL 06 章——多表查询
多表查询,也称为关联查询,是指两个表或多个表一起完成查询操作 前提条件,这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段的。这个关联字段可能建立了外键,也可能没…...
转换VMware Esxi 虚拟机到 Windows2019 Hyper-V Server
Hyper-v专用P2V工具disk2vhd实际应用 工具介绍 disk2vhd是一个非常小的P2V转换工具,可以将你的物理服务器或Esxi vm 转换成为VHD或者vhdx格式的虚拟硬盘文件,然后在虚拟平台上作为一台虚拟机来使用。目前disk2vhd的最新版本是2.0.1,已经可以…...
头歌实训2-1:面向对象程序设计-基础部分
第1关:定义银行员工类BankEmployee 本关任务:编写银行员工类BankEmployee,要求: 1.银行员工类的属性包括姓名name,工号num,工资salary 2.姓名name和工号num设置为私有属性,并将salay设置为默认参数3000 平…...
超高分辨率 图像 分割处理
文章大纲 制造业半导体领域高分辨率图像半导体数据集开源的高分辨率晶圆图像数据集1. WM-811K数据集2. Kaggle上的WM-811K Clean Subset数据集医疗 病理领域高分辨率图像1. Camelyon+2. CAMELYON173. CPIA Dataset4. UCF-WSI-Dataset航拍 遥感中的高分辨率 图像航拍遥感领域高分…...
使用 apply 方法将其他列的值传入 DataFrame 或 Series 的函数,来进行更灵活的计算或操作
可以使用 apply 方法将其他列的值传入 DataFrame 或 Series 的函数,来进行更灵活的计算或操作。apply 方法允许你逐行或逐列地对 DataFrame 或 Series 的元素进行操作,而且你可以将其他列的值作为参数传递给函数。 示例:使用 apply 结合其他…...
[CTF/网络安全] 攻防世界 warmup 解题详析
查看页面源代码,发现source.php 得到一串代码,进行代码审计: <?phpclass emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php"];…...
力扣第389题—找不同
class Solution:def findTheDifference(self, s: str, t: str) -> str:# 对字符串 s 和 t 进行排序a sorted(s)b sorted(t)# 比较排序后的两个列表for i in range(len(a)):if a[i] ! b[i]:return b[i]# 如果前面的比较没有找到差异,那么差异字符在 t 的最后一个…...
vite6+vue3+ts+prettier+eslint9配置前端项目(后台管理系统、移动端H5项目通用配置)
很多小伙伴苦于无法搭建一个规范的前端项目,导致后续开发不规范,今天给大家带来一个基于Vite6TypeScriptVue3ESlint9Prettier的搭建教程。 目录 一、基础配置1、初始化项目2、代码质量风格的统一2.1、配置prettier2.2、配置eslint2.3、配置typescript 3、…...
滴滴数据分析80道面试题及参考答案
如何衡量分类好坏? 衡量分类好坏有多种方法,常用的有准确率、精确率、召回率、F1 值、ROC 曲线与 AUC 值等。 准确率:是指分类正确的样本数占总样本数的比例,计算公式为:准确率 = (分类正确的样本数)/(总样本数)。准确率越高,说明分类器整体的分类效果越好,但在正负…...
嵌入式应用软件开发中C语言方向面试题
嵌入式应用软件开发中C语言方向面试题随笔 前言一、C语言基础二、嵌入式开发相关三、硬件相关知识五、实际编程问题前言 做嵌入式开发这么多年了,简单记录下C语言方向常见面试题,这里是应用软件方向的。 一、C语言基础 C语言的指针与数组的区别是什么?指针:指针是一个变量…...
vue3中mixins替代方案
使用自定义 Hooks(Composables) 自定义 Hooks 是一种基于函数的代码复用方式,可以在 setup 函数中使用。它允许将组件的逻辑分割成更小的、可复用的部分。 useCounter.js //useCounter.js import { ref, onMounted } from vue;export func…...
线性代数自学资源推荐我的个人学习心得
1.前言 自己这个学期的课程基本上就结束了,因此我自己就开始学习下个学期的课程--线性代数,也是我们在大学里面的最后一门数学课程了; 之前有过一些这个线性代数的基础,当时主要是参加这个数学建模比赛去学习这个matlab吗&#…...
WordPress Crypto 插件 身份认证绕过漏洞复现(CVE-2024-9989)
0x01 产品简介 WordPress Crypto插件是指那些能够为WordPress网站提供加密货币支付、信息显示或交易功能的插件。这些插件通常与WordPress电子商务插件(如WooCommerce)集成,使网站能够接受多种加密货币支付,或展示加密货币实时信息。支持多种加密货币支付,付款直接进入钱…...
软件逆向之OD基础
OD程序目录 plugin:存放OD所有插件 UDD:存放程序临时的数据,比如:程序注释、断点等 ollydbg.ini:存放OD自身配置的属性表 OLLYDBG.HLP:OD的帮助手册 OD断点 1.软件断点: 介绍:…...
C++并发编程之内存顺序一致性
std::memory_order_seq_cst 是 C11 引入的内存模型中的一种内存顺序(memory order),全称为 Sequential Consistency(顺序一致性)。它是 C 中最严格的内存顺序,提供了最强的同步保证。下面详细解释其含义、意…...
软件测试面试题整理
一、人格相关问题 1、自我介绍结构 姓名工作年限简单介绍上家公司的行业主要负责内容个人优势短期内的职业规划应聘该岗位的原因 2、对未来的发展方向怎么看 3、你对测试最大的兴趣在哪里?为什么? 二、技术相关问题 1、测试理论以及应用 1、给你一个…...
Java中如何实现线程安全的单例模式?
目录 1、懒汉式(线程安全) 2、饿汉式(线程安全) 3、双重校验锁(线程安全) 4、静态内部类(推荐) 5、枚举(最佳方法) 6、总结 在Java中,实现线…...
MYsql--------ubantu中安装mysql
在Ubuntu平台上下载、启动和关闭MySQL的方法如下: 下载安装MySQL 更新软件包列表:打开终端,输入以下命令,确保软件包列表是最新的。sudo apt update安装MySQL服务器:执行以下命令安装MySQL服务器。在安装过程中&…...
【Ubuntu】不能连上网络
1. ping路由器的IP地址 ping 192.168.1.1 如果ping不通的话,可能是网络故障导致的。需要重启配置ip地址。配置文件 sudo vi /etc/network/interface 2. ping 8.8.8.8 如果ping不通的话,可能是路由器不能链接往外网; 或者路由器显示了当…...
探索 AIGC 的基础知识:人工智能生成内容的全景视图
在数字化时代,人工智能生成内容(AIGC)正以前所未有的速度改变着我们的创作方式。本文将深入探讨 AIGC 的定义、构成要素、应用场景以及其带来的优势,帮助读者全面理解这一前沿技术。 1. AIGC 的定义与范围 人工智能生成内容&…...
使用java语言,自定义redistemplate
自定义 RedisTemplate 为了方便使用,你可以创建一个自定义的 RedisTemplate,并将其注入到服务中。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.…...
React-Router 一站式攻略:从入门到精通,掌握路由搭建与权限管控
文章目录 一、前言二、安装使用 npm 安装(推荐)使用 yarn 安装 三、基础使用设置路由基础结构定义路由和组件关联直接在组件中定义路由定义单独一个路由表 创建导航链接 四、核心组件和功能BrowserRouter 和 HashRouterRoute 组件Link 组件Switch 组件 五…...
运动控制探针功能详细介绍(CODESYS+SV63N伺服)
汇川AM400PLC和禾川X3E伺服EtherCAT通信 汇川AM400PLC和禾川X3E伺服EtherCAT通信_汇川ethercat通信-CSDN博客文章浏览阅读1.2k次。本文详细介绍了如何使用汇川AM400PLC通过EtherCAT总线与禾川X3E伺服进行通信。包括XML硬件描述文件的下载与安装,EtherCAT总线的启用,从站添加…...
七种改进爬山算法的方法
一、爬山算法 爬山算法(Hill Climbing Algorithm)是一种启发式的基于局部最优解的搜索算法,用于在给定的搜索空间中寻找全局最优解或足够好的解。它属于局部搜索算法,通常用于解决优化问题,包括连续和离散问题。 爬山算法模拟了爬山的过程,从某个随机起始点开始,不断向更…...
【Cocos TypeScript 零基础 4.1】
目录 背景滚动 背景滚动 创建一个 空节点 背景丟进去 ( 复制一个,再丢一次都行) 新建TS脚本 并绑定到 空节点 上 再对TS脚本进行编辑 export class TS2bg extends Component {property (Node) // 通过属性面板去赋值bg1:Node nullproperty (Node) bg2:Node nullprope…...
gitlab高级功能之 CICD Steps
CICD Steps 1. 介绍2. 定义 Steps2.1 Inputs2.2 Outputs 3. Using steps3.1 Set environment variables3.2 Running steps locally 4. Scripts5. Actions5.1 已知的问题 6. 表达式7. 实操7.1 单个step7.2 多个step7.3 复用steps7.4 添加output到step7.5 使用远程step 1. 介绍 …...
全国城市经纬度--包括省会(直辖市)、地级市
全国城市未必齐全,谨慎使用。 一、全国城市csv数据 北京市 北京市 北京市 116.4 39.9 天津市 天津市 天津市 117.2 39.12 河北省 石家庄市 石家庄市 114.52 38.05 河北省 唐山市 唐山市 118.2 39.63 河北省 秦皇岛市 秦皇岛市 119.6 39.93 河北省 邯郸市 邯郸市 1…...
深入解析爬虫中的算法设计:提升效率与准确度
在网络爬虫(Web Scraping)中,设计高效、准确的算法是关键,尤其当面对大量数据或复杂的网站结构时,精心设计的爬虫算法能显著提高爬取速度并提升数据提取的准确性。本篇博客将详细讲解爬虫算法的设计与优化策略…...