Spring Boot的Security安全控制——應用SpringSecurity!

應用Spring Security

前面介紹了在項目開發時為什么選擇Spring Security,還介紹了它的原理。本節開始動手實踐Spring Security的相關技術。

實戰:Spring Security入門

現在開始搭建一個新項目,實踐一個Spring Security的入門程序。

(1)新建一個spring-security-demo模塊,添加項目依賴,在pom.xml中添加如下依賴:

<properties>

<java.version>11</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

<!--thymeleaf對security5的支持依賴-->

<dependency>

<groupId>org.thymeleaf.extras</groupId>

<artifactId>thymeleaf-extras-springsecurity5</artifactId>

<!--<version>3.0.4.RELEASE</version>-->

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>javax.servlet-api</artifactId>

<version>4.0.1</version>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

(2)在application.properties中添加Spring Security配置,配置當前登錄的用戶名和密碼,配置內容如下:

#登錄的用戶名

spring.security.user.name=admin

#登錄的密碼

spring.security.user.password=123456

(3)在resources文件夾下創建頁面add.html,表示添加頁面,代碼如下:

<!DOCTYPE html>

<html xmlns:th="https://www.thymeleaf.org">

<head>

title></title>

</head>

<body>

add 頁面

</body>

</html>

(4)添加主頁home.html,代碼如下:

<!DOCTYPE html>

<html xmlns:th="https://www.thymeleaf.org">

<head>

<title>主頁</title>

</head>

<body>

你已經登錄成功!

<form th:action="@{/logout}" action="/login" method="post">

<input type="submit" value="退出系統"/>

</form>

</body>

</html>

(5)添加login.html登錄頁,用于用戶的登錄,代碼如下:

<!DOCTYPE html>

<html xmlns:th="https://www.thymeleaf.org">

<head>

<title>請登錄</title>

</head>

<body>

<div>

<form th:action="@{/login}" method="post" action="/login">

<p>

<span>請輸入用戶名:</span>

<input type="text" id="username" name="username">

</p>

<p>

<span>請輸入密碼:</span>

<input type="password" id="password"

name="password">

</p>

<input type="submit" value="登錄"/>

</form>

</div>

</body>

</html>

(6)在resources文件夾下創建一個css文件夾,新建一個my.css文件,內容如下:

my css file

(7)新建一個Controller包,再新建如下3個Controller。

AddController類,用于返回add頁面,代碼如下:

package com.example.springsecuritydemo.controller;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.GetMapping;

@Controller

public class AddController {

@GetMapping("/add")

public String ad(){

return "add";

}

}

omeController類用于訪問home頁面,代碼如下:

package com.example.springsecuritydemo.controller;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.GetMapping;

@Controller

public class HomeController {

@GetMapping("/home")

public String home(){

return "home";

}

}

LoginController類用于用戶登錄,代碼如下:

package com.example.springsecuritydemo.controller;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.GetMapping;

@Controller

public class LoginController {

@GetMapping("/login")

public String login(){

return "login";

}

}

(8)新建一個config包,添加Spring Security配置文件

WebSecurityConfig:

package com.example.springsecuritydemo.config;

import com.example.springsecuritydemo.service.LoginSuccessHandler;

import org.springframework.context.annotation.Configuration;

import

org.springframework.security.config.annotation.web.builders.HttpSecuri

ty;

import

org.springframework.security.config.annotation.web.configuration.WebSe

curityConfigurerAdapter;

@Configuration

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override

protected void configure(HttpSecurity http) throws Exception {

// 關閉csrf校驗

http.csrf().disable();

// 配置登錄頁面,用戶名和密碼已在配置文件中

http.formLogin().loginPage("/login").permitAll();

// 配置登錄成功后的操作

http.formLogin().successHandler(new LoginSuccessHandler());

// 登錄授權

http.logout().permitAll();

// 授權配置

http.authorizeRequests()

/* 所有的靜態文件可以訪問 */

.antMatchers("/js/**","/css/**","/images/**").permitAll()

/* 所有的以/add 開頭的 add頁面可以訪問 */

.antMatchers("/add/**").permitAll()

.anyRequest().fullyAuthenticated();

}

}

