MyBatis 操作数据库

news2024/11/26 22:42:16

一、什么是 MyBatis?

MyBatis 是是一个ORM 框架,ORM(Object Relational Mapping),即对象关系映射。底层实现是基于 JDBC 的,但是 MyBatis 隐藏了 JDBC 的复杂性,提供了简单易用的 API,将 SQL 语句和 Java 代码分离,让开发者能够通过 XML 或注解来描述 SQL 语句,并把结果映射到 Java 对象上。

简单来说 MyBatis 是更简单完成程序和数据库交互的工具,它可以帮助我们更方便、更快速的操作数据库。

二、MyBatis 前期准备工作

想要真正使用 MyBatis 操作数据库,我们首先要做足前期的准备工作,这其中就包括导入依赖、添加配置等操作。

1、导入依赖

一般来说需要添加如下两个依赖,分别是MyBatis框架、数据库驱动。

<!-- 添加 MyBatis 框架 -->
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>${mybatis-starter.version}</version>
</dependency>

<!-- 添加 MySQL 驱动 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>${mysql-connector.version}</version>
</dependency>

添加了 MyBatis 之后,为什么还需要添加 MySQL 驱动呢?

MyBatis 就像⼀个平台(类似京东),而数据库相当于商家有很多种,不止有 MySQL,还有 SQL Server、DB2
等等…因此这两个都是需要添加的。

2、添加数据库连接配置

这点和JDBC一样,添加连接配置就是为了让 MyBatis 连接到本机的数据库,下面是详细的配置信息:

# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/myblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Tips:spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 是配置Mysql数据库的驱动。如果使用 mysql-connector-java 是 5.x 之前的使用的是“com.mysql.jdbc.Driver”,如果是大于 5.x 使用的是“com.mysql.cj.jdbc.Driver”。

3、配置 MyBatis 中的 XML

MyBatis 是一个ORM 框架,能够通过 XML 或注解来描述 SQL 语句。所以一般在使用MyBatis实际操作数据库的时候,主要做两件事:

  1. 创建 Mapper 接口,并声明操作数据库的方法。
  2. 编辑 XML 文件。XML 文件对应着 Mapper 接口中方法的具体实现。

因此,配置 MyBatis 中的 XML 路径是为了告知 MyBatis 框架 SQL 映射文件所在的位置。下面是详细的配置信息:

# 配置 mybatis xml 的⽂件路径和命名格式
mybatis.mapper-locations=classpath:mapper/**Mapper.xml

注: 这条配置信息告知 MyBatis 框架从 “mapper” 目录开始,递归地加载所有以 “Mapper.xml” 结尾的文件作为 SQL 映射文件。这样,当调用Mapper中的接口时,就能够正确加载这些文件以执行相关的数据库操作。

4、创建 Mapper 接口、初始化 xml 文件

创建 Mapper 接口

@Mapper 
public interface UserMapper {

}

当我们使用 @Mapper 注解标记一个接口时,MyBatis 会在运行时动态地生成一个实现类,这个实现类会根据相应的 XML 文件中的配置来实现接口中定义的方法。这样,我们就可以直接调用接口中的方法来执行对应的 SQL 语句。

初始化 XML 文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--这里的namespace表明当前xml是实现那个接口的-->
<mapper namespace="com.example.demo.dao.UserMapper">
    
</mapper>

说明:

  1. 在创建XML文件时,路径命名格式 一定要和上面的配置相匹配。
  2. 下面XML中的格式化信息,前两行可认为是固定格式,重点了解 mapper 标签。mapper 中的 namespace 属性标明当前的 XML 文件是实现了哪一个接口中的方法的,因此这里的值是对应mapper接口的全限定名,即全包名.类名

方法的具体实现是在 xml 文件中 mapper 标签下的,具体实现步骤如下:

  1. 我们首先在 mapper 标签下添加具体的操作标签。比如查询就是<select></select>标签,修改是<update></update>……
  2. 完善操作标签中的属性。主要需要完善两个属性,id 对应实现的方法名;resultType 对应方法的返回类型,这里同样写全限定名。
  3. <select></select>标签里面编写具体的 SQL 语句。

三、MyBatis 增删改

PS: 如果是 添加修改删除 默认返回的是影响的行数,在 mapper.xml 中是可以不设置返回的类型的。

1、插入用户信息

方法声明:

    // 插入用户信息
    int insert(UserInfo userInfo);

方法实现:

    <insert id="insert" parameterType="com.lee.demo.model.User">
        insert into userinfo(username,password,photo)
        values(#{username},#{password},#{photo})
    </insert>

注: 在 MyBatis 中当我们传递的参数是一个对象时,我们想要拿到里面的属性值,直接写 属性名 即可,并不需要类.属性名.

由于添加、修改、删除 默认返回的是 受影响的行数。如果想要返回 自增 id,我们可以对实现部分稍作修改:

    <insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="com.lee.demo.model.User">
        insert into userinfo(username,password,photo)
        values(#{username},#{password},#{photo})
    </insert>
  1. parameterType属性:parameterType 用于指定映射语句(Mapper)的输入参数类型,可以是任何Java类的完全限定名。在MyBatis中,parameterType是可以省略的。当parameterType没有指定时,MyBatis会根据传入的参数自动推断其类型。
  2. useGeneratedKeys 属性:指定是否使用自动生成的主键。如果设置为 true,则表示插入数据后将获取数据库生成的主键值。
  3. keyColumn 属性:指定用于存储自动生成的主键值的表列名。
  4. keyProperty 属性:指定用于存储自动生成的主键值的 Java 对象属性名。

注: 做出了上述修改后并不是说,方法返回值变成了自增 id,而是传入的 UserInfo 对象中的 id 属性值被设置成了自增 id 值

2、删除指定用户信息

方法声明:

    // 根据用户 id 删除指定用户信息
    int delById(@Param("id") Integer id);

方法实现:

    <delete id="delById" parameterType="java.lang.Integer">
        delete from userinfo where id=#{id}
    </delete>

@Param 注解的主要作用就是为传入 Mapper 方法的参数进行命名,方便在 XML 配置文件中引用。如果传入的参数是一个业务对象,通常情况下不需要使用 @Param 注解来明确命名的。

3、修改指定用户信息

方法声明:

    // 根据用户 id 修改用户名
    int update(@Param("id") Integer id ,@Param("username") String username);

方法实现:

    <update id="update" parameterType="java.lang.Integer">
        update userinfo set username=#{username} where id=#{id}
    </update>

四、MyBatis 查询

1、创建实体类,并实现 setter 方法

  1. 创建实体类是为了将数据库表的记录映射到对象上,并提供方便的数据访问和操作。
  2. 当MyBatis将数据库查询结果映射到实体类时,它会查找实体类中与数据库列对应的属性,并尝试调用该属性的 setter 方法来设置值。如果实体类没有提供 setter 方法,MyBatis将无法将查询结果正确地赋值给实体类的属性。
@Data
public class UserInfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}

2、查询 userinfo 表中的所有信息

方法声明(接口):

方法的声明是放到 mapper 接口中的,在接口中只需要添加一条对应操作的方法声明即可,具体实现放到 xml 中。

@Mapper
public interface UserMapper {
    // 查询 userinfo 表中的所有信息
    List<UserInfo> getAllUserInfo();

}

方法实现(xml):

<mapper namespace="com.example.demo.dao.UserMapper">
    <select id="getAllUserInfo" resultType="com.example.demo.model.UserInfo">
        select * from userinfo;
    </select>
</mapper>

3、根据登录信息,查询 userinfo

方法声明(接口):

    // 根据登录信息,查询 userinfo
    UserInfo getByLogin(@Param("username") String username,@Param("password") String password);

方法实现(xml):

方式一: 使用${}接收参数

    <select id="getByLogin" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username='${username}' and password='${password}'
    </select>

方式二: 使用#{}接收参数(推荐)

    <select id="getByLogin" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username=#{username} and password=#{password}
    </select>

当然,从功能上来说,以上两种方式都可以成功接收参数,并查询结果,但是二者有着本质上的区别。

4、${}、#{} 与 SQL 注入问题

(1)${}#{} 的区别:

  1. #{}:预编译处理:MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的 set 方法来赋值。

  2. ${}:直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

  3. 由于 #{} 是预编译处理,会自动进行参数类型转换和安全处理,一般来说是安全的。而 ${} 是直接替换,存在着 SQL 注入的安全性问题。

下面我们演示一下使用 ${} 占位符导致的 SQL 注入 问题:

通过上述结果我们可以看到,当我们使用 ${} 进行占位时,执行时会将参数的值和 ${} 直接替换,如果此时传入一个特殊的数据:' or 1 = '1,会导致SQL查询语句改变原意或执行额外的恶意操作。

(2)${} 存在的意义:

既然使用 ${} 能实现的功能 #{} 也能实现,并且 ${} 还有 SQL 注入的风险,那么 ${} 存在的意义是什么呢?其实这句话的说法过于绝对,存在即合理,${} 有其独特的应用场景。例如最常见的 排序查询

同样是上述查询所有的 userinfo 信息,如果我们想要拿到排序的结果,那么在 xml 中,我们只能使用 ${} 实现,而不能使用 #{} 实现:

    <select id="getAllUserInfo" resultType="com.example.demo.model.UserInfo">
        select * from userinfo order by id ${sort}
    </select>

原因: 因为当使用 #{sort} 查询时,只能传入 asc、desc。如果传递的值为 String 则会加单引号,就会导致 sql 错误,因为 sql 命令不能加引号。这点也是利用了 ${} “直接替换”的特性。

虽然必要的时候可以使用 ${} ,但是使用不规范还是存在安全问题,下面就归纳了两点使用 ${} 的注意事项:

  1. ${} 适用场景:当业务需要传递 sql 命令 时,只能使用 ${} 不能使用 #{}。
  2. ${} 注意事项:如果使用 ${} ,那么传递的参数一定要能够穷举,否则存在 sql 注入风险。

5、like 模糊查询

方法声明:

    // 模糊查询
    List<UserInfo> fuzzyQuery(@Param("str") String str);

这里 like 后从参数有三种书写方式:

  • 方式1: like #{str},这种方式需要在传递参数时,传递 %。
  • 方式2: like "%${str}%",可以实现功能,但是存在 sql 注入风险。
  • 方式3: like concat('%',#{str},'%'),对字符串进行拼接,最优选择。

方法实现:

    <select id="fuzzyQuery" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username like concat('%',#{str},'%')
    </select>

6、多表联查

下面我们以查询 articleinfo 表中的信息为例,要求查询结果包含作者名。

创建一个用于接受多表联查结果的实体类:

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int rcount;
    private int state;
    // 联表字段
    private String username;
}

声明 Mapper 方法,并使用注解实现操作 SQL:

@Mapper
public interface ArticleMapper {
    @Select("select articleinfo.*,userinfo.username from userinfo,articleinfo where articleinfo.uid=userinfo.id")
    List<ArticleInfo> getAllArticle();
}

7、返回类型 resultMap

上面我们说到,如果是 添加修改删除 默认返回的是影响的行数,在 mapper.xml 中是可以不设置返回的类型的。但是对于 查询标签来说即便是最简单的查询 返回类型 也是不可以省略的。

对于 <select></select> 返回结果主要有两种映射属性 resultMapresultType,对于 resultType 来说,它的最大优点就是使用方便,直接定义到某个实体类即可。而 resultMap 相对来说就比较麻烦了,下面就详细介绍一下 resultMap 两个高频应用场景:

  1. 字段名称和程序中的属性名不同的情况,可使用 resultMap 配置映射。
  2. 一对一和一对多关系可以使用 resultMap 映射并查询数据。

(1)字段名和属性名不一致情况处理

这里的不一致,指的是数据库表中的字段名和类中的属性名不一致的情况。我们知道,MyBatis 框架提供了自动映射功能,如果字段名和属性名一致,能够自动将查询结果映射到对象中的对应属性。

但是开发中可能有些场景下需要使用不同于字段名的属性名,例如上面的实体类中,我们将文章实体类(ArticleInfo)中的连表字段修改为 author,我们又该如何处理呢?下面给出两种解决方案:

方案一:使用 sql 语句中的 as 进行字段名重命名,让字段名等于属性名。

    <select id="getAllArticle" resultType="com.example.demo.model.ArticleInfo">
        select articleinfo.*,userinfo.username as author
        from userinfo,articleinfo
        where articleinfo.uid=userinfo.id
    </select>

方案二:定义一个 resultMap,将属性名和字段名进行手动映射。

    <!-- 定义一个 resultMap -->
    <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
        <id column="id" property="id"></id>
        <result column="title" property="title"></result>
        <result column="content" property="content"></result>
        <result column="createtime" property="createtime"></result>
        <result column="updatetime" property="updatetime"></result>
        <result column="rcount" property="rcount"></result>
        <result column="state" property="state"></result>
        <!-- 联表字段 -->
        <result column="username" property="author"></result>
    </resultMap>
    
    <select id="getAllArticle" resultMap="BaseMap">
        select articleinfo.*,userinfo.username
        from userinfo,articleinfo
        where articleinfo.uid=userinfo.id
    </select>

说明:

  1. <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">:定义了一个名为 “BaseMap” 的 resultMap,这个 resultMap 用于将查询结果映射到 ArticleInfo 对象上。
  2. <id column="id" property="id"></id>:定义了一个主键映射,将数据库中名为 “id” 的列映射到 ArticleInfo 对象的 “id” 属性上。
  3. <result column="username" property="author"></result>:定义一个普通属性映射,将数据库中名为 “username” 的列映射到 ArticleInfo 对象的 “author” 属性上。
  4. resultMap 属性指定了结果映射的名称,这里是 “BaseMap”。

(2)一对一的联表查询结果

在多表查询时,在一个类中包含了另外一个或多个对象,如果使用 resultType 标签,是查询不出来被包含的对象
的(会置为 null)。

那么遇到这种场景具体该怎么处理呢?答案就是在 resultMap 中使用 <association/><association></association>标签 。

例如为了查询到文章表以及文章表管理的用户表、板块表信息,我新建了一个文章实体类 ArticleExt,其中包含了一些文章相关的属性,同时也包含关联的用户对象属性和板块对象属性。现在我进行联表查询,要求将查询出来的结果赋值到当前定义的文章实体类中。

文章实体类:

@Data
public class ArticleExt {
    private Long id;

    private Long boarId;

    private Long userId;

    private String title;

	// ...

    // 拓展所属作者字段
    private User user;
    // 拓展所属板块字段
    private Board board;
}

定义查询语句:

<select id="selectAll" resultMap="AllInfoResultMap">
    select u.id as u_id,
    u.avatarUrl as u_avatarUrl,
    u.nickname as u_nickname,
    u.gender as u_gender,
    u.isAdmin as u_isAdmin,
    u.state as u_state,
    u.deleteState as u_deleteState,
    b.id as b_id,
    b.name as b_name,
    b.state as b_state,
    b.deleteState as b_deletState,
    a.id,
    a.boarId,
    a.userId,
    a.title,
    from t_article as a,t_user as u,t_board as b
    where
    a.userId = u.id
    and
    a.boarId = b.id
</select>

AllInfoResultMap 具体实现:

  1. 分别在这三个表对应的 xml 文件下创建三个 resultMap ,分别表示 文章表映射、用户表映射、板块表映射。
  2. 在文章表对应的 xml 文件下再定义一个 resultMap 用来表示 ArticleExt 的结果映射。
  3. 在 步骤 2 定义的 resultMap 中使用 <association/> 标签关联对应映射。
  <!-- 自定义结果集映射 -->
  <resultMap id="AllInfoResultMap" type="com.lee.forum.model.ArticleExt" extends="com.lee.forum.dao.ArticleMapper.BaseResultMap">
      <!-- 关联的用户的映射 -->
      <association property="user" resultMap="com.lee.forum.dao.UserMapper.BaseResultMap" columnPrefix="u_"/>
      <!-- 关联的板块的映射 -->
      <association property="board" resultMap="com.lee.forum.dao.BoardMapper.BaseResultMap" columnPrefix="b_"/>
  </resultMap>

说明:

  1. resultMap中的extends属性:用于指定当前resultMap继承自其他 resultMap。
  2. association中的property 属性:指定 Article 中对应的属性名。
  3. association中的resultMap 属性:指定关联的结果集映射,将基于该映射配置来组织关联数据。
  4. association中的columnPrefix 属性:绑定一对一对象时,是通过 columnPrefix+association.resultMap.column 来映射结果集字段。association.resultMap.column 对应的结果集映射中,column字段。

注意: columnPrefix 属性用于区分链表中相同的字段名,通常不能省略,如果省略当联表中如果有相同的字段,那么就会导致查询出错。

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

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

相关文章

MedianFlow 跟踪算法详解

在技术日新月异的时代&#xff0c;今天的技术可能在明天就会被新的技术取代&#xff0c;例如现在爆火的大模型。但目前看来&#xff0c;大模型还不能做到无所不能。 所以这篇博客还是来考古一下&#xff0c;写一下传统的跟踪算法。这里不是为了怼大模型而为了写一篇传统算法而…

【1++的Linux】之线程(一)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;Linux线程概念二&#xff0c;线程的优缺点进程和线程类比现实 三&#xff0c; 线程的操作线程的私有资源 && 线程的创建线程的等待线程终止线程分离…

初学Flutter:swiper实现

效果展示&#xff1a; flutter swiper 1、安装 card_swiper 2、引入card_swiper import package:card_swiper/card_swiper.dart;3、使用 这里我主要是对官网例子进行实践&#xff0c;主要是5种常用的swiper 1、普遍的swiper //custom swiper class CustomSwiper extends S…

下载安装各种版本的Vscode以及解决VScode官网下载慢的问题

下载指定版本 在Vscode官网 Vscode官网更新子页 这里的左侧栏点击其中一个会跳转到某个版本&#xff0c;或者在官网子页 https://code.visualstudio.com/updates的后面跟上需要的版本号即可完成目标版本下载页面的跳转 选择Linux里的ARM包不会自动下载而是跳转到另一个页面 …

vue-admin-template 安装遇到的问题

vue-element-admin 是一个后台前端解决方案&#xff0c;它基于 vue 和 element-ui实现。 参考文档&#xff1a; 官网&#xff1a; https://panjiachen.github.io/vue-element-admin-site/zh/guide/#%E5%8A%9F%E8%83%BD遇到的问题&#xff1a; npm ERR! Error while executing…

移动硬盘怎么加密?移动硬盘加密怎么设置?

在工作中&#xff0c;我们经常需要使用移动硬盘来保存重要数据&#xff0c;但是这样却不能保护重要数据的安全。所以&#xff0c;我们可以使用加密来保护移动硬盘。那么&#xff0c;移动硬盘要怎么加密呢&#xff1f; U盘超级加密3000 U盘超级加密3000是一款专业的移动储存设备…

Java类加载机制(类加载器,双亲委派模型,热部署示例)

Java类加载机制 类加载器类加载器的执行流程类加载器的种类加载器之间的关系ClassLoader 的主要方法Class.forName()与ClassLoader.loadClass()区别 双亲委派模型双亲委派 类加载流程优缺点 热部署简单示例 类加载器 类加载器的执行流程 类加载器的种类 AppClassLoader 应用类…

利用maven的dependency插件分析工程的依赖

dependency:analyze https://maven.apache.org/plugins/maven-dependency-plugin/analyze-mojo.html 分析项目的依赖&#xff0c;确定哪些&#xff1a;用了并且声明了、用了但没有声明、没有使用但声明了。 dependency:analyze可以单独使用&#xff0c;所以它总是会执行test-…

【算法练习Day38】零钱兑换完全平方数

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 零钱兑换完全平方数总结&am…

软件测试:单元测试、集成测试、系统测试详解

实际的测试工作当中&#xff0c;我们会从不同的角度对软件测试的活动进行分类&#xff0c;题主说的“单元测试&#xff0c;集成测试&#xff0c;系统测试”&#xff0c;是按照开发阶段进行测试活动的划分。这种划分完整的分类&#xff0c;其实是分为四种“单元测试&#xff0c;…

TablePlus for Mac 数据库管理工具功能介绍

TablePlus是一款功能强大的数据库管理工具&#xff0c;专为Mac操作系统设计。它支持多种主流数据库&#xff0c;包括MySQL&#xff0c;PostgreSQL&#xff0c;SQLite&#xff0c;Microsoft SQL Server&#xff0c;Amazon Redshift等等。无论您是开发人员、数据库管理员还是数据…

【2024最新】Android Debug Bridge【下载安装】零基础到大神【附下载链接】

一、ADB简介 1、什么是adb ADB 全称为 Android Debug Bridge&#xff0c;起到调试桥的作用&#xff0c;是一个客户端-服务器端程序。其中客户端是用来操作的电脑&#xff0c;服务端是 Android 设备。 ADB 也是 Android SDK 中的一个工具&#xff0c;可以直接操作管理 Androi…

多个PDF发票合并实现一张A4纸打印2张电子/数电发票功能

python教程79--A4纸增值税电子发票合并打印_python 打印 发票设置_颐街的博客-CSDN博客文章浏览阅读7.9k次。接上篇https://blog.csdn.net/itmsn/article/details/121902974?spm1001.2014.3001.5501一张A4纸上下2张增值税电子发票实现办法。使用环境&#xff1a;python3.8、ma…

【C++基础知识学习笔记】精华版(复习专用)

常用语法 函数重载(Overload) 规则: 函数名相同 参数个数不同、参数类型不同、参数顺序不同 注意: 返回值类型与函数重载无关 调用函数时,实参的隐式类型转换可能会产生二义性 默认参数 C++ 允许函数设置默认参数,在调用时可以根据情况省略实参。规则如下: 默认参数只能…

chinese_llama_aplaca训练和代码分析

训练细节 ymcui/Chinese-LLaMA-Alpaca Wiki GitHub中文LLaMA&Alpaca大语言模型本地CPU/GPU训练部署 (Chinese LLaMA & Alpaca LLMs) - 训练细节 ymcui/Chinese-LLaMA-Alpaca Wikihttps://github.com/ymcui/Chinese-LLaMA-Alpaca/wiki/%E8%AE%AD%E7%BB%83%E7%BB%86%E…

selenium自动化测试入门 —— 获取元素对象!

一、元素定位简介 八种属性定位页面元素&#xff1a; By.ID By.XPATH By.LINK_TEXT By.PARTIAL_LINK_TEXT By.NAME By.TAG_NAME By.CLASS_NAME By.CSS_SELECTOR webdriver元素定位方法&#xff1a; driver.find_element(By.XXX,元素属性) # 定位单个元素 driver.find_elemen…

按键精灵中常用的命令

1. 声明变量&#xff1a; Dim 2. 注释语句 (1). 单行注释&#xff1a;这是一行注释&#xff0c;使用一个单引号进行注释&#xff1b; (2). 单行注释&#xff1a;// 这是一行注释&#xff0c;使用一对反斜杠进行注释; (3). 多行注释&#xff1a;/*这是多行注释&#xff0c;中…

canal+es+kibana+springboot

1、环境准备 服务器&#xff1a;Centos7 Jdk版本&#xff1a;1.8 Mysql版本&#xff1a;5.7.44 Canal版本&#xff1a;1.17 Es版本&#xff1a;7.12.1 kibana版本&#xff1a;7.12.1 软件包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1jRpCJP0-hr9aI…

基于野狗算法的无人机航迹规划-附代码

基于野狗算法的无人机航迹规划 文章目录 基于野狗算法的无人机航迹规划1.野狗搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用野狗算法来优化无人机航迹规划。 1.野狗搜索算法 …

前端面试题整理(一)

前言&#xff1a; 这篇博客是记录自己在看面试过程中还未完全掌握的前端知识点&#xff0c;也是一些前端面试需要掌握的知识点&#xff08;总结的并不全面&#xff0c;可以参考&#xff0c;具体情况以自己实际为准&#xff09;,并且这篇博客正在持续更新中… 附言&#xff1a…