全棧開發:使用.NET Core WebAPI構建前后端分離的核心技巧(一)

目錄

cors解決跨域

依賴注入使用

分層服務注冊

緩存方法使用

內存緩存使用

緩存過期清理

緩存存在問題

分布式的緩存


cors解決跨域

前后端分離已經成為一種越來越流行的架構模式,由于跨域資源共享(cors)是瀏覽器的一種安全機制,它會阻止前端應用向不同域的服務器發起請求,保護用戶的隱私和數據安全。為了在前后端分離的應用中確保前端可以安全地訪問后端的接口,不會受到瀏覽器的跨域限制,這里我們可以通過后端進行相應的cors配置。

首先我們先搭建一下.net core webapi的框架,不了解的可以參考我之前的文章:地址?,然后我們配置了一個登錄的接口,返回的結果是記錄的類型,然后固定了一下登錄成功的用戶和密碼,如下所示:

/// <summary>
/// 登錄驗證
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
public record LoginRequest(string UserName, string Password);
public record ProcessInfo(long Id, string Name, long WorkingSet); // 記錄類型
public record LoginResponse(bool OK, ProcessInfo[]? ProcessInfos);
[HttpPost]
[Route("login/user")] // 特性路由
public LoginResponse Login(LoginRequest res)
{if (res.UserName == "admin" && res.Password == "123456"){var items = Process.GetProcesses().Select(x => new ProcessInfo(x.Id, x.ProcessName, x.WorkingSet64));return new LoginResponse(true, items.ToArray()); // 返回記錄類型}else{return new LoginResponse(false, null);}
}

然后我們就需要在入口文件Program.cs中配置一下我們允許要跨域的源,這里我們直接輸入前端運行服務器的域名和端口即可,然后設置允許規則,這里我們正常就都允許,如果想配置部分允許的話,通過With函數進行篩選即可,如下:

// 配置跨域策略
builder.Services.AddCors(options =>
{options.AddDefaultPolicy(builder =>{builder.WithOrigins("http://localhost:3000") // 允許跨域的源.AllowAnyHeader() // 允許任何頭.AllowAnyMethod() // 允許任何方法.AllowCredentials() // 允許攜帶憑證.WithExposedHeaders("X-Custom-Header"); // 暴露自定義頭信息});
});app.UseCors(); // 使用跨域策略

然后前端的話,這里我們就使用react框架通過axios發起請求,不了解react的朋友,可參加我之前的文章:地址 ,然后我們通過如下的一個示例代碼進行請求的發起:

import axios from "axios"
import { useState } from "react"const WebApi = () => {const [userName, setUserName] = useState<string>('')const [password, setPassword] = useState<string>('')const [processInfo, setProcessInfo] = useState<any>([])const reqPost = () => {axios.post('http://localhost:5263/First/login/user', { userName: userName, password: password }).then(res => {if (res.data.ok) {setProcessInfo(res.data.processInfos)} else {alert('登錄失敗, 請重新登錄!')}})}return (<div>賬戶: <input type="text" onChange={(e: any) => setUserName(e.target.value)} /> <br />密碼: <input type="password" onChange={(e: any) => setPassword(e.target.value)} /> <br /><button onClick={() => reqPost()}>發起請求</button>{processInfo.map((item: any) => <div key={item.id}>{item.name}</div>)}</div>)
}export default WebApi

最終呈現的效果如下所示:

依賴注入使用

依賴注入通過將對象的創建和管理交給框架,而不是在類內部直接創建,可以有效地解耦各個模塊,使得每個組件都能夠獨立地進行測試和維護。這對于實現前后端分離的架構至關重要,因為它允許開發者更靈活地控制和管理后端服務,使得前端與后端的交互更加清晰、可靠。具體可以參考我之前的文章:地址?,這里不再贅述,然后接下來我們開始演示在WebAPI中如何使用依賴注入:

構造函數注入服務操作:傳統且經典的創建依賴注入

創建服務:這里我們直接可以創建一個兩數相加的服務函數,如下所示:

namespace netCoreWebApi
{public class Calculator{public int Add(int i1, int i2){return i1 + i2;}}
}

服務注冊:然后我們在入口文件中進行服務注冊,如下所示:

builder.Services.AddScoped<Calculator>(); // 注冊Calculator服務

依賴注入:然后我們在控制器文件中通過構造函數進行服務注入:

using Microsoft.AspNetCore.Mvc;
using netCoreWebApi.WebCore;namespace netCoreWebApi.Controllers
{[ApiController][Route("api/[controller]/[action]")][ApiExplorerSettings(GroupName = nameof(ApiVersionInfo.V1))]public class FirstController : ControllerBase{private readonly Calculator calculator;public FirstController(Calculator calculator){this.calculator = calculator;}[HttpGet]public int Add1(){return calculator.Add(1, 2);}}
}

允許項目得到的結果如下所示,果然是3:

低使用頻率服務:一些耗時的依賴注入可能會影響其他接口的調用,這里我們需要使用該注入方式進行解決,一般的接口創建不需要使用該服務,只有調用頻率不高且資源的創建比較消耗資源的服務才會使用

創建服務:這里我們直接可以創建一個比較耗費資源的掃描文件服務函數,如下所示:

namespace netCoreWebApi
{public class SearchService{private string[] files;public SearchService(){this.files = Directory.GetFiles("d:/","*.exe", SearchOption.AllDirectories);}public int Count{get{return this.files.Length;}}}
}

服務注冊:然后我們在入口文件中進行服務注冊,如下所示:

builder.Services.AddScoped<SearchService>(); // 注冊SearchService服務

依賴注入:然后我們在控制器文件中通過構造函數進行服務注入,把Action用到的服務通過Action的參數注入,在這個參數上標注[FromServices],和Action的其他參數不沖突,只有Action方法才能使用[FromServices],普通的類默認不支持,如下所示:

[HttpGet]
public int Test1([FromServices]SearchService searchService) // 只有請求這個方法時才會注入SearchService
{return searchService.Count;
}

如下當請求耗費較多資源的時候,請求時間才會過長,請求其他不耗費資源的接口,正常請求:

分層服務注冊

從上面的依賴服務注冊使用我們可以了解到,當我們想進行依賴注入的使用,都需要在入口文件進行服務的注冊,但是項目一旦龐大起來或者說服務一旦多起來,多人協作開發的時候再要求所有的服務都必須注冊在入口文件中就會導致一些問題的沖突,如下所示就是典型的例子:

這里我們需要對服務注冊進行解耦操作,即進行分層處理。在分層項目中,讓各個項目負責各自的服務注冊,這里我們需要先安裝一下下面這個依賴包:

然后這里我們創建多個類庫,模擬多個服務的使用,然后將這些服務引用到項目上:

然后在每個項目中創建一個或多個實現IModuleInitializer接口的類,然后將服務注冊的函數寫道該接口類當中,如下所示:

然后我們通過反射原理,將服務注冊的函數來映射到入口函數當中,具體代碼如下所示:

然后我們再次運行項目,發現我們的服務還是成功被運行起來了,如下所示:

緩存方法使用

緩存:是系統優化中簡單又有效的工具,投入小收效大,數據庫中的索引等簡單有效的優化功能本質上都是緩存,其將經常訪問的數據存儲在一個快速訪問的存儲區域(如內存)中,從而減少對數據庫或其他慢速存儲系統的重復訪問。緩存能夠顯著提高應用程序的性能,尤其是在需要頻繁讀取大量數據時。

客戶端響應緩存:RFC7324是HTTP協議中對緩存進行控制的規范,其中重要的是cache-control這個響應報文頭,服務器如果返回cache-control: max-age-60,則表示服務器指示瀏覽器端可以緩存這個響應內容60秒

這里我們只需要給進行緩存控制的控制器的操作方法添加ResponseCache這個Attribute,.net core會自動添加cache-control報文頭,如下所示我們設置了一個獲取當前時間的接口,正常情況下每次請求接口都是最新的時間,這里添加了緩存20秒導致了請求在20秒之內的數據都是不變的:

服務端響應緩存:服務端緩存整個HTTP響應,而不是僅僅緩存其中的數據或部分內容。這樣,服務器可以直接返回已經緩存的響應,而不需要重新處理請求和生成新的響應。服務端響應緩存可以顯著提高性能,特別是在處理重復的請求時。

如果.net core中安裝了響應緩存中間件,那么.net core不僅會繼續根據[ResponseCache]設置來生成cache-control響應報文頭來設置客戶端緩存,而且服務器端也會按照[ResponseCache]的設置來對響應進行服務器端緩存,使用方法如下所示,在入口文件處在app.MapControllers()之前添加app.UseResponseCaching(),請確保如果你的項目如果存在app.UseCors()的話,該函數的調用也要寫在app.UseResponseCaching()之前,如下所示:

注意,如果你勾選了瀏覽器當中的禁用緩存的按鈕,不僅是客戶端,服務器端在請求的時候由于帶上了no-cache,服務器端也會禁用掉所有的緩存:

當然服務器緩存還是很雞肋的,它無法解決惡意請求帶給服務器的壓力,服務器響應緩存還有很大的限制,包括但不限于:響應狀態碼為200的GET或者HEAD響應才能被緩存;報文頭中不能含有Authorization、Set-Cookie等,為了解決這些問題我們還需要采用內存或者分布式進行緩存。

內存緩存使用

內存緩存:是指將數據存儲在計算機的內存中以便快速訪問和提高系統性能的一種技術,通常內存緩存用于存儲那些頻繁訪問且計算或獲取成本較高的數據,目的是減少從磁盤或其他慢速存儲設備中讀取數據的次數,從而加速應用程序的響應速度。

內存緩存的數據保存在當前運行的網站程序的內存中,是和進程相關的。因為在Web服務器中多個不同的網站是運行在不同的進程中的,因此不同的網站的內存緩存是不會相互干擾的,而且網站重啟之后內存緩存中的所有數據也就都被清空了。內存緩存的使用方法如下所示:

注冊內存緩存服務:這里我們需要先在入口文件進行內存緩存服務的注冊,如下所示:

builder.Services.AddMemoryCache(); // 添加內存緩存服務

這里我們先創建一個MyDbContext來模擬一下數據庫當中的數據,并設置一個函數返回數據:

namespace webapi_study
{public class MyDbContext{public static Task<Book?> GetByIdAsync(long id){var result = GetById(id);return Task.FromResult(result);}public static Book? GetById(long id){switch (id){case 0:return new Book(0, "C#", "張三");case 1:return new Book(1, "Java", "李四");case 2:return new Book(2, "Python", "王五");default:return null;}}}
}

接下來我們在控制器的接口中注冊一下緩存服務,通過GetOrCreateAsync函數拿到緩存當中的數據,如果緩存當中沒有數據的話我們就正常請求接口拿到數據即可,如下所示:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;namespace webapi_study.Controllers
{[ApiController][Route("api/[controller]/[action]")]public class TestController : ControllerBase{private readonly IMemoryCache cache; // 注入緩存服務private readonly ILogger<TestController> logger; // 注入日志服務public TestController(IMemoryCache cache, ILogger<TestController> logger){this.cache = cache;this.logger = logger;}[HttpGet]public async Task<ActionResult<Book?>> GetBookById(long id){// 1) 從緩存中獲取數據 2)從數據庫中獲取數據 3)返回給調用者并將數據存入緩存logger.LogInformation($"開始執行GetBookById: {id}");Book? b = await cache.GetOrCreateAsync("book" + id, async (e) =>{logger.LogInformation($"緩存中沒有找到,到數據庫中查一查,id={id}");return await MyDbContext.GetByIdAsync(id);});logger.LogInformation($"GetOrCreateAsync結果是:{id}");if (b == null){return NotFound($"Book with id {id} not found");}else{return b;}}}
}

最終呈現的效果如下所示,我們請求兩次接口,第一次請求數據庫中的數據因為沒有緩存數據,所有是請求的接口,第二次是由于緩存中已經存在數據了,我們就直接拿到緩存當中的數據即可:

緩存過期清理

上面我們簡單的介紹了一下內存緩存的簡單使用,但是上面的例子中緩存是不會過期的,除非重啟服務器進行重置操作,但是重置服務器的代價太大了,這里我們需要對在數據改變的時候緩存的處理,如下所示:

手動清理緩存:在數據改變的時候調用Remove或者Set來刪除或修改緩存(優點:及時)

設置過期時間:只要過期時間比較短,緩存數據不一致的清空也不會持續太少時間,可以通過兩種過期時間策略進行:絕對過期時間;滑動過期時間

絕對過期時間:顧名思義就是我設置了一個過期時間,超過這個時間緩存自動被清除,如下所示:

滑動過期時間:顧名思義就是只要在緩存沒過期的時候請求一次,緩存就會自動續命一段時間:

兩種過期時間混用:使用滑動過期時間策略,如果一個緩存項一直被頻繁訪問,那么這個緩存項就會一直被續期而不會過期,可以對一個緩存項同時設定滑動過期時間和絕對過期時間,并且把絕對過期時間設定比滑動過期時間長,這樣緩存項的內容會在絕對過期時間內隨著訪問被滑動續期,但是一旦超過了絕對過期時間,緩存項就會被刪除,如下所示:

總結:無論使用哪種過期時間策略,程序中都會存在緩存不一致的清空,部分系統(博客系統等)無所謂,部分系統不能忍受(比如金融),可以通過其他機制獲取數據源改變的消息,再通過代碼調用IMemoryCache的Set方法更新緩存。

緩存存在問題

在內存緩存中,緩存穿透和緩存雪崩是兩種常見且需要特別注意的問題,下面簡要討論這兩個問題及其解決方法:

緩存穿透:是指查詢的數據在緩存中不存在,并且每次查詢都直接訪問數據庫。通常緩存穿透發生在以下幾種情況:

1)查詢的請求數據根本不在數據庫中(例如,惡意請求或數據不存在)。

2)數據被誤刪除或沒有被正確存入緩存。

造成影響

1)每次請求都訪問數據庫,導致數據庫負載加重,降低系統性能。
2)緩存無法有效提高訪問速度,因為每次都需要從數據庫中讀取數據。