9)新建一個登錄成功后的業務處理服務類LoginSuccessHandler,代碼如下:

package com.example.springsecuritydemo.service;

import org.springframework.security.core.Authentication;

import org.springframework.security.web.authentication.Authentication

SuccessHandler;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

/**

* 登錄成功后的業務處理類

*/

public class LoginSuccessHandler implements

AuthenticationSuccessHandler {

@Override

public void onAuthenticationSuccess(HttpServletRequest request,

HttpServletResponse response,

Authentication authentication)

throws

IOException {

System.out.println("登錄成功");

//重定向到home.html頁面

response.sendRedirect("/home");

}

}

(10)添加當前項目的啟動類
SpringSecurityDemoApplication,使用注解@EnableWeb- Security啟動Spring Security功能:

package com.example.springsecuritydemo;

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableWebSecurity

@SpringBootApplication

public class SpringSecurityDemoApplication {

public static void main(String[] args) {

SpringApplication.run(SpringSecurityDemoApplication.class,

args);

}

}

(11)執行
SpringSecurityDemoApplication啟動當前項目,訪問localhost:8080,因為沒有登錄,所以跳轉到登錄頁,如圖5.1所示。再訪問localhost:8080/home,還是會自動跳轉到登錄頁面,因為沒有登錄。前兩次訪問Spring Security時會自動判斷用戶還未登錄,直接跳轉到登錄頁面,提示用戶登錄。

再訪問localhost:8080/add,可以看到add頁面,如圖5.2所示。之所以能夠在沒有登錄的情況下看到add頁面,是因為Spring Security配置了未登錄時可以訪問/add這個鏈接。配置在WebSecurityConfig.java的代碼如下:

.antMatchers("/add/**").permitAll()

這個代碼的含義是所有以/add開頭的鏈接都允許訪問,因此可以看到add頁面。

同理,訪問localhost:8080/css/my.css會返回項目的靜態文件my.css,因為在WebSecurity-Config中配置了靜態文件的訪問權限。

/* 所有的靜態文件可以訪問 */

.antMatchers("/js/**","/css/**","/images/**").permitAll()

所以,js、css和images文件夾下的所有文件可以直接獲取,不會有任何校驗,訪問結果如圖5.3所示。

現在輸入用戶名admin和密碼123456登錄系統,登錄成功后的頁面如圖5.4所示,因為在LoginSuccessHandler中配置了登錄成功后的跳轉頁面代碼,即response.sendRedirect ("/home"),所以登錄成功后直接跳轉到了home頁面。

Spring Security適配器

Spring大量使用適配器模式,適配器的好處是當選擇性地修改一部分配置時不用覆蓋其他不相關的配置,Spring Security常用的適配器有
WebSecurityConfigurerAdapter。在開發中,可以選擇覆蓋部分自定義的配置,從而快速完成開發。

設計模式中適配器模式的結構如圖5.5所示。

適配器模式有3個類,分別是Adapter適配者類、Target目標類和ObjectAdapter適配器,可以通過這3個類實現適配器的相關功能。

在Spring Security框架中,
WebSecurityConfigurerAdapter類圖如圖5.6所示。

在圖5.6中,SecurityBuilder、SecurityConfigurer和SecurityBuilder這3個類非常重要,它們是用來構建過濾器鏈的,在用HttpSecurity實現SecurityBuilder時,傳入的泛型是
DefaultSecurityFilterChain,因此SecurityBuilder.build()用來構建過濾器鏈,而WebSecurity- Configurer用來配置WebSecurity。


WebSecurityConfigurerAdapter中有兩個方法非常重要,下面分別介紹。

(1)第一個是init()方法,其部分源碼如下:

public void init(final WebSecurity web) throws Exception {

final HttpSecurity http = getHttp();

web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {

FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.class);

web.securityInterceptor(securityInterceptor);

});

}

首先init()方法調用了getHttp()方法,其作用是進行HttpSecurity的初始化,其部分源碼如下:

@SuppressWarnings({ "rawtypes", "unchecked" })

