MyBatis(该篇足已)

目录

一.MyBatis是什么?

二.为什么学习MyBatis呢?

三.MyBatis的学习

3.1MyBatis的开发流程

3.2MyBatis项目

四.MyBatis的增删改操作

五.参数占位符 #{} 和 ${}

六.映射返回

七.映射失败

八.数据库连接池

九.动态SQL

9.1<if>标签

9.2<trim>标签

9.3<where>标签

9.4<set>标签

9.5<foreach>标签

9.6<include>标签


一.MyBatis是什么?

  1. MyBatis 是一款优秀的半自动的ORM持久层框架,它支持自定义 SQL、存储过程以及高级映射。
  2. MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  3. MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

ORM介绍:

        ORM代表对象关系映射(Object-Relational Mapping),它是一种编程技术,用于在关系数据库和面向对象编程语言之间建立一种映射关系,从而将数据库中的数据以对象的形式进行操作和访问。

半自动的原因:

  1. 手动编写SQL语句:与全自动的ORM框架不同,MyBatis需要开发者手动编写SQL语句或者使用XML配置文件来定义SQL映射。这使得开发者可以更精确地控制SQL查询的逻辑,包括优化查询性能、处理复杂的查询需求等。

  2. 灵活的映射配置:MyBatis允许开发者通过XML配置文件或者注解来定义对象与数据库表之间的映射关系,包括字段映射、关联关系等。这种灵活性使得开发者可以根据具体需求进行定制化配置。

  3. 不强制使用领域模型:MyBatis不强制要求开发者使用特定的领域模型,开发者可以自由选择使用普通的Java对象或者自定义的POJO(Plain Old Java Object)作为持久化对象。这种灵活性使得开发者可以更加灵活地设计应用程序的数据模型。

二.为什么学习MyBatis呢?

        对于后端人员,获取数据库的信息,是需要从后端程序当中获取,而如何获取,最常用的方法就是JDBC方法!

往常使用JDBC的步骤:

  1. 创建数据库连接池 DataSource
  2. 通过 DataSource 获取数据库连接 Connection
  3. 编写要执⾏带 ? 占位符的 SQL 语句
  4. 通过 Connection 及 SQL 创建操作命令对象 Statement
  5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
  6. 使⽤ Statement 执⾏ SQL 语句
  7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
  8. 处理结果集
  9. 释放资源

        从上述代码和操作流程可以看出,对于 JDBC 来说,整个操作⾮常的繁琐,我们不但要拼接每⼀个参 数,而且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接等, 而所有的这些操作步骤都需要在每个⽅法中重复书写。

因此我们需要学习更为简便的MyBatis操作数据库

注:如果你硬要说可以使用ComboPooledDataSource也可以简化代码,我就不想用MyBatis,那你就杠吧!

三.MyBatis的学习

3.1MyBatis的开发流程

        MyBatis 也是⼀个 ORM 框架, ORM(Object Relational Mapping),即对象关系映射。在⾯向对象编程语言中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
  1. 将输⼊数据(即传⼊对象)+SQL 映射成原生 SQL
  2. 将结果集映射为返回对象,即输出对象

所谓的映射(数据库<-->对象):

  • 数据库表(table)--> 类(class)
  • 记录(record,⾏数据)--> 对象(object)
  •  字段(field) --> 对象的属性(attribute)
流程图

        调用者向Controller层请求数据,因此会逐层调用到Mapper层,Mapper层通过接口和配置文件.xml来进行调用数据库的数据。因此很明显,我们需要配置的环境有两个地方,一个是xml配置文件,一个是接口的定义。

当然,我们需要在application.yml当中配置好数据库连接配置 ,后期在创建项目当中会有详细讲解。

3.2MyBatis项目

        第一步.我们创建一个SpringBoot项目。并且勾选好需要的依赖!

问:或许有人问,我都添加了MyBatis依赖,我为什么还要添加MySql驱动呢?   

答:MyBatis只是一个持久层框架,它本身并不包含数据库驱动,而是依赖于特定的数据库驱动来连接和操作数据库。MySQL数据库驱动是一个单独的库,它负责与MySQL数据库建立连接、执行SQL语句等数据库操作。因此,你需要将MySQL数据库驱动添加到项目的依赖中,以便MyBatis能够使用它来与MySQL数据库进行交互。

