【JavaEE进阶】——一万字带你深刻理解Spring IoCDI

目录

🚩Spring是什么

🎈什么是容器?

🎈什么是 IoC?

📝传统开发思路

📝IOC思想

📝IoC 优势

🎈DI 介绍

🚩IoC 详解

🎈Bean的存储

🔴五大类注解

📝@Controller(控制器存储)

👩🏻‍💻获取bean对象的方式

📝@Service(服务存储)

📝@Repository(仓库存储)

📝@Component(组件存储)

📝@Configuration(配置存储)

🍭类注解之间的关系

🔴⽅法注解 @Bean

🔴Bean传递参数

🎈SpringBoot特点

🚩DI 详解

🎈属性注⼊

🎈构造方法注入

🎈Setter注入

🔴@Autowired存在问题

📝解决方法一 属性名和bean名称相同

📝解决方法二 @Primary

📝解决方法三 @Qualifier

📝解决方法四 @Resource

🔴五大注解修改名以及Bean修改名

📝Bean修改名

📝类注解修改


我们学习了springBoot和spring mvc的开发,完成了基本的功能开发了,但是真正的spring,spring mvc以及spring boot之间又有什么关系呢?


🚩Spring是什么

spring是一个开源框架,让我们的开发更加的简单,支持广泛的应用场景,有着活跃而庞大的社区,这可能就是spring一直存在的原因吧。

我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的 IoC 容器
什么是容器?IOC是什么?

🎈什么是容器?

容器是⽤来容纳某种物品的(基本)装置。⸺来⾃:百度百科
⽣活中的⽔杯, 垃圾桶, 冰箱等等这些都是容器.
我们想想,之前课程我们接触的容器有哪些?
List/Map -> 数据存储容器
Tomcat -> Web 容器

🎈什么是 IoC?

IOC是Spring的核心思想,什么是IOC呢?IOC是一种思想,之前我们在学习spring MVC 中,我们在类上添加@RestController 和 @Controller 注解,就是把这个类对象交给spring管理,spring框架启动时就会加载该类,把对象交给spring管理,就是IOC思想。

IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器
  • 什么是控制反转?——控制权反转
  • 控制权反转具体是体现在哪里呢?

获得依赖对象的过程中被反转了,也就是说,当需要某个对象时 ,传统开发模式都是自己new创建对象,现在不需要自己去创建对象了,把创建的对象的任务交给容器(也就是spring容器),程序中只需要注入(Dependency Injection,DI)就可以了.

  • spring是根据什么创建对象的呢?

之前我们在学习spring MVC 中,我们在类上添加@RestController 和 @Controller 注解,就是把这个类对象交给spring管理。——通过注解


IOC思想(在我的理解):通过注解对该对象进行了控制,将其存入到spring容器中,让spring对这个对象进行管理和创建。

相信大家看完上述的描述,对IOC思想了解了很多。下面我们通过一个案例进行加深理解。


📝传统开发思路

我们的实现思路是这样的:
先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦.

我们首先在newCarExample中创建car,然后在car类中创建Framework,然后根据车身创建底盘,然后进而创建轮胎。

public class NewCarExample {public static void main(String[] args) {Car car = new Car();car.run();}/*** 汽⻋对象*/static class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}/*** ⻋⾝类*/static class Framework {private Bottom bottom;public Framework() {bottom = new Bottom();System.out.println("Framework init...");}}/*** 底盘类*/static class Bottom 
{private Tire tire;public Bottom() {this.tire = new Tire();System.out.println("Bottom init...");}
}/*** 轮胎类*/static class Tire {// 尺⼨private int size;public Tire(){this.size = 17;System.out.println("轮胎尺⼨:" + size);}}
}
设计问题:
这样的设计看起来没问题,但是可维护性却很低.
接下来需求有了变更: 随着对的⻋的需求量越来越⼤, 个性化需求也会越来越多,我们需要加⼯多种尺⼨的轮胎.
那这个时候就要对上⾯的程序进⾏修改了,修改后的代码如下所⽰:
我们要加上轮胎大小属性,我们要给size传到底盘,然后底盘传到车身,最后传到车子。size这个属性增加了程序的耦合度,让每个对象都要对size进行添加。
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.
程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)

