SpringBootWeb 篇-深入了解 Mybatis 删除、新增、更新、查询的基础操作与 SQL 预编译解决 SQL 注入问题

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 Mybatis 的基础操作

        2.0 基础操作 - 环境准备

        3.0 基础操作 - 删除操作

        3.1 SQL 预编译

        3.2 SQL 预编译的优势

        3.3 参数占位符

        4.0 基础操作 - 新增

        4.1 主键返回

        5.0 基础操作 - 更新

        6.0 基础操作 - 查询

        6.1 根据 ID 来查询

        6.2 数据封装

        6.3 根据条件查询

        7.0 本篇文章的完整代码

        7.1 application.properties 属性文件

        7.2 pom.xml 文件

        7.3 Mapper 接口

        7.4 测试代码

        7.5 Emp 类


        1.0 Mybatis 的基础操作

        Mybatis 是一个基于 Java 的持久层框架,它可以帮助开发者简化数据库操作。

        下面是 Mybatis 的基础操作:查询操作、新增操作、更新操作、删除操作。通过以上基础的操作,开发者可以使用 Mybatis 进行数据库操作,实现数据的增删改查功能。

        2.0 基础操作 - 环境准备

        1)准备数据库表 emp

        2)创建一个新的 Springboot 工程,选择引入对应的起步依赖(mybatis、mysql 驱动包、lombok 工具包)

    <!--mybatis的起步依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency><!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

        3)application.properties 中引入数据库连接信息

spring.datasource.drive-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db01?characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456

        4)创建对应的实体类 Emp

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;
import java.time.LocalDateTime;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {private int id;private String username;private String password;private String name;private int gender;private int job;private LocalDate entrydate;private int deptId;private LocalDateTime createTime;private LocalDateTime updateTime;}

        5)准备 Mapper 接口 EmpMapper

        基础操作的抽象方法都写在该接口中,该接口用 @Mapper 注解。

        3.0 基础操作 - 删除操作

        在 Mapper 接口中定义一个 delete() 的抽象方法,且在该方法上加上 @Delete("删除的 SQL 语句") 注解,只要实现类调用重写的 delete() 方法时,就会自动执行 SQL 语句。

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//删除数据操作@Delete("delete from emp where id = #{id}")public void delete(int id);}

        SQL 语句:根据 ID 来删除数据。#{} 是 mybatis 中的占位符,当实体类调用 delete 方法的时候,方法中的参数 id 自动赋值给 #{id} 占位符中的 id 。

测试删除数据操作:

@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper deleteMapper;@Testpublic void testDelete(){deleteMapper.delete(3);}}

        通过 @Autowired 注解根据类型注入到 deleteMapper 变量中,再由 deleteMapper 调用 delete() 方法,就可以自动执行 SQL 语句,且方法参数也会自动赋值给 #{id} 。

测试结果:

初始的 emp:

测试后的 emp:

        注意事项:如果 mapper 接口方法形参只有一个普通类型的参数,#{...} 里面的属性名可以随便写,如:#{id}、#{value} 。

        3.1 SQL 预编译

        SQL 预编译是在执行 SQL 语句之前,将 SQL 语句编译成可执行的硬编码形式,并在执行时直接使用编译好的代码,从而减少了每次执行 SQL 语句时的语法解析和优化等过程,提高了 SQL 语句执行的效率。

        预编译 SQL 语句的过程主要包括 SQL 语法解析、语义分析、查询优化和生成可执行代码等步骤。

        在执行 SQL 语句之前,先将 SQL 语句传递给数据库驱动程序进行预编译,然后再执行预编译好的 SQL 语句。

        3.2 SQL 预编译的优势

        在发送给数据库之前,会先进行一次 SQL 预编译,将 #{id} 占位符变为 '?' ,再将方法中的参数 id 一起发送给数据库进行运行操作,而不是直接将拼接好的 SQL 语句发送给数据库。

        1)性能更高

        采取 SQL 预编译,可以提升性能。

        对于 SQL 预编译的方式来说,由于 #{id} 无论 id 为何值都会变为 '?' ,所以相同的 SQL 语句只需要编译一次就够了,因为内存中已经有相同的 SQL 语句了。预编译好的 SQL 连同参数 id 一起发送到数据库中。

        对于 SQL 直接拼接参数的方式来说,简单来说,将 SQL “写死”了,每一次的 id 大概率都是不一样的,那么每一条 SQL 语句都要进行SQL 语法解析、语义分析、查询优化和生成可执行代码等步骤。因此采取 SQL 预编译的方式,性能会更好。

        2)更安全(防止 SQL 注入)

        预编译语句可以将 SQL 查询语句和参数分开,从而避免用户输入的数据直接被拼接到 SQL 语句中。

        对于 SQL 语句直接与参数拼接,可能会存在 SQL 注入。举个例子:

         

