Spring Security 6.x 系列(10)—— SecurityConfigurer 配置器及其分支实现源码分析(二)

一、前言

在本系列文章:

Spring Security 6.x 系列(4)—— 基于过滤器链的源码分析(一)
中着重分析了Spring SecuritySpring Boot自动配置、 DefaultSecurityFilterChainFilterChainProxy 的构造过程。

Spring Security 6.x 系列(7)—— SecurityBuilder 继承链源码分析
中详细分析了Spring SecurityWebSecurityHttpSecurityAuthenticationManagerBuilder 三个构造器的公共继承链。

Spring Security 6.x 系列(8)—— SecurityConfigurer 配置器及其分支实现源码分析(一)
中分析SecurityConfigurer配置器及其主要分支实现。

Spring Security 6.x 系列(9)—— 基于过滤器链的源码分析(二)
着重分析了@EnableGlobalAuthentication注解的作用、对AuthenticationConfiguration构造AuthenticationManager过程和上文中未介绍的GlobalAuthenticationConfigurerAdapter 配置器的五个分支实现进行了详细的说明。

今天我们就从未被介绍的SecurityConfigurerAdapter配置器的具体分支实现进行展开。

二、SecurityConfigurerAdapter

SecurityConfigurerAdapter在上文中有过详解介绍,它是SecurityConfigurer的基类,它允许子类仅实现它们感兴趣的方法。它还提供了使用 SecurityConfigurer以及完成后获取正在配置的SecurityBuilder(构造器)的访问权限的机制。

SecurityConfigurerAdapter 的实现主要有三大类:

  • UserDetailsAwareConfigurer
  • AbstractHttpConfigurer
  • LdapAuthenticationProviderConfigurer

考虑到 LDAP 现在使用很少,所以重点介绍前两个。

三、UserDetailsAwareConfigurer

这个类名就能大概知道是和用户详细信息配置有关。

再通过继承关系图,看看UserDetailsAwareConfigurer的顶层架构设计:

在这里插入图片描述

UserDetailsAwareConfigurer是一个抽象类,源码比较简单:

/*** Base class that allows access to the {@link UserDetailsService} for using as a default* value with {@link AuthenticationManagerBuilder}.** @param <B> the type of the {@link ProviderManagerBuilder}* @param <U> the type of {@link UserDetailsService}* @author Rob Winch*/
public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>extends SecurityConfigurerAdapter<AuthenticationManager, B> {/*** Gets the {@link UserDetailsService} or null if it is not available* @return the {@link UserDetailsService} or null if it is not available*/public abstract U getUserDetailsService();}

通过源码我们可知:

  • 泛型U继承了UserDetailsService接口,也就意味着
    getUserDetailsService()方法返回的对象肯定是UserDetailsService接口的实现。

  • 泛型B继承了ProviderManagerBuilder接口,ProviderManagerBuilder构造器的作用是用来构建AuthenticationManager对象,可就意味UserDetailsAwareConfigurer(配置器)用来配置ProviderManagerBuilder构造器。

3.1 AbstractDaoAuthenticationConfigurer

AbstractDaoAuthenticationConfigurer也是一个抽象类,是模版模式:

