使用JUnit进行单元测试、JUL日志系统配置、Mybatis日志系统配置、Lombok开启日志

news2024/11/19 10:31:58

文章目录

  • 使用JUnit进行单元测试
    • 原因
    • 测试
    • 断言工具类
        • 案例一:错误冒泡排序
        • 案例二:从数据库获取数据
      • @Before注解
      • @After
  • JUL日志系统
    • 使用
    • JUL日志
    • 修改日志的打印级别
    • 文件处理器
    • 控制打印格式
    • 日志设置过滤器
  • Properties配置文件
  • 编写日志配置文件
  • 使用Lombok快速开启日志
  • Mybatis日志系统

使用JUnit进行单元测试

原因

首先一问:我们为什么需要单元测试?

随着项目逐渐变大,不可能每次都去完整地启动一个项目来测试某一个功能,这样显然会降低开发效率,因此,需要使用单元测试来帮助我们针对于某个功能或是某个模块单独运行代码进行测试,而不是启动整个项目

同时,在项目的维护过程中,难免会涉及到一些原有代码的修改,很有可能出现改了代码导致之前的功能出现问题(牵一发而动全身),又不一定能立即察觉到,因此,可以提前保存一些测试用例,每次完成代码后都可以跑一遍测试用例,来确保之前的功能没有因为后续的修改而出现问题。

可以利用单元测试来评估某个模块或是功能的耗时和性能,快速排查导致程序运行缓慢的问题,这些都可以通过单元测试来完成,可见单元测试对于开发的重要性。

测试

首先需要导入JUnit依赖,这里使用Junit4进行介绍

创建一个新的类,来编写单元测试用例:

通过打上@Test注解,即可将一个方法标记为测试案例,可以直接运行此测试案例,但是编写的测试方法有以下要求:

  • 方法必须是public的
  • 不能是静态方法
  • 返回值必须是void
  • 必须是没有任何参数的方法
package com.test.test;
import org.junit.Test;

public class MainTest {
    @Test
    public void method() {
        System.out.println("I'm the one");
    }

    @Test
    public void method1() {
        System.out.println("I'm the second");
    }
}

通过点击类前面的测试按钮,或是单个方法前的测试按钮来进行测试;如果点击类前面的测试按钮,会执行所有的测试用例。

运行测试后,我们发现控制台得到了一个测试结果,显示为绿色表示测试通过。

image-20230517203732191

对于一个测试案例来说,如果测试的结果并不是所期望的结果,那么这个测试就应该没有成功通过!

断言工具类

可以通过断言工具类来进行判定:

public class MainTest {
    @Test
    public void method() {
        System.out.println("I'm the one");
        Assert.assertEquals("断言工具类",1,2 );
    }
}

通过运行代码后,我们发现测试过程中抛出了一个错误,并且IDEA给显示了期盼结果和测试结果

image-20230517204256078

案例一:错误冒泡排序

测试一个案例,比如我们想查看冒泡排序的编写是否正确:

@Test
public void method(){
    int[] arr = {0, 4, 5, 2, 6, 9, 3, 1, 7, 8};

    //错误的冒泡排序
    for (int i = 0; i < arr.length - 1; i++) {
        for (int j = 0; j < arr.length - 1 - i; j++) {
            if(arr[j] > arr[j + 1]){
                int tmp = arr[j];
                arr[j] = arr[j+1];
                // arr[j+1] = tmp;
            }
        }
    }
	System.out.println(Arrays.toString(arr));
    Assert.assertArrayEquals(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, arr);
}

通过测试,我们发现得到的结果并不是我们想要的结果,因此现在我们需要去修改为正确的冒泡排序,修改后,测试就能正确通过了

image-20230517204449003

案例二:从数据库获取数据

测试从数据库中取数据是否为我们预期的数据:

@Test
public void method(){
    try (SqlSession sqlSession = MybatisUtil.getSession(true)){
        TestMapper mapper = sqlSession.getMapper(TestMapper.class);
        Student student = mapper.getStudentBySidAndSex(1, "男");

        Assert.assertEquals(new Student().setName("小明").setSex("男").setSid(1), student);
    }
}

@Before注解

