一文搞定MybatisPlus

news2024/12/23 6:47:08

Mybatis简介

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

 (来自官网) 

体验Mybatisplus

1.创建SpringBoot工程,导入mysql,lombok,spring web

2.改setting里面的encoding为utf-8

3.pom文件中引入依赖

<!--        druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
<!--        mybatisplus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

4.yml文件中设置数据源相关参数

4.编写实体类

package com.example.entity;
import lombok.Data;
@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}

 

5.编写mapper接口

继承BaseMapper,指定泛型为User

加上@Mapper注解

tips:如何让springboot的启动类扫到mapper文件夹里面的mapper接口

1.加上@Mapper注解,同时需要保证mapper文件夹在启动类所在包或其子包中(也就是启动类所在的层次要比被扫描的文件夹更高或同级)

2.启动类加上@MapperScan,指定要扫描的文件夹

 6.写一个测试类,进行测试

@SpringBootTest
public class TestUserMapper {
    @Autowired
    private UserMapper userMapper;


    @Test
    void testSelectAll(){
        List<User> users = userMapper.selectList(null);
        System.out.println("users:"+users);
    }
}

ps:如果是第二种方式扫描mapper接口,userMapper会爆红,这是因为UserMapper是一个接口,不能实例化对象 。只有在服务器启动IOC容器初始化后,由框架创建DAO接口的代理对象来注入。 现在服务器并未启动,所以代理对象也未创建,IDEA查找不到对应的对象注入,所以提示报红 一旦服务启动,就能注入其代理对象,所以该错误提示不影响正常运行。 

Mybatisplus标准CURD以及分页

    @Test
    void testInsert(){
        //增
        User user = new User();
        user.setName("李四");
        user.setAge(18);
        user.setPassword("1599");
        user.setTel("18959657411");
        int i = userMapper.insert(user);
        System.out.println("新增了"+i+"条数据");
    }

    @Test
    void testDelete(){
        //删
        int i = userMapper.deleteById(1827551884282552322L);
        System.out.println("删除了"+i+"条数据");
    }

    @Test
    void testUpdate(){
        //改
        User user = new User();
        user.setId(1L);
        user.setName("Tom·A·Cat");
        int i = userMapper.updateById(user);
        System.out.println("修改了"+i+"条数据");
    }

ps:修改的时候,只修改实体对象中有值的字段 。如果是我们以前用的mybatis做开发,没有指定password,age和tel,这些字段会被覆盖为null,mybatisplus的优势就体现出来了。

    @Test
    void testSelect(){
        //查
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

分页

官网:分页插件 | MyBatis-Plus

首先要添加一个分页拦截器

package com.example.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}

使用分页功能

    @Test
    void testPage(){
        //1.创建IPage对象(Page实现了IPage接口),设置分页参数
        Page<User> page = new Page<>(1,3);//当前页码为1  每页5条数据
        //2.执行分页查询
        userMapper.selectPage(page,null);//没有指定条件
        //3.获取分页结果
        System.out.println("当前页码:"+page.getCurrent());
        System.out.println("每页显示数:"+page.getSize());
        System.out.println("一共多少页:"+page.getPages());
        System.out.println("一共多少条数据:"+page.getTotal());
        System.out.println("数据:"+page.getRecords());
    }

 *****************************************************

DQL编程控制

条件查询

 我们需要依靠wrapper来构建要查询的条件

构建条件查询的三种方式

年龄小于10岁的

1.QueryWrapper
    //1.QueryWrapper
    @Test
    void testQuery01(){
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.lt("age",10);
        System.out.println(userMapper.selectList(qw));
    }
2.lambda方式的QueryWrapper
    //2.lambda方式的QueryWrapper
    @Test
    void testQuery02(){
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.lambda().lt(User::getAge,10);
        System.out.println(userMapper.selectList(qw));
    }

解决了字段可能写错的问题 。

3.LambdaQueryWrapper
    //3.LambdaQueryWrapper
    @Test
    void testQuery03(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.lt(User::getAge,10);
        System.out.println(userMapper.selectList(lqw));
    }

不用 .lambda()了,代码更加简洁。 

多条件查询

年龄大于10小于20的 (and)
    //年龄大于10且小于20
    @Test
    void testQuery04(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.gt(User::getAge,10).lt(User::getAge,20);//支持链式编程
        System.out.println(userMapper.selectList(lqw));
    }