第二步:创建数据库 名MyBatis,在其中搞一个表

create database MyBatis DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
use mycnblog;
-- 创建表[⽤户表]
drop table if exists userinfo;
create table userinfo(
 id int primary key auto_increment,
 username varchar(100) not null,
 password varchar(32) not null,
 photo varchar(500) default '',
 createtime datetime default now(),
 updatetime datetime default now(),
 `state` int default 1
) default charset 'utf8mb4';

自己插入一系列数据:

第三步:配置好数据库连接的yml文件和MyBatis的xml路径

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/库名?characterEncoding=utf8&useSSL=false
    username: root
    password: 密码
    driver-class-name: com.mysql.cj.jdbc.Driver

# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

解析:设置MyBatis的xml路径,是为了告诉MyBatis去指定的位置寻找mapper文件,以便读取其中的SQL语句和映射配置

第四步:添加实体类

添加的实体类当中的属性需要和我们创建的表字段名一致,这是一致性!

import lombok.Data;
import java.util.Date;
@Data
public class User {
     private Integer id;
     private String username;
     private String password;
     private String photo;
     private Date createTime;
     private Date updateTime;
}

第五步:添加mapper接口

  数据持久层的接口定义:      

import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
 public List<User> getAll();
}

第六步:添加UserMapper.xml

如果想要实现数据持久层的,我们需要添加一个Mapper的xml格式!

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
 <select id="getAll" resultType="com.example.demo.model.User">
 select * from userinfo
 </select>
</mapper>

详细说明: 

标签的说明:
  • <mapper>标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接⼝的全限定 名,包括全包名.类名。
  • <select>查询标签:是⽤来执⾏数据库的查询操作的:
    • id:是和 Interface(接⼝)中定义的⽅法名称⼀样的,表示对接⼝的具体实现⽅法resultType:是返回的数据类型,也就是开头我们定义的实体类。

第五、六步化作一步的方法:

        我们直接在Mapper接口上使用sql语句,执行调用。代码如下:

@Mapper
public interface UserMapper {
   @Select("select * from userinfo")
   public List<User> getAll();
}

不需要配置文件,直接调用,然后就会执行该方法

第七步:添加Service

这一步是为了Controller层调用而使用

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class UserService {
 @Resource
 private UserMapper userMapper;
 public List<User> getAll() {
 return userMapper.getAll();
 }
}

第八步:Controller层不调用,直接进行测试代码

@SpringBootTest
class BlogMyBatisApplicationTests {
    @Autowired
    private UserService userService;
    @Test
    void contextLoads() {
        List<User> t1= userService.getAll();
        for(User user: t1){
            System.out.println(user.toString());
        }
    }
}

结果:

四.MyBatis的增删改操作

        MyBatis要实现增加、删除和修改的操作,对应使⽤ MyBatis 的标签如下:

  • <insert>标签:插⼊语句
  • <update>标签:修改语句
  • <delete>标签:删除语句

没有主键的插入代码:

<insert id="add2" useGeneratedKeys="true" keyProperty="id">
     insert into userinfo(username,password,photo,state)
     values(#{username},#{password},#{photo},1)
</insert>
  • useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据 库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
  • keyColumn:设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果生成列不止⼀个,可以⽤逗号分隔多个属性 名称。
  • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果生成列不止⼀个,可以⽤逗号分隔多个属性名称。

修改操作:

<update id="update">
 update userinfo set username=#{name} where id=#{id}
</update>

删除操作:

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

parameterType:表示的是删除的行数。

五.参数占位符 #{} 和 ${}

        在增删查找里,我们可以发现我们使用了#{} 或者 ${},那么两者之间的区别?

  • #{}:预编译处理。
        预编译处理是指:MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 号,使⽤ PreparedStatement的 set ⽅法来赋值。
  • ${}:字符直接替换。
    直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。如果是字符串类型,则会自动加单引号。容易SQL 注入攻击

或许你看不懂,但是我直接举例几种常见的情况:

情况一:使用${}的情况下,字符串会变成单引号:

UserMapper接口:

@Mapper
public interface UserMapper {
    User get(String name);
}

Service服务层:

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    public User get(String name) {
    return userMapper.get(name);
    }
}

配置文件:

