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.pswp.cn/news/209240.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209240.shtml
英文地址,請注明出處:http://en.pswp.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地址。 我們如果出于某種目的想…

vue打包完成后出現空白頁原因及解決

vue打包完成后出現空白頁原因及解決 原因 資源路徑不對 路由模式&#xff1a;使用history&#xff0c; 此模式上線后易出現404 解決 1、vue.config.js中配置: publicPath: ./2、在后端要求做重定向 如在nginx中使用rewrite做重定向

【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 。…

29 水仙花數

題目描述 所謂水仙花數&#xff0c;是指一個n位的正整數&#xff0c;其各位數字的n次方和等于該數本身。 例如153是水仙花數&#xff0c;153是一個3位數&#xff0c;并且1531^35^33^3. 輸入描述 第一行輸入一個整數n&#xff0c;表示一個n位的正整數。n在3到7之間&#xff0c;…

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…

數組區段的最大最小值

題干 本題要求實現一個函數&#xff0c;找出數組中一部分數據的最大值和最小值。 題目保證沒有無效數據。 函數接口定義&#xff1a; void sublistMaxMin ( int* from, int* to, int* max, int* min ); 其中 from和to都是用戶傳入的參數&#xff0c;分別存放數組部分數據的起…

深度綁定的二維碼

南京西祠 500 萬股股份被以 1 元價格掛牌轉讓。 唏噓不已&#xff0c;就像現在的孩子們都知道玩抖音&#xff0c;我們那個時代&#xff0c;西祠胡同就是互聯網的代名詞。在一個叫做西祠胡同的地方&#xff0c;住著一群村里的年輕人&#xff0c;他們痛并快樂著&#xff0c;渴望…

節省時間,提高效率:深入解析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

CSS 文字超出變為省略號

1.單行文本溢出顯示符號--必須滿足三個條件 width: 100px 先強制一行內顯示文本 white-space:nowrap; (默認 normal 自動換行) 超出的部分隱藏 overflow:hidden; 文字用省略號代替超出的部分 text-overflow:ellipsis; 2.多行文本溢出顯示省略號 width: 100px overflow&#x…