年龄小于10大于20的   (or)
    //年龄小于10或大于20
    @Test
    void testQuery05(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.lt(User::getAge,10).or().gt(User::getAge,20);// or()
        System.out.println(userMapper.selectList(lqw));
    }

null条件判定 

需求

用户输入两个年龄(minAge和maxAge),查询用户指定年龄范围里的User,但是如果用户只想查看18岁以下的User,只填写了maxAge为18,那么minAge为null,这时候要怎样让minAge不加入条件呢?MybatisPlus早就想到了这一点。

 **************************************************************

写一个AgeField实体类来模拟前端传来的minAge和maxAge

package com.example.entity;
import lombok.Data;
@Data
//模拟前端传过来的最小年龄和最大年龄
public class AgeField {
    private Integer minAge;
    private Integer maxAge;
}
 测试代码
    /**
     * null判定
     */
    @Test
    void testQuery06(){
        AgeField af = new AgeField();
        af.setMinAge(10);
        af.setMaxAge(20);
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.gt(af.getMinAge()!=null,User::getAge,af.getMinAge())
           .lt(af.getMaxAge()!=null,User::getAge,af.getMaxAge());
        List<User> users = userMapper.selectList(lqw);
        System.out.println(users);
        System.out.println(users.size());
    }

参数condition:为真时该条件才加入查询语句

参数column:表中字段

参数val:传入的字段值

 数据库

共15条记录

测试结果

传入10和20 ,查到两条数据

 现在我们把这两条注掉,两条的条件都为false,不加入查询条件,相当于select * from user

//        af.setMinAge(10);
//        af.setMaxAge(20);

 查到15条数据,也就是user表中的所有数据,符合预期。

查询投影

user表中新增一个sex字段,同时修改实体类

查询结果包含模型类中部分属性

LambdaQueryMapper写法

    @Test
    //查询结果包含模型类中部分属性
    void testQuery07(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //查询年龄在10~20之间的所有用户的id,name,age信息
        lqw.select(User::getId,User::getName,User::getAge);
        lqw.gt(User::getAge,10);
        lqw.lt(User::getAge,20);
        System.out.println(userMapper.selectList(lqw));
    }

QueryMapper写法

    @Test
    void testQuery08(){
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.select("id","name","age");
        qw.gt("age",10);
        qw.lt("age",20);
        System.out.println(userMapper.selectList(qw));
    }
 测试结果

查询结果包含模型类中未定义属性

聚合和分组,无法使用lambda表达式完成,正如MP官网所说的,MybatisPlus只是对Mybatis进行增强,MP无法做到的事情我们还是要老老实实地回到mapper接口里面写sql。

聚合查询
    @Test
    //聚合
    void testQuery09(){
        QueryWrapper<User> qw = new QueryWrapper<>();
        
        //这里也可以连着写,为了方便看,用逗号分开
        qw.select("count(*) as count",
                "max(age) as maxAge",
                "min(age) as minAge",
                "sum(age) as sumAge",
                "avg(age) as avgAge");
        
        //用selectMaps方法,返回一个map,这个map的key为聚合字段,value为聚合结果
        List<Map<String, Object>> maps = userMapper.selectMaps(qw);
        System.out.println(maps);
    }

分组查询

相当于 select sex,count(*) from user group by sex;

    @Test
    //分组
    void testQuery10(){
        //按性别分组
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.select("sex,count(*) as count");
        qw.groupBy("sex");
        List<Map<String, Object>> maps = userMapper.selectMaps(qw);
        System.out.println(maps);
    }

深入体验查询条件的设置

条件构造器 | MyBatis-Plus

等值查询

    @Test
    void testQuery11(){
        //等值查询 模拟登录校验
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getName,"张三").eq(User::getPassword,"zs666");
        User loginUser = userMapper.selectOne(lqw);//只查一个用selectOne就可以
        System.out.println(loginUser);
    }

范围查询

    @Test
    void testQuery12(){
        //范围查询 lt le gt ge between
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.between(User::getAge,10,20);
        userMapper.selectList(lqw);
    }

