Java阶段四-SpringBoot02

news2024/12/23 19:41:02

第4章-第2节

一、知识点

Mybatis-Plus、Lambda

二、目标

  • 理解什么是Mybatis-Plus

  • 理解Mybatis和Mybatis-Plus的区别

  • 学会使用Mybatis-Plus的CRUD

  • 条件构造器的使用

  • 分页查询的使用

三、内容分析

  • 重点

    • 学会使用Mybatis-Plus的CRUD

    • 什么是查询过滤,有什么用

    • 条件构造器的使用

    • 分页查询的使用

  • 难点

    • 学会使用Mybatis-Plus的CRUD

    • 条件构造器的使用

四、内容

1、简介

1.1 概念

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

1.2 特性
  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,BaseMapper

  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,简单的CRUD操作不用自己编写。

  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

1.3 和Mybatis的区别
  • MyBatis 是一种持久层框架,用来连接数据库并对其进行增删改查操作的开源框架,底层就是一个 JDBC 封装的组件,访问数据库的 sql 语句存放于 mapper (或Dao) 包下的 xml 配置文件中。

  • Mybatis-Plus 是 MyBatis 的一个增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatis-Plus 已经封装好了一些 CRUD 方法,因此不需要再写 xml 了,仅仅通过少量配置即可实现单表大部分的CRUD操作。使用时直接调用这些方法就行。

2、基本使用

2.1 新建一个项目引入依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
2.2 配置yml
# 配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot-mysql?userSSL=false;serverTimezone=Asia/Shanghai
    username: root
    password: 123456