protected final HttpSecurity getHttp() throws Exception {

if (http != null) {

return http;

}

AuthenticationEventPublisher eventPublisher =

getAuthenticationEventPublisher();

localConfigureAuthenticationBldr.authenticationEventPublisher(eventPub

lisher);

AuthenticationManager authenticationManager =

authenticationManager();

authenticationBuilder.parentAuthenticationManager(authenticationManage

r);

Map<Class<?>, Object> sharedObjects = createSharedObjects();

http = new HttpSecurity(objectPostProcessor, authenticationBuilder,

sharedObjects);

if (!disableDefaults) {

// @formatter:off

http

.csrf().and()

.addFilter(new WebAsyncManagerIntegrationFilter())

.exceptionHandling().and()

.headers().and()

.sessionManagement().and() .securityContext().and()

.requestCache().and()

.anonymous().and()

.servletApi().and()

.apply(new DefaultLoginPageConfigurer<>()).and()

.logout();

// @formatter:on

ClassLoader classLoader = this.context.getClassLoader();

List<AbstractHttpConfigurer> defaultHttpConfigurers =

SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class,

classLoader);

for (AbstractHttpConfigurer configurer : defaultHttpConfigurers)

{

http.apply(configurer);

}

}

configure(http);

return http;

}

在初始化完成后,init()方法調用了configure()方法配置默認的攔截器,當完成HttpSecurity初始化后,將HttpSecurity放入WebSecurity中,最終保存在WebSecurity的
securityFilterChainBuilders集合中。configure()方法的部分源碼如下:

/**

* 覆蓋此方法以配置{@link HttpSecurity}。

通常子類不建議通過調用super來調用此方法,因為它可能會覆蓋它們的配置。默認配置如下:

*

* <pre>

*

http.authorizeRequests().anyRequest().authenticated().and().formLogin(

).and().httpBasic();

* </pre> *

* 任何需要防御常見漏洞的端點都可以在這里指定,包括公共的端點

* See {@link HttpSecurity#authorizeRequests} and the

`permitAll()`authorization rule

* 更多關于公共端點的詳細信息

*

* @param http the {@link HttpSecurity} to modify

* @throws Exception if an error occurs

*/

// @formatter:off

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests().anyRequest().authenticated().and()

.formLogin().and().httpBasic();

}

(2)另外一個非常重要的方法是前面提到的configure()方法。可以看到,抽象類
WebSecurityConfigurerAdapter中的configure是個protect()方法,開發者可以新建類或繼承此類后實現該方法,從而實現業務邏輯。

在當前項目中,自定義的WebSecurityConfig類繼承了
WebSecurityConfigurerAdapter()方法,實現了空的configure()方法,并配置了當前項目的登錄和攔截信息。當前方法的入參是HttpSecurity,可以使用HttpSecurity的builder構建方式來靈活制定訪問策略。Http- Security的常用方法參見表5.1。

表5.1 HttpSecurity的常用方法

實戰:用戶授權

在Spring Security中可以設置不同的用戶擁有不同的角色,同時不同的角色有不同的權限。下面舉例說明。

修改HomeController.java文件,增加一個/home2方法,增加的代碼如下:

@GetMapping("/home2")

public String home2(){ return "home2";

}

修改WebSecurityConfig.java文件,增加配置屬性:

/**

* 授權,賦予用戶角色,基于內存授權

*/

@Override

protected UserDetailsService userDetailsService() {

InMemoryUserDetailsManager manager = new

InMemoryUserDetailsManager();

manager.createUser(User.withUsername("admin").password("123456").

roles("admin").build());

return manager;

}

修改WebSecurityConfig.java中的configure()方法,增加/home2連接的

角色權限配置:

// 授權配置

http.authorizeRequests()

//可以訪問所有靜態文件

.antMatchers("/js/**","/css/**","/images/**").permitAll()

//可以訪問所有以/add開頭的add頁面

.antMatchers("/add/**").permitAll()

.antMatchers("/home2").hasRole("user")

.anyRequest().fullyAuthenticated();

重啟項目,登錄之后訪問localhost:8080/home2,結果如圖5.7所示。因為當前用戶沒有權限,所以訪問報錯。

Spring Security核心類