模糊查询

   @Test
    void testQuery13(){
        /**
         * 模糊查询 like
         * %:匹配任意字符
         * _:匹配任意单个字符
         * **********************
         * 官网中并没有看到匹配任意单个字符要怎么写,
         * 如果要匹配 刘亦菲、刘二菲、刘三菲...这样的名字可能还是要自己写sql (like 刘_菲)
         */
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //lqw.like(User::getName,"o"); //名字里带o的   like %o%
        //lqw.likeRight(User::getName,"杨"); // like 杨%
        //lqw.likeLeft(User::getName,"at"); // like %at
        lqw.notLike(User::getName,"月"); //not like %月%
        userMapper.selectList(lqw);
    }

排序查询

1.

    @Test
    void testQuery14(){
        //排序查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        /**
         * 参数:condition isAsc columns
         * conidtion:条件,为true时 orderby 加入查询语句
         * isAsc:是否为升序
         * columns:按哪个列排序
         */
        //按年龄降序,年龄一样按id降序
        lqw.orderBy(true,false,User::getAge,User::getId);
        userMapper.selectList(lqw);
    }

 

 2.

    @Test
    void testQuery15(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //按年龄降序,按id升序
        //注意这里哪个字段写在前面,它的优先级就更高
        lqw.orderByDesc(User::getAge);
        lqw.orderByAsc(User::getId);
        userMapper.selectList(lqw);
    }

字段映射和表名映射

问题1:表字段与编码属性设计不同步

实体类里面是pwd,数据库里面是password

解决:

问题2:编码中添加了数据库中未定义的属性

问题3:采用默认查询开放了更多的字段查看权限

pwd是敏感数据,如果进行查询,返回的json数据中携带了pwd,这是很危险的,因此我们需要在查询中将pwd默认隐藏

    @Test
    void testQuery16(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        userMapper.selectList(lqw);
    }

默认的查询是查不出来pwd的

    @Test
    void testQuery17(){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.select(User::getPwd);
        userMapper.selectList(lqw);
    }

指定要查pwd,这样是可以查出来的

问题4:表名与编码开发设计不同步

DML编程控制

id生成策略

MP通过@TableId控制id的生成策略

ctrl+鼠标左键,进入IdType源码

    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER_STR(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
     */
    @Deprecated
    UUID(4);

AUTO(0)

id自增,同时数据库中要设置id自增

    @TableId(type = IdType.AUTO)
    private Long id;
ALTER TABLE tb_user  AUTO_INCREMENT=16;
    @Test
    void testInsert01(){
        User user = new User();
        user.setName("李薇");
        user.setPwd("12637489");
        user.setAge(50);
        user.setSex(1);
        user.setTel("959559999");
        user.setId(20L);
        userMapper.insert(user);
    }

指定它的id为20,insert到数据库的id仍是16

删除这条数据,重新insert一次

id为17,由此知道AUTO_INCREMENT不会因为数据的删除而回退
 

NONE(1)

该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)

    @TableId(type = IdType.NONE)
    private Long id;

执行两次 testInsert01 ,指定id为20,25,结果如下

 

INPUT(2)

需要自己输入id

    @TableId(type = IdType.INPUT)
    private Long id;

执行两次 testInsert01 ,指定id为30,35,结果如下


ASSIGN_ID(3)<——过时的ID_WORKER和ID_WORKER_STR合并

雪花算法生成id(可兼容数值型和字符串型)

    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

指定id为40,这样生成的id为40

    @Test
    void testInsert01(){
        User user = new User();
        user.setName("李薇");
        user.setPwd("12637489");
        user.setAge(50);
        user.setSex(1);
        user.setTel("959559999");
        user.setId(40L);
        userMapper.insert(user);
    }

不指定id,按照雪花算法生成id

//        user.setId(45L);

雪花算法生成的id的格式

 

ASSIGN_UUID(4)<——过时的UUID

以UUID生成算法作为id生成策略

需要表中主键的id为varchar(32),

因为生成的uuid为32位,形如b098c2c603a317326af11fe64371e916

    @TableId(type = IdType.ASSIGN_UUID)
    private String id;

执行1次添加

 

多数据删除

    @Test
    void testDelete01(){
        //根据id删除多条数据
        ArrayList<Long> list = new ArrayList<>();
        list.add(1827910579805876225L);
        list.add(40L);
        userMapper.deleteBatchIds(list);
    }

成功删除两条数据

逻辑删除

问题分析

实战演练 

1.数据库表中添加一个deleted字段,默认0