SELECT * FROM users WHERE username='admin' AND password='' OR '1'='1';

        在登录密码的时候,密码写成:' OR '1'='1 ,再将其直接拼接到 SQL 语句中,就会导致以上情况 '1' = '1' 恒成立,因此就可以绕过登录验证,从而直接登录。

        上述 SQL 查询语句将返回数据库中的所有用户数据,导致登录成功,即使用户输入的密码是错误的。这就是 SQL 注入攻击,利用用户输入的恶意代码来绕过登录验证。要防止这种情况发生,可以使用预编译语句或参数化查询来避免直接拼接用户输入数据到 SQL 查询语句中。

        而对于 SQL 预编译来说:不存在 SQL 注入攻击,因为 SQL 语句和参数分开了,没有直接拼接到 SQL 语句中。

        3.3 参数占位符

        1)#{...}:执行 SQL 时,会将 #{...} 替换为 ? ,生成预编译 SQL ,会自动设置参数值。使用时机:参数传递,都使用 #{...} 。

在编写 SQL 语句中使用 #{} 这个占位符,就会自动进行 SQL 预编译,将 #{id} 就会被 '?' 替代掉。

        2)${...}:拼接 SQL ,直接将参数拼接在 SQL 语句中,存在 SQL 注入问题。使用时机:如果对表名、列表进行动态设置时使用。

        4.0 基础操作 - 新增

        在 Mapper 接口中定义 insert() 抽象方法,且在该方法加上 @Insert("新增的 SQL 语句")

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//增加数据操作@Insert("insert into emp(username,name,gender,job,entrydate,dept_id,create_time,update_time) " +"values (#{username},#{name},#{gender},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")public void insert(Emp emp);}

        当实体类调用该重写的 insert() 方法,就会自动执行该 SQL 语句,由于参数比较多,可以用对象进行封装起来,用 emp 作为参数,emp 中的字段都会一一对应的赋值到 SQL 语句中 #{} 占位符中,占位符中的变量名需要与 emp 中的字段保持一致,才能进行正常的赋值操作。

测试新增操作:

@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper mapper;@Testpublic void testInsert(){Emp emp = new Emp();emp.setUsername("小板");emp.setName("XB");emp.setJob(1);emp.setEntrydate(LocalDate.of(2024,3,4));emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);mapper.insert(emp);}}

        先通过 @Autowire 注解,将新增对象注入给 mapper 变量名。创建一个新的 emp 对象,将其字段进行赋值后,再将 emp 以参数的形式交给 #{} 占位符中的变量。

测试结果:

新增之前的数据库:

新增之后的数据库:

        4.1 主键返回

        在数据添加成功后,需要获取插入数据库数据的主键。

        只需在 @Insert 注解上再添加一个 @Options(useGeneratedKeys = true,keyProperty = "id") 注解,其中 useGeneratedKeys = true 代表:数据添加成之后,需要返回主键。keyProperty = "id" 代表:返回的主键交给 id 变量。

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {@Options(useGeneratedKeys = true,keyProperty = "id")//增加数据操作@Insert("insert into emp(username,name,gender,job,entrydate,dept_id,create_time,update_time) " +"values (#{username},#{name},#{gender},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")public void insert(Emp emp);}
@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper mapper;@Testpublic void testInsert(){Emp emp = new Emp();emp.setUsername("小童");emp.setName("TT");emp.setJob(0);emp.setEntrydate(LocalDate.of(2024,3,4));emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);mapper.insert(emp);System.out.println(emp.getId());}}

运行结果:

        这样就拿到了主键,也称为主键返回。

        5.0 基础操作 - 更新

        在 Mapper 接口中定义一个 update(参数) 抽象方法,且在该方法加上 @Update("更新 SQL 语句") 注解,当实体类调用重写的 update(参数) 方法时,就会自动执行 SQL 语句,且方法中的参数就会自动赋值给 #{} 占位符。

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//更新数据操作@Update("update emp set username = #{username} , name = #{name} , gender = #{gender} , job = #{job}," +"entrydate = #{entrydate} , dept_id = #{deptId}, create_time = #{createTime}, update_time = #{updateTime} where id = #{id}")public void update(Emp emp);}

        需要注意的是, emp 中的字段名必须要跟 #{} 占位符中的变量名保持相同,才能进行正常的赋值操作。