可以通过@Before注解来添加测试用例开始之前的前置操作:

public class TestMain {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        System.out.println("测试前置正在初始化...");
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(new FileInputStream("mybatis-config.xml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("测试初始化完成,正在开始测试案例...");
    }

    @Test
    public void method1(){
        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            Student student = mapper.getStudentBySidAndSex(1, "男");

            Assert.assertEquals(new Student().setName("小明").setSex("男").setSid(1), student);
            System.out.println("测试用例1通过!");
        }
    }

    @Test
    public void method2(){
        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            Student student = mapper.getStudentBySidAndSex(2, "女");

            Assert.assertEquals(new Student().setName("小红").setSex("女").setSid(2), student);
            System.out.println("测试用例2通过!");
        }
    }
}

https://asdxz.oss-cn-beijing.aliyuncs.com/img/202305172051681.png

@After

同理,在所有的测试完成之后,只需要使用@After注解即可添加结束动作:

@After
public void after(){
    System.out.println("测试结束,收尾工作正在进行...");
}

JUL日志系统

原因:

  1. 如果项目中存在大量的控制台输出语句,会显得很凌乱
  2. 日志的粒度是不够细的,假如我们现在希望,项目只在debug的情况下打印某些日志,而在实际运行时不打印日志,采用直接输出的方式就很难实现了

因此需要使用日志框架来规范化日志输出

使用

而JDK为我们提供了一个自带的日志框架,位于java.util.logging包下,我们可以使用此框架来实现日志的规范化打印,使用起来非常简单:

public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getName()); //获取日志打印器
        logger.info("我是一个日志啊?"); //调用info输出一个普通信息
    }
}

可以在主类中使用日志打印,得到日志的打印结果:

image-20230517205802184

通过日志输出的结果会更加规范

JUL日志

日志分为7个级别,详细信息可以在Level.class中查看:

  • SEVERE(最高值)- 一般用于代表严重错误
  • WARNING - 一般用于表示某些警告,但是不足以判断为错误
  • INFO (默认级别) - 常规消息
  • CONFIG
  • FINE
  • FINER
  • FINEST(最低值)

之前通过info方法直接输出的结果就是使用的默认级别的日志,可以通过log方法来设定该条日志的输出级别:

    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getName());
        logger.log(Level.SEVERE, "严重的错误", new IOException("It's me, hi! I'm the problem! It's me"));
        logger.log(Level.WARNING, "警告的内容");
        logger.log(Level.INFO, "普通的信息");
        logger.log(Level.CONFIG, "级别低于普通信息");
    }

输出:

image-20230517210342366

修改日志的打印级别

级别低于默认级别的日志信息,无法输出到控制台,可以通过设置来修改日志的打印级别

public static void main(String[] args) {
    Logger logger = Logger.getLogger(Main.class.getName());

    //修改日志级别
    logger.setLevel(Level.CONFIG);
    //不使用父日志处理器
    logger.setUseParentHandlers(false);
    //创建并使用自定义日志处理器
    ConsoleHandler handler = new ConsoleHandler();
    handler.setLevel(Level.CONFIG);
    logger.addHandler(handler);

    logger.log(Level.SEVERE, "严重的错误", new IOException("我就是错误"));
    logger.log(Level.WARNING, "警告的内容");
    logger.log(Level.INFO, "普通的信息");
    logger.log(Level.CONFIG, "级别低于普通信息");
}

每个Logger都有一个父日志打印器,我们可以通过getParent()来获取:

public static void main(String[] args) throws IOException {
    Logger logger = Logger.getLogger(Main.class.getName());
    System.out.println(logger.getParent().getClass());
}

得到的是java.util.logging.LogManager$RootLogger这个类

image-20230517210927851

它默认使用的是ConsoleHandler,且日志级别为INFO,由于每一个日志打印器都会直接使用父类的处理器,因此需要先关闭父类然后使用自定义处理器

文件处理器