2.实体类添加属性
    //0表示正常值 1表示该数据已被逻辑删除
    @TableLogic(value = "0",delval = "1")
    private Integer deleted;
3.测试
3.1先进行一次查询所有,注意现在数据库里面的记录的deleted字段都是0

    @Test
    void testLogic(){
        userMapper.selectList(null);
    }

查出来所有的19条记录(注意这个sql,我们的代码中并没有显示地设定任何查询条件)

 3.2 删除第一条数据再进行一次查询所有
    @Test
    void testLogic(){
        userMapper.deleteById(1L);
        userMapper.selectList(null);
    }

 id为1的记录已被逻辑删除,这里只有18条记录

deleted字段为1,表示被逻辑删除了 

3.3 指定查询条件查一下

    @Test
    void testLogic02(){
        userMapper.selectById(1L);
    }

 他会自动把逻辑删除字段加到查询条件里

4.设置逻辑删除字段的另一种方式:在yml文件中配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志
  global-config:
    banner: off # 关闭MybatisPlus启动图标
    db-config:
      table-prefix: tb_ #表名前缀
      logic-delete-field: deleted #逻辑删除字段名
      logic-not-delete-value: 0 #正常值
      logic-delete-value: 1 #逻辑删除后的值

乐观锁

 实现思路

 0.添加拦截器
@Configuration
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//添加乐观锁的拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}
1.表中添加字段version,用作版本控制

给默认值为1,长度为int的最大值11位

 2.实体类中添加属性
    @Version
    private Integer version;
3.测试
测试1

起始数据

执行更新语句

    @Test
    void testLock01(){
        User user = new User();
        user.setId(1L);
        user.setName("tomcat");
        userMapper.updateById(user);
    }

 发现version并没有改变,这是因为我们并没有拿到过version

重新执行如下语句

    @Test
    void testLock02(){
        User user = userMapper.selectById(1L);
        user.setName("tomkitty");
        userMapper.updateById(user);
    }

 我们先查询id为1的用户拿到了该用户的实体(当然包括它的version)这样一来更新就会自动校验version

 测试2

模拟两个请求对同一个记录进行修改 

    void testLock03(){
        User user1 = userMapper.selectById(2L);
        User user2 = userMapper.selectById(2L);

        user1.setName("JerryA");
        user2.setName("JerryB");


        userMapper.updateById(user2);//version被修改成2
        userMapper.updateById(user1);//它还以为是version=1 结果和数据库的version对不上 修改失败
    }

最终结果

代码生成器

1.新创建一个springboot项目

引入mysql lombok,web(会生成controller) 即可

2.在pom文件中加入代码生成器需要的依赖

        <!--代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--velocity模板引擎-->
        <dependency>
         <groupId>org.apache.velocity</groupId>
         <artifactId>velocity-engine-core</artifactId>
         <version>2.3</version>
        </dependency>

3.创建代码生成类

package com.example;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;

public class CodeGenerator {
    public static void main(String[] args) {
        //1.获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();


        //2.设置数据库相关配置
        DataSourceConfig ds = new DataSourceConfig();
        ds.setDriverName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");
        ds.setUsername("root");
        ds.setPassword("root");

        autoGenerator.setDataSource(ds);


        //3.设置全局配置
        GlobalConfig gc = new GlobalConfig();
        //代码生成位置(默认D盘的根目录) user.dir=D:/java_workspace
        gc.setOutputDir("D:/java_workspace/MybatisPlusProject02/src/main/java/com/example");
        //设置生成完毕后是否打开生成代码所在的目录(默认打开)
        gc.setOpen(false);
        gc.setAuthor("chen");//设置作者
        gc.setFileOverride(true);//是否覆盖原来生成的文件
        gc.setMapperName("%sMapper"); //设置名字格式为为 UserMapper,AccountMapper.....
        gc.setIdType(IdType.ASSIGN_ID); //设置id生成策略

        autoGenerator.setGlobalConfig(gc);


        //4.设置包名相关配置
        PackageConfig pc = new PackageConfig();
        //pc.setParent("com.baomidou");
        pc.setParent("mpGenerator");//设置生成的包名
        pc.setEntity("entity");//设置实体类包名
        pc.setMapper("mapper");//设置mapper接口文件夹的名字

        autoGenerator.setPackageInfo(pc);


        //5.策略设置
        StrategyConfig sc = new StrategyConfig();
        sc.setInclude("tb_user");//设置参与代码生成的表
        sc.setTablePrefix("tb_");//设置数据库表前缀,这样它生成的类前面就不会带Tb_了
        sc.setRestControllerStyle(true);//设置控制器为rest风格的控制器
        sc.setVersionFieldName("version");//设置乐观锁字段名
        sc.setLogicDeleteFieldName("deleted");//设置逻辑删除字段名,仍然需要自己指定逻辑删除的值
        sc.setEntityLombokModel(true);//启用lombok

        autoGenerator.setStrategy(sc);


        //6.执行代码生成
        autoGenerator.execute();

    }
}