解決方案如下:

緩存空結果:對于一些常見的不存在數據(例如查詢某個ID的數據返回為空),可以將“空”數據也緩存起來。設置一個較短的過期時間防止數據庫不斷查詢相同的無效數據:

緩存雪崩:是指緩存中的大量數據在同一時刻過期或失效,導致大量請求同時訪問數據庫,造成數據庫壓力劇增,甚至崩潰。常見的觸發場景是:

1)大量緩存失效:如果緩存的失效時間設置相同或接近,那么這些緩存項會在同一時刻失效,導致大量請求同時查詢數據庫。

2)數據庫訪問壓力驟增:所有緩存失效后,系統會將大量的請求直接發送到數據庫,從而加重數據庫負載。

造成影響

1)短時間內大量請求集中訪問數據庫,容易造成數據庫崩潰或性能嚴重下降。

2)數據庫的負載激增,可能導致響應延遲和系統整體性能下降。

解決方案如下:

在基礎過期時間之上再加一個隨機的過期時間:

分布式的緩存

分布式緩存是一種將緩存數據分布在多個節點上的技術,目的是提高系統的可擴展性、可用性和性能。在大型系統中,單一的緩存節點往往無法滿足高并發、高可用的需求,分布式緩存應運而生。

分布式內存緩存:如果集群節點的數量非常多的話,這樣的重復查詢也同樣可能會把數據庫壓垮