mybatis-plus:
  # mapper配置文件
  mapper-locations: classpath:mapper/*.xml
  # resultType别名,没有这个配置resultType包名要写全,配置后只要写类名
  type-aliases-package: com.example.springboot01.entity
  configuration:
    # 日志的配置,直接添加即可,内部有自带配置项
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.3 配置启动类
@MapperScan("com.example.demo.mapper") // 填mapper/dao路径
2.4 创建Student实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    ...
}
2.5 创建mapper接口
// BaseMapper后面的泛型写的是需要返回的实体类
@Repository
public interface StudentMapper extends BaseMapper<Student> {
    // 基本的CRUD已经写好了
}
2.6 调用
@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private StudentMapper mapper;
    @GetMapping("/list")
    public List<Student> queryAll() {
        // 调用baseMapper中封装好的方法直接查询即可
        return mapper.selectList(null);
    }
}

3、Service的使用

为了让我们的开发更符合一般的JAVA开发规范,我们一般会使用Service来进一步封装

3.1 创建IStudentService接口实现IService<T> 接口
public interface IStudentService extends IService<Student> {
}
3.2 创建StudentServiceImpl实现类继承ServiceImpl<M extends BaseMapper<T>, T>
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements IStudentService {
    // 实现了通用Service的CRUD方法
}
3.3 Controller调用
@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private StudentService service;
    @GetMapping
    public List<Student> queryAll(){
        return service.list();
    }
}

4、常用方法

官方网址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3

4.1 Mapper CRUD 接口
  • Insert
    // 插入一条记录
    int insert(T entity);

  • Delete
    // 根据 entity 条件,删除记录
    int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
    // 删除(根据ID 批量删除)
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // 根据 ID 删除
    int deleteById(Serializable id);
    // 根据 columnMap 条件,删除记录
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

  • Update
    // 根据 whereWrapper 条件,更新记录
    int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
    // 根据 ID 修改
    int updateById(@Param(Constants.ENTITY) T entity);

  • select
    // 根据 ID 查询
    T selectById(Serializable id);
    // 根据 entity 条件,查询一条记录
    T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
    // 查询(根据ID 批量查询)
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // 根据 entity 条件,查询全部记录
    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 查询(根据 columnMap 条件)
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
    // 根据 Wrapper 条件,查询全部记录
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
    // 根据 entity 条件,查询全部记录(并翻页)
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录(并翻页)
    IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询总记录数
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4.2 Service CRUD 接口
  • Save
    // 插入一条记录(选择字段,策略插入)
    boolean save(T entity);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList, int batchSize);

  • SaveOrUpdate
    // TableId 注解存在更新记录,否插入一条记录
    boolean saveOrUpdate(T entity);
    // 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
    boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
    // 批量修改插入
    boolean saveOrUpdateBatch(Collection<T> entityList);
    // 批量修改插入
    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

  • Remove
    // 根据 entity 条件,删除记录
    boolean remove(Wrapper<T> queryWrapper);
    // 根据 ID 删除
    boolean removeById(Serializable id);
    // 根据 columnMap 条件,删除记录
    boolean removeByMap(Map<String, Object> columnMap);
    // 删除(根据ID 批量删除)
    boolean removeByIds(Collection<? extends Serializable> idList);

  • Update
    // 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
    boolean update(Wrapper<T> updateWrapper);
    // 根据 whereWrapper 条件,更新记录
    boolean update(T updateEntity, Wrapper<T> whereWrapper);
    // 根据 ID 选择修改
    boolean updateById(T entity);
    // 根据ID 批量更新
    boolean updateBatchById(Collection<T> entityList);
    // 根据ID 批量更新
    boolean updateBatchById(Collection<T> entityList, int batchSize);

  • Get
    // 根据 ID 查询
    T getById(Serializable id);
    // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
    T getOne(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    T getOne(Wrapper<T> queryWrapper, boolean throwEx);
    // 根据 Wrapper,查询一条记录
    Map<String, Object> getMap(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

  • List
    // 查询所有
    List<T> list();
    // 查询列表
    List<T> list(Wrapper<T> queryWrapper);
    // 查询(根据ID 批量查询)
    Collection<T> listByIds(Collection<? extends Serializable> idList);
    // 查询(根据 columnMap 条件)
    Collection<T> listByMap(Map<String, Object> columnMap);
    // 查询所有列表
    List<Map<String, Object>> listMaps();
    // 查询列表
    List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
    // 查询全部记录
    List<Object> listObjs();
    // 查询全部记录
    <V> List<V> listObjs(Function<? super Object, V> mapper);
    // 根据 Wrapper 条件,查询全部记录
    List<Object> listObjs(Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录
    <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

  • Page
    // 无条件分页查询
    IPage<T> page(IPage<T> page);
    // 条件分页查询
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
    // 无条件分页查询
    IPage<Map<String, Object>> pageMaps(IPage<T> page);
    // 条件分页查询
    IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

  • Count
    // 查询总记录数
    int count();
    // 根据 Wrapper 条件,查询总记录数
    int count(Wrapper<T> queryWrapper);

5、注解

官网地址:https://baomidou.com/pages/223848/#tablename

  • @TableName
    • 描述:表名注解,标识实体类对应的表

    • 使用位置:实体类

      // 表名这个类对应的是数据库的哪一张表,如果没有写则默认是使用类名,也就是user表
      // 这个时候这个User的实体类对的是sys_user表
      @TableName("sys_user")
      public class User {}

  • @Tableld
    • 描述:主键注解

    • 使用位置:实体类主键字段

      @TableName("sys_user")
      public class User {
          @TableId
          private Long id;
          private String name;
          private Integer age;
          private String email;
      }
      属性类型必须指定默认值描述
      valueString""主键字段名
      typeEnumIdType.NONE指定主键类型
      IdType
      描述
      AUTO数据库 ID 自增
      NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
      INPUTinsert 前自行 set 主键值
      ASSIGN_ID分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
      ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
  • @TableField
    • 描述:字段注解(非主键)

      @TableName("sys_user")
      public class User {
          @TableId
          private Long id;
          @TableField("nickname")
          private String name;
          private Integer age;
          private String email;
      }

6、条件构造器

官网地址:https://baomidou.com/pages/10c804/

6.1 AbstractWrapper

QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类 用于生成 sql 的 where 条件

  • eq

    等于 =

    eq(R column, Object val)
    eq(boolean condition, R column, Object val)
    例: eq("name", "老王")--->name = '老王'

  • ne

    不等于 <>

    ne(R column, Object val)
    ne(boolean condition, R column, Object val)
    例: ne("name", "老王")--->name <> '老王'

  • like

    LIKE '%值%'

    like(R column, Object val)
    like(boolean condition, R column, Object val)
    例: like("name", "王")--->name like '%王%'

  • or
    • 拼接 OR

      主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)

      or()
      or(boolean condition)
      例: eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'

    • OR 嵌套

      or(Consumer<Param> consumer)
      or(boolean condition, Consumer<Param> consumer)
      例: or(i -> i.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着')

  • and
    • AND 嵌套

      and(Consumer<Param> consumer)
      and(boolean condition, Consumer<Param> consumer)
      例: and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')

6.2 QueryWrapper

继承自 AbstractWrapper,所以可以使用 AbstractWrapper 的方法,常用于查询条件的设置

@GetMapping("/conditions")
public List<Student> queryByConditions(Student student){
    QueryWrapper<Student> wrapper = new QueryWrapper<>();
    // 添加年龄的判断,第一个参数为true的时候才会拼接到字符串中,第二个参数是数据库的字段名,第三个参数是值
    wrapper.eq(student.getAge() != null,"age", student.getAge());
    // 添加姓名的模糊查询
    wrapper.like(StringUtils.isNotEmpty(student.getName()),"name", student.getName());
    return service.list(wrapper);
}
6.3 LambdaQueryWrapper

使用lambda语法写条件

6.3.1 lambda表达式概念

Lambda表达式是Java8中的新特性,编码时,我们一般尽可能轻量级的将代码封装为数据,传统的解决方案是通过接口和实现类(匿名内部类)实现,他是函数式编程思想的一种体现,我们不用关注对象是什么,只要关注对对象做什么操作就好了

6.3.2 基本格式和使用
(参数列表)->{代码块}
  • 线程
    // 之前这么写
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("启动线程");
        }
    }).start();
    // 使用lambda
    new Thread(() -> {
        System.out.println("Lambda启动线程");
    }).start();

  • 自己定义
    • 定义接口(只能写一个方法 )
      public interface LambdaFun {
          Integer getSum(int x, int y);
      }

    • 使用
      LambdaFun fn = (int x, int y) -> {
          return x + y;
      };
      System.out.println(fn.getSum(10, 20));

6.3.3 省略规则
  • 参数类型可以省略
    LambdaFun fn = (x,y) -> {
        return x + y;
    };

  • 方法体只有一句的时候大括号、return、唯一一句的分号可以省略
    LambdaFun fn = (x, y) -> x + y;

  • 只有一个参数的时候可以省略小括号
    LambdaFun fn = x -> x;

  • 如果记不住 那就记住 alt+enter
6.3.4 使用LambdaQueryWrapper
@GetMapping("/conditions/lambda")
public List<Student> queryByConditionsLambda(Student student){
    LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
    // 添加年龄的判断,第一个参数为true的时候才会拼接到字符串中,第二个参数是数据库的字段名,第三个参数是值
    wrapper.eq(student.getAge() != null,Student::getAge, student.getAge());
    // 添加姓名的模糊查询
    wrapper.like(StringUtils.isNotEmpty(student.getName()),student1 -> student1.getName(), student.getName());
    return service.list(wrapper);
}

7、分页查询

7.1 新建配置类
@Configuration
public class MyBatisPlusConfig {
    // MybatisPlus的配置
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 在拦截器中加入了一个分页的拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
7.2 使用page方法
public List<Student> queryAll(){
    // 创建一个Page对象
    Page<Student> studentPage = new Page<>(1,5);
    // 传入刚刚的Page对象进行查询,得到一个新的Page对象
    Page<Student> page = service.page(studentPage);
    // 获取到Page的记录返回,同时也可以获取到总数等
    return page.getRecords();
}

8、小结

本章节中我们学习了Mybatis-Plus的概念、和Myabtis的区别、基本使用、条件查询等功能,初步了解了Mybatis-Plus的使用,提高我们操作数据库的效率。

下一节中我们将会继续学期Mybatis-Plus的其他用法,提高自己对Mybatis-Plus的使用熟练度。

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

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

相关文章

McDonald‘s Event-Driven Architecture 麦当劳事件驱动架构

原文链接 1 mcdonalds-technical-blog/ 原文链接 2 mcdonalds-technical-blog/ 麦当劳在异步、事务性和分析性处理用例中使用跨技术栈的事件&#xff0c;包括移动订单进度跟踪和向客户发送营销通信&#xff08;交易和促销&#xff09;。 统一事件平台&#xff08;unified eve…

【CSS in Depth 2 精译_089】15.2:CSS 过渡特效中的定时函数

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 15 章 过渡】 ✔️ 15.1 状态间的由此及彼15.2 定时函数 ✔️ 15.2.1 定制贝塞尔曲线 ✔️15.2.2 阶跃 ✔️ 15.3 非动画属性 文章目录 15.2 定时函数 Timing function…

一个开源的自托管虚拟浏览器项目,支持在安全、私密的环境中使用浏览器

大家好&#xff0c;今天给大家分享一个开源的自托管虚拟浏览器项目Neko&#xff0c;旨在利用 WebRTC 技术在 Docker 容器中运行虚拟浏览器&#xff0c;为用户提供安全、私密且多功能的浏览体验。 项目介绍 Neko利用 WebRTC 技术在 Docker 容器中运行虚拟浏览器&#xff0c;提供…

AW36518芯片手册解读(3)

接前一篇文章&#xff1a;AW36518芯片手册解读&#xff08;2&#xff09; 二、详述 3. 功能描述 &#xff08;1&#xff09;上电复位 当电源电压VIN降至预定义电压VPOR&#xff08;典型值为2.0V&#xff09;以下时&#xff0c;该设备会产生复位信号以执行上电复位操作&#x…

浅谈目前我开发的前端项目用到的设计模式

浅谈目前我开发的前端项目用到的设计模式 前言 设计模式很多&#xff0c;看到一个需求&#xff0c;项目&#xff0c;我们去开发的时候&#xff0c;肯定是做一个整体的设计进行开发&#xff0c;而在这次我项目中&#xff0c;我也做了一个整体的设计&#xff0c;为什么要设计&a…

线性规划中的几种逻辑表达式

线性规划中的几种逻辑表达式 注意&#xff1a; 摘录字刘博士的《数学建模与数学规划》&#xff0c; 以便用时可查。 实际上Gurobi API 中自身放啊变的逻辑表达式函数&#xff0c;下面列出自定义的实现方式。 1 逻辑与 如果 x 1 1 x_1 1 x1​1, x 2 1 x_2 1 x2​1, 那…

JVM对象分配内存如何保证线程安全?

大家好&#xff0c;我是锋哥。今天分享关于【JVM对象分配内存如何保证线程安全&#xff1f;】面试题。希望对大家有帮助&#xff1b; JVM对象分配内存如何保证线程安全&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中&#xff0c;对象的内存分配…

Antd react上传图片格式限制

限制分辨率&#xff08;像素&#xff09; <a-upload :before-upload"beforeUpload">// 上传图片宽高比例限制const beforeUpload file > {return new Promise((resolve, reject) > {// // 图片类型限制// let isJpgOrPng file.type image/png || fil…

基于 iAP2 协议 的指令协议,用于对安防设备的 MCU 进行操作

协议设计目标 1. 安全性&#xff1a;通过 iAP2 协议与 MCU 设备进行安全通信。 2. 通用性&#xff1a;支持对安防设备的常见功能进行操作&#xff0c;如状态查询、设备控制、参数配置等。 3. 高效性&#xff1a;数据结构简洁清晰&#xff0c;易于解析和扩展。 4. 扩展性&#x…

Type-C单口便携屏LDR6021

随着科技的飞速发展&#xff0c;便携式电子产品在我们的日常生活中扮演着越来越重要的角色。在这一背景下&#xff0c;Type-C单口便携显示器作为一种新兴的显示设备&#xff0c;凭借其独特的优势迅速崭露头角&#xff0c;成为市场的新宠。本文将深入探讨Type-C单口便携显示器的…

Ubuntu 20.04 卸载和安装 MySQL8.0

卸载 首先&#xff0c;检查一下系统安装的软件包有哪些&#xff0c;使用dpkg -l | grep mysql命令&#xff1a; 为了将MySQL卸载干净&#xff0c;这些文件都需要被删除。 在Ubuntu20.04系统下&#xff0c;卸载干净MySQL8.0以确保下一次安装不会出错&#xff0c;可以按照以下…

NOTEBOOK_11 汽车电子设备分享(工作经验)

汽车电子设备分享 摘要 本文主要列出汽车电子应用的一些实验设备和生产设备&#xff0c;部分会给予一定推荐。目录 摘要一、通用工具&#xff1a;二、测量与测试仪器2.1测量仪器2.2无线通讯测量仪器2.3元器件测试仪2.4安规测试仪2.5电源供应器2.6电磁兼容测试设备2.7可靠性环境…

黑马Java面试教程_P8_并发编程

系列博客目录 文章目录 系列博客目录前言1.线程的基础知识1.1 线程和进程的区别&#xff1f;难2频3面试文稿 1.2 并行和并发有什么区别&#xff1f; 难1频1面试文稿 1.3 创建线程的四种方式 难2频4面试文稿 1.4 runnable 和 callable 有什么区别 难2频3面试文稿 1.5 线程的 run…

【活动邀请·深圳】深圳COC社区 深圳 AWS UG 2024 re:Invent re:Cap

re:Invent 是全球云计算领域的顶级盛会&#xff0c;每年都会吸引来自世界各地的技术领袖、创新者和实践者汇聚一堂&#xff0c;分享最新的技术成果和创新实践&#xff0c;深圳 UG 作为亚马逊云科技技术社区的重要组成部分&#xff0c;将借助 re:Invent 的东风&#xff0c;举办此…

一起学Git【第二节:创建版本库】

创建库 这个库相当于一个目录&#xff0c;目录中的文件都被Git管理&#xff0c;会记录每个文件的修改删除和添加工作&#xff0c;便于之后随时跟踪历史记录还原到之前的某一版本。如何创建库呢&#xff1f;有两种方式&#xff0c;本地创建库和云端克隆一个库。 1.本地创建库 …

本地部署webrtc应用怎么把http协议改成https协议?

环境&#xff1a; WSL2 Ubuntu22.04 webrtc视频聊天应用 问题描述&#xff1a; 本地部署webrtc应用怎么把http协议改成https协议&#xff1f; http协议在安卓手机浏览器上用不了麦克风本&#xff0c;来地应用webrtc 本来是http协议&#xff0c;在安卓手机上浏览器不支持使…

web实操8-cookie

会话技术 会话&#xff1a; 一次会话中包含多次请求和响应。 客户端浏览器访问服务器的资源&#xff0c;只要客户端或者服务器端不关闭&#xff0c;这始终在一次会话范围内&#xff0c;这一次会话范围内可以包含多次请求并且收到多次相应。 一次会话&#xff1a;浏览器第一…

vue2 - Day03 - (生命周期、组件、组件通信)

文章目录 一、生命周期1. 创建阶段2. 挂载阶段3. 更新阶段4. 销毁阶段5. 错误捕获总结 二、组件2.1 注册1. 全局注册 - 公共的组件。2. 局部注册总结 2.2 三大重要的组成部分1. 模板 (Template)主要功能&#xff1a;说明&#xff1a; 2. 脚本 (Script)主要功能&#xff1a;说明…

java日常工作开发高并发问题

前言 本篇文章将是以工作中经常遇到的问题&#xff0c;和面试中经常遇到的java问题进行描写。内容包括微服架构&#xff0c;java并发编程以及相应的中间件的高级知识。本文所有的问题都在描述多线程编程的高级知识。 一. 面试题 1.Sychronized和ReentrantLock有哪些不同点? …

【Python】【数据分析】深入探索 Python 数据可视化:Matplotlib 绘图库完整教程

目录 引言一、什么是 Matplotlib&#xff1f;1.1 Matplotlib 的安装1.2 Matplotlib 的基本功能 二、Matplotlib 的基础绘图2.1 绘制折线图2.2 绘制柱状图2.3 绘制散点图2.4 绘制饼图 三、高级功能与定制3.1 设置图表样式3.2 使用子图3.3 保存图表 四、Matplotlib 流程图4.1 Mer…