4.运行代码生成类中的main方法,查看结果

开启Mybatisplus日志

yml文件里面配置

#查看MP执行的sql语句
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

 关闭Spring初始化日志,SpringBoot图标,MybatisPlus图标

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

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

相关文章

HarmonyOS--认证服务-操作步骤

HarmonyOS–认证服务 文章目录 一、注册华为账号开通认证服务二、添加项目&#xff1a;*包名要与项目的包名保持一致三、获取需要的文件四、创建项目&#xff1a;*包名要与项目的包名保持一致五、添加json文件六、加入请求权限七、加入依赖八、修改构建配置文件&#xff1a;bui…

【UDS诊断】——0x34、0x36、0x37服务

&#x1f64b;‍♂️【UDS诊断服务介绍合集】系列&#x1f481;‍♂️点击跳转 文章目录 一、服务概述1.0x34服务——请求下载数据1.1.0x34格式 2.0x36服务——数据传输2.1.0x36格式 3.0x37服务——退出上传下载3.1.0x37格式 一、服务概述 Client端使用Routine Control服务来…

WIN32实现远程桌面监控

文章目录 完整代码API简介调试代码 后记reference 完整代码 server.cpp #include <winsock2.h> #include <Ws2tcpip.h> #include <windows.h> #include <stdio.h> #include <vector> #pragma comment(lib, "ws2_32.lib")LRESULT CAL…

什么是韦恩图,怎么制作?用这款软件在线绘制,简单又好用!

在日常工作和学习中&#xff0c;我们经常需要用图表来可视化呈现复杂的信息和关系。其中&#xff0c;韦恩图是一种简洁而强大的可视化工具&#xff0c;能够清晰地展现集合之间的关系&#xff0c;诸如包含与被包含、互斥、并列等。 不过对刚接触韦恩图的人而言&#xff0c;或多…

traceroute命令这样用,追踪主机路由没烦恼

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 网络的稳定性和可靠性对于业务连续性至关重要。当涉及到网络连接问题时&#xff0c;有一个强大的工具就是 tr…

Certum Domain Validation CA SHA2

Certum是波兰的一家数字证书厂家&#xff0c;该机构也是目前世界第四家兼容性在99%机构&#xff08;包括历史版本浏览器&#xff09;&#xff0c;目前在国内有授权提供商&#xff1a;Gworg提供签发和认证&#xff0c;拥有二级代理划分&#xff0c;适合长期做SSL证书业务或者集成…

年薪100K入职字节测试岗现在分享下我常背的软件测试面试题

800道软件测试面试真题&#xff0c;高清打印版打包带走&#xff0c;横扫软件测试面试高频问题&#xff0c;涵盖测试理论、Linux、MySQL、Web测试、接口测试、APP测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块面试题&am…

Linux文件编程(系统API调用)

文章目录 Linux文件编程标注C的IO缓存类型代码示例--缓存区的存在 文件I/O系统调用标准C库关于文件的输入输出函数FILE结构体文件描述符文件描述符与文件指针的相互转换 系统调用常用函数open函数&#xff08;打开或者创建文件&#xff09;creat函数&#xff08;创建一个现有文…

JAVA-封装

目录 一、封装的概念 二、封装扩展之包 1. 包的概念 2.导入包中的类 3.自定义包 4.常见的包 三、访问限定符 在同一包中&#xff1a; 在不同包中&#xff1a;​编辑 一、封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主…

ESP32修改分区表

修改分区表 官方参考 在工程目录文件夹新建分区表&#xff0c;参考官方的写就行&#xff0c;我这里改成了8M的FLASH&#xff0c;所以新建的分区表为名字是 default_8MB.csv &#xff0c;内容如下&#xff1a; # Name, Type, SubType, Offset, Size, Flags nvs, data, …