分布式緩存服務器: 分布式緩存是指將緩存數據分布到多個不同的服務器節點上,這些節點共同協作提供緩存服務。用戶的請求通過負載均衡的方式訪問不同的緩存節點。常見的分布式緩存技術有:

1)Redis:最流行的分布式緩存系統之一,支持內存存儲和豐富的數據結構。

2)Memcached:另一個常見的分布式緩存,適合簡單的鍵值對緩存場景。

3)Alibaba Tair:阿里巴巴自研的分布式緩存系統,主要服務于大規模的互聯網應用。

.net core中提供了統一的分布式緩存服務器的操作接口IDistributedCache,用法和內存緩存類似,分布式緩存和內存緩存的區別在于:緩存值的類型為byte[],需要我們進行類型轉換,也提供了一些安裝string類型存取緩存值的擴展方法,如下所示:

方法說明
Task<byte[]>GetAsync(string key)查詢緩存鍵key對應的緩存值,返回值是byte[]類型,如果對應的緩存不存在,則返回null。
Task RefreshAsync(string key)刷新緩存鍵key對應的緩存項,會對設置了滑動過期時間的緩存項續期。
Task RemoveAsync(string key)刪除緩存鍵key對應的緩存項
Task SetAsync(string key, byte[] value,DistributedCacheEntryOptions options)設置緩存鍵key對應的緩存項:value屬性為byte類型的緩存值,注意value不能是null值
Task<string> GetStringAsync(string key)按照string類型查詢緩存鍵key對應的緩存值,返回值是string類型,如果對應的緩存不存在則返回null。
Task SetStringAsync(string key. string value,DistributedCacheEntryOptions options)設置緩存鍵key對應的緩存項,value屬性為string類型的緩存值,注意value不能是null值。