测试方法:

    @Autowired
    private UserService userService;
    @Test
    void contextLoads() {
        String name = "tq02";
        User t1= userService.get(name);
        System.out.println(t1.toString());
    }

测试结果:

解析:获取tq02字符串时,实际获取的是 'tq02' ,而不是tq02.想要避免这种情况,从配置文件入手,在${name}上,添加一个单引号:

    <select id="get" resultType="com.example.blog_mybatis.model.User">
        select * from userinfo where username = '${name}';
    </select>

情况二:使用${}的情况下,却不传递任何值

 配置文件:

<select id="getAllBySort" parameterType="java.lang.String" resultType="com.
example.demo.model.User">
 select * from userinfo order by id ${sort}
</select>

Mapper接口:

@Mapper
public interface UserMapper {
    void getAllBySor();
}

编译结果:

        当 ${sort} 没有传递数据时,MyBatis 会将 ${sort} 原封不动地插入到 SQL 查询语句中,导致最终执行的 SQL 查询语句:select * from userinfo order by id

情况三:使用${}的情况下,却乱传递值

配置文件 UserMapper.xml

<select id="getUsersByCondition" resultType="User">
    SELECT * FROM user WHERE name = '${name}'
</select>

接口还是第一种的方式,但是我传递的值如果是  tq03' or '1' = '1  呢?

你会发现返回值不再是一个User类,而是表的全部结果,因为 or '1' = '1 ' 总是为真

而这种情况就是SQL 注入攻击


情况四:使用#{}的情况下,传递值为String类型

和情况一,一样,只不过把#变成$。

你会发现,会正常运行,返回数据。

情况五:使用${}的情况下,不传递值

会报错,sql语句会显示?

情况五:使用#{}的情况下,胡乱传递

与情况三的操作一致,只不过唯一的区别是,$变为了# ,就会变成:

SELECT * FROM userinfo WHERE username = 'tq02\' OR \'1\'=\'1'

这种情况下\’会变成空字符:也就是后半部分为:username = ' tq02' OR 1'=1' '


在传统的 SQL 查询中,通常使用单引号 ' 来表示字符串的开始和结束因此,如果在字符串中需要包含单引号本身,需要使用转义字符 \ 来转义,表示单引号不是字符串的结束,而是字符串的一部分。

 表中数据存在时:

只不过在数据库查询时,我们不能直接使用单引号,我们需要转义字符 \’ 

情况六:使用#{}的情况下,模糊查询 like

        like查询不能直接使用 #{}

 <select id="findUserByName2" resultType="com.example.demo.model.User">
     select * from userinfo where username like '%#{username}%';
 </select>

相当于:

sql语句:select * from userinfo where username like '%'username'%';

这种情况也不能使用${}的,我们需要使用内置函数concat() 来处理,

<select id="findUserByName3" resultType="com.example.demo.model.User">
 select * from userinfo where username like concat('%',#{usernam
e},'%');
</select>

六.映射返回

1.增、删、改返回的是影响的行数,但是在mapper.xml 中是可以不设置返回的类型。但如果是数据,例如是String类型的数据,不返回就报错!

正确情况下,使用resultType:

<select id="getNameById" resultType="java.lang.String">
 select username from userinfo where id=#{id}
</select>

2.parameterType和resultType:

   parameterType可以来明确指定传递的参数类型,但是简单情况下,可以不设置,MyBatis 会尝试根据传递的参数来推断参数类型,然后将参数传递给 SQL 语句。

特殊情况下:

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

这种情况下,指定传递的参数类型为int,但是我的username却是String类型啊

解析:尽管 parameterType 被设置为 java.lang.Integer,但你仍然可以在 SQL 语句中引用其他类型的参数,只要参数名正确匹配即可。因此,设置 parameterType 的目的是为了提高代码的可读性和可维护性,以及防止类型不匹配或错误的结果发生。

        ResultType用于指定查询结果的类型的属性。在 MyBatis 中, ResultType 用于映射 SQL 查询的结果到 Java 对象或基本数据类型,和parameterType不一样,当需要返回值不为影响的行数时,必须写上去。

3.返回字典映射:resultMap

resultMap 使用场景:
  • 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
  • ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据。

我们的表中字段和数据库字段名不同

而类中实际的属性:

对比发现:表中的password变成了pas,那我们进行查询时,这个属性是永远装到不表中的password数据,