后端微服务与分布式系统

编写一篇关于后端微服务和分布式系统的文档&#xff0c;需要详细讨论微服务架构的核心概念、优缺点、关键技术&#xff0c;以及在分布式系统中的应用。以下是文档的大纲和内容概述&#xff1a; 后端微服务与分布式系统 1. 简介 微服务架构是一种将大型应用程序分解为一系列小…

leetCode - - - 二叉树

目录​​​​​​​ 1.前中后序遍历&#xff08;递归&#xff09; 2.前中后序遍历&#xff08;迭代&#xff09; 3.翻转二叉树&#xff08;LeetCode 226&#xff09; 4.最大二叉树&#xff08; LeetCode 654 &#xff09; 5.平衡二叉树&#xff08; LeetCode 110 &#xf…

02- javascript 高阶-构造函数(知识点)呀

目录 1.构造函数 1.1 JS构造函数的实例成员和静态成员 1.1.1实例成员 1.1.2静态成员 1.2构造函数原型prototype 1.3对象原型 1.4 constructor构造函数 1.5原型链 1.6构造函数实例和原型对象三角关系 1.7原型链和成员的查找机制 1.7.1 Object.prototype.hasOwnPropert…

WEB渗透Win提权篇-提权工具合集

提权工具合集包&#xff1a; 夸克网盘分享 往期文章 WEB渗透Win提权篇-RDP&Firewall-CSDN博客 WEB渗透Win提权篇-MSSQL-CSDN博客 WEB渗透Win提权篇-MYSQL-udf-CSDN博客 WEB渗透Win提权篇-AccountSpoofing-CSDN博客 WEB渗透Win提权篇-弱权限提权-CSDN博客 Tools合集 工…

UVa1670/LA5920 Kingdom Roadmap

UVa1670/LA5920 Kingdom Roadmap 题目链接题意分析AC 代码 题目链接 本题是2011年icpc欧洲区域赛东北欧赛区的K题 题意 输入一个n&#xff08;n≤100000&#xff09;个结点的树&#xff0c;添加尽量少的边&#xff0c;使得任意删除一条边之后图仍然连通。如下图所示&#xff0…

如果是你,你会背叛师门吗?看了凌晨一点杭州隧道里睡满的外卖员,我觉得李佳琦被骂一点也不冤——早读(逆天打工人爬取热门微信文章解读)

如果是你&#xff0c;你会背叛师门吗&#xff1f;&#xff1f; 引言Python 代码第一篇 洞见 看了凌晨一点杭州隧道里睡满的外卖员&#xff0c;我觉得李佳琦被骂一点也不冤第二篇 股市风云结尾 (先不论人品如何&#xff0c;这个问题就有点类似董宇辉跟新东方&#xff0c;大伙且看…

Java学习第一天

Java介绍&#xff1a; Java是一种高级编程语言&#xff1b;由sun公司研发&#xff0c;之后被Oracle公司收购&#xff1b;Java之父是詹姆斯.高斯林&#xff1b;Java什么都能做但主要用于企业互联网系统的开发&#xff1b;包括JavaSE&#xff08;标准版&#xff09;、JavaEE&…

C程序设计——表达式的值0

表达式 表达式是一组序列&#xff0c;由操作符或操作数组成。 表达式的值 C语言中&#xff0c;所有的表达式&#xff0c;都是有值的&#xff0c;所以本节专门讲讲表达式的值。 算数表达式 算数表达式的值&#xff0c;就是算数运算的结果&#xff0c;比如表达式 1 1的值就…

Threejs三要素及demo

本文目录 前言一、threejs三要素1.1 场景Scene1.2 相机Camera1.3 渲染器Renderer1.4 项目构建准备 二、安装Threejs2.1 编写代码 前言 Three.js是一个在 MIT 许可下的 JavaScript 库&#xff0c;它在 WebGL 之上运行。这个库的目标就是简化处理3D内容的过程。它是一个WebGL引擎…

【Linux】第一次使用linux向gitee上提交代码

1.首先要在gitee上新建一个仓库 2.然后&#xff0c;复制https的仓库链接 3. 三板斧 第一斧 git add . 4.三板斧 第二斧 git commit -m ‘日志’ 5.三板斧 第三斧 git push