對于用什么做緩存服務器,用SQL Server做緩存其性能并不好;Memcached是緩存專用,性能非常高但是集群、高可用等方面比較弱,而且有”緩存鍵的最大長度為250字節“等限制,可以安裝EnyimMemcachedCore這個第三方NuGet包;Redis不局限于緩存,Redis做緩存服務器比Memcached性能稍差,但是Redis的高可用、集群等方面非常強大,適合在數據量大、高可用性等場合使用,可以按照如下插件進行使用:

然后我們在入口文件進行服務注冊:

builder.Services.AddStackExchangeRedisCache(options =>
{options.Configuration = "localhost:6379"; // 配置連接字符串options.InstanceName = "SampleInstance"; // 配置實例名稱,避免緩存沖突
});

然后我們在控制器當中構造分布式緩存的服務:

然后通過GetStringAsync函數構造當前的id,來判斷當前是否存在緩存

[HttpGet]
public async Task<ActionResult<Book?>> GetBookById1(long id)
{Book? book;string? s = await disCache.GetStringAsync("book" + id);if (s == null){book = await MyDbContext.GetByIdAsync(id);await disCache.SetStringAsync("book" + id, JsonSerializer.Serialize(book));}else{book = JsonSerializer.Deserialize<Book?>(s);}if (book == null){return NotFound($"Book with id {id} not found");}else{return book;}
}