/*** Allows configuring a {@link DaoAuthenticationProvider}** @param <B> the type of the {@link SecurityBuilder}* @param <C> the type of {@link AbstractDaoAuthenticationConfigurer} this is* @param <U> The type of {@link UserDetailsService} that is being used* @author Rob Winch* @since 3.2*/
public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>extends UserDetailsAwareConfigurer<B, U> {// 声明了一个 providerprivate DaoAuthenticationProvider provider = new DaoAuthenticationProvider();// 声明了一个 userDetailsService 的泛型属性private final U userDetailsService;/*** 创建一个实例* @param userDetailsService,userDetailsService的类型可以是UserDetailsService或者UserDetailsPasswordService*/AbstractDaoAuthenticationConfigurer(U userDetailsService) {this.userDetailsService = userDetailsService;this.provider.setUserDetailsService(userDetailsService);if (userDetailsService instanceof UserDetailsPasswordService) {this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);}}/*** Adds an {@link ObjectPostProcessor} for this class.* @param objectPostProcessor* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations*/@SuppressWarnings("unchecked")public C withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {addObjectPostProcessor(objectPostProcessor);return (C) this;}/*** Allows specifying the {@link PasswordEncoder} to use with the* {@link DaoAuthenticationProvider}. The default is to use plain text.* @param passwordEncoder The {@link PasswordEncoder} to use.* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations*/@SuppressWarnings("unchecked")public C passwordEncoder(PasswordEncoder passwordEncoder) {this.provider.setPasswordEncoder(passwordEncoder);return (C) this;}public C userDetailsPasswordManager(UserDetailsPasswordService passwordManager) {this.provider.setUserDetailsPasswordService(passwordManager);return (C) this;}@Overridepublic void configure(B builder) throws Exception {this.provider = postProcess(this.provider);// 向builder添加provider(配置构造器阶段)builder.authenticationProvider(this.provider);}/*** Gets the {@link UserDetailsService} that is used with the* {@link DaoAuthenticationProvider}* @return the {@link UserDetailsService} that is used with the* {@link DaoAuthenticationProvider}*/@Overridepublic U getUserDetailsService() {return this.userDetailsService;}}

通过源码我们可知:

  • AbstractDaoAuthenticationConfigurer初始时创建了一个DaoAuthenticationProvider类型的AuthenticationProvider实例。
  • 为使用者提供设置DaoAuthenticationProvider属性UserDetailsService的功能并指定类型为:UserDetailsService/U serDetailsPasswordService
  • 为使用者提供设置DaoAuthenticationProvider属性PasswordEncoder功能;
  • 为使用者提供设置对象后置处处理器的功能。
  • AbstractDaoAuthenticationConfigurer配置构造器对应的初始化阶段方法为空。
  • AbstractDaoAuthenticationConfigurer配置构造器对应的配置阶段方法:
    • DaoAuthenticationProvider执行后置处理
    • DaoAuthenticationProvider添加到构造器中

3.2 DaoAuthenticationConfigurer

DaoAuthenticationConfigurer继承自 AbstractDaoAuthenticationConfigurer,在构造方法中调用AbstractDaoAuthenticationConfigurer的构造方法。

/*** Allows configuring a {@link DaoAuthenticationProvider}** @param <B> The type of {@link ProviderManagerBuilder} this is* @param <U> The type of {@link UserDetailsService} that is being used* @author Rob Winch* @since 3.2*/
public class DaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>extends AbstractDaoAuthenticationConfigurer<B, DaoAuthenticationConfigurer<B, U>, U> {/*** Creates a new instance* @param userDetailsService*/public DaoAuthenticationConfigurer(U userDetailsService) {super(userDetailsService);}}

3.3 UserDetailsServiceConfigurer

UserDetailsServiceConfigurer继承了AbstractDaoAuthenticationConfigurer,并重写了AbstractDaoAuthenticationConfigurer中的configure方法,在configure方法执行之前加入了initUserDetailsService方法,以方便开发时按照自己的方式去初始化 UserDetailsService。这里的initUserDetailsService方法是空的,会交于子类进行具体实现,也是模版模式。

/*** Allows configuring a {@link UserDetailsService} within a* {@link AuthenticationManagerBuilder}.** @param <B> the type of the {@link ProviderManagerBuilder}* @param <C> the {@link UserDetailsServiceConfigurer} (or this)* @param <U> the type of UserDetailsService being used to allow for returning the* concrete UserDetailsService.* @author Rob Winch* @since 3.2*/
public class UserDetailsServiceConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsServiceConfigurer<B, C, U>, U extends UserDetailsService>extends AbstractDaoAuthenticationConfigurer<B, C, U> {/*** Creates a new instance* @param userDetailsService the {@link UserDetailsService} that should be used*/public UserDetailsServiceConfigurer(U userDetailsService) {super(userDetailsService);}@Overridepublic void configure(B builder) throws Exception {initUserDetailsService();super.configure(builder);}/*** Allows subclasses to initialize the {@link UserDetailsService}. For example, it* might add users, initialize schema, etc.*/protected void initUserDetailsService() throws Exception {}}

3.4 UserDetailsManagerConfigurer

UserDetailsManagerConfigurer继承了UserDetailsServiceConfigurer,并实现了 UserDetailsServiceConfigurer中定义的initUserDetailsService空方法,具体的实现逻辑就是将UserDetailsBuilder所构建出来的 UserDetails以及提前准备好的UserDetails中的用户存储到UserDetailsService中。

在实例构造上进一步限制了父类中的U userDetailsService的类型为UserDetailsManager

在这里插入图片描述

该类同时添加 withUser方法用来添加用户,同时还增加了一个UserDetailsBuilder用来构建用户,这些逻辑都比较简单,大家可以自行查看。

/*** Base class for populating an* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}* with a {@link UserDetailsManager}.** @param <B> the type of the {@link SecurityBuilder} that is being configured* @param <C> the type of {@link UserDetailsManagerConfigurer}* @author Rob Winch* @since 3.2*/
public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsManagerConfigurer<B, C>>extends UserDetailsServiceConfigurer<B, C, UserDetailsManager> {private final List<UserDetailsBuilder> userBuilders = new ArrayList<>();private final List<UserDetails> users = new ArrayList<>();protected UserDetailsManagerConfigurer(UserDetailsManager userDetailsManager) {super(userDetailsManager);}/*** Populates the users that have been added.* @throws Exception*/@Overrideprotected void initUserDetailsService() throws Exception {for (UserDetailsBuilder userBuilder : this.userBuilders) {getUserDetailsService().createUser(userBuilder.build());}for (UserDetails userDetails : this.users) {getUserDetailsService().createUser(userDetails);}}/*** Allows adding a user to the {@link UserDetailsManager} that is being created. This* method can be invoked multiple times to add multiple users.* @param userDetails the user to add. Cannot be null.* @return the {@link UserDetailsBuilder} for further customizations*/@SuppressWarnings("unchecked")public final C withUser(UserDetails userDetails) {this.users.add(userDetails);return (C) this;}/*** Allows adding a user to the {@link UserDetailsManager} that is being created. This* method can be invoked multiple times to add multiple users.* @param userBuilder the user to add. Cannot be null.* @return the {@link UserDetailsBuilder} for further customizations*/@SuppressWarnings("unchecked")public final C withUser(User.UserBuilder userBuilder) {this.users.add(userBuilder.build());return (C) this;}/*** Allows adding a user to the {@link UserDetailsManager} that is being created. This* method can be invoked multiple times to add multiple users.* @param username the username for the user being added. Cannot be null.* @return the {@link UserDetailsBuilder} for further customizations*/@SuppressWarnings("unchecked")public final UserDetailsBuilder withUser(String username) {UserDetailsBuilder userBuilder = new UserDetailsBuilder((C) this);userBuilder.username(username);this.userBuilders.add(userBuilder);return userBuilder;}/*** Builds the user to be added. At minimum the username, password, and authorities* should provided. The remaining attributes have reasonable defaults.*/public final class UserDetailsBuilder {private UserBuilder user;private final C builder;/*** Creates a new instance* @param builder the builder to return*/private UserDetailsBuilder(C builder) {this.builder = builder;}/*** Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to* add another user)* @return the {@link UserDetailsManagerConfigurer} for method chaining*/public C and() {return this.builder;}/*** Populates the username. This attribute is required.* @param username the username. Cannot be null.* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/private UserDetailsBuilder username(String username) {this.user = User.withUsername(username);return this;}/*** Populates the password. This attribute is required.* @param password the password. Cannot be null.* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder password(String password) {this.user.password(password);return this;}/*** Populates the roles. This method is a shortcut for calling* {@link #authorities(String...)}, but automatically prefixes each entry with* "ROLE_". This means the following:** <code>*     builder.roles("USER","ADMIN");* </code>** is equivalent to** <code>*     builder.authorities("ROLE_USER","ROLE_ADMIN");* </code>** <p>* This attribute is required, but can also be populated with* {@link #authorities(String...)}.* </p>* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,* contain null values or start with "ROLE_"* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder roles(String... roles) {this.user.roles(roles);return this;}/*** Populates the authorities. This attribute is required.* @param authorities the authorities for this user. Cannot be null, or contain* null values* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)* @see #roles(String...)*/public UserDetailsBuilder authorities(GrantedAuthority... authorities) {this.user.authorities(authorities);return this;}/*** Populates the authorities. This attribute is required.* @param authorities the authorities for this user. Cannot be null, or contain* null values* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)* @see #roles(String...)*/public UserDetailsBuilder authorities(List<? extends GrantedAuthority> authorities) {this.user.authorities(authorities);return this;}/*** Populates the authorities. This attribute is required.* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,* etc). Cannot be null, or contain null values* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)* @see #roles(String...)*/public UserDetailsBuilder authorities(String... authorities) {this.user.authorities(authorities);return this;}/*** Defines if the account is expired or not. Default is false.* @param accountExpired true if the account is expired, false otherwise* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder accountExpired(boolean accountExpired) {this.user.accountExpired(accountExpired);return this;}/*** Defines if the account is locked or not. Default is false.* @param accountLocked true if the account is locked, false otherwise* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder accountLocked(boolean accountLocked) {this.user.accountLocked(accountLocked);return this;}/*** Defines if the credentials are expired or not. Default is false.* @param credentialsExpired true if the credentials are expired, false otherwise* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder credentialsExpired(boolean credentialsExpired) {this.user.credentialsExpired(credentialsExpired);return this;}/*** Defines if the account is disabled or not. Default is false.* @param disabled true if the account is disabled, false otherwise* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate* additional attributes for this user)*/public UserDetailsBuilder disabled(boolean disabled) {this.user.disabled(disabled);return this;}UserDetails build() {return this.user.build();}}}

3.5 JdbcUserDetailsManagerConfigurer

JdbcUserDetailsManagerConfigurer继承了UserDetailsManagerConfigurer,在父类的基础上补充了 DataSource对象,同时还提供了相应的数据库查询方法。

/*** Configures an* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}* to have JDBC authentication. It also allows easily adding users to the database used* for authentication and setting up the schema.** <p>* The only required method is the {@link #dataSource(javax.sql.DataSource)} all other* methods have reasonable defaults.** @param <B> the type of the {@link ProviderManagerBuilder} that is being configured* @author Rob Winch* @since 3.2*/
public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>extends UserDetailsManagerConfigurer<B, JdbcUserDetailsManagerConfigurer<B>> {private DataSource dataSource;private List<Resource> initScripts = new ArrayList<>();public JdbcUserDetailsManagerConfigurer(JdbcUserDetailsManager manager) {super(manager);}public JdbcUserDetailsManagerConfigurer() {this(new JdbcUserDetailsManager());}/*** Populates the {@link DataSource} to be used. This is the only required attribute.* @param dataSource the {@link DataSource} to be used. Cannot be null.* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource) {this.dataSource = dataSource;getUserDetailsService().setDataSource(dataSource);return this;}/*** Sets the query to be used for finding a user by their username. For example:** <code>*     select username,password,enabled from users where username = ?* </code>* @param query The query to use for selecting the username, password, and if the user* is enabled by username. Must contain a single parameter for the username.* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) {getUserDetailsService().setUsersByUsernameQuery(query);return this;}/*** Sets the query to be used for finding a user's authorities by their username. For* example:** <code>*     select username,authority from authorities where username = ?* </code>* @param query The query to use for selecting the username, authority by username.* Must contain a single parameter for the username.* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) {getUserDetailsService().setAuthoritiesByUsernameQuery(query);return this;}/*** An SQL statement to query user's group authorities given a username. For example:** <code>*     select*         g.id, g.group_name, ga.authority*     from*         groups g, group_members gm, group_authorities ga*     where*         gm.username = ? and g.id = ga.group_id and g.id = gm.group_id* </code>* @param query The query to use for selecting the authorities by group. Must contain* a single parameter for the username.* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) {JdbcUserDetailsManager userDetailsService = getUserDetailsService();userDetailsService.setEnableGroups(true);userDetailsService.setGroupAuthoritiesByUsernameQuery(query);return this;}/*** A non-empty string prefix that will be added to role strings loaded from persistent* storage (default is "").* @param rolePrefix* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> rolePrefix(String rolePrefix) {getUserDetailsService().setRolePrefix(rolePrefix);return this;}/*** Defines the {@link UserCache} to use* @param userCache the {@link UserCache} to use* @return the {@link JdbcUserDetailsManagerConfigurer} for further customizations*/public JdbcUserDetailsManagerConfigurer<B> userCache(UserCache userCache) {getUserDetailsService().setUserCache(userCache);return this;}@Overrideprotected void initUserDetailsService() throws Exception {if (!this.initScripts.isEmpty()) {getDataSourceInit().afterPropertiesSet();}super.initUserDetailsService();}@Overridepublic JdbcUserDetailsManager getUserDetailsService() {return (JdbcUserDetailsManager) super.getUserDetailsService();}/*** Populates the default schema that allows users and authorities to be stored.* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional* customizations*/public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {this.initScripts.add(new ClassPathResource("org/springframework/security/core/userdetails/jdbc/users.ddl"));return this;}protected DatabasePopulator getDatabasePopulator() {ResourceDatabasePopulator dbp = new ResourceDatabasePopulator();dbp.setScripts(this.initScripts.toArray(new Resource[0]));return dbp;}private DataSourceInitializer getDataSourceInit() {DataSourceInitializer dsi = new DataSourceInitializer();dsi.setDatabasePopulator(getDatabasePopulator());dsi.setDataSource(this.dataSource);return dsi;}}

在实例构造上进一步限制了父类中的U userDetailsService的类型为JdbcUserDetailsManager

JdbcUserDetailsManager的继承关系图:

在这里插入图片描述

3.6 InMemoryUserDetailsManagerConfigurer

InMemoryUserDetailsManagerConfigurer继承了UserDetailsManagerConfigurer,在实例构造上进一步限制了父类中的U userDetailsService的类型为InMemoryUserDetailsManager

/*** Configures an* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}* to have in memory authentication. It also allows easily adding users to the in memory* authentication.** @param <B> the type of the {@link ProviderManagerBuilder} that is being configured* @author Rob Winch* @since 3.2*/
public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>extends UserDetailsManagerConfigurer<B, InMemoryUserDetailsManagerConfigurer<B>> {/*** Creates a new instance*/public InMemoryUserDetailsManagerConfigurer() {super(new InMemoryUserDetailsManager(new ArrayList<>()));}}

InMemoryUserDetailsManager的继承关系图:

在这里插入图片描述

未完待续~~~~!!!!

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

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

相关文章

Oauth2.0 认证

目录 前言 1.介绍 2.Oauth2.0过程详解 3.Oauth 整合到 Spring Boot 实践 4.方法及配置详解&#xff1a; 总结 前言 Oauth2.0 是非常流行的网络授权表准&#xff0c;已经广泛应用在全球范围内&#xff0c;比较大的公司&#xff0c;如腾讯等都有大量的应用场景。 1.介绍 …

ARP欺骗攻击

一.大概原理 ARP&#xff1a;address solution protocol 地址解析协议 ARP是一种基于局域网的TCP/IP协议&#xff0c;arp欺骗就是基于此协议的漏洞来达成我们的目的的&#xff0c;局域网中的数据传输并不是用ip地址传输的&#xff0c;而是靠mac地址。 我们如果出于某种目的想…

【Fastadmin】利用 build_select 做一个树状下拉选择框

1.效果展示 系统crud生成的下拉分类有些不是很好看&#xff0c;并且选择困难&#xff0c;看不出级差&#xff0c;效果如下&#xff1a; 经过 build_select 加工后的效果,美观好看&#xff0c;并添加上搜索功能: 2. 首先需要写一个树状图的数据格式 protected $datalist []; pu…

前沿科技与医药领域碰撞,《AI制药方法与实践》课程重磅上线

药物发现是生物学、化学、医学、药学等基础研究与工业转化的重要窗口。近年来&#xff0c;AI技术的发展&#xff0c;为高投入、高失败率的制药行业带来了全新机遇&#xff0c;或将彻底改变传统制药的研究范式。为了帮助更多人了解并掌握这一前沿技术&#xff0c;百度飞桨联合清…

LeedCode刷题---滑动窗口问题

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、长度最小的子数组 题目链接&#xff1a;长度最小的子数组 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。…

uniapp各种小程序分享 share - 主要流程 - 微信、抖音、快手、qq

参考 小程序环境 分享 | uni-app官网uni-app,uniCloud,serverless,分享,uni.share(OBJECT),分享到微信聊天界面示例代码,分享到微信朋友圈示例代码,uni.share 在App端各社交平台分享配置说明,uni.shareWithSystem(OBJECT),plus.share.sendWithhttps://uniapp.dcloud.net.cn/a…

MCS-51系列与AT89C5x系列单片机的介绍与AT系列的命名规则

MCS-51系列与AT89C5x系列单片机 主要涉及MCS-51系列与AT89C5x系列单片机的介绍与AT系列单片机的命名规则 文章目录 MCS-51系列与AT89C5x系列单片机一、 MCS-51系列单片机二、AT89C5x系列单片机2.1 AT89C5x/AT89S5x系列单片机的特点2.2 AT89系列单片机的型号说明2.2.1 前缀2.2.2…

节省时间,提高效率:深入解析MyBatis Plus

1. MyBatis Plus 概述 将Mybatis 通用Mapper PageHelper 升级成 MyBatis Plus 1.1 简介 官网&#xff1a;https://baomidou.com/ 参考教程&#xff1a;https://baomidou.com/pages/24112f/ MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#…

QT之常用按钮组件

QT之常用按钮组件 导入图标 布局 显示选中 实验结果 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }void Widget::on_push…