此时此刻,我们为了让这个类和我们的数据表匹配,可以使用:resultMap

<resultMap id="BaseMap" type="com.example.demo.model.User">
 <id column="id" property="id"></id>
 <result column="username" property="username"></result>
 <result column="password" property="pwd"></result>
</resultMap>

此时此刻,我们查询就有了结果的。

一对一的表映射的情况

        换句话,一对一的映射就是指,一个类和一张表对应,只不过,我们使用一些标签使其属性和字段名映射成功。

<resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
 <id property="id" column="id"></id>
 <result property="title" column="title"></result>
 <result property="content" column="content"></result
 <result property="createtime" column="createtime"></result>
 <result property="updatetime" column="updatetime"></result>
 <result property="uid" column="uid"></result>
 <result property="rcount" column="rcount"></result>
 <result property="state" column="state"></result>
 <association property="user"
 resultMap="com.example.demo.mapper.UserMapper.BaseMap"
 columnPrefix="u_">
 </association>
</resultMap>

<select id="getAll" resultMap="BaseMap">
 select a.*,u.* from articleinfo a
 left join userinfo u on u.id=a.uid
 </select>

如上图,我们使用了<association>标签,表示⼀对⼀的结果映射:

  • property 属性:指定 Article 中对应的属性,即⽤户。
  • resultMap 属性:指定关联的结果集映射,将基于该映射配置来组织⽤户数据。
  • columnPrefix 属性:指定了关联查询中,关联表(userinfo表)的列名前缀,效果类似 as

注:columnPrefix 属性不能省略,原因:省略当联表中如果有相同的字段,那么就会导致查询出来的列名会有重复。重复情况下:

id列有2行,可见性差。

一对多的情况下:

        一对多指的是一个类中有一个列表,而数据库却不能存在改字段:

例如:两个实体类 UserArticle

public class User {
    private Long id;
    private String username;
    private List<Article> articles; // 用户拥有的文章列表,使用集合类型表示
    // 省略其他属性和方法
}

public class Article {
    private Long id;
    private String title;
    private Long userId; // 文章所属用户的ID,用于关联查询
    // 省略其他属性和方法
}

假设你有两表,结构如下:

  •  uer_info表包含用户信息:

    • id
    • username
  • article_info 表包含文章信息:

    • id
    • title
    • user_id (对应用户表中的 id)

七.映射失败

        当数据库的表名和属性不一致时,有三种解决方法:

  1. 起别名
  2. 结果映射 ,第6部分写了详细内容,这里再举其他方式
  3. 开启驼峰命名

起别名:

@Select("select id, username, 'password', age, gender, phone, delete_flag as del
 "create_time as createTime, update_time as updateTime from userinfo")
 public List<UserInfo> queryAllUser();

