HarmonyOS學習記錄5

HarmonyOS學習記錄5

本文為個人學習記錄,僅供參考,如有錯誤請指出。本文主要記錄網絡請求的開發知識。
參考文檔:HTTP和RCP訪問網絡


網絡連接

概述

網絡連接管理提供管理網絡一些基礎能力,包括WiFi/蜂窩/Ethernet等多網絡連接優先級管理、網絡質量評估、訂閱默認/指定網絡連接狀態變化、查詢網絡連接信息、DNS解析等功能。

接收指定網絡的狀態變化通知
  1. 聲明接口調用所需要的權限:ohos.permission.GET_NETWORK_INFO

  2. 從@kit.NetworkKit中導入connection命名空間

// 引入包名。
import { connection } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
  1. 調用調用createNetConnection方法,指定網絡能力、網絡類型和超時時間(可選,如不傳入代表默認網絡;創建不同于默認網絡時可通過指定這些參數完成),創建一個NetConnection對象
let netSpecifier: connection.NetSpecifier = {netCapabilities: {// 假設當前默認網絡是WiFi,需要創建蜂窩網絡連接,可指定網絡類型為蜂窩網。bearerTypes: [connection.NetBearType.BEARER_CELLULAR],// 指定網絡能力為Internet。networkCap: [connection.NetCap.NET_CAPABILITY_INTERNET]},
};// 指定超時時間為10s(默認值為0)。
let timeout = 10 * 1000;// 創建NetConnection對象。
let conn = connection.createNetConnection(netSpecifier, timeout); 
  1. 調用該對象的register方法,訂閱指定網絡狀態變化的通知。當網絡可用時,會收到netAvailable事件的回調;當網絡不可用時,會收到netUnavailable事件的回調
// 訂閱指定網絡狀態變化的通知。
conn.register((err: BusinessError, data: void) => {console.log(JSON.stringify(err));
});
  1. 調用該對象的on()方法,傳入type和callback,訂閱關心的事件
// 訂閱事件,如果當前指定網絡可用,通過on_netAvailable通知用戶。
conn.on('netAvailable', ((data: connection.NetHandle) => {console.log("net is available, netId is " + data.netId);
}));// 訂閱事件,如果當前指定網絡不可用,通過on_netUnavailable通知用戶。
conn.on('netUnavailable', ((data: void) => {console.log("net is unavailable, data is " + JSON.stringify(data));
}));
  1. 當不使用該網絡時,可以調用該對象的unregister()方法,取消訂閱
// 當不使用該網絡時,可以調用該對象的unregister()方法,取消訂閱。
conn.unregister((err: BusinessError, data: void) => {
});

HTTP數據請求

概述

應用通過HTTP發起一個數據請求,支持常見的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。當前提供了2種HTTP請求方式,若請求發送或接收的數據量較少,可使用HttpRequest.request,若是大文件的上傳或者下載,且關注數據發送和接收進度,可使用HTTP請求流式傳輸HttpRequest.requestInstream。

發起HTTP數據請求
  1. 導入HTTP一般數據請求所需模塊
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
  1. 調用createHttp()方法,創建HttpRequest對象
let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
// 每一個httpRequest對應一個HTTP請求任務,不可復用。
let httpRequest = http.createHttp();
  1. 調用該對象的on()方法,訂閱HTTP響應頭事件,此接口會比request請求先返回。可以根據業務需要訂閱此消息
// 用于訂閱HTTP響應頭,此接口會比request請求先返回。可以根據業務需要訂閱此消息。
// 從API 8開始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。
httpRequest.on('headersReceive', (header) => {console.info('header: ' + JSON.stringify(header));
});
  1. 發起HTTP請求,解析服務器響應事件,調用該對象的request()方法,傳入HTTP請求的url地址和可選參數,發起網絡請求,按照實際業務需要,解析返回結果
  httpRequest.request(// 填寫HTTP請求的URL地址,可以帶參數或不帶參數。URL地址由開發者自定義。請求的參數可以在extraData中指定。"EXAMPLE_URL",{method: http.RequestMethod.POST, // 可選,默認為http.RequestMethod.GET,用于從服務器獲取數據,而POST方法用于向服務器上傳數據。// 開發者根據自身業務需要添加header字段。header: {'Content-Type': 'application/json'},// 當使用POST請求時此字段用于傳遞請求體內容,具體格式與服務端協商確定。extraData: "data to send",expectDataType: http.HttpDataType.STRING, // 可選,指定返回數據的類型。usingCache: true, // 可選,默認為true。priority: 1, // 可選,默認為1。connectTimeout: 60000, // 可選,默認為60000ms。readTimeout: 60000, // 可選,默認為60000ms。usingProtocol: http.HttpProtocol.HTTP1_1, // 可選,協議類型默認值由系統自動指定。usingProxy: false, // 可選,默認不使用網絡代理,自API 10開始支持該屬性。caPath:'/path/to/cacert.pem', // 可選,默認使用系統預制證書,自API 10開始支持該屬性。clientCert: { // 可選,默認不使用客戶端證書,自API 11開始支持該屬性。certPath: '/path/to/client.pem', // 默認不使用客戶端證書,自API 11開始支持該屬性。keyPath: '/path/to/client.key', // 若證書包含Key信息,傳入空字符串,自API 11開始支持該屬性。certType: http.CertType.PEM, // 可選,默認使用PEM,自API 11開始支持該屬性。keyPassword: "passwordToKey" // 可選,輸入key文件的密碼,自API 11開始支持該屬性。},multiFormDataList: [ // 可選,僅當Header中,'content-Type'為'multipart/form-data'時生效,自API 11開始支持該屬性,該屬性用于支持向服務器上傳二進制數據,根據上傳的具體數據類型進行選擇。{name: "Part1", // 數據名,自API 11開始支持該屬性。contentType: 'text/plain', // 數據類型,自API 11開始支持該屬性,上傳的數據類型為普通文本文件。data: 'Example data', // 可選,數據內容,自API 11開始支持該屬性。remoteFileName: 'example.txt' // 可選,自API 11開始支持該屬性。}, {name: "Part2", // 數據名,自API 11開始支持該屬性。contentType: 'text/plain', // 數據類型,自API 11開始支持該屬性,上傳的數據類型為普通文本文件。// data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.txt。filePath: `${context.filesDir}/fileName.txt`, // 可選,傳入文件路徑,自API 11開始支持該屬性。remoteFileName: 'fileName.txt' // 可選,自API 11開始支持該屬性。}, {name: "Part3", // 數據名,自API 11開始支持該屬性。contentType: 'image/png', // 數據類型,自API 11開始支持該屬性,上傳的數據類型為png格式的圖片。// data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.png。filePath: `${context.filesDir}/fileName.png`, // 可選,傳入文件路徑,自API 11開始支持該屬性。remoteFileName: 'fileName.png' // 可選,自API 11開始支持該屬性。}, {name: "Part4", // 數據名,自API 11開始支持該屬性。contentType: 'audio/mpeg', // 數據類型,自API 11開始支持該屬性,上傳的數據類型為mpeg格式的音頻。// data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.mpeg。filePath: `${context.filesDir}/fileName.mpeg`, // 可選,傳入文件路徑,自API 11開始支持該屬性。remoteFileName: 'fileName.mpeg' // 可選,自API 11開始支持該屬性。}, {name: "Part5", // 數據名,自API 11開始支持該屬性。contentType: 'video/mp4', // 數據類型,自API 11開始支持該屬性,上傳的數據類型為mp4格式的視頻。// data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.mp4。filePath: `${context.filesDir}/fileName.mp4`, // 可選,傳入文件路徑,自API 11開始支持該屬性。remoteFileName: 'fileName.mp4' // 可選,自API 11開始支持該屬性。}]}, (err: BusinessError, data: http.HttpResponse) => {if (!err) {// data.result為HTTP響應內容,可根據業務需要進行解析。console.info('Result:' + JSON.stringify(data.result));console.info('code:' + JSON.stringify(data.responseCode));// data.header為HTTP響應頭,可根據業務需要進行解析。console.info('header:' + JSON.stringify(data.header));console.info('cookies:' + JSON.stringify(data.cookies)); // 8+// 當該請求使用完畢時,調用destroy方法主動銷毀。httpRequest.destroy();} else {console.error('error:' + JSON.stringify(err));// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,調用destroy方法主動銷毀。httpRequest.destroy();}});
  1. 調用該對象的off()方法,取消訂閱HTTP響應頭事件
// 在不需要該回調信息時,需要取消訂閱HTTP響應頭事件,該方法調用的時機,可以參考步驟4中的示例代碼。
httpRequest.off('headersReceive');
  1. 當該請求使用完畢時,調用destory()方法銷毀
// 當該請求使用完畢時,調用destroy方法主動銷毀,該方法調用的時機,可以參考步驟4中的示例代碼。
httpRequest.destroy();

基于RCP的網絡請求

概述

Remote Communication Kit中的@hms.collaboration.rcp(后續簡稱RCP)指的是遠程通信平臺(remote communication platform),RCP提供了網絡數據請求功能,相較于Network Kit中HTTP請求能力,RCP更具易用性,且擁有更多的功能。在開發過程中,如果有些場景使用Network Kit中HTTP請求能力達不到預期或無法實現,那么就可以嘗試使用RCP中的數據請求功能來實現。

RCP與HTTP的區別
功能分類功能名稱功能描述HTTPRCP
基礎功能發送PATCH類型請求以PATCH的方式請求??
基礎功能設置會話中URL的基地址會話中URL的基地址將自動加在URL前面,除非URL是一個絕對的URL??
基礎功能取消自動重定向HTTP請求不會自動重定向??
基礎功能攔截請求和響應在請求后或響應前進行攔截??
基礎功能取消請求發送請求前取消、發送請求過程中取消、請求接收后取消??
基礎功能響應緩存是否使用緩存,請求時優先讀取緩存。緩存跟隨當前進程生效,新緩存會替換舊緩存??
基礎功能設置響應數據的類型設置數據以何種方式返回,將要響應的數據類型可設置為string、object、arraybuffer等類型??
基礎功能定義允許的HTTP響應內容的最大字節數服務器成功響應時,在獲取數據前校驗響應內容的最大字節數??
證書驗證自定義證書校驗自定義邏輯校驗客戶端和服務端的證書,判斷是否可以連接??
證書驗證忽略SSL校驗在建立SSL連接時不驗證服務器端的SSL證書??
DNS自定義DNS解析包括自定義DNS服務器或靜態DNS規則??
RCP特有捕獲詳細的跟蹤信息在會話中的HTTP請求期間捕獲詳細的跟蹤信息。跟蹤有助于調試、性能分析和深入了解通信過程中的數據流??
RCP特有數據打點,獲取HTTP請求的具體數據HTTP請求各階段的定時信息??
發起基礎的RCP網絡請求

通過RCP模塊能夠發起基礎的網絡請求,如GET、POST、HEAD、PUT、DELETE、PATCH、OPTIONS等請求。以PATCH請求為例,開發過程中經常會遇到發送請求修改資源的場景,假設有一個UserInfo,里面有userId、userName、 userGender等10個字段。可編輯功能因為需求,在某個特別的頁面里只能修改userName,這時就可以用PATCH請求,來更新局部資源

  1. 導入RCP模塊
  2. 創建headers,設置可接受的數據內容的類型為json字符串;創建modifiedContent,傳入想要修改的內容
  3. 調用rcp.createSession()創建通信會話對象session
  4. 使用new rcp.Requset()方法創建請求對象req
  5. 調用session.fetch()方法發起請求
  6. 獲取響應結果
核心代碼
// 定義請求頭
let headers: rcp.RequestHeaders = {'accept': 'application/json'
};
// 定義要修改的內容
let modifiedContent: UserInfo = {'userName': 'xxxxxx'
};
const securityConfig: rcp.SecurityConfiguration = {tlsOptions: {tlsVersion: 'TlsV1.3'}
};
// 創建通信會話對象
const session = rcp.createSession({ requestConfiguration: { security: securityConfig } });
// 定義請求對象rep
let req = new rcp.Request('http://example.com/fetch', 'PATCH', headers, modifiedContent);
// 發起請求
session.fetch(req).then((response) => {Logger.info(`Request succeeded, message is ${JSON.stringify(response)}`);
}).catch((err: BusinessError) => {Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

實驗

一、網絡狀態監聽的實現

本實驗希望實現的效果是在首頁登錄時,不僅僅對賬號密碼進行非空校驗,還需要對網絡狀態進行檢測,在沒有網絡的情況下,拒絕登錄操作并提示用戶網絡未連接。

首先,我們在ets目錄下創建一個common文件夾,用于存放一些公共能力。隨后在common文件夾下創建network文件夾并創建ConnectionUtils.ets(網絡連接工具類),我們將在這個文件中實現網絡狀態監聽功能。

step1 分析需要實現的功能:

  1. 能夠完成是否有網絡連接的校驗,從而在點擊登錄時,不僅對賬號密碼進行非空校驗,還要完成對網絡狀態的校驗,無網絡時不進行跳轉
  2. 能夠訂閱網絡狀態,在網絡狀態變化時,主動觸發彈窗提醒用戶網絡狀態的變化

step2 網絡連接工具類的封裝:
在實現網絡連接工具類的封裝前,首先需要申請權限,在entry/src/main目錄下的module.json5中,添加網絡訪問權限和網絡信息查看權限(即代碼塊中requestPermissions包含的內容,其中的string:Internet和string:Internet和string:Internetstring:network_info字段需要在resource/base/element/string.json文件中自行添加)

{"module": {"name": "entry","type": "entry","description": "$string:module_desc","mainElement": "EntryAbility","deviceTypes": ["phone"],"routerMap": "$profile:route_map","deliveryWithInstall": true,"installationFree": false,"pages": "$profile:main_pages","abilities": [{"name": "EntryAbility","srcEntry": "./ets/entryability/EntryAbility.ets","description": "$string:EntryAbility_desc","icon": "$media:startIcon","label": "$string:EntryAbility_label","startWindowIcon": "$media:icon","startWindowBackground": "$color:start_window_background","exported": true,"skills": [{"entities": ["entity.system.home"],"actions": ["action.system.home"]}]}],"requestPermissions": [{"name": "ohos.permission.INTERNET","reason": "$string:Internet","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.GET_NETWORK_INFO","reason": "$string:network_info","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]}
}

接下來,在剛才創建的ConnectionUtils.ets文件中寫入下方的代碼。實現是否有網絡的校驗,需要使用@kit.NetworkKit的connection模塊,首先我們定義一個名為isNetworkConnected()的方法用于判斷是否有網絡連接,所以該函數應該返回一個布爾值。而具體的方法實現,需要使用connection模塊提供的connection.getDefaultNet()方法,該方法可以獲取到當前連接網絡的信息,同時也可以判斷是否有網絡連接。connection模塊還提供了connection.getNetCapabilities()方法,可以獲取當前網絡的具體信息,包括網絡類型、網絡具體能力等

import { connection } from '@kit.NetworkKit';
import { hilog } from '@kit.PerformanceAnalysisKit';const TAG: string = 'ConnectionUtils';/*** 這里的ConnectionUtils類用于提供網絡監聽的能力*/
export class ConnectionUtils {/*** 這里的isNetworkConnected方法用于檢查監測網絡是否連接*/async isNetworkConnected(): Promise<boolean> {let result: boolean = false;await connection.getDefaultNet().then(async (data: connection.NetHandle) => {if (data.netId === 0) {hilog.info(0x0000, TAG, 'network error');return;}await connection.getNetCapabilities(data).then((data: connection.NetCapabilities) => {let bearerTypes: Set<number> = new Set(data.bearerTypes);let bearerTypesNum = Array.from(bearerTypes.values());for (let item of bearerTypesNum) {if (item === 0) {result = true;hilog.info(0x0000, TAG, 'BEARER_CELLULAR');} else if (item === 1) {result = true;hilog.info(0x0000, TAG, 'BEARER_WIFI');} else if (item === 3) {result = true;hilog.info(0x0000, TAG, 'BEARER_ETHERNET');} else {return;}}})})return result;}
}export default new ConnectionUtils();

在上述代碼的基礎上繼續完善監聽功能。完成了關于網絡狀態判斷的方法后,我們來實現網絡狀態的監聽功能,目的是在網絡狀態發生變更時,及時通過彈窗提醒用戶。主要需要使用NetConnection提供的訂閱能力以及網絡監聽能力,在使用網絡狀態監聽之前,我們需要首先進行訂閱,在這里,我們繼續為工具類中添加自定義封裝方法,首先是訂閱方法openRegister()以及取消訂閱方法closeRegister(),另外封裝了一個用于網絡狀態監聽的方法registerNetworkAvailableStatus()(其中的r(′app.string.NetworkAvailable’)、r('app.string.Network_Available’)、r(app.string.NetworkA?vailable)r('app.string.Network_Unavailable’)和$r(‘app.string.Network_Lost’)字段需要在resource/base/element/string.json文件中自行添加)

import { connection } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';const TAG: string = 'ConnectionUtils';/*** 這里的ConnectionUtils類用于提供網絡監聽的能力*/
export class ConnectionUtils {netConnection = connection.createNetConnection();/*** 這里的isNetworkConnected方法用于檢查監測網絡是否連接*/async isNetworkConnected(): Promise<boolean> {let result: boolean = false;await connection.getDefaultNet().then(async (data: connection.NetHandle) => {if (data.netId === 0) {hilog.info(0x0000, TAG, 'network error');return;}await connection.getNetCapabilities(data).then((data: connection.NetCapabilities) => {let bearerTypes: Set<number> = new Set(data.bearerTypes);let bearerTypesNum = Array.from(bearerTypes.values());for (let item of bearerTypesNum) {if (item === 0) {result = true;hilog.info(0x0000, TAG, 'BEARER_CELLULAR');} else if (item === 1) {result = true;hilog.info(0x0000, TAG, 'BEARER_WIFI');} else if (item === 3) {result = true;hilog.info(0x0000, TAG, 'BEARER_ETHERNET');} else {return;}}})})return result;}/*** 該方法用于打開注冊表*/openRegister() {this.netConnection.register((error: BusinessError) => {hilog.info(0x0000, TAG, JSON.stringify(error));});}/*** 該方法用于監聽網絡的狀態*/registerNetworkAvailableStatus() {this.netConnection.on('netAvailable', () => {promptAction.showToast({message: $r('app.string.Network_Available'),duration: 2000});});this.netConnection.on('netUnavailable', () => {promptAction.showToast({message: $r('app.string.Network_Unavailable'),duration: 2000});});this.netConnection.on('netLost', () => {promptAction.showToast({message: $r('app.string.Network_Lost'),duration: 2000});});}/*** 該方法用于關閉注冊表*/closeRegister() {this.netConnection.unregister((error: BusinessError) => {hilog.info(0x0000, TAG, JSON.stringify(error));});}
}export default new ConnectionUtils();

至此,我們完成了網絡狀態監聽工具類的封裝。接下來,我們來使用工具類中的方法,豐富登錄頁面的網絡校驗功能

step3 使用網絡連接工具類實現網絡檢驗登錄
封裝好網絡狀態工具類后,我們來使用工具類中的方法實現網絡檢驗登錄。首先我們修改一下首頁登錄按鈕的邏輯,使用網絡狀態工具類中的判斷是否有網絡連接的方法,并根據返回的布爾值進行網絡狀態的校驗,無網絡不進行跳轉(需要先在pages文件夾中創建一個LoginPage.ets文件)

import { promptAction } from '@kit.ArkUI';
import ConnectionUtils from '../common/network/ConnectionUtils';@Extend(TextInput)
function inputStyle() {.placeholderColor('#99182431').height('45vp').fontSize('18fp').backgroundColor('#F1F3F5').width('328vp').margin({ top: 12 })
}@Extend(Line)
function lineStyle() {.width('328vp').height('1vp').backgroundColor('#33182431')
}@Extend(Text)
function blueTextStyle() {.fontColor('#007DFF').fontSize('14fp').fontWeight(FontWeight.Medium)
}/*** Login page*/
@Entry
@Component
struct LoginPage {@State account: string = '';@State password: string = '';@State isShowProgress: boolean = false;private timeOutId: number = -1;pathStack: NavPathStack = new NavPathStack();@BuilderimageButton(src: Resource) {Button({ type: ButtonType.Circle, stateEffect: true }) {Image(src)}.height('48vp').width('48vp').backgroundColor('#F1F3F5')}login(result: boolean): void {if (this.account === '' || this.password === '') {promptAction.showToast({message: $r('app.string.input_empty_tips')});} else {this.isShowProgress = true;if (this.timeOutId === -1) {this.timeOutId = setTimeout(async () => {this.isShowProgress = false;this.timeOutId = -1;if (result) {this.pathStack.pushPathByName('MainPage', null);} else {promptAction.showToast({message: '無網絡連接,無法登錄'});}}, 2000);}}}aboutToDisappear() {clearTimeout(this.timeOutId);this.timeOutId = -1;}build() {Navigation(this.pathStack) {Column() {Image($r('app.media.logo')).width('78vp').height('78vp').margin({top: '150vp',bottom: '8vp'})Text($r('app.string.login_page')).fontSize('24fp').fontWeight(FontWeight.Medium).fontColor('#182431')Text($r('app.string.login_more')).fontSize('16fp').fontColor('#99182431').margin({bottom: '30vp',top: '8vp'})TextInput({ placeholder: $r('app.string.account') }).maxLength(11).type(InputType.Number).inputStyle().onChange((value: string) => {this.account = value;})Line().lineStyle()TextInput({ placeholder: $r('app.string.password') }).maxLength(8).type(InputType.Password).inputStyle().onChange((value: string) => {this.password = value;})Line().lineStyle()Row() {Text($r('app.string.message_login')).blueTextStyle()Text($r('app.string.forgot_password')).blueTextStyle()}.justifyContent(FlexAlign.SpaceBetween).width('328vp').margin({ top: '8vp' })Button($r('app.string.login'), { type: ButtonType.Capsule }).width('328vp').height('40vp').fontSize('16fp').fontWeight(FontWeight.Medium).backgroundColor('#007DFF').margin({top: '48vp',bottom: '12vp'}).onClick(async () => {await ConnectionUtils.isNetworkConnected().then((value) => {this.login(value);})})Text($r('app.string.register_account')).fontColor('#007DFF').fontSize('16fp').fontWeight(FontWeight.Medium)if (this.isShowProgress) {LoadingProgress().color('#182431').width('30vp').height('30vp').margin({ top: '20vp' })}Blank()Text($r('app.string.other_login_method')).fontColor('#838D97').fontSize('12fp').fontWeight(FontWeight.Medium).margin({top: '50vp',bottom: '12vp'})Row({ space: 44 }) {this.imageButton($r('app.media.login_method1'))this.imageButton($r('app.media.login_method2'))this.imageButton($r('app.media.login_method3'))}.margin({ bottom: '16vp' })}.height('100%').width('100%').padding({left: '12vp',right: '12vp',bottom: '24vp'})}.backgroundColor('#F1F3F5').width('100%').height('100%').hideTitleBar(true).hideToolBar(true)}
}

接下來我們還需要啟動網絡狀態的監聽,主要在EntryAbility.ets中完成。在onCreate()方法中開啟訂閱,onWindowStageCreate()方法中調用監聽方法,在onWindowStageDestroy()方法中關閉訂閱

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
import ConnectionUtils from '../common/network/ConnectionUtils';/*** Lift cycle management of Ability.*/
export default class entryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {ConnectionUtils.openRegister();hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');}onDestroy(): void | Promise<void> {hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');}onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');windowStage.getMainWindow().then((data: window.Window) => {// Window immersive.data.setWindowLayoutFullScreen(true);});windowStage.loadContent('pages/LoginPage', (err, data) => {if (err.code) {hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.ERROR);hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}ConnectionUtils.registerNetworkAvailableStatus();hilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');});}onWindowStageDestroy(): void {// Main window is destroyed, release UI related resourceshilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');ConnectionUtils.closeRegister();}onForeground(): void {// Ability has brought to foregroundhilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');}onBackground(): void {// Ability has back to backgroundhilog.isLoggable(0x0000, 'testTag', hilog.LogLevel.INFO);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');}
}

這樣,我們就完成了登錄邏輯中網絡狀態校驗及訂閱網絡狀態變化的監聽

二、使用HTTP請求網絡數據

這個部分需要在ets/common/network中重新創建一個文件,命名為HttpUtils.ets

step1 分析具體實現功能

  1. 使用HTTP發起get請求,獲取一張箭頭圖片并保存在沙箱路徑中,并返回其沙箱路徑對應的uri,以便使用箭頭圖片作為首頁列表的布局元素
  2. 使用HTTP發起post請求,獲取官網中的圖片與文本信息,并將其封裝在實體類數組中,以便將這些信息作為首頁列表的布局元素

step2 HTTP工具類的封裝
首先,使用@kit.NteworkKit中的http模塊提供的createHttp()方法獲取一個HttpRequest對象,再通過封裝request()方法實現通過get請求網絡圖片,在獲取到網絡圖片之后,我們需要使用到@kit.CoreFileKit提供的文件管理能力將獲取的圖片資源保存到沙箱路徑。然后需要再實現一個與get請求一致的postHttpRequest()方法,用于傳入網絡請求地址url以及網絡請求配置參數HttpRequestOptions

import { http } from '@kit.NetworkKit';
import { fileIo, fileUri } from '@kit.CoreFileKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import ListInfo from '../../viewmodel/ListInfo';
import ResponseData from '../../viewmodel/ResponseData';const TAG: string = 'HttpUtils';/*** 類的頭部*/
class Header{contentType: string;constructor(contentType: string) {this.contentType = contentType;}
}/*** HttpUtils提供通過HTTP協議進入網絡的能力*/
export class HttpUtils {httpRequest: http.HttpRequest;constructor() {this.httpRequest = http.createHttp();}/*** 通過 HTTP 發起 GET 請求的方法*/async getHttpRequest(cacheDir: string): Promise<string> {let responsePictureUri: string = '';await this.httpRequest.request('https://developer.huawei.com/system/modules/org.opencms.portal.template.core/' +'resources/harmony/img/jiantou_right.svg',{ method: http.RequestMethod.GET }).then((data: http.HttpResponse) => {let filePath = cacheDir + '/test.svg';let file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);responsePictureUri = fileUri.getUriFromPath(filePath);fileIo.writeSync(file.fd, data.result as ArrayBuffer);fileIo.closeSync(file.fd);})return responsePictureUri;}async postHttpRequest(): Promise<ListInfo[]> {let responseData: Array<ListInfo> = [];await this.httpRequest.request('https://svc-drcn.developer.huawei.com/community/servlet/consumer' +'/partnerActivityService/v1/developer/activity/terminalActivities/list',{method: http.RequestMethod.POST, extraData: {'status': '1','belong': '1','language': 'cn','needTop': 1,'displayChannel': [1, 3],'count': 4,'pagestart': 1,'type': '1,4,5,6'},header: new Header('application/json;charset=UTF-8')}).then((data: http.HttpResponse) => {let result: ResponseData = JSON.parse(data.result as string);responseData = result.value.list;}).catch((err: Error) => {hilog.info(0x0000, TAG, JSON.stringify(err));});return responseData;}/*** 銷毀HttpRequest對象的方法*/destroyHttpRequest(){this.httpRequest.destroy();}
}

其中,還需要在/ets/viewmodel中創建ResponseData文件夾并創建ListInfo、ResponseData、Value三個實體類,注意,這三個類需要分別存放,本文中將代碼寫在了同一塊中只是為了便于查看,這三個類用于承接回調函數中HttpResponse類型的對象data獲取的返回值
在這里插入圖片描述

// ListInfo.ets
export default class ListInfo{public activityName: string;public theme: string;public indexNavPic: string;constructor(activityName: string,theme: string,indexNavPic: string) {this.activityName = activityName;this.theme = theme;this.indexNavPic = indexNavPic;}
}// ResponseData.ets
import Value from "./Value";export default class ResponseData{public code: string;public value: Value;constructor(code: string,value: Value) {this.code = code;this.value = value;}
}// Value.ets
import ListInfo from "./ListInfo";export default class Value{public list: Array<ListInfo>;constructor(list: Array<ListInfo>) {this.list = list;}
}

至此,就完成了HttpUtils工具類的封裝

step3 使用HTTP工具類實現首頁列表
首先需要做的是在Home組件的aboutToAppear生命周期中,通過postHttpRequest()和getHttpRequest()方法,分別獲取到列表項中的文字以及圖片數據源和箭頭圖片的uri,并定義兩個狀態變量httpGridItems和pictureUri用來獲取返回結果。注意,使用完之后記得通過前面封裝好的destoryHttpRequest()方法銷毀HttpRequest對象。在獲取到List所需要的資源并存儲到狀態變量后,我們通過List組件配合ForEach進行循環渲染,從而實現首頁List的渲染

import { HttpUtils } from "../common/network/HttpUtils";
import { common } from "@kit.AbilityKit";
import GridData from "../viewmodel/GridData";
import ListInfo from "../viewmodel/ResponseData/ListInfo";
import mainViewModel from "../viewmodel/MainViewModel";@Component
export default struct Home {@State httpGridItems: Array<ListInfo> = [];@State pictureUri: string = '';private TopSwiperController: SwiperController = new SwiperController();private context = getContext(this) as common.UIAbilityContext;private applicationContext = this.context.getApplicationContext();private cacheDir = this.applicationContext.filesDir;async aboutToAppear(): Promise<void> {let httpUtil: HttpUtils = new HttpUtils();await httpUtil.postHttpRequest().then((value: Array<ListInfo>) => {this.httpGridItems = value;});await httpUtil.getHttpRequest(this.cacheDir).then((value: string) => {this.pictureUri = value;});httpUtil.destroyHttpRequest();}build() {Column() {Text('首頁').width('95%').textAlign(TextAlign.Start).fontWeight(FontWeight.Bold).fontSize(25).margin({ top: 10, bottom: 10 })Scroll() {Column() {Swiper(this.TopSwiperController) {ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {Image(img).width('95%').objectFit(ImageFit.Auto)})}.autoPlay(true).loop(true).width('95%').height(220).margin({ bottom: 10 })Grid() {ForEach(mainViewModel.getGridItem(), (item: GridData) => {GridItem() {Column() {Image(item.img).size({width: 30,height: 30})Text(item.title).fontSize(16)}}})}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr').backgroundColor('#ffffff').width('95%').height(120).borderRadius(15)Text('列表').fontWeight(FontWeight.Bold).fontSize(20).width('95%').textAlign(TextAlign.Start).margin({top: 10,bottom: 10})List() {ForEach(this.httpGridItems, (secondItem: ListInfo) => {ListItem() {Row() {Image(secondItem.indexNavPic).width('130vp').height('80vp').objectFit(ImageFit.TOP_START).borderRadius('8vp').margin({ right: '12vp' })Column() {Text(secondItem.activityName).width('190vp').textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(1).fontSize('16fp').fontWeight(FontWeight.Medium)Text(secondItem.theme).width('190vp').textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(2).margin({ top: '4vp' }).fontSize('12fp').fontColor('#99182431')Row() {Image(this.pictureUri).width('20vp').opacity(0.5)}.width('170vp').margin({ top: '10.5vp' }).justifyContent(FlexAlign.End).alignItems(VerticalAlign.Bottom)}.alignItems(HorizontalAlign.Start)}.width('100%').padding({left: '12vp',right: '12vp',top: '12vp',bottom: '12vp'}).justifyContent(FlexAlign.SpaceBetween)}.margin({ bottom: '8vp' }).borderRadius('16vp').backgroundColor('#ffffff').align(Alignment.TopStart).width('100%')}, (secondItem: ListInfo) => JSON.stringify(secondItem))}.scrollBar(BarState.Off).width('100%')}}.scrollBar(BarState.Off)}.justifyContent(FlexAlign.Start).height('100%').width('100%')}
}

整體效果:
在這里插入圖片描述

三、使用RCP請求網絡數據

我們不僅可以通過HTTP訪問網絡,還可以通過RCP發起網絡請求實現相同的功能

step1 分析具體實現功能

  1. 使用RCP發起get請求,獲取一張箭頭圖片并保存在沙箱路徑中,并返回其沙箱路徑對應的uri,以便使用箭頭圖片作為首頁列表的布局元素
  2. 使用RCP發起post請求,獲取官網中的圖片與文本信息,并將其封裝在實體類數組中,以便將這些信息作為首頁列表的布局元素

step2 RCP工具類的封裝
我們通過@kit.RemoteCommunicationKit中的rcp模塊來使用RCP能力。在使用RCP發起網絡請求前,首先需要獲取一個Session類型的網絡會話對象,在這里,我們將該類型的對象作為工具類的對象屬性,并在構造方法中通過模塊提供的rcp.createSession()方法為該對象屬性賦值,以便后續方便的使用它。完成了獲取網絡會話對象Session后,我們就可以進一步封裝get請求和post請求獲取網絡信息的方法了。網絡會話對象Session提供了get()方法與post()方法,可以用于實現發起get請求和post請求,具體實現與http模塊類似,這里就不過多贅述了。最后,我們還需要像HTTP工具類一樣,封裝一個銷毀會話對象的方法,需要使用會話對象的close()方法。

import { rcp } from '@kit.RemoteCommunicationKit';
import { fileIo, fileUri } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import ResponseData from '../../viewmodel/ResponseData/ResponseData';
import ListInfo from '../../viewmodel/ResponseData/ListInfo';const TAG: string = 'RCPUtils';
const list_source: string = 'https://svc-drcn.developer.huawei.com/community/servlet/consumer/' +'partnerActivityService/v1/developer/activity/terminalActivities/list';/*** RCPUtils提供了通過RCP訪問網絡的功能*/
export class RCPUtils {rcpSession: rcp.Session;constructor() {this.rcpSession = rcp.createSession();}/*** 通過RCP發起GET請求的方法*/async getRCPRequest(cacheDir: string): Promise<string> {let responsePictureUri: string = '';await this.rcpSession.get('https://developer.huawei.com/system/modules/org.opencms.portal.template.core/' +'resources/harmony/img/jiantou_right.svg').then((response) => {let filePath = cacheDir + '/test.svg';let file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);responsePictureUri = fileUri.getUriFromPath(filePath);fileIo.writeSync(file.fd, response.body);fileIo.closeSync(file.fd);}).catch((err: BusinessError) => {hilog.error(0x0000, TAG, `err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);});return responsePictureUri;}/*** 通過RCP發起POST請求的方法*/async postRCPRequest(): Promise<ListInfo[]> {let responseData: Array<ListInfo> = [];let requestContent: rcp.RequestContent = {'status': '1','belong': '1','language': 'cn','needTop': 1,'displayChannel': [1, 3],'count': 4,'pagestart': 1,'type': '1,4,5,6'}await this.rcpSession.post(list_source, requestContent).then((response) => {let result: ResponseData = response.toJSON() as ResponseData;responseData = result.value.list;}).catch((err: BusinessError) => {hilog.error(0x0000, TAG, `err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);});return responseData;}/*** 關閉RCP會話的方法*/destroySession() {this.rcpSession.close();}
}

至此,我們就完成了RCP工具類的封裝

step3 使用RCP工具類實現首頁列表
完成RCP工具類的封裝后,我們也可以通過RCP請求網絡數據,與HTTP實現渲染類似,只需要在生命周期aboutToAppear中,創建工具類對象,使用工具類封裝好的方法發起請求并存儲在在狀態變量中,然后通過List渲染即可。這個部分的代碼只需要在之前頁面的基礎上更換aboutToAppear生命周期中的方法就行將原來HTTP的方式修改成封裝好的RCP即可,代碼的最終效果和上面一樣,只是網絡請求的方式不同

import { common } from "@kit.AbilityKit";
import GridData from "../viewmodel/GridData";
import ListInfo from "../viewmodel/ResponseData/ListInfo";
import mainViewModel from "../viewmodel/MainViewModel";
import { RCPUtils } from "../common/network/RCPUtils";@Component
export default struct Home {@State httpGridItems: Array<ListInfo> = [];@State pictureUri: string = '';private TopSwiperController: SwiperController = new SwiperController();private context = getContext(this) as common.UIAbilityContext;private applicationContext = this.context.getApplicationContext();private cacheDir = this.applicationContext.filesDir;async aboutToAppear(): Promise<void> {let rcpUtil: RCPUtils = new RCPUtils();await rcpUtil.postRCPRequest().then((value: Array<ListInfo>) => {this.httpGridItems = value;});await rcpUtil.getRCPRequest(this.cacheDir).then((value: string) => {this.pictureUri = value;});rcpUtil.destroySession();}build() {Column() {Text('首頁').width('95%').textAlign(TextAlign.Start).fontWeight(FontWeight.Bold).fontSize(25).margin({ top: 10, bottom: 10 })Scroll() {Column() {Swiper(this.TopSwiperController) {ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {Image(img).width('95%').objectFit(ImageFit.Auto)})}.autoPlay(true).loop(true).width('95%').height(220).margin({ bottom: 10 })Grid() {ForEach(mainViewModel.getGridItem(), (item: GridData) => {GridItem() {Column() {Image(item.img).size({width: 30,height: 30})Text(item.title).fontSize(16)}}})}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr').backgroundColor('#ffffff').width('95%').height(120).borderRadius(15)Text('列表').fontWeight(FontWeight.Bold).fontSize(20).width('95%').textAlign(TextAlign.Start).margin({top: 10,bottom: 10})List() {ForEach(this.httpGridItems, (secondItem: ListInfo) => {ListItem() {Row() {Image(secondItem.indexNavPic).width('130vp').height('80vp').objectFit(ImageFit.TOP_START).borderRadius('8vp').margin({ right: '12vp' })Column() {Text(secondItem.activityName).width('190vp').textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(1).fontSize('16fp').fontWeight(FontWeight.Medium)Text(secondItem.theme).width('190vp').textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(2).margin({ top: '4vp' }).fontSize('12fp').fontColor('#99182431')Row() {Image(this.pictureUri).width('20vp').opacity(0.5)}.width('170vp').margin({ top: '10.5vp' }).justifyContent(FlexAlign.End).alignItems(VerticalAlign.Bottom)}.alignItems(HorizontalAlign.Start)}.width('100%').padding({left: '12vp',right: '12vp',top: '12vp',bottom: '12vp'}).justifyContent(FlexAlign.SpaceBetween)}.margin({ bottom: '8vp' }).borderRadius('16vp').backgroundColor('#ffffff').align(Alignment.TopStart).width('100%')}, (secondItem: ListInfo) => JSON.stringify(secondItem))}.scrollBar(BarState.Off).width('100%')}}.scrollBar(BarState.Off)}.justifyContent(FlexAlign.Start).height('100%').width('100%')}
}

至此,完成了網絡狀態的監聽以及使用HTTP和RCP請求網絡數據的學習


遇到的問題
  • stack組件的布局的使用問題,我想編寫一個層疊的效果,將按鈕顯示在頂部圖片的右側并緊貼,設置align屬性好像沒有效果,暫時設置了position屬性設置絕對位置來解決這個問題。最終,再次嘗試修改Stack的alignContent屬性并刪除了對position屬性的修改,實現了想要的效果,但是暫時不清楚之前出現問題的原因

  • scroll滾動組件在整體頁面中顯示不完整。因為原來使用的是NavDestination和Tabs的組合來構建底部標簽欄。Tabs 組件默認會在其包含的內容下方顯示標簽欄,這可能導致內容被標簽欄遮擋。修改之后將NavDestination組件修改成Flex組件,根據內容的大小動態地改變高度,現在就可以完整地顯示內容了

    • 修改前:

      • 在這里插入圖片描述
    • 修改后:

      • 在這里插入圖片描述
  • 網絡問題,設置好了網絡監聽,檢查過判斷邏輯應該沒有出現問題,但是在部署到模擬器上時,斷開網絡仍可以進行登錄操作

  • 在進行關系型數據庫案例開發的時候,遇到點擊“新增計劃”按鈕頁面中內容不顯示的問題。進行了逐個部分的排查,首先,在對應頁面Goal.ets的aboutToAppear()生命周期中查看了一下創建數據表和初始化數據表的方法調用代碼是否正確,發現正常;然后,前往關系型數據庫的相關文件中查看調用的方法本身是否有編寫或者邏輯錯誤,和官方代碼沒有區別,沒有問題;因為這個部分涉及到數據庫的使用,所以也需要檢查了一下CommonConstants.ets文件中的SQL語句是否有誤,也沒問題;然后仔細校對了官方代碼最后發現問題很簡單,但是容易遺漏,就是需要在EntryAbility.ets文件中,添加“RDBStoreUtil.createObjectiveRDB(this.context);”這段代碼,在組件實例化之前創建和獲取RdbStore實例,添加完這個代碼之后,終于可以正常點擊“新增計劃”按鈕并顯示相關數據了

    • 在這里插入圖片描述
  • 但是在上述問題解決之后又出現了新的問題。在添加完新的數據之后,使用篩選功能對任務是否完成為條件進行篩選無法選出正確的結果

    • 效果展示:在這里插入圖片描述
      在這里插入圖片描述
  • 對網絡請求的加深學習與函數的加深理解

// 通過HTTP發起POST請求的方法
async postHttpRequest(): Promise<ListInfo[]> { // async為關鍵字,說明這個函數將進行異步操作let responseData: Array<ListInfo> = []; // 定義了一個Array類型結構為ListInfo的變量并賦了一個空值await this.httpRequest.request('https://svc-drcn.developer.huawei.com/community/servlet/consumer' + //await也為關鍵字,代表同步,需與async同時出現,有async必有await,但是有await不一定有async'/partnerActivityService/v1/developer/activity/terminalActivities/list', // 這里是發起一個request請求,具體參數類型可點擊request查看,第一個參數為請求的接口地址,第二個參數為{請求方法(如POST、PUT、GET等),請求的數據的結構,請求的頭部}{method: http.RequestMethod.POST, extraData: {'status': '1','belong': '1','language': 'cn','needTop': 1,'displayChannel': [1, 3],'count': 4,'pagestart': 1,'type': '1,4,5,6'},header: new Header('application/json;charset=UTF-8')}).then((data: http.HttpResponse) => { // 這里的.then的作用是在上述request之后進行的一個串行操作,就是接收上述request請求返回的值并作為匿名函數的參數進行后續步驟let result: ResponseData = JSON.parse(data.result as string); // 在上述接收到request請求返回的值之后,將該值轉譯并賦值給ResponseData類型的result變量responseData = result.value.list; // 再次賦值}).catch((err: Error) => { // 獲取報錯信息hilog.info(0x0000, TAG, JSON.stringify(err));});return responseData; // 返回結果
}

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

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

相關文章

【C/C++】explicit_bzero

explicit_bzero explicit_bzero 是一個為了解決 memset 在安全清除內存場景中可能被優化器移除的問題而設計的函數&#xff0c;廣泛用于安全編程中&#xff0c;比如密碼、密鑰清除等。Introduce 頭文件 #include <string.h>函數原型 void explicit_bzero(void *s, size_t…

MySQL 鏈接方法思考

代碼: import subprocess import os from dotenv import load_dotenv import pymysql from sqlalchemy import create_enginedef check_mysql_service():"""檢查 MySQL 服務是否運行"""try:result = subprocess.run(["systemctl", &…

jxORM--查詢數據

jxORM提供了豐富的數據查詢功能。在jxORM中&#xff0c;有兩種數據查詢方式&#xff1a; 通過數據類執行查詢直接使用SQL的select語句查詢 數據類查詢 數據類查詢的優勢&#xff1a; 可以根據數據類的定義&#xff0c;自動完成查詢條件中的條件值和查詢到的數據的類型轉換直接獲…

詳解力扣高頻SQL50題之1084. 銷售分析 III【簡單】

傳送門&#xff1a;1084. 銷售分析 III 題目 表&#xff1a; Product --------------------- | Column Name | Type | --------------------- | product_id | int | | product_name | varchar | | unit_price | int | --------------------- product_id 是該表的主鍵&#x…

Kafka入門指南:從零開始掌握分布式消息隊列

為什么要有消息隊列 生活中有這樣的場景快遞員將包裹送給買家。 我記得在小時候&#xff0c;收快遞是需要快遞員電話聯系上門時間的。這非常不方便&#xff0c;一方面快遞員手中可能有多個包裹&#xff0c;另一方面買家可能在上班時間抽不出身。 后來有了驛站&#xff0c;快遞員…

基于Matlab圖像處理的瓶子自動檢測與質量評估系統

本文提出了一種基于圖像處理的瓶子缺陷檢測系統&#xff0c;旨在通過圖像分析自動識別和檢測瓶子在生產過程中可能出現的缺陷。系統首先通過圖像預處理技術&#xff0c;包括灰度轉換、二值化處理、噪聲去除等步驟&#xff0c;將原始圖像轉換為適合分析的格式。然后&#xff0c;…

【Pandas】pandas Index objects Index.name

Pandas2.2 Index objects Properties方法描述Index.values返回 Index 對象的值&#xff0c;通常是一個 NumPy 數組Index.is_monotonic_increasing用于檢查索引的元素是否 單調遞增Index.is_monotonic_decreasing用于判斷索引的值是否 單調遞減Index.is_unique用于檢查索引中的標…

JDBC教程,2025版最新講解.超詳細入門教程

以下內容全面詳盡地梳理了 JDBC &#xff08;Java Database Connectivity&#xff09;的核心知識點&#xff0c;并在關鍵環節配以示例代碼。若要快速定位&#xff0c;可先查看下方結構&#xff1a; JDBC 概覽驅動加載與注冊獲取數據庫連接執行 SQL&#xff08;Statement、Prepa…

PyTorch中nn.Module詳解和綜合代碼示例

在 PyTorch 中&#xff0c;nn.Module 是神經網絡中最核心的基類&#xff0c;用于構建所有模型。理解并熟練使用 nn.Module 是掌握 PyTorch 的關鍵。一、什么是 nn.Module nn.Module 是 PyTorch 中所有神經網絡模塊的基類。可以把它看作是“神經網絡的容器”&#xff0c;它封裝了…

深入解析三大Web安全威脅:文件上傳漏洞、SQL注入漏洞與WebShell

文章目錄文件上傳漏洞SQL注入漏洞WebShell三者的核心關聯&#xff1a;攻擊鏈閉環文件上傳漏洞 文件上傳漏洞&#xff08;File Upload Vulnerability&#xff09; 當Web應用允許用戶上傳文件但未實施充分的安全驗證時&#xff0c;攻擊者可上傳惡意文件&#xff08;如WebShell、…

【對比】群體智能優化算法 vs 貝葉斯優化

在機器學習、工程優化和科學計算中&#xff0c;優化算法的選擇直接影響問題求解的效率與效果。群體智能優化算法&#xff08;Swarm Intelligence, SI&#xff09;和貝葉斯優化&#xff08;Bayesian Optimization, BO&#xff09;是兩種截然不同的優化范式&#xff0c;分別以不同…

LLMs之Agent:ChatGPT Agent發布—統一代理系統將研究與行動無縫對接,開啟智能助理新時代

LLMs之Agent&#xff1a;ChatGPT Agent發布—統一代理系統將研究與行動無縫對接&#xff0c;開啟智能助理新時代 目錄 OpenAI重磅發布ChatGPT Agent—統一代理系統將研究與行動無縫對接&#xff0c;開啟智能助理新時代 第一部分&#xff1a;Operator 和深度研究的自然演進 第…

Linux726 raid0,raid1,raid5;raid 創建、保存、停止、刪除

RAID創建 創建raid0 安裝mdadm yum install mdadm mdadm --create /dev/md0 --raid-devices2 /dev/sdb5 /dev/sdb6 [rootsamba caozx26]# mdadm --create /dev/md0 --raid-devices2 /dev/sdb3 /dev/sdb5 --level0 mdadm: Defaulting to version 1.2 metadata mdadm: array /dev…

深入剖析 MetaGPT 中的提示詞工程:WriteCode 動作的提示詞設計

今天&#xff0c;我想和大家分享關于 AI 提示詞工程的文章。提示詞&#xff08;Prompt&#xff09;是大型語言模型&#xff08;LLM&#xff09;生成高質量輸出的關鍵&#xff0c;而在像 MetaGPT 這樣的 AI 驅動軟件開發框架中&#xff0c;提示詞的設計直接決定了代碼生成的可靠…

關于 ESXi 中 “ExcelnstalledOnly 已禁用“ 的解決方案

第一步&#xff1a;使用ssh登錄esxi esxcli system settings advanced list -o /User/execInstalledOnly可能會得到以下內容 esxcli system settings advanced list -o /User/execInstalledOnlyPath: /User/ExecInstalledOnlyType: integerInt Value: 0Default Int Value: 1Min…

HTML5 Canvas 繪制圓弧效果

HTML5 Canvas 繪制圓弧效果 以下是一個使用HTML5 Canvas繪制圓弧的完整示例&#xff0c;你可以直接在瀏覽器中運行看到效果&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"view…

智能Agent場景實戰指南 Day 18:Agent決策樹與規劃能力

【智能Agent場景實戰指南 Day 18】Agent決策樹與規劃能力 開篇 歡迎來到"智能Agent場景實戰指南"系列的第18天&#xff01;今天我們將深入探討智能Agent的核心能力之一&#xff1a;決策樹與規劃能力。在現代業務場景中&#xff0c;Agent需要具備類似人類的決策能力…

AI 編程工具 Trae 重要的升級。。。

大家好&#xff0c;我是櫻木。 今天打開 Trae &#xff0c;已經看到它進行圖標升級&#xff0c;之前的圖標&#xff0c;國際和國內版本長得非常像&#xff0c;現在做了很明顯的區分&#xff0c;這點給 Trae 團隊點個贊。 自從 Claude 使出了壓力以來&#xff0c;Cursor 鎖區&…

排序算法,咕咕咕

1.選擇排序void selectsort(vector<int>& v) { for(int i0;i<v.size()-1;i) {int minii;for(int ji1;j<v.size();j){if(v[i]>v[j]){minij;}}if(mini!i)swap(v[i],v[mini]); } }2.堆排序void adjustdown(vector<int>& v,int root,int size) { int …

數據庫查詢系統——pyqt+python實現Excel內查課

一、引言 數據庫查詢系統處處存在&#xff0c;在教育信息化背景下&#xff0c;數據庫查詢技術更已深度融入教務管理場景。本系統采用輕量化架構&#xff0c;結合Excel課表&#xff0c;通過PythonPyQt5實現跨平臺桌面應用&#xff0c;以實現簡單查課效果。 二、GUI界面設計 使用…