通過redis服務器可以看到我們的緩存信息:

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

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

相關文章

《Linux服務與安全管理》| 數據庫服務器安裝和配置

《Linux服務與安全管理》| 數據庫服務器安裝和配置 目錄 《Linux服務與安全管理》| 數據庫服務器安裝和配置 任務一&#xff1a; 安裝PostgreSQL數據庫&#xff0c;設置遠程登錄&#xff0c;客戶端可以成功登錄并操作數據庫。 任務二&#xff1a; 安裝MySQL數據庫&#xf…

Linux系統之whereis命令的基本使用

Linux系統之whereis命令的基本使用 一、whereis命令介紹二、whereis命令的使用幫助2.1 whereis命令的幫助信息2.2 whereis命令幫助解釋 三、whereis命令的基本使用3.1 查找命令的位置3.2 僅查找二進制文件3.3 僅查找手冊頁3.4 輸出實際使用的查找路徑3.5 指定自定義搜索路徑 四…

Autosar-以太網是怎么運行的?(Davinci配置部分)

寫在前面&#xff1a; 入行一段時間了&#xff0c;基于個人理解整理一些東西&#xff0c;如有錯誤&#xff0c;歡迎各位大佬評論區指正&#xff01;&#xff01;&#xff01; 目錄 1.Autosar ETH通訊軟件架構 2.Ethernet MCAL配置 2.1配置對應Pin屬性 2.2配置TXD引腳 2.3配…

