ASP.NET Core 6.0 如何處理丟失的 Startup.cs 文件

介紹

?? ?.NET 6.0 已經發布,ASP.NET Core 6.0 也已發布。其中有不少變化讓很多人感到困惑。例如,“誰動了我的奶酪”,它在哪里Startup.cs?在這篇文章中,我將深入研究這個問題,看看它移動到了哪里以及其他變化。

?? ?ASP.NET Core 的中間件并沒有發生根本性的變化,但部分項目結構以及注冊依賴項的位置發生了變化。為了更好地理解它,最好從 .NET Core 3.1 項目模板開始,然后手動升級它,看看它與新模板相比如何。

升級舊式控制臺項目

?? ?首先,讓我們創建一個新的控制臺項目。我將其命名為OldToNew。我選擇了 .NET Core 3.1 目標,并將其升級到 .NET 6.0 以查看差異。如果您已經使用 .NET 一段時間,您會在文件中認出這個項目結構Program.cs。?

using System;

namespace OldToNew
{
? ? internal class Program
? ? {
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("Hello World!");
? ? ? ? }
? ? }
}

????????在 .NET 6.0 中,這些變化旨在簡化和消除應用程序中的冗余。他們引入的首批功能之一是所謂的Filescoped Namespaces。傳統命名空間如下所示:

namespace OldToNew
{
? ? // code goes here.
}

????????如果您已經使用過 .NET 一段時間,那么您可能從未在文件中放置過多個命名空間。您可以刪除花括號,只需添加分號,將整個文件標記為使用一個命名空間。

namespace OldToNew;
// code goes here.
?

using System;

namespace OldToNew;

internal class Program
{
? ? static void Main(string[] args)
? ? {
? ? ? ? Console.WriteLine("Hello World!");
? ? }
}
?

????????Visual Studio 將會向我抱怨,因為這是一個 .NET Core 3.1 項目,所以在我們走得太遠之前,我們需要編輯 .NET Core 3.1 .csproj 文件并將其轉換為 .NET 6.0 應用程序。

<!-- .NET Core 3.1 -->
<Project Sdk="Microsoft.NET.Sdk">

? <PropertyGroup>
? ? <OutputType>Exe</OutputType>
? ? <TargetFramework>netcoreapp3.1</TargetFramework>
? </PropertyGroup>

</Project>

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk">

? <PropertyGroup>
? ? <OutputType>Exe</OutputType>
? ? <TargetFramework>net6.0</TargetFramework>
? </PropertyGroup>

</Project>

????????一旦我們做出這一改變,Visual Studio 就會對文件范圍的命名空間感到滿意。

????????我們要做的下一個更改是刪除該using System;行。為此,我們需要再次編輯項目文件并啟用Implicit Usings。

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk">

? <PropertyGroup>
? ? <OutputType>Exe</OutputType>
? ? <TargetFramework>net6.0</TargetFramework>
? ? <ImplicitUsings>enable</ImplicitUsings>
? </PropertyGroup>

</Project>

????????如果我們啟用隱式 using 語句,我們通常使用的大多數常用 using 語句將默認包含在 SDK 中,您不再需要將它們包含在文件中。我們可以刪除該using System;行,因為編譯器會自動為我們添加 using 語句。

namespace OldToNew;

internal class Program
{
? ? static void Main(string[] args)
? ? {
? ? ? ? Console.WriteLine("Hello World!");
? ? }
}?

????????他們引入的下一個功能是所謂的“頂級語句”。 其目的是刪除每個控制臺應用程序或 ASP.NET Core 應用程序中存在的“垃圾”。

????????使用頂級語句,我們可以刪除static void Main(string[] args)方法和花括號以及命名空間和class Program聲明。

Console.WriteLine("Hello World!");

????????一旦刪除所有這些,您就會看到我們剩下的唯一代碼就是我們的Console.WriteLine()方法!

將控制臺應用更改為 Web 應用 (ASP.NET Core)

?? ?目前,這只是一個簡單的控制臺應用程序,但我想將其轉換為 ASP.NET Core 應用程序。在執行此操作之前,讓我們先查看解決方案資源管理器中的依賴項和框架節點。