📝IOC思想

解决方案:
在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改。
我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝, ⻋⾝依赖汽⻋。
我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改. 此时, 我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式) ,因为我们不 需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修 改任何代码,这样就完成了程序的解耦.
我们把创建子类的方式,改成注入传递的方式。
public class newCarExample {public static void main(String[] args) {Tire tire=new Tire(20);Bottom bottom=new Bottom(tire);Framwork framwork=new Framwork(bottom);Car car=new Car(framwork);car.run();}
}public class Tire {private int size;public Tire(int size){System.out.println("轮胎的尺寸:"+size);}
}//轮胎依赖底盘
public class Bottom {private Tire tire;public Bottom(Tire tire){this.tire=tire;System.out.println("bottom init ..........");}
}//底盘依赖机身
public class Framwork {private  Bottom bottom;public Framwork(Bottom bottom){this.bottom=bottom;System.out.println("framwork init....");}
}//机身依赖车子
public class Car {private Framwork framwork;public Car(Framwork framwork){this.framwork=framwork;System.out.println("car init....");}public void run(){System.out.println("car run....");}
}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了

📝IoC 优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再 是使⽤⽅对象创建并控制依赖对象了,⽽是把 依赖对象注⼊将当前对象中,依赖对象的控制权不再由 当前类控制了。而是由newCarExample总体进行创建(也就是Spring容器)
传统上我们都在当前类进行new对象,现在我们只需要将属性注入,创建对象交给容器管理创建,这就是IOC思想。