测试更新操作:

@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper updateMapper;@Testpublic void testUpdate(){Emp emp = new Emp();emp.setId(5);emp.setUsername("小扳手");emp.setName("TT");emp.setJob(3);emp.setEntrydate(LocalDate.of(2022,3,5));emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);mapper.update(emp);}}

更新之前:

更新之后:

        6.0 基础操作 - 查询

        在 Mapper 接口中定义一个 select(参数) 抽象方法,且在该抽象方法加上 @Select("查询 SQL 的语句"),实体类调用重写的 select(参数) 方法时,就自动执行 SQL 语句,且查询出来的数据可以用 Emp 实体对象来接收。

        6.1 根据 ID 来查询

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//根据ID查询@Select("select * from emp where id = #{id}")public Emp selectID(int id);}

测试根据 ID 查询: 

@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper selectMapper;@Testpublic void testSelect(){Emp emp = selectMapper.selectID(1);System.out.println(emp);}}

        首先通过 @Autowired 注解,将 Mapper 类型的对象注入给 selectMapper 对象,再调用 selectID(1) 方法,代表查询 ID 为 1 的数据。接着查询的结果交给 emp 。

运行结果:

        6.2 数据封装

        实体类属性名和数据库表查询返回的字段名一致,mybatis 会自动封装;如果实体类属性名和数据库查询返回的字段名不一致,不能自动分装。

解决属性名与字段名不一致的方法:

        1)给字段起别名,让别名与实体类属性名保持一致。

        2)通过 @Results,@Result 注解手动映射封装

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//手动建立映射关系@Results({//column 代表原来的字段名、property 代表替换的字段名@Result(column = "create_time",property = "createTime"),@Result(column = "dept_id",property = "deptId"),@Result(column = "update_time",property = "updateTime")})//根据ID查询@Select("select * from emp where id = #{id}")public Emp selectID(int id);}

        3)开启 mybatis 的驼峰命名自动映射开关(create_Time ----> createTime)

        在 application.properties 属性文件中配置:

#开启 mybatis 的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true

        6.3 根据条件查询

        条件:根据输入的员工姓名、员工性别、入职时间搜索满足条件的员工信息。其中员工姓名,支持模糊匹配;性别进行精确查询;入职时间进行范围查询;并对查询的结果,根据最后修改时间进行倒叙排序。

代码演示:

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//根据条件进行查询@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +"entrydate between #{start} and #{end} order by update_time desc ")public List<Emp> selectCondition(String name, int gender, LocalDate start,LocalDate end);}

        这里用到了 concat() 方法用于连接两个或多个字符串的方法。它将指定的字符串与调用字符串连接,并将返回一个新的字符串,而不会更改原始字符串。这个方法可以接受任意数量的参数,然后将它们连接在一起,以创建一个新的字符串。

        注意事项:#{} 占位符不能内嵌在 "" 中,而 ${} 占位符可以内嵌在 "" 中。

        7.0 本篇文章的完整代码

        7.1 application.properties 属性文件

spring.datasource.drive-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db01?characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456#将日志打印到控制台上
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl#开启驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true

        7.2 pom.xml 文件

<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>org.example</groupId><artifactId>code_24_5_20_2</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>code_24_5_20_2</name><url>http://maven.apache.org</url><!--1、spring-boot-starter-parent自动引入springboot中最基础的组件,所有springboot项目都要依赖它进行构建--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.4</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--2、引入springboot依赖,spring-boot-starter-web表示在项目中增加支持javaweb的功能,版本信息已经在parent中定义--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--mybatis的起步依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency><!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--Druid依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency></dependencies><!--3、定义springboot的打包方式,spring-boot-maven-plugin可以在打包时自动将所有类和资源打包成一个独立可运行的jar包--><build><!--打包指定名称--><finalName>projectName</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

        7.3 Mapper 接口

import org.apache.ibatis.annotations.*;import java.time.LocalDate;
import java.util.List;@org.apache.ibatis.annotations.Mapper
public interface Mapper {//根据条件进行查询@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +"entrydate between #{start} and #{end} order by update_time desc ")public List<Emp> selectCondition(String name, int gender, LocalDate start,LocalDate end);//手动建立映射关系@Results({//column 代表原来的字段名、property 代表替换的字段名@Result(column = "create_time",property = "createTime"),@Result(column = "dept_id",property = "deptId"),@Result(column = "update_time",property = "updateTime")})//根据ID查询@Select("select * from emp where id = #{id}")public Emp selectID(int id);//更新数据操作@Update("update emp set username = #{username} , name = #{name} , gender = #{gender} , job = #{job}," +"entrydate = #{entrydate} , dept_id = #{deptId}, create_time = #{createTime}, update_time = #{updateTime} where id = #{id}")public void update(Emp emp);@Options(useGeneratedKeys = true,keyProperty = "id")//增加数据操作@Insert("insert into emp(username,name,gender,job,entrydate,dept_id,create_time,update_time) " +"values (#{username},#{name},#{gender},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")public void insert(Emp emp);//删除数据操作@Delete("delete from emp where id = #{id}")public void delete(int id);}