结果映射:

 @Select("select delete_flag, creat_time,update_time from userinfo)
 @Results({
    @Result(column = "delete_flag",property = "deleteFlag"),
    @Result(column = "create_time",property = "createTime"),
    @Result(column = "update_time",property = "updateTime")
})
List<UserInfo> queryAllUser();

colum:表示数据库的字段,porperty表示类的属性,

如果我查询很多语句,那我岂不是要重写很多段@Results注解?

便利方法:

如果其他SQL, 也希望可以复⽤这个映射关系, 可以给这个Results定义⼀个名称

开启驼峰命名

        数据库字段和类属性的不一致,原因:数据库列使⽤蛇形命名法进⾏命名(下划线分割各个单词), ⽽ Java 属性⼀般遵循驼峰命名法约定.

解决方法:为了在这两种命名⽅式之间启⽤⾃动映射,需要将 mapUnderscoreToCamelCase 设置为 true。

 mybatis:
    configuration:
        map-underscore-to-camel-case: true #配置驼峰⾃动转换

八.数据库连接池

        连接池介绍: 数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接。⽽不是再重新建⽴⼀个(开销太大了)

 

在常见的连接池当中,我们常用的几种:

  1. C3P0
  2. DBCP
  3. Druid
  4. Hikari

在MyBatis当中,以及内置好了连接池,可以直接使用,而默认的是Hikari,证据如下:

如果我们想使用其他连接池,可以通过加载对应的jar包。

九.动态SQL

        动态 SQL 在 MyBatis 中的存在是为了处理那些需要在运行时根据条件动态生成的 SQL 语句。这种特性允许我们在一个映射文件中编写复杂的 SQL 查询,并根据不同的条件生成不同的 SQL 语句,而不需要写多个相似的 SQL 查询。

9.1<if>标签

例如,查询操作,当你查询某个人时,可以通过姓名、性别、年龄等查询,但查询时,我们难道应该写多个sql语句吗?进行分别查询吗?

nonono!

我们可以直接使用动态语句:

<select id="getUsers" parameterType="map" resultType="User">
    SELECT * FROM user_info
    where
        <if test="username != null">
            AND username = #{username}
        </if>
        <if test="sex != null">
            AND sex = #{sex}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
</select>

<if> 标签根据传入的参数来动态生成 WHERE 子句,如果 usernamesex和age 参数哪些存在,则会同时根据存在的条件查询用户信息。

9.2<trim>标签

        和<if>标签搭配使用,当你查询或者插入某个人的信息时,如果没有可查询的信息或者插入,则不会使用trim标签:

<select id="getUsers" parameterType="map" resultType="User">
    SELECT * FROM user_info
    <trim prefix="WHERE" prefixOverrides="AND | OR" suffixOverrides="AND | OR">
        <if test="username != null">
            AND username = #{username}
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
    </trim>
</select>
  • prefix:表⽰整个语句块,以prefix的值作为前缀,如果数据存在,则添加在sql首部
  • suffix:表⽰整个语句块,以suffix的值作为后缀,如果数据存在,则加入sql语句尾部
  • prefixOverrides:表⽰整个语句块要去除掉的前缀,如果首部是约定的存在,则删除
  • suffixOverrides:表⽰整个语句块要去除掉的后缀,如果尾部部是约定的存在,则删除

当username和email不存在时,sql语句就相当于:

        SELECT * FROM user_info

当username不存在,email存在时,sql语句相当于:

        SELECT * FROM user_info where email = #{email};

当username和email存在时,sql语句就相当于:

      SELECT * FROM user_info where  username = #{username}   and   email =  #{email};

9.3<where>标签

        和<trim>标签有异曲同工之妙,不过它只能限定where。

<select id="queryByCondition" resultType="com.example.demo.model.UserInfo">
 select id, username, age, gender, phone, delete_flag, create_time, update_ti
     from userinfo
     <where>
         <if test="age != null">
             and age = #{age}
         </if>
         <if test="gender != null">
             and gender = #{gender}
         </if>
         <if test="deleteFlag != null">
                and delete_flag = #{deleteFlag}
         </if>
     </where>
</select>
<where> 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或
OR

9.4<set>标签

       <set>就是sql语句当中的修改update当中的set

<update id="updateUserByCondition">
 update userinfo
     <set>
         <if test="username != null">
             username = #{username},
         </if>
         <if test="age != null">
             age = #{age},
         </if>
         <if test="deleteFlag != null">
             delete_flag = #{deleteFlag},
         </if>
     </set>
     where id = #{id}
</update>
<set> :动态的在SQL语句中插⼊set关键字,并会自动删掉额外的逗号. (⽤于update语句中)

9.5<foreach>标签

对集合进行遍历时可以使用该标签。标签有如下属性:
  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串
这个标签和之前不太一样,因为他需要传入的是多个数据,例如多选删除, 根据多个userid, 删除用户数据。

接口方法:

void deleteByIds(List<Integer> ids);
ArticleMapper.xml 中新增删除 sql:
<delete id="deleteByIds">
     delete from userinfo
     where id in
         <foreach collection="ids" item="id" separator="," open="(" close=")">
             #{id}
         </foreach>
</delete>

通过这种方式,可以动态生成一个类似于 DELETE FROM userinfo WHERE id IN (id1, id2, id3) 的 SQL 语句。

9.6<include>标签

        在sql语句当中,不同的语句,但是会有大量冗余的代码,例如:我们查询所有用户信息、查询指定用户信息、查询条件用户信息,但是他们查询的字段名都是一样的,那么我们能不能简便一点呢?

<select id="queryAllUser" resultMap="BaseMap">
select id, username, age, gender, phone, delete_flag, create_time, update_time
from userinfo
</select>


<select id="queryById" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time, update_time
from userinfo where id= #{id}

</select>


<select id="queryByCondition" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time, update_time  from userinfo  where  id = #{id}  and age >18;

解决方法:

抽取重复代码片段,通过<sql>标签封装到SQL片段,再使用<include>标签引用。

  • <sql> :定义可重⽤的SQL⽚段
  • <include> :通过属性refid,指定包含的SQL⽚段
<sql id="allColumn">
 id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>

<select id="queryAllUser" resultMap="BaseMap">
     select
     <include refid="allColumn"></include>
     from userinfo
 </select>

结尾小注:要动起你们的小手,敲哦!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

https从入门到放弃(概念+实战+上线)

什么是HTTPS 大家都知道http&#xff0c;为什么现在又多了一个https呢&#xff1f;HTTP是明文传输的&#xff0c;也就意味着&#xff0c;介于发送端、接收端中间的任意节点都可以知道传输的内容是什么。这些节点可能是路由器、代理等。 举个最常见的例子&#xff0c;用户登陆…

微服务领域的寻路者 —— Eureka深度探索与实战秘籍

文章目录 一、引言定义目标一个接地气的例子引言小结 二、Eureka架构2.1 Eureka Server一个有趣的例子2.2 Eureka Client一段简单的代码示例架构小结 三、工作流程1. 服务注册2. 心跳检测3. 服务发现4. 健康检查与失效剔除工作流程小结 四、核心机制4.1 服务注册与续约4.2 服务…

五、VGA 叠加图像原理和实现(十字光标)

前言&#xff1a;该案例在VGA项目&#xff1a;联合精简帧双fifosobel算法 实现VGA显示项目的基础上进行改动。 要求&#xff1a;通过串口助手把 198x198 的十字光标图像二进制数据传递给 FPGA 板卡&#xff0c;FPGA 板 卡接收到后存储到 Ram 中用于 VGA 叠加显示。 预期效果展…

保护身份安全:FIDO2认证在钓鱼攻击中的应用

攻击者主要使用钓鱼攻击来窃取和滥用用户身份。根据全球统计局&#xff08;Statista&#xff09;对员工报告的恶意电子邮件的研究显示&#xff0c;2023年第一季度&#xff0c;58.2%的恶意电子邮件是凭证窃取攻击&#xff0c;40.5%是冒充攻击&#xff0c;1.3%是恶意软件传送。钓…

aop获取方法运行时间

Slf4j Component Aspect//aop类 public class TimeAspect {/*Around 环绕通知 用ProceedingJoinPoint Before 前置通知 用JoinPoint&#xff08;是ProceedingJoinPoint的父类型&#xff09;&#xff0c;用它可以获得方法执行的相关信息&#xff0c;如目标类名&#xff0c;方法…

硬盘格式化后找不到硬盘原因是什么?硬盘格式化后能恢复数据吗

在日常使用电脑过程中&#xff0c;硬盘格式化是一个常见的操作&#xff0c;它可以帮助我们清除硬盘上的数据并重新整理文件系统。然而&#xff0c;有时在格式化硬盘后&#xff0c;我们可能会发现硬盘在系统中无法被识别或找到&#xff0c;这往往让人感到困惑和焦虑。同时&#…

海外静态IP购买指南:探索全球网络连接的奥秘

在数字化时代&#xff0c;互联网连接的重要性不言而喻。对于企业和个人而言&#xff0c;拥有稳定、高速的网络连接是成功的关键。而在特定应用场景下&#xff0c;如远程办公、跨境电商、服务器托管等&#xff0c;海外静态IP地址的需求日益凸显。本文将为您详细解读海外静态IP购…

航空电子ARINC818采集卡

ARINC818采集卡是针对航空电子数字视频总线协议&#xff08;Avionics Digital Video BUS&#xff0c;ADVB&#xff09;的高性能PCIe视频光纤采集测试设备。ARINC818协议主要应用于机载设备间的实时高清图像传输&#xff0c;目前已经成功应用于多款民用、军用机型当中&#xff0…

软件测试编写文档模板

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、测试岗位必备的文档 在一个常规的软件测试流程中&#xff0c;会涉及到测试计划、测试方案、…

《一“企”谈》∣企企通走进『鹏辉能源』,探索百亿储能上市企业如何实现供应链数字化转型

随着运营模式的升级和市场竞争的加剧&#xff0c;采购数字化已成为企业提升竞争力的关键。通过整合人工智能、大数据、云计算和物联网等先进技术&#xff0c;采购流程正逐步实现智能化、协同化和绿色化&#xff0c;大幅提升采购效率和决策质量。 广州鹏辉能源科技股份有限公司&…

C#调用电脑摄像头拍照

1.打开VS2019&#xff0c;新建一个Form窗体&#xff0c;工具->NuGet包管理工具->管理解决方案的NuGet包&#xff0c;在浏览里搜索AForge.Controls、AForge.Video.DirectShow&#xff0c;安装AForge.Controls和AForge.Video.DirectShow 2.安装AForge组件完成后&#xff0c…

Workfine签章方案使用说明

概述 为支持绝大部分第三方签章平台&#xff0c;Workfine针对性添加了部分动作事件与message支持。用户只需要自己开发中间代理程序&#xff0c;用于Workfine与签章平台的通讯即可完成整套签章方案。 整体业务流程图如下&#xff1a; 设计端添加发送PDF动作事件&#xff0c;生…

Java常见数据结构---八大结构

前言&#xff1a; 数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。 通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率 常见的八大数据结构&#xff1a; 栈&#xff1a; 思想&#xff1a; 栈是一种数据结构&…

JL-杰理芯片-认识TA的SDK的第二天

耳机升级 测试盒的有线升级和无线升级&#xff08;要加key&#xff09; 烧录器的有线升级&#xff08;不要key&#xff09;&#xff08;强制升级&#xff09; 一拖八的强制升级 测试盒无线升级 要求&#xff1a;耳机的主控&#xff08;芯片&#xff09;至少是D4的 测试盒设…

WordPress中插入视频的两种方法详解

最近我在建设WordPress网站的时候需要上传视频&#xff0c;我使用的是Hostease的主机安装的WordPress&#xff0c;随后在咨询了他们的技术支持后获得了一些解决方法。下面将介绍WordPress中插入视频的两种方法&#xff1a;本地上传和外部引用。 本地上传视频 使用WordPress的古…

springmvc核心流程

核心流程及配置 核心流程 执行流程 用户发送请求到DispatcherServlet前端控制器&#xff0c;前端控制器收到请求后自己不进行处理&#xff0c;而是委托给其他的解析器进行处理&#xff0c;作为统一访问点&#xff0c;进行全局的流程控制 DispatcherServlet调用HandlerMapping映…

Postman基础功能-Collection和批量运行

一、Collection&#xff08;集合&#xff09;介绍 当我们对一个或多个系统中的很多接口用例进行维护时&#xff0c;首先想到的就是对接口用例进行分类管理&#xff0c;同时还希望对这批接口用例做回归测试。 在 Postman 中也提供了这样一个功能&#xff0c;就是 Collec…

基础ArkTS组件:帧动画,内置动画组件,跑马灯组件(HarmonyOS学习第三课【3.6】)

帧动画 帧动画也叫序列帧动画&#xff0c;其原理就是在时间轴的每帧上逐帧绘制不同的内容&#xff0c;使其连续播放而成动画。ArkUI开发框架提供了 ImageAnimator 组件实现帧动画能力&#xff0c;本节笔者介绍一下 ImageAnimator 组件的简单使用。 官方文献 说明 该组件从A…

亚马逊测评实操干货,跨境电商做测评,卖家店铺测评攻略!

亚马逊在全球有超过 2 亿付费 Prime 会员和数以亿计的活跃买家账户&#xff0c;卖家们可以通过亚马逊一流的国际物流扩展业务。这是一个知名度极高的老牌跨境电商平台&#xff0c;而且平台流量非常大&#xff0c;成功打造爆款Listing这是每位亚马逊卖家渴望的诉求&#xff0c;做…

拿走不谢,送你一份HCIA自学攻略

HCIE固然是许多网络工程师梦寐以求的认证&#xff0c;但攀登这座高峰之前&#xff0c;先要稳扎稳打地从华为认证HCIA开始。 对于零基础的学员来说&#xff0c;自学HCIA不仅是一个挑战&#xff0c;更是一次宝贵的学习机会&#xff0c;为以后学习IP、IE打基础。 以HCIA数通方向…