🎈DI 介绍

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。
程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过 引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
上述代码中, 是通过构造函数的⽅式, 把依赖对象注⼊到需要使⽤的对象中的.。
IoC 是⼀种思想,也是"⽬标", ⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现.
我们不用自己创建该依赖对象,我们只需要将依赖对象注入到所需要的对象中,创建对象的事情交给spring来管理。
⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和⽬标(是
IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是 DI。

对IOC和DI有了初步的了解,我们接下来就要学习spring IOC和DI。

既然 Spring 是⼀个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:
• 存
• 取
Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由 Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出 对象。

🚩IoC 详解

通过上⾯的案例, 我们已经知道了Spring IoC 和DI的基本操作, 接下来我们来系统的学习Spring IoC和DI的操作. 前⾯我们提到 IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。 也就是bean的存储.

🎈Bean的存储

在之前的⼊⻔案例中,要把某个对象交给IOC容器管理,需要在类上添加⼀个注解: @Component
⽽Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解.
共有两类注解类型可以实现:
  • 1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.
  • 2. ⽅法注解:@Bean

🔴五大类注解

📝@Controller(控制器存储)
使⽤ @Controller 存储 bean 的代码如下所⽰:
@Controller
public class TestController {public void doController(){System.out.println("do controller....");}
}
如何观察这个对象已经存在Spring容器当中了呢? 接下来我们学习如何从Spring容器中获取对象
ApplicationContext 翻译过来就是: Spring 上下⽂
因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下⽂。
观察运⾏结果, 发现成功从Spring中获取到Controller对象, 并执⾏Controller的doController⽅法

为什么TestController对象存入到spring中呢?@Controller注解的作用是什么呢?

NoSuchBeanDefinitionException表示没有注解,那么spring就获取不了该对象bean。所以我们知道了@Controller这个注解就是为了让我们获得该Bean对象存储到spring中,后续我们在主程序中getBean就获取到该对象了,所以我们上面也说了,注解的作用就是让程序运行时,控制这个注解对应的类对象。后续对这个对象进行创建和获取。


👩🏻‍💻获取bean对象的方式

⽐如
  • 类名: UserController, Bean的名称为: userController
  • 类名: AccountManager, Bean的名称为: accountManager
  • 类名: AccountService, Bean的名称为: accountService
也有⼀些特殊情况, 当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写. 这些规则 与java.beans.Introspector.decapitalize (Spring在这⾥使⽤的)定义的规则相同.
⽐如
  • 类名: UController, Bean的名称为: UController
  • 类名: AManager, Bean的名称为: AManage
根据这个命名规则, 我们来获取Bean

1》根据类型来获取

2》根据名称来获取

根据名称获取的时候,首字母小写,我们看到类名时TestController,不是前两个字母大写,那么就将大写字母转成小写字母即可。并且类型要转换。

2》根据类型和名称来获取


📝@Service(服务存储)
@Service
public class TestService {public void doService(){System.out.println("do service.....");}
}
public class IocDemoApplication {public static void main(String[] args) {ApplicationContext context=SpringApplication.run(IocDemoApplication.class);TestService testService=context.getBean(TestService.class);testService.doService();}
}


📝@Repository(仓库存储)
📝@Component(组件存储)
📝@Configuration(配置存储)

代码形式都是和上述的两个方式相同


  • @Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.
  • @Servie:业务逻辑层, 处理具体的业务逻辑.
  • @Repository:数据访问层,也称为持久层. 负责数据访问操作
  • @Configuration:配置层. 处理项⽬中的⼀些配置信息

🍭类注解之间的关系
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:
其实这些注解⾥⾯都有⼀个注解 @Component ,说明 它们本⾝就是属于 @Component 的"⼦类". @Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service , @Repository 等. 这些注解被称为 @Component 的衍⽣注解。
@Controller , @Service @Repository ⽤于更具体的⽤例(分别在控制层, 业务逻辑层, 持
久化层), 在开发过程中, 如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择。
⽐如杯⼦有喝⽔杯, 刷⽛杯等, 但是我们更倾向于在⽇常喝⽔时使⽤⽔杯, 洗漱时使⽤刷⽛杯。不同的场景运用不同的功能,我们在实际开发中,我们实现业务的时候,我们会更倾向于用@Service。

🔴⽅法注解 @Bean

为什么需要方法注解呢?如何我们使用内部包的其他类或者外部包的其他类,我们就无法添加类注解的,还有一种是一个类中需要多个对象,这些场景,都是需要使用方法注解@Bean.
类注解是添加到某个类上的, 但是存在两个问题:
  • 1. 使⽤外部包⾥的类, 没办法添加类注解
@Data
public class UserInfo {private Integer age;private String name;private Integer id;
}
@Configuration
public class BeanConfigTest {@Beanpublic UserInfo userInfo(){UserInfo userInfo=new UserInfo();userInfo.setName("张老师");userInfo.setAge(20);userInfo.setId(1);return userInfo;}
}

在 Spring 框架的设计中, ⽅法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中

  • 2. ⼀个类, 需要多个对象, ⽐如多个数据源
@Configuration
public class BeanConfigTest {@Beanpublic UserInfo userInfo(){UserInfo userInfo=new UserInfo();userInfo.setName("张老师");userInfo.setAge(20);userInfo.setId(1);return userInfo;}@Beanpublic UserInfo userInfo2(){UserInfo userInfo=new UserInfo();userInfo.setName("chlorine");userInfo.setAge(19);userInfo.setId(2);return userInfo;}
}

我们观察上述代码,是同一个类型,存在多个Bean,我们此时是无法通过类型来获取bean。程序会启动失败。

同一个类型,存在多个Bean,我们此时可以通过名称或者(名称+类型)来获取Bean


🔴Bean传递参数

定义了一个叫name2的String类型的对象,定义了一个叫name的String类型的对象。

我们根据名称去拿,如果对应的对象只有一个时,就直接赋值,如果有多个时,通过名称去匹配,如果名称都不匹配,按照内部逻辑来匹配。


🎈SpringBoot特点

Q: 使⽤前⾯学习的四个注解声明的bean,⼀定会⽣效吗?
A: 不⼀定(原因:bean想要⽣效,还需要被Spring扫描)

约定大于配置

比如我们上课,教务处在开学前都会给给定的课表都约定好,等到开学后学生按照课程就直接去哪个教室上课就行了,而配置就是临时老师说调课,就需要老师临时通知,但是肯定是学校提前弄好的课程进行更多,而少数是进行老师进行调课。

springboot也有一个自己的约定,其中之一体现就是:扫描路径。默认的扫描路径是:启动类所在的目录及其子孙目录。

我们创建下项目默认的启动类都是在最大的包中,如果我们调动启动类的位置。将其移到controller包下,我们现在执行Configuration包下的程序,看是否成功。

报错,显示无法找到UserInfo,我们上面说Springboot约定大于配置,约定默认扫描路径是启动类所在的目录及其子孙目录。此时所在的目录和子孙目录,并没有user'Info而在自己的同级目录里,此时报错。

我们就相当于老师突然调课,我们需要给springboot增加配置。添加注解@Component,这个注解可以指定扫描路径,如果没有指定,默认就是该注解所在类的目录及其子孙目录。

我们增加注解,让启动类进行扫描到Configuration包下的类。执行成功。


推荐做法:
把启动类放在我们希望扫描的包的路径下, 这样我们定义的bean就都可以被扫描到

🚩DI 详解

上⾯我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注⼊DI的细节。
依赖注⼊是⼀个过程,是指IoC容器在创建Bean时, 去提供运⾏时所依赖的资源,⽽资源指的就是对象.在上⾯程序案例中,我们使⽤了 @Autowired 这个注解,完成了依赖注⼊的操作.简单来说, 就是把对象取出来放到某个类的属性中.
关于依赖注⼊, Spring也给我们提供了三种⽅式:
  • 1. 属性注⼊(Field Injection)
  • 2. 构造⽅法注⼊(Constructor Injection)
  • 3. Setter 注⼊(Setter Injection)
下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中

🎈属性注⼊

属性注⼊是使⽤ @Autowired 实现的,将UserInfo类注⼊到 Controller 类中
@Controller
public class UserController {@Autowiredprivate  UserInfo userInfo2;public void doController(){System.out.println(userInfo2);System.out.println("do Controller.........");}
@SpringBootApplication
public class IocDemoApplication {public static void main(String[] args) {
//1.属性注入ApplicationContext context=SpringApplication.run(IocDemoApplication.class);TestController testController=(TestController)context.getBean("testController") ;testController.doControl();}
}

属性注入以类型进行匹配,与注入的属性名称无关。但是如果一个类型存在多个对象时,有优先名称匹配,如果名称都匹配不上,那就会报错。

我们看到同一个类型出现了两个对象userInfo和userInfo2,那么此时我们要名称匹配,我定义的时候用的是us,此时匹配匹配不上,报错。


🎈构造方法注入

//二、构造方法注入private TestService testService;public TestController(){};public TestController(UserInfo userInfo){this.userInfo=userInfo;}@Autowiredpublic TestController(TestService testService){this.testService=testService;}public TestController(UserInfo userInfo,TestService testService){this.userInfo=userInfo;this.testService=testService;}public void doControl2(){testService.doService();System.out.println("do Controller.........");}

注意:

  • 1.如果存在多个构造函数时,需要加@AutoWired注明使用哪个构造函数
  • 2.再添加了有参的构造方法中,最好加上无参的构造方式,防止报错
  • 3.如果只有一个构造函数,@AutoWired可以省略掉
  • 4.明确注入哪个构造函数,否则会造成空指针异常


🎈Setter注入

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解。
    //三、setter注入private TestService testService2;@Autowiredpublic void setTestService2(TestService testService2) {this.testService2 = testService2;}public void doController3(){testService2.doService();System.out.println("do Controller.........");}


🔴@Autowired存在问题

当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题

程序启动失败,发现类型UserInfo存在多个Bean。


📝解决方法一

属性名和你需要使用的对象名保持一致。


📝解决方法二

使用@Primary注解标识默认的对象


📝解决方法三

使用@Qualifier指定哪个对象


📝解决方法四

使用@Resource注解指定ben


上述四个方法,使用率最高的是@Qualifier和@Resource注解

解决方法思路:给bean重命名或者指定名称


🔴五大注解修改名以及Bean修改名

📝Bean修改名

  @Bean({"u1","uu"})@Bean("u1")

一个Bean可以有多个名称,但是一个名称只能对应一个Bean。


📝类注解修改


人生小满胜万全。

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

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

相关文章

Vue2全局封装modal弹框

Vue2全局封装modal弹框使用&#xff1a; 一.components下封装 1.index.js import ModalCheck from ./modal-check.vue export default ModalCheck2.modal-check.vue <template><div><Modalv-model"selSingleShow":title"editTitle(convertCa…

四信云-设备维保管理系统上线,实现设备全生命周期管理

在当今的制造业中&#xff0c;设备是企业生产的核心要素&#xff0c;是企业竞争力的基石。 随着企业发展规模不断扩大&#xff0c;设备数量急速增长&#xff0c;传统的手工管理方式已经无法满足企业需求&#xff0c;设备管理系统的出现则填补了市场需求空白&#xff0c;其目标…

优先级队列(堆)的实现

1.什么是优先级队列 队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队 列时&#xff0c;可能需要优先级高的元素先出队列&#xff0c;该中场景下&#xff0c;使用队列显然不合适&#xff0c;比如&#x…

堆的实现

前言&#xff1a;本文讲述堆实现的几个难点&#xff0c;注意本文主要是以实现为主&#xff0c;建议有些基本概念认识的人阅读。 目录 1.堆 2.堆的实现 堆结构的定义&#xff1a; 要实现的接口&#xff1a; 接口的实现&#xff1a; 堆的初始化和销毁&#xff1a; 向堆中插…

人工智能-YOLOv10-行人和车辆检测-yolo改进测距测速代码和原理

YOLOv10: 实时端到端目标检测技术的全新突破 YOLOv10代表了实时目标检测领域的重大进展&#xff0c;是YOLO系列模型的最新迭代&#xff0c;专为追求极致效率与精度平衡的应用场景设计。此项目由北京大学机器智能研究组&#xff08;THU-MIG&#xff09;的Ao Wang、Hui Chen、Li…

02_前端三大件HTML

文章目录 HTML用于网页结构搭建1. 标签2. 客户端服务器交互流程3. 专业词汇4. html语法细节5. 安装VSCODE安装插件6. Live Server插件使用7. 标题&段落&换行&列表8. 超链接标签使用9. 图片10. 表格的写法11. 表单标签*(重点)12. 下拉框13. 页面布局标签14. 块元素和…

RT-Thread Env开发探索——以HC-SR04超声波传感器为例

RT-Thread Env开发探索——以HC-SR04超声波传感器为例 0.前言一、BSP优化1.修改芯片功能配置2.修改RTT配置菜单 二、软件包加载1.外设配置2.驱动框架配置3.软件包配置 三、编译及运行四、源码分析五、总结 参考文章&#xff1a;RT Thread Env CLion环境搭建 0.前言 对比使用R…

mac下安装airflow

背景&#xff1a;因为用的是Mac的M芯片的电脑&#xff0c;安装很多东西都经常报错&#xff0c;最近在研究怎么把大数据集群上的crontab下的任务都配置到一个可视化工具中&#xff0c;发现airflow好像是个不错的选择&#xff0c;然后就研究怎么先安装使用起来&#xff0c;后面再…

部署LAMP平台

目录 一、LAMP简介与概述 1.1 各组件作用 1.2 LAMP平台搭建时各组件安装顺序 1.3 httpd服务的目录结构 1.4 httpd.conf配置文件 二、编译安装Apache httpd服务 2.1 关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下 2.2 安装环境依赖包 ​2.3 配置软件模块…

基于RK3588的AI边缘计算网关设计

随着物联网和人工智能技术的飞速发展&#xff0c;边缘计算逐渐成为数据处理和分析的重要趋势。RK3588作为一款高性能的处理器&#xff0c;具备强大的计算能力和丰富的接口&#xff0c;为构建AI边缘计算网关提供了有力的支持。本文将介绍基于RK3588的AI边缘计算网关设计&#xf…

【Redis】 关于 Redis 哈希类型

文章目录 &#x1f343;前言&#x1f38b;命令介绍&#x1f6a9;hset&#x1f6a9;hget&#x1f6a9;hexists&#x1f6a9;hdel&#x1f6a9;hkeys&#x1f6a9;hvals&#x1f6a9;hgetall&#x1f6a9;hmget&#x1f6a9;hlen&#x1f6a9;hsetnx&#x1f6a9;hincrby&#x1…

弹性盒子布局,flex布局

弹性盒子布局&#xff08;Flexbox&#xff09;是CSS3引入的一种新的布局模式&#xff0c;它提供了一种更加有效的方式来设计、布局和对齐容器中的项目&#xff0c;即使容器的大小动态改变或者项目的数量未知。 弹性盒子布局的主要特点是能够轻松地在不同的屏幕大小和设备上实现…

使用VCPKG编译并使用Qt5

一、背景 Qt就不介绍了。VCPKG可以看这里VCPKG资料记录_vcpkg boost 多久-CSDN博客 为什么搞Qt5而不是Qt6&#xff1f;因为Qt5比较稳定吧。而且我公司也是用的Qt5。 为什么要自己编译而不是去下载Qt5&#xff1f; 第一&#xff0c;因为Qt5在Qt在线安装版本只提供到Qt5.15.2&…

【CTF Web】CTFShow web3 Writeup(SQL注入+PHP+UNION注入)

web3 1 管理员被狠狠的教育了&#xff0c;所以决定好好修复一番。这次没问题了。 解法 注意到&#xff1a; <!-- flag in id 1000 -->但是拦截很多种字符。 if(preg_match("/or|\-|\\|\*|\<|\>|\!|x|hex|\/i",$id)){die("id error"); }使用…

Linux驱动设备导论(1)

最近本人在学习Linux驱动&#xff0c;本系列教程是本人在一边学习&#xff0c;一边总结的系列教程&#xff0c;希望能够给很多刚学驱动小伙伴一些总结。 1.Linux设备分类 驱动针对的对象是存储器和外设&#xff0c;不是针对CPU&#xff0c;可以分为以下三大类&#xff1a; 1.…

『Stable Diffusion 』AI绘画,不会写提示词怎么办?

提示词 有没有想过&#xff0c;为什么你用 SD 生成的猫是长这样的。 而其他人可以生成这样的猫。 虽然生成的都是猫&#xff0c;但猫与猫之间还是有差距的。 如果你的提示词只是“cat”&#xff0c;那大概率就会出现本文第一张图的那个效果。而如果你加上一些形容词&#xff…

C#应用的用户配置窗体方案 - 开源研究系列文章

这次继续整理以前的代码。本着软件模块化的原理&#xff0c;这次笔者对软件中的用户配置窗体进行剥离出来&#xff0c;单独的放在一个Dll类库里进行操作&#xff0c;这样在其它应用程序里也能够快速的复用该类库&#xff0c;达到了快速开发软件的效果。 笔者其它模块化应用的例…

SQL面试题练习 —— 波峰波谷

来源&#xff1a;字节今日头条 目录 1 题目2 建表语句3 题解 1 题目 有如下数据&#xff0c;记录每天每只股票的收盘价格&#xff0c;请查出每只股票的波峰和波谷的日期和价格&#xff1b; 波峰定义&#xff1a;股票价格高于前一天和后一天价格时为波峰 波谷定义&#xff1a;股…

在linux下的ROS中下载超级终端Terminator ROS开发得力助手

在一般我们运行机器人包时要打开三个终端来运行&#xff0c;关闭时还要一个一个关闭&#xff08;ctrlc&#xff09;过于麻烦 现在下载用了terminator后&#xff0c;就支持一键关闭多个终端了&#xff0c;很方便&#xff0c;具体操作如下&#xff1a; sudo apt install termin…

JDBCTemplate介绍

Spring JDBC Spring框架对Spring的简单封装。提供一个JDBCTemplate对象简化JDBC开发 *步骤&#xff1a; 1、导入jar包 2、创建JDBCTemplate对象。依赖于数据源DataSource *JdbcTemplate templatenew JdbcTemplate(ds); 3、调用JdbcTemplate的方法来完成CRUD的操作 *update()&…