通过使用自己日志处理器来自定义级别的信息打印到控制台,当然,日志处理器不仅仅只有控制台打印,也可以使用文件处理器来处理日志信息,我们继续添加一个处理器:

        try {
            FileHandler handler = new FileHandler("test.log");
            handler.setLevel(Level.INFO);
            logger.addHandler(handler);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

输出:会发现Config没被写进去

image-20230517211433814

控制打印格式

可以自定义打印格式,比如我们控制台处理器就默认使用的是SimpleFormatter,而文件处理器则是使用的XMLFormatter,我们可以自定义:

//使用自定义日志处理器(控制台)
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.CONFIG);
handler.setFormatter(new XMLFormatter());
logger.addHandler(handler);

可以直接配置为想要的打印格式,如果这些格式还不能满足你,也可以自行实现:

public static void main(String[] args) throws IOException {
    Logger logger = Logger.getLogger(Main.class.getName());
    logger.setUseParentHandlers(false);

    //为了让颜色变回普通的颜色,通过代码块在初始化时将输出流设定为System.out
    ConsoleHandler handler = new ConsoleHandler(){{
        setOutputStream(System.out);
    }};
    //创建匿名内部类实现自定义的格式
    handler.setFormatter(new Formatter() {
        @Override
        public String format(LogRecord record) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            String time = format.format(new Date(record.getMillis()));  //格式化日志时间
            String level = record.getLevel().getName();  // 获取日志级别名称
            // String level = record.getLevel().getLocalizedName();   // 获取本地化名称(语言跟随系统)
            String thread = String.format("%10s", Thread.currentThread().getName());  //线程名称(做了格式化处理,留出10格空间)
            long threadID = record.getThreadID();   //线程ID
            String className = String.format("%-20s", record.getSourceClassName());  //发送日志的类名
            String msg = record.getMessage();   //日志消息

          //\033[33m作为颜色代码,30~37都有对应的颜色,38是没有颜色,IDEA能显示,但是某些地方可能不支持
            return "\033[38m" + time + "  \033[33m" + level + " \033[35m" + threadID
                    + "\033[38m --- [" + thread + "] \033[36m" + className + "\033[38m : " + msg + "\n";
        }
    });
    logger.addHandler(handler);

    logger.info("我是测试消息1...");
    logger.log(Level.INFO, "我是测试消息2...");
    logger.log(Level.WARNING, "我是测试消息3...");
}

日志设置过滤器

日志可以设置过滤器,可以通过配置过滤结果的作用来输出只想输出的内容:

public static void main(String[] args) throws IOException {
    Logger logger = Logger.getLogger(Main.class.getName());

    //自定义过滤规则
    logger.setFilter(record -> !record.getMessage().contains("普通"));

    logger.log(Level.SEVERE, "严重的错误", new IOException("我就是错误"));
    logger.log(Level.WARNING, "警告的内容");
    logger.log(Level.INFO, "普通的信息");
}

实际上,整个日志的输出流程如下:

在这里插入图片描述

Properties配置文件

本质:跟Map一样结构

Properties文件是Java的一种配置文件:

name=Test
desc=Description

该文件配置很简单,格式为配置项=配置值,可以直接通过Properties类来将其读取为一个类似于Map一样的对象:

public static void main(String[] args) throws IOException {
    Properties properties = new Properties();
    properties.load(new FileInputStream("test.properties"));
    System.out.println(properties);
}

输出

image-20230517215531288

Properties类是继承自Hashtable,而Hashtable是实现的Map接口,也就是说,Properties本质上就是一个Map一样的结构,它会把所有的配置项映射为一个Map,这样就可以快速地读取对应配置的值了

可以将已经存在的Properties对象放入输出流进行保存,这里就不保存文件了,而是直接打印到控制台,只需要提供输出流即可:

    public static void main(String[] args) throws IOException {
        Properties p = new Properties();
        p.setProperty("test","hahah");
        p.load(new FileInputStream("name.properties"));
        p.store(System.out, "Test message");
        p.storeToXML(System.out, "hahha"); //转换为XML格式
    }

输出

image-20230517215754384

可以通过System.getProperties()获取系统的参数,来看看:

public static void main(String[] args) throws IOException {
    System.getProperties().store(System.out, "系统信息:");
}

编写日志配置文件

通过进行配置文件来规定日志打印器的一些默认值:

# RootLogger 的默认处理器为
handlers= java.util.logging.ConsoleHandler
# RootLogger 的默认的日志级别
.level= CONFIG

使用配置文件来进行配置:

public static void main(String[] args) throws IOException {
    //获取日志管理器
    LogManager manager = LogManager.getLogManager();
    //读取我们自己的配置文件
    manager.readConfiguration(new FileInputStream("logging.properties"));
    //再获取日志打印器
    Logger logger = Logger.getLogger(Main.class.getName());
    logger.log(Level.CONFIG, "我是一条日志信息");   //通过自定义配置文件,我们发现默认级别不再是INFO了
}

可以去修改ConsoleHandler的默认配置:

# 指定默认日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定默认日志消息格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# 指定默认的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8

阅读ConsoleHandler的源码就会发现,它就是通过读取配置文件来进行某些参数设置:

// Private method to configure a ConsoleHandler from LogManager
// properties and/or default values as specified in the class
// javadoc.
private void configure() {
    LogManager manager = LogManager.getLogManager();
    String cname = getClass().getName();

    setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
    setFilter(manager.getFilterProperty(cname +".filter", null));
    setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
    try {
        setEncoding(manager.getStringProperty(cname +".encoding", null));
    } catch (Exception ex) {
        try {
            setEncoding(null);
        } catch (Exception ex2) {
            // doing a setEncoding with null should always work.
            // assert false;
        }
    }
}

使用Lombok快速开启日志

如果现在需要全面使用日志系统,而不是传统的直接打印,那么就需要在每个类都去编写获取Logger的代码,这样显然是很冗余的,能否简化一下这个流程呢?

前面学习了Lombok,也体会到Lombok给我们带来的便捷,可以通过一个注解快速生成构造方法、Getter和Setter,同样的,Logger也是可以使用Lombok快速生成的。

@Log
public class Main {
    public static void main(String[] args) {
        System.out.println("自动生成的Logger名称:"+log.getName());
        log.info("我是日志信息");
    }
}

只需要添加一个@Log注解即可,添加后,可以直接使用一个静态变量log,而它就是自动生成的Logger。也可以手动指定名称:

@Log(topic = "打工是不可能打工的")
public class Main {
    public static void main(String[] args) {
        System.out.println("自动生成的Logger名称:"+log.getName());
        log.info("我是日志信息");
    }
}

输出

image-20230518200059498

Mybatis日志系统

Mybatis也有日志系统,它详细记录了所有的数据库操作等,来监控所有的数据库操作,要开启日志系统,需要进行配置:

<setting name="logImpl" value="STDOUT_LOGGING" />

logImpl包括很多种配置项,包括 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING,而默认情况下是未配置,也就是说不打印。
将其设定为STDOUT_LOGGING表示直接使用标准输出将日志信息打印到控制台,编写一个测试案例来看看效果:

public class TestMain {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(new FileInputStream("mybatis-config.xml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try(SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            System.out.println(mapper.getStudentBySidAndSex(1, "男"));
            System.out.println(mapper.getStudentBySidAndSex(1, "男"));
        }
    }
}

我们发现,两次获取学生信息,只有第一次打开了数据库连接,而第二次并没有。

现在我们学习了日志系统,那么我们来尝试使用日志系统输出Mybatis的日志信息:

<setting name="logImpl" value="JDK_LOGGING" />

将其配置为JDK_LOGGING表示使用JUL进行日志打印,因为Mybatis的日志级别都比较低,因此我们需要设置一下logging.properties默认的日志级别:

handlers= java.util.logging.ConsoleHandler
.level= ALL
java.util.logging.ConsoleHandler.level = ALL

代码编写如下:

@Log
public class TestMain {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(new FileInputStream("mybatis-config.xml"));
            LogManager manager = LogManager.getLogManager();
            manager.readConfiguration(new FileInputStream("logging.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try(SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            log.info(mapper.getStudentBySidAndSex(1, "男").toString());
            log.info(mapper.getStudentBySidAndSex(1, "男").toString());
        }
    }
}

但们发现,这样的日志信息根本没法看,因此需要修改一下日志的打印格式,创建一个格式化类:

public class TestFormatter extends Formatter {
    @Override
    public String format(LogRecord record) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String time = format.format(new Date(record.getMillis()));  //格式化日志时间
        return time + " : " + record.getMessage() + "\n";
    }
}

现在再来修改一下默认的格式化实现:

handlers= java.util.logging.ConsoleHandler
.level= ALL
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = com.test.TestFormatter

现在就好看多了,当然,我们还可以继续为Mybatis添加文件日志

image-20230518200527583

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/541534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

短信验证码

阿里云短信 1.1 介绍 短信服务&#xff08;Short Message Service&#xff09;由阿里云提供短信平台&#xff0c;调用API即可发送验证码、通知类和营销类短信&#xff1b;国内验证短信秒级触达&#xff0c;到达率最高可达99%。 官方网站&#xff1a;https://www.aliyun.com/…

getchar、putchar以及输入缓冲区

目录 1.getchar和putchar的文献 1.1关于getchar的文献: 1.2关于putchar的文献 1.3返回值问题 2.从键盘中输入一个字符 2.1原理&#x1f4a8; &#x1f6a9;2.2如何理解: ❗理解1: ❗理解2&#xff1a; 2.3关于程序如何结束 3.输入密码 3.1调用一次getchar读取相当于…

开发笔记之:文件读取值溢出bug分析(JAVA版)

&#xff08;1&#xff09;引言 以下是Java读取数据文件&#xff08;FileInputStream&#xff09;的代码&#xff1a; /*** 按双字读取* param fis 文件输入流* param isBigEndian 是否大头&#xff08;字节序&#xff09;* return 双字值 | <code>-1</cod…

vue2 axios请求后端数组数据 并展示

目录 1 vue加依赖 --> 终端中install 2 main.js 引入依赖 3 components -> 组件中 如 HelloWorld.vue 中 3.1 中定义数组 并接收数据赋值给数组 3.2 el表格 接收数据数据 并展示出来 4 效果 1 vue加依赖 --> 终端中install npm i axios vue-axiosnpm i element…

Cesium教程(一):Cesium的下载和安装

目录 1、Cesium简介 2、Cesium下载和安装 2.1 下载方式1 2.2 下载方式2 3、Cesium测试 4、我的第一个Ceisum程序《HelloCesium》 1、Cesium简介 首先进入Cesium官网 Cesium 是 3D 地理空间平台Cesium 是软件应用程序的开放平台&#xff0c;旨在释放 3D 数据的力量。用于…

RocketMQ的安装讲解详细手册--------以及启动Broker启动找不到类问题

RocketMQ的安装 1.RocketMQ安装 1.1下载RocKetMQ 下载地址&#xff1a;https://rocketmq.apache.org/release-notes/2017/12/13/4.2.0 下载解压后 bin:可执行文件目录 confidence&#xff1a;配置文件目录 lib:依赖库&#xff0c;是一些jar包 1.1配置ROCKETMQ_HOME 解压…

前端工程化配置

前端工程化配置指南 如何构建一个工程化的前端库&#xff0c;并结合 Github Actions&#xff0c;自动发布到 Github 和 NPM 的整个详细流程。 示例 我们经常看到像 Vue、React 这些流行的开源项目有很多配置文件&#xff0c;他们是干什么用的&#xff1f;他们的 Commit、Releas…

如何利用Jmeter从0到1做一次完整的压测

压测&#xff0c;在很多项目中都有应用&#xff0c;是测试小伙伴必备的一项基本技能&#xff0c;刚好最近接手了一个小游戏的压测任务&#xff0c;一轮压测下来&#xff0c;颇有收获&#xff0c;赶紧记录下来&#xff0c;与大家分享一下&#xff0c;希望大家能少踩坑。 一、压测…

Selenium自动化测试设计模式 —— PO模式

前言&#xff1a; 在python自动化过程中&#xff0c;Selenium自动化测试中有一个名字常常被提及PageObject&#xff08;思想与面向对象的特性相同&#xff09;&#xff0c;通过PO模式可以大大提高测试用例的维护效率。 不了解po设计模式的可自行百度 面向对象的特性&#xf…

Class 05 - 逻辑运算符and,or,not 和 条件语句 if