Spring Security框架中最核心的接口類是AuthenticationManager,其部分源碼如下:

Authentication authenticate(Authentication authentication)

throws AuthenticationException;

AuthenticationManager是用來處理認證(Authentication)請求的基本接口。這個接口定義了方法authenticate(),此方法只接收一個代表認證請求的Authentication對象作為參數,如果認證成功,則會返回一個封裝了當前用戶權限等信息的Authentication對象,否則認證無法通過。

AuthenticationManager接口有兩個重要的實現。


AuthenticationManagerDelegator是一個委托類,由SecurityBuilder接口的子類來配置生成一個身份管理器;另外一個實現類是ProviderManager,此類的部分源碼如下:

public class ProviderManager implements AuthenticationManager, Message

SourceAware,

InitializingBean {

private List<AuthenticationProvider> providers =

Collections.emptyList();

private AuthenticationManager parent;public ProviderManager(AuthenticationProvider... providers) {

this(Arrays.asList(providers), null);

}

/**

* 使用給定的{@link AuthenticationProvider}構造一個{@link

ProviderManager}

*

* @param providers the {@link AuthenticationProvider}s to use

*/

public ProviderManager(List<AuthenticationProvider> providers) {

this(providers, null);

}

/**

* 使用給定的參考構造一個{@link ProviderManager}

*

* @param providers the {@link AuthenticationProvider}s to use

* @param parent a parent {@link AuthenticationManager} to fall back

to

*/

public ProviderManager(List<AuthenticationProvider> providers,

AuthenticationManager parent) {

Assert.notNull(providers, "providers list cannot be null");

this.providers = providers;

this.parent = parent;

checkState();

}

}

在此類中,構造函數有List<AuthenticationProvider> providers,它的作用是真正地完成認證工作。Spring Security有多種認證方式,如郵箱登錄、手機號登錄和第三方登錄等,只要一個認證成功了,就表示認證成功。

Spring Security的驗證機制

核心類AuthenticationManager調用其他的實現類進行認證。在SpringSecurity中提供認證功能的接口是
org.springframework.security.authentication.AuthenticationProvider。

該接口有兩個方法:authenticate()方法用來認證處理,返回一個authentication的實現類,代表認證成功;supports()方法表示當前身份提供者支持認證什么類型的身份信息,如果支持返回true,才會執行authenticate()方法進行身份認證。該接口的部分源碼如下:

public interface AuthenticationProvider {

Authentication authenticate(Authentication authentication)

throws AuthenticationException;

boolean supports(Class<?> authentication);

}

AuthenticationProvider接口有幾個常用的實現類,用來實現認證類型的具體方式,包括
AbstractUserDetailsAuthenticationProvider、DaoAuthenticationProvider和RememberMe- AuthenticationProvider。

DaoAuthenticationProvider的作用是從數據源中加載身份信息,其類圖如圖5.8所示。
RememberMeAuthenticationFilter的作用是當用戶沒有登錄而直接訪問資源時,首先從cookie中查找用戶信息,如果Spring Security能夠識別出用戶提供的remember me cookie,則不用再輸入用戶名和密碼,表示用戶已經認證成功。如圖5.9所示為RememberMeAuthenticationProvider類圖。

Spring Security的認證流程如下:

(1)從
WebSecurityConfigurerAdapter認證配置的configure(HttpSecurity http)方法進入,并添加攔截器addFilterBefore。

(2)進入
AbstractAuthenticationProcessingFilter攔截器的attemptAuthentication方法,指定認證對象AbstractAuthenticationToken。

(3)執行AuthenticationProvider認證邏輯,根據supports的判斷對認證的目標對象選擇一個攔截器進行認證,進入具體的認證邏輯方法authenticate()。

(4)如果認證成功,則進入攔截器的successfulAuthentication()方法;如果認證失敗,則進入攔截器的
unsuccessfulAuthentication方法()。

(5)對認證結果進行處理。

認證成功的邏輯:進入
SimpleUrlAuthenticationSuccessHandler的onAuthentication-Success()方法。

認證失敗的邏輯:進入
SimpleUrlAuthenticationFailureHandler的onAuthentication-Failure()方法。

