Mybatis学习基础篇(一)——使用Maven快速搭建一个mybatis项目,并实现简单的增删改查

news2024/11/24 5:49:21

题外话:
在了解mybatis框架之前,我先说明一句,目前主流的框架技术层出不穷,每个人都有自己喜欢的技术框架,自己喜欢用就行。技术并没有高低之分,喜欢用就用,虽然目前大部分人都喜欢向新技术看齐,但是我个人觉得任何技术,都有他自己存在的意义,新的技术可以学,但旧技术我们也不能说他不行。

本文将带你使用java快速搭建一个MyBatis项目,并且实现简单的增删改查操作,动态增删改查将在本文第二篇

MyBatis框架介绍

Mybatis是一款优秀的持久层框架,它是一个基于Java语言的、开源的、轻量级的ORM框架,可以用于处理关系型数据库的操作。

Mybatis作为ORM框架,其内部封装JDBC,故而使得开发者只需要关注SQL本身,并不需要花费精力去加载驱动,创建链接,创建statement等繁琐的过程。

Mybatis的主要特点是灵活、简单、易于学习和使用。Mybatis的主要工作原理是将Java对象映射成数据库的记录,实现Java对象和数据库表之间的转换。Mybatis的核心组件包括SqlSessionFactory、SqlSession、Mapper和MappedStatement。

  1. SqlSessionFactory
    SqlSessionFactory是用于创建SqlSession对象的工厂类。SqlSession对象是Mybatis中最重要的核心类之一,它是一个线程安全的、非常轻量级的对象,用于执行数据库操作和管理事务。SqlSessionFactory通常通过Mybatis的配置文件进行配置,可以指定数据源、事务管理器和Mapper映射文件等信息。

  2. SqlSession
    SqlSession是一个线程安全的、非常轻量级的对象,用于执行数据库操作和管理事务。SqlSession提供了多种操作数据库的方法,包括查询、插入、更新和删除等,还可以设置事务的隔离级别和自动提交等。

  3. Mapper
    Mapper是一个Java接口,用于定义SQL语句的执行方法。Mapper接口中的方法与SQL语句是一一对应的,可以通过SqlSession的getMapper方法获取Mapper接口的实例,并调用其中的方法执行SQL语句。

  4. MappedStatement
    MappedStatement是一个Java对象,用于描述Mapper接口中的SQL语句和参数信息。MappedStatement包括SQL语句的ID、SQL语句的类型、输入参数和输出参数等信息。

Mybatis的主要优点是:

  1. 灵活性高:Mybatis的配置文件非常灵活,可以使用XML或注解进行配置,支持自定义标签和属性,可以灵活地进行SQL语句的编写和调优。

  2. 易于学习和使用:Mybatis的API非常简单,容易学习和使用,开发人员可以快速上手,快速实现对数据库的操作。

  3. 易于维护和调试:Mybatis的映射文件和Java代码是分离的,容易维护和调试,开发人员可以很方便地对SQL语句进行调优和修改,提高SQL语句的执行效率。

  4. 易于扩展和定制化:Mybatis的插件机制非常强大,可以对SQL语句进行拦截和修改,也可以自定义类型处理器和结果集处理器,实现对特定数据类型的处理和转换。

  5. 良好的性能和扩展性:Mybatis采用了基于XML的配置方式和基于Java的Mapper接口,可以实现动态SQL语句的生成和优化,同时也支持多数据源和分布式数据库的操作,具有良好的性能和扩展性。

总之,Mybatis是一款优秀的持久层框架,它具有灵活性高、易于学习和使用、易于维护和调试、易于扩展和定制化、良好的性能和扩展性等优点,被广泛应用于Java企业级应用中的数据持久化层。

我的文件目录结构:
在这里插入图片描述
文件目录结构摆上了,如果跟着我的步骤下来的出现问题,我觉得是你的目录结构出问题了。

简单介绍完了,开始重头戏

第一步,先拿到数据库,这里提供一个实例数据库:

create database if not exists MyBatis_stu default character set utf8 collate utf8_bin; 

use MyBatis_stu ;