????????您可以在上方看到,Frameworks這Microsoft.NETCore.App是包含創建控制臺應用程序所需的所有包的 SDK。讓我們將 .csproj 文件中的 SDK 類型更改為 .Web 類型項目,看看會發生什么Microsoft.NET.Sdk:Microsoft.NET.Sdk.Web。

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk.Web">

? <PropertyGroup>
? ? <OutputType>Exe</OutputType>
? ? <TargetFramework>net6.0</TargetFramework>
? </PropertyGroup>

</Project>
注意現在依賴下發生的情況:

????????該框架現在包括Microsoft.AspNetCore.App將引入創建 ASP.NET Core 應用程序所需的所有包。它還將修改全局 using 語句以包含 ASP.NET 特定的 using 語句。

????????現在讓我們刪除該Console.WriteLine("Hello World!");行并添加 ASP.NET Core 特定的代碼。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run();?

????????我們現在正在構建一個 Web 應用程序。WebApplication對象從哪里來?它屬于Microsoft.AspNetCore.Builder命名空間。

????????我們可以運行這個應用程序,但是由于沒有端點,所以會有點無聊。讓我們添加一個端點來完成這個任務:

app.MapGet("/", () => {
? ? return "Hello World!";
}); ??

????????我們剛剛在 ASP.NET Core 6.0 中創建了一個最小 API Web 應用程序。讓我們運行它并看看會發生什么。?

????????當我們啟動默認路徑時,它會返回,hello world因此我們有一個功能齊全的 Web 應用程序。最少的 API 是快速構建 Web API 項目的好方法。

Startup.cs 怎么樣?

?? ?ASP.NET Core 6.0 中的中間件流程與完整 Web API MVC 項目的流程類似,并且共享許多相同的實現。在以前的 ASP.NET Core 項目中,您將獲得一個Startup.cs包含兩個方法的類ConfigureServices()和Configure()。

?? ?在 ConfigureServices()中,您注冊了依賴項注入服務。在 Configure() 中,您概述了中間件管道順序和結構。

?? ?在我們的新項目中,這是什么樣子的?您將依賴注入放在哪里?答案是在第一行和第二行之間,注冊中間件在第二行和第三行之間,如下所示。

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.Run();

例如,如果我想添加身份驗證,我會像這樣注冊:?

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication(...) ...
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => {
? ? return "Hello World!";
}); ?
app.Run();

????????中間件管道中的順序很重要,因此我在中間件MapGet()上方添加了UseAuthentication()和UseAuthorization()。但是,為了使其生效,您需要使用屬性注釋要保護的端點。這將需要使用語句[Authorize],必須引用:Microsoft.AspNetCore.Authorization?。

using Microsoft.AspNetCore.Authorization;

...

app.MapGet("/",[Authorize]() => {
? ? return "Hello World!";
});

Program.cs到目前為止,我們的文件的完整代碼如下所示:?

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/",[Authorize] () => {
? ? return "Hello World!";
}); ?
app.Run();?

????????如果我們現在運行它,我們將會得到一個異常,因為我們從未指定身份驗證方案。

????????讓我們修復它。我們可以選擇多種不同類型的身份驗證方案,但在 WebAPI 中,我們通常使用諸如 bearer token 或 JWT token 之類的東西來保護應用程序。

????????讓我們繼續將 JWT 承載者添加到最小 API。我們需要Microsoft.AspNetCore.Authentication.JwtBearer通過 NuGet 導入包,然后添加以下代碼:

using Microsoft.AspNetCore.Authentication.JwtBearer;

...

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();

所以完整的塊應該是這樣的:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", [Authorize] () => {
? ? return "Hello World!";
});
app.Run();

????????JWT Bearer 已添加到應用程序中,讓我們運行它并查看會發生什么。現在我們得到了我們正在尋找的狀態,401 unauthorized因為我們沒有為其提供任何類型的令牌。還需要其他步驟來設置獲取令牌的方法并確保我們只允許接受有效的令牌,但這超出了本文的范圍。本文的重點是演示在哪里注冊依賴項和中間件以及如何使用它們。