        7.4 测试代码

import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.example.CURD.Emp;
import org.example.CURD.Mapper;
import org.example.Project.GetData;
import org.example.Project.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;/*** Unit test for simple App.*/
@SpringBootTest
public class AppTest extends TestCase {@AutowiredMapper selectMapper;@Testpublic void testSelect(){Emp emp = selectMapper.selectID(1);System.out.println(emp);}@AutowiredMapper updateMapper;@Testpublic void testUpdate(){Emp emp = new Emp();emp.setId(5);emp.setUsername("小扳手");emp.setName("TT");emp.setJob(3);emp.setEntrydate(LocalDate.of(2022,3,5));emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);mapper.update(emp);}@AutowiredMapper mapper;@Testpublic void testInsert(){Emp emp = new Emp();emp.setUsername("小童");emp.setName("TT");emp.setJob(0);emp.setEntrydate(LocalDate.of(2024,3,4));emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());emp.setDeptId(1);mapper.insert(emp);System.out.println(emp.getId());}@AutowiredMapper deleteMapper;@Testpublic void testDelete(){deleteMapper.delete(3);}@AutowiredGetData get;@Testpublic void test(){List<User>  list = get.getData();list.forEach(System.out::println);}@AutowiredMapper selectCondition;@Testpublic void testSelectCondition(){List<Emp> list = selectCondition.selectCondition("童",0,LocalDate.of(2022,3,5),LocalDate.of(2025,4,4));System.out.println(list);}
}

        7.5 Emp 类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;
import java.time.LocalDateTime;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {private int id;private String username;private String password;private String name;private int gender;private int job;private LocalDate entrydate;private int deptId;private LocalDateTime createTime;private LocalDateTime updateTime;}

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

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

相关文章

Python图像处理:从基础到高级的全方位指南

目录 第一部分&#xff1a;Python图像处理基础 1.1 图像处理概念 1.2 Python图像处理常用库 1.3 实战案例&#xff1a;图像显示与保存 1.4 注意事项 第二部分&#xff1a;Python图像处理高级技巧 2.1 图像变换 2.2 图像增强 2.3 图像复原 第三部分&#xff1a;Python…

20232802 黄千里 2023-2024-2 《网络攻防实践》实践十一报告

20232802 2023-2024-2 《网络攻防实践》实践十一报告 1.实践过程 1.1web浏览器渗透攻击 攻击机&#xff1a;kali172.20.10.10靶机&#xff1a;win2k172.20.10.3 首先在kali中启动msfconsole 输入命令search MS06-014&#xff0c;搜索渗透攻击模块 输入use exploit/window…

终于让我找到了,你也可以学会的人工智能-机器学习教程

给大家分享一套非常棒的python机器学习课程——《AI小天才&#xff1a;让小学生轻松掌握机器学习》&#xff0c;2024年5月完结新课&#xff0c;提供配套的代码笔记软件包下载&#xff01;学完本课程&#xff0c;可以轻松掌握机器学习的全面应用&#xff0c;复杂特征工程&#x…

关于新配置的adb,设备管理器找不到此设备问题

上面页面中一开始没有找到此android设备&#xff0c; 可能是因为我重新配置的adb和设备驱动&#xff0c; 只把adb配置了环境变量&#xff0c;驱动没有更新到电脑中&#xff0c; 点击添加驱动&#xff0c; 选择路径&#xff0c;我安装时都放在了SDK下面&#xff0c;可以尝试…

SpringBoot 实现 RAS+AES 自动接口解密

一、讲个事故 接口安全老生常谈了 过年之前做了过一款飞机大战的H5小游戏&#xff0c;里面无限模式-需要保存用户的积分&#xff0c;因为使用的Body传参&#xff0c;参数是可见的。 为了接口安全我&#xff0c;我和前端约定了传递参数是&#xff1a;用户无限模式的积分“我们…

HTML静态网页成品作业(HTML+CSS)——魅族商城首页网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