create table if not exists classinfo(
  cid int primary key auto_increment,
  cname varchar(100) not null unique comment '班级编号' 
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;

create table if not exists stuinfo (
   sid int primary key auto_increment,
   sname varchar(100) not null comment '学生姓名',
   cid int comment '所在班级编号',
   tel varchar(15) unique comment '联系方式',
   addr varchar(100) comment '家庭住址',
   constraint FK_stuinfo_cid foreign key(cid) references classinfo(cid)
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;

这一步,我觉得不要多说了,毕竟你学java到现在,这一步还是没看懂的话,我觉得你可以准备考虑考虑其他路了。

第二步前台条件,你要创建好一个maven项目,并导入相关依赖,别告诉我你忘记了maven工程如何创建了?

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.xh</groupId>
  <artifactId>Maven</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>Maven</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
  
  <!--导入maven链接,让maven去下载
   https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>8.0.28</version>
	</dependency>
	
	<dependency>
	  <groupId>org.mybatis</groupId>
	  <artifactId>mybatis</artifactId>
	  <version>3.5.8</version>
	</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
	<dependency>
	    <groupId>org.apache.logging.log4j</groupId>
	    <artifactId>log4j-slf4j-impl</artifactId>
	    <version>2.17.2</version>
	    <scope>test</scope>
	</dependency>
		
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

第二步,根据我们的数据库创建Bean类,什么?你告诉我你不知道什么事Bean类?额,你该恶补一下java了。

public class ClassInfo {
	private Integer cid;
	private String cname;
	
	public Integer getCid() {
		return cid;
	}
	public void setCid(Integer cid) {
		this.cid = cid;
	}
	public String getCname() {
		return cname;
	}
	public void setCname(String cname) {
		this.cname = cname;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((cid == null) ? 0 : cid.hashCode());
		result = prime * result + ((cname == null) ? 0 : cname.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ClassInfo other = (ClassInfo) obj;
		if (cid == null) {
			if (other.cid != null)
				return false;
		} else if (!cid.equals(other.cid))
			return false;
		if (cname == null) {
			if (other.cname != null)
				return false;
		} else if (!cname.equals(other.cname))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "ClassInfo [cid=" + cid + ", cname=" + cname + "]";
	}
	//记得这里我的需要创建的构造方法,你可以选择跟我也可以选择不跟
	public ClassInfo( String cname) {
		this.cname = cname;
	}
	
	public ClassInfo(Integer cid, String cname) {
		super();
		this.cid = cid;
		this.cname = cname;
	}

	public ClassInfo() {
		super();
	}
}

注意,这个类,我实际上在本篇没用上,我会在下篇才用到,你可以自行选择创建或者不创建

public class StudentInfo {
	
	private Integer sid;//学生id
	private String sname;//学生姓名
	private Integer cid; //外键管理,类id
	private String tel; //电话号码
	private String addr;//地址
	
	public Integer getSid() {
		return sid;
	}
	public void setSid(Integer sid) {
		this.sid = sid;
	}
	public String getSname() {
		return sname;
	}
	public void setSname(String sname) {
		this.sname = sname;
	}
	public Integer getCid() {
		return cid;
	}
	public void setCid(Integer cid) {
		this.cid = cid;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((addr == null) ? 0 : addr.hashCode());
		result = prime * result + ((cid == null) ? 0 : cid.hashCode());
		result = prime * result + ((sid == null) ? 0 : sid.hashCode());
		result = prime * result + ((sname == null) ? 0 : sname.hashCode());
		result = prime * result + ((tel == null) ? 0 : tel.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		StudentInfo other = (StudentInfo) obj;
		if (addr == null) {
			if (other.addr != null)
				return false;
		} else if (!addr.equals(other.addr))
			return false;
		if (cid == null) {
			if (other.cid != null)
				return false;
		} else if (!cid.equals(other.cid))
			return false;
		if (sid == null) {
			if (other.sid != null)
				return false;
		} else if (!sid.equals(other.sid))
			return false;
		if (sname == null) {
			if (other.sname != null)
				return false;
		} else if (!sname.equals(other.sname))
			return false;
		if (tel == null) {
			if (other.tel != null)
				return false;
		} else if (!tel.equals(other.tel))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "StudentInfo [sid=" + sid + ", sname=" + sname + ", cid=" + cid + ", tel=" + tel + ", addr=" + addr
				+ "]";
	}
	public StudentInfo(Integer sid, String sname, Integer cid, String tel, String addr) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.cid = cid;
		this.tel = tel;
		this.addr = addr;
	}
	public StudentInfo() {
		super();
	}
}

第三步,我们要准备数据库配置文件

这个自行确定,账号密码请你更改为自己安装数据库的账号密码,我给出我的实例db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis_stu?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useOldAliasMetadataBehavior=true
username=root
password=123456

第四步,创建mybatis配置文件

有了上边三步的基础之后,我们需要配置mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE configuration 
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 引入配置文件 请好好的看我  我是db.properties -->
	<properties resource="db.properties"></properties>
	<!-- 配置环境变量 development :开发环境 work :工作环境 -->

	<environments default="development">
		<environment id="development">
			<!-- 事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 配置数据库连接信息 POOLED UNPOOLED -->
			<dataSource type="POOLED">
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>

	<mappers>
	<!-- 加载mapper指向位置 -->
		<mapper resource="mapper/ClassInfoMapper.xml" />
		<mapper resource="mapper/StudentInfoMapper.xml"></mapper>

	</mappers>


</configuration>

至此,第四步就完成。

第五步,配置映射

我想说的这上面的每一步都很重要,但是这一步也很重要,我们将相关SQL语句全部写在这里,这一步,我们其实可以说是直接对数据库进行操作,我的理解是这样的,但是不同的人有不同的理解,我也不能去把我的思想强加给别人,对吧?

对了,如果你是初学者,我推荐你了解一下我在本项目的注释
ClassInfoMapper.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 :命名空间 ,就是用来避免命名冲突的,同一个命名空间下面都不能出现相同的id
	时间上这个就是指向 "ClassInfo.findAll" 测试类的这个属性的ClassInfo代表命名空间,findAll代表id
 -->
<mapper namespace="ClassInfo">  


	<!-- 写insert delete update select 语句 每一个语句都有一个id,到时候通过命名空间.id 来获取对应的sql语句执行 
		通过paramenterType 属性来指定这个sql执行语句的参数 通过resultType属性指定这个sql语句后返回值的类型,是每条结果对应的类型 -->
	<select id="findAll" resultType="com.xh.mybatis.bean.ClassInfo">
		select cid,cname from classinfo;
	</select>

	<!-- 假设我们要查询某单一的字段,我们需要的操作是如下 -->
	<select id="find" resultType="com.xh.mybatis.bean.ClassInfo">
		select cid,cname from classinfo
		where cname=#{cname};
	</select>

	<insert id="add" parameterType="com.xh.mybatis.bean.ClassInfo">
		<!--#{} 采用预编译的方式 ${} 采用字符串拼接的方法 -->
		insert into classinfo values(0,#{cname});
	</insert>

	<!-- 模糊查询 vague '%${parameters}%' %#{parameters}%此时这个语句是有问题的,不能这么写 应该是 '%#{parameters}%' 
		_${parameters}这种模糊查询也是可以的,但是没有%那么灵活,不过你觉得你使用哪个舒服就使用哪个 -->
	<select id="findByVague"
		resultType="com.xh.mybatis.bean.ClassInfo">
		select cid,cname from classinfo where cname like
		'_${parameters}';
	</select>

	<!--更新表中的数据 -->
	<update id="update"
		parameterType="com.xh.mybatis.bean.ClassInfo">
		update classinfo set cname = #{cname} where cid =
		#{cid};
	</update>

	<!-- 删除表中的数据 -->
	<delete id="delete"
		parameterType="com.xh.mybatis.bean.ClassInfo">
		delete from classinfo where cid = #{cid};
	</delete>
</mapper>

另一个文件StudentInfoMapper.xml我不会在本篇使用,故而我不在本篇展示,如果你感兴趣的话,请查看下篇。

第六步,测试类的编写

package com.xh.mybatis;

import java.io.IOException;
import java.io.InputStream;

import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;


import com.xh.mybatis.bean.ClassInfo;

public class MyTest {

	/**
	 * classinfo中的所有的值
	 * @throws IOException
	 */
	@Test
	public void test1() throws IOException {

		try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")
				){
			//创建sqlSession工厂

			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
			System.out.println("-----------");
			//从sqlsession工厂中获取一个sql会话
			SqlSession sqlSession = sqlSessionFactory.openSession();

			//通过这个回话执行与sql语句 
			//将从表中查询的多条数据以作为对象的方式添加到list中
			List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");
			//遍历list中的所有的值
			cls.forEach(System.out::println);
			sqlSession.close();
		}
	}

	/**
	 * 在classinfo表中添加值 ,非动态添加
	 * @throws IOException
	 */
	@Test
	public void test2() throws IOException {
		try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")){
			//创建sqlSession工厂
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

			SqlSession sqlSession = sqlSessionFactory.openSession();

			//通过这个回话执行与sql语句,      
			/**
			 * 这里的new ClassInfo对象是由于我们创建的表是主键存在主键自增,故而在构造方法中不需要添加cid
			 * 我们可以选择几种方式,这边我们对构造方法可以进行多种构造,让构造方法去选择添加,也可以直接用全部构造
			 * 不够就是我们需要对构造方法进行置空处理
			 */
			int result = sqlSession.insert("ClassInfo.add",new ClassInfo("相关"));
			System.out.println(result);
			sqlSession.commit();
			sqlSession.close();
		}
	}

	/**
	 * ClassInfo表中
	 * mybatis查询某数据库中某个值
	 * @throws IOException
	 */
	@Test
	public void test3() throws IOException {
		InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
		//创建SqlSession工厂
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

		SqlSession sqlSession = sqlSessionFactory.openSession();

		//我们可以查看到当前查到的对象可以被查出来
		//ClassInfo obj = sqlSession.selectOne("ClassInfo.find",new ClassInfo("四班"));
		//ClassInfo.find表示调用Mybatis中的com.xh.bean.ClassInfo下的id=find的sql语句
		//如果我们使用的是MVC架构进行开发,这个语句应该是属于serviceImpl层调用dao接口的时候
		ClassInfo obj = sqlSession.selectOne("ClassInfo.find","四班");
		//查找单个
		//int result = sqlSession.selectOne("Classinfo.find","四班");
		System.out.println(obj);
		sqlSession.commit();
		sqlSession.close();
	}

	/**
	 * 使用模糊查询classInfo中的数据
	 * 没做动态查询
	 * @throws IOException 
	 */
	@Test
	public void test4() throws IOException {
		InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
		//创建sqlSession工厂
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		System.out.println("-----------");
		//从sqlsession工厂中获取一个sql会话
		SqlSession sqlSession = sqlSessionFactory.openSession();

		//通过这个回话执行与sql语句 
		//将从表中查询的多条数据以作为对象的方式添加到list中
		List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findByVague","班");
		//遍历list中的所有的值
		cls.forEach(System.out::println);
		sqlSession.commit();
		sqlSession.close();
	}
	
	/**
	 * 更新表中数据,先从简单的开始,ClassInfo表中的数据
	 * @throws IOException
	 */
	@Test
	public void test5() throws IOException {
		InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
		//创建sqlSession工厂
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		System.out.println("-----------");
		//从sqlsession工厂中获取一个sql会话
		SqlSession sqlSession = sqlSessionFactory.openSession();

		//通过这个回话执行与sql语句 
		//将从表中查询的多条数据以作为对象的方式添加到list中
		ClassInfo obj = new ClassInfo();
		
		obj.setCid(1);
		obj.setCname("一班");
		
		int result = sqlSession.update("ClassInfo.update",obj);
		if(result > 0) {
			System.out.println("更新成功");
		}else {
			System.out.println("更新失败");
		}
		
		List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");
		//遍历list中的所有的值
		cls.forEach(System.out::println);
		
		//注意在开启事务的情况下,你不提交数据库是查不到值的
		sqlSession.commit();
		
		sqlSession.close();
	}
	
	/**
	 * 删除
	 * @throws IOException 
	 */
	
	@Test
	public void test6() throws IOException {
		
		InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
		//创建sqlSession工厂
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		
		//从sqlsession工厂中获取一个sql会话
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");
		
		System.out.println("删除之前的数据");
		cls.forEach(System.out::println);
		/*
		 * ClassInfo obj = new ClassInfo(); obj.setCid(7);
		 */
		int result = sqlSession.delete("ClassInfo.delete",8);
		if(result > 0) {
			System.out.println("删除成功");
		}else {
			System.out.println("删除失败");
		}
		//注意在开启事务的情况下,你不提交数据库是查不到值的
		sqlSession.commit();
		
		System.out.println("删除之后的数据");
		List<ClassInfo> cls1 = sqlSession.selectList("ClassInfo.findAll");
		//遍历list中的所有的值
		cls1.forEach(System.out::println);
		
		sqlSession.close();
		
	}
	
	//至此,上边对mybatis的简单操作到此结束
}

至此,我们搭建简单的Mybatis项目就完成了,如果您觉得本文不错的话,请你对本文点一下点赞或者收藏,或者一键三连。您的鼓励将是我最大的动力

mybatis 注意事项:

#{} 和 ${} 的区别

注意:#{}是预编译处理,${}是字符替换

注意:#{}会在mybatis运行的过程中替换为?,调用PreparedStatement的set方法来赋值。

mybatis 在处理$()会将他替换为变量的值。

多使用#{}可以防止sql注入,提高系统安全性。

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

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

相关文章

flex布局下两端对齐,不满左对齐

文章目录 解决方案一 (利用父级的 :after 占位)解决方案二(利用:last-child和:nth-child()占位)解决方案三(补位添加节点法&#xff0c;这种方案适用于多种排列方式) 问题情境&#xff1a; 在flex布局下&#xff0c;多行排列&#xff0c;如何让flex布局最后一行没有排满时&…

如何构建适合自己的DevOps软件测试改进方案

根据2022年的DevOps全球调查报告显示&#xff0c;主流软件企业采用或部分采用DevOps且已获得良好成效的占比已达70%&#xff0c;DevOps俨然成为当下软件开发研究的重要方向。 测试作为软件开发的必要过程&#xff0c;是提升软件可靠性、保证软件质量的关键环节。然而&#xff…

上海亚商投顾:沪指失守3300点 传媒、游戏板块逆市大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日继续调整&#xff0c;沪指午后跌超1%&#xff0c;失守3300点整数关口&#xff0c;创业板指一度跌逾2%…

基于PWM技术的三相光伏逆变器研究(Simulink)

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

【手把手做ROS2机器人系统开发二】熟悉ROS2基本命令

【手把手做ROS2机器人系统开发二】熟悉ROS2基本命令 一、上讲回顾 在上一讲开发环境搭建中&#xff0c;我们讲解了如何搭建Ubuntu系统环境和ROS2开发运行环境。 1.Ubuntu系统安装 2.ROS2系统环境安装 二、ROS2核心命令讲解 1、daemon-各种守护进程相关的子命令 查看帮助&am…

[网络原理] 详解Cookie与Session

做好准备,迎接所有的成功吧 文章目录 1. Cookie的概念2. Session的概念3. Cookie与Session的关联与区别3.1 关联3.2 区别 4. Cookie与Session中的核心方法 1. Cookie的概念 Cookie是用户首次登陆网站成功之后,对应页面的服务器会返回给用户一个身份标识,被保存在用户主机的硬盘…

无人机视频与GIS融合三维实景怎么实现?

无人机视频与GIS融合三维实景怎么实现?无人机三维GIS作为一项新兴的测绘重要手段&#xff0c;具有续航时间长、成本低、机动灵活等优点&#xff0c;为城市的规划建设带来极大便利。 那么此项技术有什么样的特点呢?下面智汇云舟就带大家一起来了解一下。 三维是将采集以及经运…

leetcode 1416. Restore The Array(恢复数组)

一台打印机没有把空格打印出来&#xff0c;以至于不知道打印出的 s 中到底有哪些数字。 现在知道数字的取值范围在1 ~ k, 数字开头不能是0. 返回可能的数字个数。取模1097. 思路&#xff1a; DP 假设dp[ i ]为 i ~ n位的s 所能组成的数字组合数。 从右到左遍历&#xff0c;…

【云原生进阶之容器】第六章容器网络6.7.1--阿里云Terway网络模式综述

《云原生进阶之容器》专题索引: 第一章Docker核心技术1.1节——Docker综述第一章Docker核心技术1.2节——Linux容器LXC第一章Docker核心技术1.3节——命名空间Namespace第一章Docker核心技术1.4节——chroot技术第一章Docker核心技术1.5.1节——cgroup综述

如何在在一个账户内管理多个WhatsApp号

许多企业拥有多个WhatsApp Business账户。这可能是因为他们在多个地点都有商店&#xff0c;或者可能在全球范围内都有客户&#xff0c;并希望用当地语言迎合他们每个人。 无论出于何种原因&#xff0c;管理多个WhatsApp企业帐户既耗时又困难。但是&#xff0c;如果我们说有一种…

LoadRunner参数化最佳实践:让你的性能测试更加出色!

距离上次使用loadrunnr 已经有一年多的时间了。初做测试时在项目中用过&#xff0c;后面项目中用不到&#xff0c;自己把重点放在了工具之外的东西上&#xff0c;认为性能测试不仅仅是会用工具&#xff0c;最近又想有一把好的利器毕竟可以帮助自己更好的完成性能测试工作。这算…

【AI实战】微小目标检测模型MMDet-RFLA--训练环境从零开始搭建

【AI实战】微小目标检测模型MMDet-RFLA--训练环境搭建 RFLA介绍环境搭建安装依赖参考 RFLA介绍 官方连接 https://github.com/Chasel-Tsui/mmdet-rflaarxiv https://arxiv.org/abs/2208.08738 环境搭建 我的机器的cuda是10.2&#xff0c;根据自己的cuda版本到 https://hub.do…

python使用KDDockWidget

编译原理&#xff1a;KDDockWidget是一个C库&#xff0c;通过shiboken转成python的绑定支持。针对特殊版本&#xff0c;需要在cmake文件中增加一些变量。 注&#xff1a;本次编译&#xff0c;Qt版本统一指定为6.4.2&#xff0c;库支持Qt>5.12或6.2.0以上版本 下载仓库 Git…

解决npm安装慢卡顿reify:ajv: timing reifyNode问题、报错require() of ES Module

网上方法众多&#xff0c;但是都没有具体说明原因和具体解决办法 镜像优先推荐&#xff1a;cnpm 和 taobao 文章目录&#xff1a; 第一个错&#xff1a;Error [ERR_REQUIRE_ESM]: require() of ES Module 1.来源 2.错误显示 3.问题解决 第二个错&#xff1a; 卡顿在reify:…

(原创)Flutter基础入门:手把手教你搭建Flutter混合项目

前言 Flutter是Google开源的构建用户界面&#xff08;UI&#xff09;工具包 支持在不同平台构建一致的ui效果 但在实际业务中&#xff0c;一般不会整个APP都用纯Flutter开发 尤其一些老的项目&#xff0c;会采用接入Flutter的方式来混合开发 那么今天就主要讲一下如何搭建一个…

0424作业

实现串口收发字符/字符串 uart4.c #include "uart4.h"void hal_uart_init() {//rcc初始化//使能CPIOB组控制器RCC->MP_AHB4ENSETR | (0x1 << 1);//使能CPIOG组控制器RCC->MP_AHB4ENSETR | (0x1 << 6);//使能UART4控制器RCC->MP_APB1ENSETR | …

Linux网路服务之PXE网络批量装机和Kickstart全自动化安装

文章目录 一 、PXE网络批量装机的简介和相关知识1.1 什么是PXE1.2搭建PXE 远程安装服务器1.3 PXE装机的过程描述 二、PXE批量安装的具体操作过程2.1安装并启用 TFTP 服务2.2安装并启用 DHCP 服务2.3准备 Linux 内核、初始化镜像文件2.4准备 PXE 引导程序2.5安装FTP服务&#xf…

Android分屏流程分析

本文基于Android 11。 SystemUI模块中的Divider管理着所有关于分屏的对象&#xff1a; DividerView&#xff08;分屏分割线&#xff0c;分屏显示界面&#xff09;SplitScreenTaskOrganizer&#xff08;分屏Task组织者&#xff0c;分屏逻辑&#xff09; 这里重点关注分屏逻辑…

有道CEO周枫:当我们谈论大模型时,应该关注哪些新能力?

作者&#xff1a;周枫 基于大语言模型技术的ChatGPT推出已经有4个月了&#xff0c;更多同类产品还在快速出现。比如&#xff0c;前天谷歌更新了Bard&#xff0c;将辅助编程能力支持的语言数量扩展到20种。 然而&#xff0c;对大模型技术的重要性也出现了质疑&#xff0c;前段…

开发框架之Furion

目录 概述 框架特点 功能模块 支持平台 运行环境 数据库 应用部署 Nuget框架扩展包 Nuget框架脚手架 FurionEFCore脚手架 FurionEFCore脚手架安装命令 FurionSqlSugar脚手架 FurionSqlSugar脚手架安装命令 使用脚手架 脚手架更新 概述 Furion是一个免费开源的.Ne…