????????我們應該做的最后一項修改是將 [Authorize] 屬性更改為使用“流暢的語法”,如下所示:

//FROM THIS:
app.MapGet("/", [Authorize] () => {
? ? return "Hello World!";
});

//TO THIS:
app.MapGet("/", () => {
? return "Hello World!";
}).RequireAuthorization();

它們都做同樣的事情,但是在最小 API 情況下,“流暢的語法”感覺更自然。?

恢復丟失的 Startup.cs 文件

?? ?接下來,讓我們看看能否恢復我們的老朋友Startup.cs文件。如果將所有內容都放在一個文件中,最小 API 結構可能會變得混亂和臃腫。

?? ?一定有辦法讓我們更好地組織這些。我將首先向Startup.cs項目添加一個名為的新類。

public class Startup
{
? ? public Startup(IConfiguration configuration)
? ? {
? ? ? ? Configuration = configuration;
? ? }

? ? public IConfiguration Configuration { get; }

? ? public void ConfigureServices(IServiceCollection services)
? ? {

? ? }

? ? ?public void Configure(WebApplication app, IWebHostEnvironment env)
? ? {

? ? }
}?

????????這看起來應該與過去的完整 Web API 項目模板很相似。我只是將其粘貼到我的新Startup.cs文件中并刪除了命名空間。該Startup.cs文件需要IConfiguration傳入一個對象。我們可以從我們的 中提供該對象嗎Program.cs??

// ?Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);?

????????是的。我們可以這樣做。builder創建的對象包含一個Configuration屬性,我們可以使用該屬性將其傳遞給Startup構造函數。

????????接下來,讓我們嘗試為該ConfigureServices()方法提供一個IServiceCollection。

// ?Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);?

????????同樣,builder包含一個Services我們可以用來傳遞給ConfigureServices()方法的屬性。現在我們可以從中刪除所有依賴注入代碼Program.cs并將其移動到ConfigureServices中的方法Startup.cs。?

// Startup.cs file
public void ConfigureServices(IServiceCollection services)
{
? ? services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
? ? services.AddAuthorization();
}

接下來,讓我們嘗試Configure()WebApplication類提供方法。?

// ?Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);

var app = builder.Build();

startup.Configure(app, builder.HostingEnvironment);?

????????有趣的是,雖然我們傳遞的app是 類型WebApplication,但如果你檢查它,該Configure()方法需要的是IApplicationBuilder,但它似乎沒問題。為什么?如果你深入研究該WebApplication對象,你會看到它實現了IApplicationBuilder接口。

????????我們將中間件管道代碼剪切出來Program.cs,并將其粘貼到Configure()方法中Startup.cs。

// Startup.cs file
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
? app.UseAuthentication();
? app.UseAuthorization();

? app.MapGet("/", () =>
? {
? ? ? return "hello world";
? }).RequireAuthorization();

? app.Run();
}

????????不幸的是,這實際上行不通,因為接口IApplicationBuilder沒有MapGet()方法或Run()方法。那些存在于WebApplication類中。如果我們將Configure()方法更改為接受WebApplication對象,它應該可以工作。?

// Startup.cs file
public void Configure(WebApplication app, IWebHostEnvironment env)
{
? app.UseAuthentication();
? app.UseAuthorization();

? app.MapGet("/", () =>
? {
? ? ? return "hello world";
? }).RequireAuthorization();

? app.Run();
}

讓我們看一下完整的文件“Program.cs”和“Startup.cs”,看看它們現在是什么樣子。?

// Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, builder.Environment);

// Startup.cs file
using Microsoft.AspNetCore.Authentication.JwtBearer;

public class Startup
{
? ? public Startup(IConfiguration configuration)
? ? {
? ? ? ? Configuration = configuration;
? ? }

? ? public IConfiguration Configuration { get; }

? ? // This method gets called by the runtime. Use this method to add services to the container.
? ? public void ConfigureServices(IServiceCollection services)
? ? {
? ? ? ? services.AddAuthentication(options =>
? ? ? ? {
? ? ? ? ? ? options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
? ? ? ? }).AddJwtBearer();
? ? ? ? services.AddAuthorization();
? ? }

? ? // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
? ? public void Configure(WebApplication app, IWebHostEnvironment env)
? ? {
? ? ? ? app.UseAuthentication();
? ? ? ? app.UseAuthorization();

? ? ? ? app.MapGet("/", () =>
? ? ? ? {
? ? ? ? ? ? return "hello world";
? ? ? ? }).RequireAuthorization();

? ? ? ? app.Run();
? ? }
}