(6)將數據封裝在ObjectMapper對象中后即可返回結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87568.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87568.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87568.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FPGA基礎 -- Verilog行為級建模之alawys語句

Verilog 中的 always 語句塊&#xff0c;這是行為級建模的核心結構之一&#xff0c;在 RTL 級設計中廣泛用于時序邏輯和組合邏輯的建模。 一、什么是 always 語句&#xff1f; ? 定義&#xff1a; always 語句用于描述可綜合的硬件行為邏輯&#xff0c;表示一個**“事件驅動…

【力扣 簡單 C】704. 二分查找

目錄 題目 解法一&#xff1a;二分查找 題目 解法一&#xff1a;二分查找 int find(const int* nums, int size, int target) {int left 0, right size - 1;while (left < right){int mid (left right) / 2;if (nums[mid] < target)left left 1;else if (nums[m…

Java并發編程實戰 Day 30:并發編程未來展望與最佳實踐總結

【Java并發編程實戰 Day 30】并發編程未來展望與最佳實踐總結 文章簡述 經過30天的系統學習&#xff0c;我們從Java并發編程的基礎知識逐步深入到高并發系統的架構設計與性能優化。本文作為“Java并發編程實戰”系列的收官之作&#xff0c;將全面回顧整個系列的核心內容&#…

量化面試綠皮書:23. 醉酒乘客

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。 23. 醉酒乘客 100名乘客排隊登機&#xff0c;每人持有一張對應座位的機票&#xff08;第n位乘客的座位號為n&#xff09;。 第一位乘客喝醉后…

AntV G6入門教程

以下教程聚焦于 AntV?G6 的 數據操作 API,詳細介紹各個方法的用途、參數以及完整的使用示例,幫助你在圖實例上精細地讀取、修改和管理節點/邊/組合等數據。文中示例代碼均基于 G6 v5.0.47 官方文檔 ([g6.antv.antgroup.com][1])。 一、獲取完整圖數據 1.1 graph.getData() …

67、數據訪問-crud實驗-分頁數據展示

67、數據訪問-crud實驗-分頁數據展示 分頁數據展示是數據訪問中常見的功能&#xff0c;用于將大量數據分割成多個頁面顯示&#xff0c;提升用戶體驗和系統性能。以下是分頁數據展示的相關介紹&#xff1a; #### 基本原理 1. **確定每頁顯示數量**&#xff1a;設定每頁顯示的數…

常見 Web 服務器

Web 服務器有很多種&#xff0c;功能和用途略有不同&#xff0c;下面我會分類介紹主流的 Web 服務器&#xff08;包含靜態/動態/反向代理支持&#xff09;并重點說明類似 Tomcat 的 Java 支持型。 常見 Web 服務器分類 類型名稱描述與特點&#x1f310; 靜態資源服務器Nginx高…

【MacOS】M3 Pro芯片MacBook極速搭建Kubernetes

M3 Pro 芯片 MacBook 2023上使用 Colima 安裝 Kubernetes。 Colima 輕量、高效&#xff0c;并且在 Apple Silicon 架構上表現出色。 下面是詳細的、一步一步的安裝和配置指南。 核心思路 我們將通過以下步驟完成整個過程&#xff1a; 準備工作: 安裝必要的工具&#xff0c;…

import { Add, Dongdong, UserAdd } from ‘@nutui/icons-react‘ 使用圖標導入庫報錯

import { Add } from "nutui/icons-react-taro"; 官網的導入的庫名字不全&#xff0c;后面要加-taro&#xff0c;就行了

猿人學js逆向比賽第一屆第七題

分析響應 看到響應體里面的data是個字體加密&#xff0c;于是這里可以看到woff文件也給返回了&#xff0c;這里現分析這個文件。 打開可以看到這里a351對應的是3和頁面中的3是對應的&#xff0c;于是用ddddocr動態識別字體文件中的字體&#xff0c;然后對應對應的字體替換是不…

股票心理學習篇:交易的人性弱點 - 頻繁交易