Class 05 - 逻辑运算符and,or,not 和 条件语句 if 逻辑运算符和条件语句逻辑运算符 and , or , notand 运算符“&”OR 运算符 “|”not 运算符“&#xff01; 案例运用 and , or , notsubset() 筛选数据AND 实例OR 实例NOT 实例混合使用实例 条件语句 ifif 语句else语句els…

五分钟搞懂Web UI自动化测试中的POM设计模式。

今天&#xff0c;我们来聊聊Web UI自动化测试中的POM设计模式。 为什么要用POM设计模式 前期&#xff0c;我们学会了使用PythonSelenium编写Web UI自动化测试线性脚本 线性脚本&#xff08;以快递100网站登录举栗&#xff09;&#xff1a; 使用以上代码&#xff0c;最基础最…

RabbitMQ五种消息模型

文章目录 1.简单消息队列模型2.Work工作队列模型3.发布订阅模型3.1.Fanout广播3.2.Direct路由3.3.Topics通配符 RabbitMQ官方文档 RabbitMQ 提供了5种常用消息模型。但是其实3、4、5这三种都属于订阅模型&#xff0c;只不过进行路由的方式不同。 1.简单消息队列模型 简单消息队…

Midjourney提示词资源、使用技巧、艺术家资源网站收录

为了帮助艺术家们使用Midjourney更专业、准确地创作更完美的艺术作品&#xff0c;我们收录了一些Midjourney提示词资源分享、提示词书写技巧、相关专业工具&#xff0c;同时还有一些相关艺术家资源帮艺术家们找到创作灵感。有很多是社区内资深玩家分享的云文档&#xff0c;资源…

【机器视觉3】双目立体视觉模型

双目立体视觉模型 简单模型一般模型 简单模型 假设两个摄像机平行放置于同一高度、光轴平行、成像平面重合、焦距相同、左右图像每一行y坐标方向、大小相同&#xff0c;如下图所示&#xff1a; 由左右成像平面上的点、目标物点、焦距、摄像机中心基线距离的几何关系可以得到&…

MySQL学习指南笔记经典案例句

作者&#xff1a;BSXY_19计科_陈永跃 BSXY_信息学院 注&#xff1a;未经允许禁止转发任何内容 该文章是一篇关于MySQL的一个学习的笔记或是指南&#xff0c;该文章中有很多的经典的案例可进行相应的练习和参考&#xff0c;后期的话会持续更新关于数据库系统方面的文章。 MySQL学…

供应商评估:关键标准以及如何执行

几乎每个行业的企业都与制造商、进口商、服务提供商和分销商等供应商合作。由于通常有几个供应商可供选择&#xff0c;进行供应商评估有助于企业选出其中最符合其业务需求的供应商。 什么是供应商评估&#xff1f; 供应商评估是企业在为其产品或材料选择供应商时使用的过程。…

常见电子元器件和电路

目录 常见电子元器件一览表(字母标志)NTC(负温度系数热敏电阻)压敏电阻X2电容(抑制电源电磁干扰用电容器)泄放电阻共模电压共模电感整流桥滤波电容RCD吸收二极管Y电容整流器的原理输出整流肖特基二极管 功率晶体管&#xff08;GTR&#xff0c;三极管)双极型晶体管(BJT&#xff…

iOS swift5 获取系统或其他app已经连接的蓝牙设备

文章目录 chatGPT答案1.2 retrievePeripheralsWithIdentifiers 本人实例参考博客 chatGPT答案 1.1 retrieveConnectedPeripherals(withServices (本人没有测试成功) 要获取系统或其他app已连接的蓝牙设备&#xff0c;你可以使用CoreBluetooth框架提供的CBCentralManager类。下…

【节点边际电价】机组运行约束对机组节点边际电价的影响分析(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

新人如何学习软件测试

零基础学习软件测试不失为一个好的选择&#xff0c;虽然IT行业里对小白最友好的非软件测试莫属了&#xff0c;但是也要看你个人在学习软件测试这件事上面花费了多少的时间和努力了~ 每年毕业季&#xff0c;IT行业依然是比较热门且收入是最高的行业。对于应届毕业生来说想要进入…