????????如果我們運行它,我們會得到401 Unauthorized狀態,這意味著它正在運行。除了將我們的配置內容移到 中之外Startup.cs,我們沒有做太多改變,這讓它看起來更像舊的 .Net Core 風格。?

我們可以做得更好嗎?

?? ?使用Startup.cs確實有助于改善組織,但我認為我們可以做得更好。我一直討厭文件中Startup.cs單詞ConfigureServices()和Configure()彼此太接近,而且你還要傳遞一個IConfiguration對象。這可能會讓人搞不清楚什么放在哪里。

?? ?我們為什么不嘗試改進這一點呢?我不喜歡這個名字ConfigureServices()。如果我們將它重命名為RegisterDependentServices()并將其放在自己的文件中會怎么樣?這將使我們更容易理解發生了什么。

// RegisterDependentServices.cs file
using Microsoft.AspNetCore.Authentication.JwtBearer;

public static class RegisterDependentServices
{
? ? public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
? ? {
? ? ? ? // Register your dependencies
? ? ? ? builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
? ? ? ? ? ? .AddJwtBearer();
? ? ? ? builder.Services.AddAuthorization();
? ? ? ? return builder;
? ? }
}

????????我決定創建該類static并使用擴展方法將其添加到該類中。我們稍后WebApplicationBuilder會看到這如何改進文件。Program.cs

????????接下來,讓我們創建一個新文件SetupMiddlewarePipeline.cs。此文件將包含中間件管道。

public static class SetupMiddlewarePipeline
{
? ? public static WebApplication SetupMiddleware(this WebApplication app)
? ? {
? ? ? ? // Configure the pipeline !! ORDER MATTERS !!
? ? ? ? app.UseAuthorization();
? ? ? ? app.UseAuthentication();
? ? ? ? app.MapGet("/", () =>
? ? ? ? {
? ? ? ? ? ? return "hello world";
? ? ? ? }).RequireAuthorization();
? ? ? ? return app;
? ? }
}

現在,這會如何改變我們的Program.cs文件??

// Program.cs file
WebApplication app = WebApplication.CreateBuilder(args)
? ? .RegisterServices()
? ? .Build();

app.SetupMiddleware()
? ? .Run();

這樣就生成了一個非常干凈的Program.cs文件。事實上,如果您愿意,您可以將其全部放在一行中。

// Program.cs file
WebApplication.CreateBuilder(args)
? ? .RegisterServices()
? ? .Build()
? ? .SetupMiddleware()
? ? .Run();

我并不討厭它。事實上,我覺得我喜歡它。

那么 IConfiguration 怎么樣?

?? ?之前,Startup()構造函數需要IConfiguration注入其中。但是,由于WebApplication和WebApplicationBuilder都具有.Configuration屬性,因此我們不再需要顯式注入它。

// RegisterDependentServices.cs file
public static class RegisterDependentServices
{
? public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
? {
? ? // ******* Access the configuration *******
? ? var config = builder.Configuration;

? ? // Register your dependencies
? ? builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
? ? ? ? .AddJwtBearer();
? ? builder.Services.AddAuthorization();
? ? return builder;
? }
}

// setupMiddlewarePipeline.cs file
public static class SetupMiddlewarePipeline
{
? public static WebApplication SetupMiddleware(this WebApplication app)
? {
? ? // ******** Access the configuration ********
? ? var config = app.Configuration;

? ? // Configure the pipeline !! ORDER MATTERS !!
? ? app.UseAuthorization();
? ? app.UseAuthentication();
? ? app.MapGet("/", () =>
? ? {
? ? ? return "hello world";
? ? }).RequireAuthorization();
? ? return app;
? }
}

如果我們需要訪問應用程序的配置,它是可用的,而且我們的狀況很好。?