基于Python+OpenCV卷积神经网络的字符识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 字符识别是计算机视觉和模式识别领域的一个重要应用&#xff0c;它在文档数字化、车牌识别、验…

gpt-4o考场安排

说明 &#xff1a;经过多次交互&#xff0c;前后花了几个小时&#xff0c;总算完成了基本功能。如果做到按不同层次分配考场&#xff0c;一键出打印结果就完美了。如果不想看中间“艰苦”的过程&#xff0c;请直接跳到“最后结果”及“食用方法”。中间过程还省略了一部分交互&…

go slice 扩容

扩容 slice 会迁移到新的内存位置&#xff0c;新底层数组的长度也会增加&#xff0c;这样就可以放置新增的元素。同时&#xff0c;为了应对未来可能再次发生的 append 操作&#xff0c;新的底层数组的长度&#xff0c;也就是新 slice 的容量是留了一定的 buffer 的。否则&…

【C++】STL快速入门基础

文章目录 STL&#xff08;Standard Template Library&#xff09;1、一般介绍2、STL的六大组件2.1、STL容器2.2、STL迭代器2.3、相关容器的函数vectorpairstringqueuepriority_queuestackdequeset, map, multiset, multimapunordered_set, unordered_map, unordered_multiset, …

LabVIEW2022安装教程指南【附安装包】

文章目录 前言一、安装指南1、软件包获取 二、安装步骤总结 前言 LabVIEW是一种程序开发环境&#xff0c;提供一种图形化编程方法&#xff0c;可可视化应用程序的各个方面&#xff0c;包括硬件配置、测量数据和调试&#xff0c;同时可以通过FPGA数学和分析选板中的NI浮点库链接…

有趣的css - 两个圆形加载效果

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是一款小清新的加载动画&#xff0c;适用于 app 列表加载&#xff0c;页面加载或者弹层内容延迟加载等场景。 最新文章通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html…

20年交易老兵悟出的宝贵经验,做到这10点或许你也能躺着赚钱

交易要靠亲身体验来真正获得发展&#xff0c;在正确引导下&#xff0c;我们就不会把时间和精力浪费在弯路上。交易之技易学&#xff0c;实难在心态与思考。接下来&#xff0c;我将与您分享一位交易了20年的老兵所积累的10条珍贵经验。 Nial Fuller,一个交易了接近20年的市场“老…

Git远程控制

文章目录 1. 创建仓库1.1 Readme1.2 Issue1.3 Pull request 2. 远程仓库克隆3. 推送远程仓库4. 拉取远程仓库5. 配置Git.gitignore配置别名 使用GitHub可以&#xff0c;采用Gitee也行 1. 创建仓库 1.1 Readme Readme文件相当于这个仓库的说明书&#xff0c;gitee会初始化2两份…

go mod模式下,import gitlab中的项目

背景 为了go项目能够尽可能复用代码&#xff0c;把一些公用的工具类&#xff0c;公用的方法等放到共用包里统一管理。把共用包放到gitlab的私有仓库中。 遇到的问题 通过https方式&#xff0c;执行go get报了错误。 通过ssh方式&#xff0c;执行go get报了错误。 修改配置&am…

面试八股之MySQL篇2——索引篇

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

Springboot阶段项目---《书城项目》

一 项目介绍 本项目采用集成开发平台IntelliJ IDEA开发了在线作业成绩统计系统的设计与实现&#xff0c;实现了图书商城系统的综合功能和图形界面的显示&#xff0c;可以根据每个用户登录系统后&#xff0c;动态展示书城首页图书&#xff0c;实现了分类还有分页查询&#xff0c…

Linux应用入门(二)

1. 输入系统应用编程 1.1 输入系统介绍 常见的输入设备有键盘、鼠标、遥控杆、书写板、触摸屏等。用户经过这些输入设备与Linux系统进行数据交换。这些设备种类繁多&#xff0c;如何去统一它们的接口&#xff0c;Linux为了统一管理这些输入设备实现了一套能兼容所有输入设备的…

怎么压缩pdf pdf在线压缩 pdf文件压缩大小

pdf文件无论在何种设备上打开&#xff0c;PDF文件都能保持其原始的布局和格式&#xff0c;这对于文档共享和打印非常重要。PDF不仅支持文本&#xff0c;还能嵌入图像、视频、音频以及动态链接等元素。PDF文件支持加密和密码保护&#xff0c;可以限制访问、编辑、复制或打印文档…

K8S认证|CKA题库+答案| 5. 创建 Ingress

5 . 创建 Ingress 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node k8s master …