mybatis 的快速入门以及基于spring boot整合mybatis(一)

MyBatis基础 MyBatis是一款非常优秀的持久层框架&#xff0c;用于简化JDBC的开发 准备工作&#xff1a; 1&#xff0c;创建sprong boot工程&#xff0c;引入mybatis相关依赖2&#xff0c;准备数据库表User&#xff0c;实体类User3&#xff0c; 配置MyBatis&#xff08;在applic…

前端打包环境配置步骤

获取node安装包并解压 获取node安装包 wget https://npmmirror.com/mirrors/node/v16.14.0/node-v16.14.0-linux-x64.tar.xz 解压 tar -xvf node-v16.14.0-linux-x64.tar.xz 创建软链接 sudo ln -s 此文件夹的绝对路径/bin/node /usr/local/bin/node&#xff0c;具体执行如下…

实现手机扫码——扫描识别路由器参数

有个应用是批量自动检测无线路由器&#xff0c;检测前需要自动登录路由器的管理界面进行设置&#xff0c;如设置wifi参数、连接模式&#xff0c;或者恢复出厂设置等。进入管理界面的登录用户名是admin&#xff0c;密码则各不相同。此外也需要知道路由器的MAC地址&#xff0c;因…

【已解决】Win7虚拟机安装VMtools报错