如果您喜歡此文章,請收藏、點贊、評論,謝謝,祝您快樂每一天。?

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

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

相關文章

歐幾里得算法求最小公倍數和最大公約數

一.最大公約數 gcd(a,b)gcd(b,a%b) 遞歸式,當且僅當b0&#xff0c;易得0和a的公約數為a.(可作為遞歸的出口) 證明&#xff1a; int gcd(int a, int b) {if (b 0) return a;else return gcd(b, a % b); } 二.最小公倍數 給定整數a b&#xff0c;求a b的最小公倍數 有圖可知…

文檔解析:PDF里的復雜表格、少線表格如何還原?

PDF中的復雜表格或少線表格還原通常需要借助專業的工具或在線服務&#xff0c;以下是一些可行的方法&#xff1a; 方法一&#xff1a;使用在線PDF轉換工具 方法二&#xff1a;使用桌面PDF編輯軟件 方法三&#xff1a;通過OCR技術提取表格 方法四&#xff1a;手動重建表格 …

局域網中 Windows 與 Mac 互相遠程連接的最佳方案

由于工作需要&#xff0c;經常需要遠程連接或登錄到幾臺不同的工作用機上進行操作。 下面基于免費、高體驗等基本訴求&#xff0c;簡要記錄幾種不同場景下的實踐方案選擇&#xff0c;僅供參考。如您有更簡單且更優的方案&#xff0c;歡迎一起探討。 1 遠程桌面連接的幾種不同…

二叉樹的所有路徑(力扣257)

因為題目要求路徑是從上到下的&#xff0c;所以最好采用前序遍歷。這樣可以保證按從上到下的順序將節點的值存入一個路徑數組中。另外&#xff0c;此題還有一個難點就是如何求得所有路徑。為了解決這個問題&#xff0c;我們需要用到回溯。回溯和遞歸不分家&#xff0c;每遞歸一…

Centos 修改歷史讀錄( HISTSIZE)

history命令 -c #清空命令歷史 -r #讀歷史文件附加到歷史列表 -w #保存歷史列表到指定的歷史文件 命令歷史相關環境變量 HISTSIZE #命令歷史記錄的條數 HISTFILE #指定歷史文件&#xff0c;默認為~/.bash_history HISTFILESIZE #命令歷史文件記錄歷史的條數 以上變量可以 exp…

【C++高并發服務器WebServer】-2:exec函數簇、進程控制

本文目錄 一、exec函數簇介紹二、exec函數簇 一、exec函數簇介紹 exec 函數族的作用是根據指定的文件名找到可執行文件&#xff0c;并用它來取代調用進程的內容&#xff0c;換句話說&#xff0c;就是在調用進程內部執行一個可執行文件。 exec函數族的函數執行成功后不會返回&…

TDengine 與上海電氣工業互聯網平臺完成兼容性認證

在工業數字化轉型和智能化升級的浪潮中&#xff0c;企業對高效、可靠的數據管理解決方案的需求日益增長。特別是在風電智能運維、火電遠程運維、機床售后服務等復雜多樣的工業場景下&#xff0c;如何實現海量設備和時序數據的高效管理&#xff0c;已經成為推動行業升級的關鍵。…

Jenkins pipline怎么設置定時跑腳本

目錄 示例&#xff1a;在Jenkins Pipeline中設置定時觸發 使用pipeline指令設置定時觸發 使用Declarative Pipeline設置定時觸發 使用Scripted Pipeline設置定時觸發 解釋Cron表達式 保存和應用配置 小結 在Jenkins中&#xff0c;定時跑腳本&#xff08;例如定時執行Pip…

kotlin的協程的基礎概念

Kotlin的協程是一種用于簡化異步編程的強大工具。 理解協程的基礎概念可以幫助開發者有效地利用其能力。 以下是Kotlin協程的一些關鍵基礎概念&#xff1a; 協程&#xff08;Coroutines&#xff09; &#xff1a; 協程是一種用于處理并發任務的編程模型&#xff0c;它可以在單…

machine learning knn算法之使用KNN對鳶尾花數據集進行分類