2024年度總結

首先&#xff0c;我是在2023年結束高中生涯進入大學的&#xff0c;難免會有固化的“高中生”思維&#xff0c;我等著老師的安排&#xff0c;看著課表上課&#xff0c;跟著時間吃飯&#xff0c;睡覺&#xff0c;偶爾會熬夜&#xff0c;但整體跟高中沒差太多。我對社團沒興趣&…

【Block總結】CSAM,包含分割、關鍵點、切分等均適用!|即插即用

論文信息 標題: CSAM: A 2.5D Cross-Slice Attention Module for Anisotropic Volumetric Medical Image Segmentation 論文鏈接: https://arxiv.org/pdf/2311.04942 GitHub鏈接: https://github.com/aL3x-O-o-Hung/CSAM 創新點 CSAM&#xff08;跨切片注意力模塊&#xff…

解決PyG安裝中torch-sparse安裝失敗問題:詳細指南

1 問題描述 最近在學習GNN&#xff0c;需要使用PyTorch Geometric&#xff08;PyG&#xff09;庫。在安裝PyG的過程中&#xff0c;遇到了torch-sparse安裝失敗的問題&#xff0c;錯誤提示為&#xff1a; ERROR: Failed building wheel for torch-sparse本文將詳細記錄問題的解…

鳥哥Linux私房菜筆記(三)

鳥哥Linux私房菜筆記&#xff08;三&#xff09; 該第三部分和第四部分主要為原書的第十一章&#xff08;正則表達式與文件格式化處理&#xff09;&#xff0c;第十二章學習shell腳本&#xff0c;第十六章&#xff08;進程管理與SElinux初探部分&#xff09;&#xff0c;第十七…

學習日記-250203

一.論文 看師兄寫好的一稿。 二、計劃&#xff1a; 繼續看論文里的問題。 然后繼續看promptCD相關&#xff0c;明天要看論文啦,今天家里有些事比較忙&#xff08;碎碎念&#xff09; 三. &#xff09;——&#xff08; 注冊了 openreview,ORCID,Google scholar&…

python學opencv|讀取圖像(五十四)使用cv2.blur()函數實現圖像像素均值處理

【1】引言 前序學習進程中&#xff0c;對圖像的操作均基于各個像素點上的BGR值不同而展開。 對于彩色圖像&#xff0c;每個像素點上的BGR值為三個整數&#xff0c;因為是三通道圖像&#xff1b;對于灰度圖像&#xff0c;各個像素上的BGR值是一個整數&#xff0c;因為這是單通…

Kafka ACL(訪問控制列表)介紹

文章目錄 Kafka ACL&#xff08;訪問控制列表&#xff09;介紹1. Kafka ACL 的基本概念1.1 Kafka ACL 的目標1.2 Kafka ACL 的組成部分 2. Kafka 支持的資源類型2.1 Topic&#xff08;主題&#xff09;2.2 Consumer Group&#xff08;消費者組&#xff09;2.3 Cluster&#xff…

在 WSL2 中重啟 Ubuntu 實例