在做以前的实验的时候发现要用到Win7虚拟机&#xff0c;于是就安装了一个Win7的虚拟机&#xff0c;但是发现屏幕太小&#xff0c;而且来回复制文本、复制文件太不方便了&#xff0c;索性就安装了VMtools&#xff0c;发现还安装不成– 情况1 报错&#xff1a;本程序需要您将此…

视频转场PR素材|专业级电影故障闪光效果视频过渡PR转场模板

这是一个以故障为主题的专业级电影故障闪光效果视频过渡pr转场模板。使用这些效果来增强视觉效果。包含视频教程。适用软件&#xff1a;Premiere Pro 2023|分辨率&#xff1a;38402160&#xff08;4K&#xff09; 来自PR模板网&#xff1a;https://prmuban.com/36092.html

数据库后门是什么?我们要如何预防它的危害

数据库后门是黑客在数据库中安装的一种特殊程序或代码&#xff0c;可以绕过正常的认证和授权机制&#xff0c;从而获取数据库的敏感信息或者控制整个数据库。黑客可以通过各种方式安装后门&#xff0c;比如利用漏洞、钓鱼、社会工程学等。 数据库后门的危害主要体现在以下几个方…

10 大 Android 手机系统修复软件深度评测

您的新 Android 手机可能因其令人兴奋的性能而印象深刻。然而&#xff0c;随着时间的推移&#xff0c;您可能会发现系统有些地方与以前不太一样。您可能会遇到屏幕无响应、 Android应用程序崩溃、连接问题、电池耗尽等现象。 10 大 Android 手机系统修复软件 好吧&#xff0c;…

Java网络通信-第21章

Java网络通信-第21章 1.网络程序设计基础 网络程序设计基础涵盖了许多方面&#xff0c;包括网络协议、Web开发、数据库连接、安全性等。 1.1局域网与互联网 局域网&#xff08;LAN&#xff09;与互联网&#xff08;Internet&#xff09;是两个不同的概念&#xff0c;它们分…

老胡的周刊(第119期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 Weekly Hub[2] 汇聚优质精选技术周刊&#x…

虹科Pico汽车示波器 | 汽车免拆检修 | 2018款东风风神AX7车发动机怠速抖动、加速无力

一、故障现象 一辆2018款东风风神AX7车&#xff0c;搭载10UF01发动机&#xff0c;累计行驶里程约为5.3万km。该车因发动机怠速抖动、加速无力及发动机故障灯异常点亮而进厂维修&#xff0c;维修人员用故障检测仪检测&#xff0c;提示气缸3失火&#xff1b;与其他气缸对调点火线…