通過導入必要的scikit-learn導入必要的庫&#xff0c;加載給定的數據&#xff0c;劃分測試集和訓練集之后訓練預測和評估即可 具體代碼如下&#xff1a; import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split f…

springEl 構建通用樹

再項目開發中&#xff0c;需要構建組織的樹形&#xff0c;菜單的樹形&#xff0c;字典樹形。感覺相似的代碼寫了一堆&#xff0c;就想著有沒有辦法&#xff0c;寫個通用的方法去處理下&#xff1f; 學習了《SpringEL詳解》&#xff0c;用springEl處理下。 構建樹形&…

C++ 入門速通-第1章【黑馬】

內容來源于&#xff1a;黑馬 集成開發環境&#xff1a;CLion CLion的官方下載網址&#xff1a;CLion: A Cross-Platform IDE for C and C by JetBrains 我在b站找到了一個安裝教程&#xff0c;可以按照這個視頻教程進行安裝&#xff08;內置漢化教程&#xff09;&#xff1a; …

Python的進程和線程

ref 接受幾個設定: 進程是一家almost密不透風的公司,緬甸KK園區 線程里面工作的…人 進程**[園區]**內公共資源對于進程來說,可以共享. 別的園區[進程],一般不能和自己的園區共享人員資源,除非… 好的,現在再接受設定: 單個CPU在任一時刻只能執行單個線程&#xff0c;只有…

算法基礎 -- AVL樹初識

AVL樹初識 一、AVL樹簡介 AVL樹是一種自平衡二叉搜索樹&#xff08;Binary Search Tree, BST&#xff09;&#xff0c;于1962年由Georgy Adelson-Velsky和Evgenii Landis提出&#xff0c;名字也來自他們兩位的姓氏首字母組合。它通過在插入、刪除節點后維持平衡性&#xff0c…

MySQL數值型函數詳解

簡介 本文主要講解MySQL數值型函數&#xff0c;包括&#xff1a;ROUND、RAND、ABS、MOD、TRUNCATE、CEIL、CEILING、FLOOR、POW、POWER、SQRT、LOG、LOG2、LOG10、SIGN、PI。 本文所有示例中&#xff0c;雙橫杠左邊為執行的SQL語句&#xff0c;右邊為執行語句的返回值。 ROU…

自動化01

測試用例的萬能公式&#xff1a;功能測試界面測試性能測試易用性測試安全性測試兼容性測試 自動化的主要目的就是用來進行回歸測試 新產品--第一個版本 (具備豐富的功能)&#xff0c;將產品的整體進行測試&#xff0c;人工創造一個自動化測試用例&#xff0c;在n個版本的時候…

Spring中的事務管理器TransactionManager

目錄 一、主要功能 二、使用場景說明 在Spring框架中&#xff0c;事務管理器&#xff08;TransactionManager&#xff09;是用于管理事務的重要接口。它提供了對事務的全面控制&#xff0c;包括事務的狀態管理和資源管理等功能。本文將詳細介紹TransactionManager的主要功能、…

c語言(轉義字符)

前言&#xff1a; 內容&#xff1a; 然后記一下轉義字符 \? 在書寫連續多個問號時使用&#xff0c;防止他們被解析成三字母詞 \ 用于表示字符常量 \\ 用于表示一個反斜杠&#xff0c;防止他被解析為一個轉義序列符 \n 換行 \r …

Vue3 30天精進之旅:Day02 - 環境搭建

引言 在前一天的學習中&#xff0c;我們了解了Vue.js的基本概念和優勢。今天&#xff0c;我們將進入實際開發的第一步——環境搭建。良好的開發環境是順利開展項目的基礎&#xff0c;本文將指導你在本地設置Vue開發環境&#xff0c;并快速上手第一個Vue項目。 1. 環境準備 在…

代碼隨想錄 棧與隊列 test 7

347. 前 K 個高頻元素 - 力扣&#xff08;LeetCode&#xff09; 首先想到哈希&#xff0c;用key來存元素&#xff0c;value來存出現次數&#xff0c;最后進行排序&#xff0c;時間復雜度約為o(nlogn)。由于只需求前k個&#xff0c;因此可以進行優化&#xff0c;利用堆來維護這…