以下內容為學習時的筆記整理&#xff0c;視頻作者來自B站&#xff1a;老貓與指標 視頻鏈接&#xff1a;頻繁交易必死&#xff1f;底層邏輯深度剖析&#xff0c;老貓的的破局心法與實戰策略分享 交易的人性弱點 - 頻繁交易 主講人&#xff1a; 老貓 1. 引言&#xff1a;問題的…

WPF入門 #1 WPF布局基礎、WPF樣式基礎、WPF數據模板、WPF綁定

WPF當中有許多的布局容器控件&#xff0c;例如<Grid>、<StackPanel>、<WrapPanel>、<DockPanel>、<UniformGrid>。接下來分別介紹一下各個布局容器控件。 布局基礎 Grid <Grid><Grid.RowDefinitions><RowDefinition Height&qu…

開源大型語言模型的文本記憶新突破!

在現代科技的推動下&#xff0c;人工智能領域正在不斷地突破人類認知的極限。今年&#xff0c;由斯坦福大學、康奈爾大學和西弗吉尼亞大學的計算機科學家們&#xff0c;與法律學者共同展開了一項引人入勝的研究&#xff0c;聚焦于開源大型語言模型的文本記憶表現。這項研究不僅…

LeetCode 3090.每個字符最多出現兩次的最長子字符串

題目鏈接 https://leetcode.cn/problems/maximum-length-substring-with-two-occurrences/ 題目描述 給定一個字符串 s&#xff0c;找出滿足每個字符最多出現兩次的最長子字符串&#xff0c;并返回其長度。 示例 輸入&#xff1a;s "aabba" 輸出&#xff1a;5解…

使用開源NVIDIA cuOpt加速決策優化

使用開源NVIDIA cuOpt加速決策優化 文章目錄 使用開源NVIDIA cuOpt加速決策優化決策優化的現實挑戰供應鏈優化的復雜性實時決策的挑戰計算復雜性的挑戰 NVIDIA cuOpt&#xff1a;GPU加速的決策優化解決方案cuOpt的核心技術架構支持的優化問題類型性能優勢分析 實際應用案例&…

【JVM 09-垃圾回收】

垃圾回收 筆記記錄 1. 如何判斷對象可以回收1.1 引用計數法1.1.1 缺點 1.2 可達性分析算法1.2.1 可達分析、根對象1.2.2 優缺點 1.3 四種引用(強軟弱虛)1.3.1 軟引用的實際使用案例1.3.2 軟引用-引用隊列1.3.3 弱引用的實際使用案例 2. 垃圾回收算法2.1 標記清除算法2.2 標記整…

《二叉搜索樹》

引言&#xff1a; 上次我們結束了類和對象的收尾&#xff0c;之后我們就要學習一些高級的數據結構&#xff0c;今天我們先來看一個數據結構-- 二叉搜索樹。 一&#xff1a; 二叉搜索樹的概念(性質) 二叉搜索樹又稱二叉排序樹&#xff0c;它或者是一棵空樹&#xff0c;或者是…

【Redis】Sentinel哨兵

&#x1f6e1;? 深入理解 Redis Sentinel&#xff1a;高可用架構的守護者 在實際開發中&#xff0c;我們常用 Redis 構建緩存系統或數據中間件。然而&#xff0c;主從復制雖然能實現數據同步&#xff0c;但無法自動故障轉移&#xff08;failover&#xff09;&#xff0c;這就…

Shell腳本應用及實戰演練

文章目錄 一、Shell腳本語言的基本結構1、Shell腳本的用途&#xff1a;2、 Shell腳本基本結構&#xff1a;3、 創建Shell腳本過程4、 腳本注釋規范 二、Shell腳本語言的變量用法詳解位置與預定義變量 三、 Shell字符串詳解1、Shell字符串拼接2、Shell字符串截取3、 Shell的格式…

軟件工程瀑布模型學習指南

軟件工程瀑布模型學習指南 一、瀑布模型核心概念 1.1 定義與特點 瀑布模型是一種經典的軟件開發流程,將項目劃分為順序性的階段,每個階段有明確的輸入和輸出,如同瀑布流水般單向推進。其特點包括: 階段間具有明確的順序性和依賴性強調文檔驅動和階段評審適合需求明確、穩…