在 WSL2 中重啟 Ubuntu 實例&#xff0c;可以按照以下步驟操作&#xff1a; 方法 1: 使用 wsl 命令 關閉 Ubuntu 實例: 打開 PowerShell 或命令提示符&#xff0c;運行以下命令&#xff1a; wsl --shutdown這會關閉所有 WSL2 實例。 重新啟動 Ubuntu: 再次打開 Ubuntu&#x…

Spring Boot 2 快速教程:WebFlux處理流程(五)

WebFlux請求處理流程 下面是spring mvc的請求處理流程 具體步驟&#xff1a; 第一步&#xff1a;發起請求到前端控制器(DispatcherServlet) 第二步&#xff1a;前端控制器請求HandlerMapping查找 Handler &#xff08;可以根據xml配置、注解進行查找&#xff09; 匹配條件包括…

小程序設計和開發:如何研究同類型小程序的優點和不足。

一、確定研究目標和范圍 明確研究目的 在開始研究同類型小程序之前&#xff0c;首先需要明確研究的目的。是為了改進自己的小程序設計和開發&#xff0c;還是為了了解市場趨勢和用戶需求&#xff1f;不同的研究目的會影響研究的方法和重點。例如&#xff0c;如果研究目的是為了…

使用 Numpy 自定義數據集,使用pytorch框架實現邏輯回歸并保存模型,然后保存模型后再加載模型進行預測,對預測結果計算精確度和召回率及F1分數

1. 導入必要的庫 首先&#xff0c;導入我們需要的庫&#xff1a;Numpy、Pytorch 和相關工具包。 import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import accuracy_score, recall_score, f1_score2. 自定義數據集 …

Unity-編譯構建Android的問題記錄

文章目錄 報錯&#xff1a;AAPT2 aapt2-4.1.2-6503028-osx Daemon #0 Failed to shutdown within timeout報錯信息解讀&#xff1a;原因分析最終處理方法 報錯&#xff1a;AAPT2 aapt2-4.1.2-6503028-osx Daemon #0 Failed to shutdown within timeout 報錯信息解讀&#xff1…

【axios二次封裝】

axios二次封裝 安裝封裝使用 安裝 pnpm add axios封裝 // 進行axios二次封裝&#xff1a;使用請求與響應攔截器 import axios from axios import { ElMessage } from element-plus//創建axios實例 const request axios.create({baseURL: import.meta.env.VITE_APP_BASE_API,…

SQL進階實戰技巧:如何構建用戶行為轉移概率矩陣,深入洞察會話內活動流轉?

目錄 1 場景描述 1.1 用戶行為轉移概率矩陣概念 1.2 用戶行為轉移概率矩陣構建方法 (1) 數據收集

Vue3.0實戰:大數據平臺可視化(附完整項目源碼)

文章目錄 創建vue3.0項目項目初始化項目分辨率響應式設置項目頂部信息條創建頁面主體創建全局引入echarts和axios后臺接口創建express銷售總量圖實現完整項目下載項目任何問題都可在評論區,或者直接私信即可。 創建vue3.0項目 創建項目: vue create vueecharts選擇第三項:…

Java自定義IO密集型和CPU密集型線程池

文章目錄 前言線程池各類場景描述常見場景案例設計思路公共類自定義工廠類-MyThreadFactory自定義拒絕策略-RejectedExecutionHandlerFactory自定義阻塞隊列-TaskQueue&#xff08;實現 核心線程->最大線程數->隊列&#xff09; 場景1&#xff1a;CPU密集型場景思路&…

【VM】VirtualBox安裝ubuntu22.04虛擬機

閱讀本文之前&#xff0c;請先根據 安裝virtualbox 教程安裝virtulbox虛擬機軟件。 1.下載Ubuntu系統鏡像 打開阿里云的鏡像站點&#xff1a;https://developer.aliyun.com/mirror/ 找到如圖所示位置&#xff0c;選擇Ubuntu 22.04.3(destop-amd64)系統 Ubuntu 22.04.3(desto…