鸿蒙开发-网络数据访问、应用本地数据保存

HTTP概述

HTTP,全称Hyper Text Transfer Protocol 超文本传输协议。

HTTP请求为短连接。客户端发起请求,服务器返回响应。本次连接即结束。

添加网络权限

在访问网络之前,需要在module.json5中给APP添加网络权限

"module": {"requestPermissions": [{"name": "ohos.permission.INTERNET"}]
}

HTTP请求开发步骤

导入http模块

import { http } from '@kit.NetworkKit'

创建http请求

let httpRequest = http.createHttp()

订阅响应事件

httpRequest.on('headersReceive', (header) => {});

发起请求

let promise = httpRequest.request(url,{method: http.RequestMethod.POST,extraData: {"param1": "value1","param2": "value2"},connectTimeout: 60000,readTimeout: 60000,expectDataType: http.HttpDataType.STRING,usingCache: true,priority: 1,usingProtocol: http.HttpProtocol.HTTP1_1,usingProxy: false,header: {'Content-Type': 'application/json'}})

请求参数解读如下表

字段类型
method请求方式
extraData请求的额外数据
connectTimeout连接超时时间
readTimeout读取超时时间
expectDataType指定返回数据的类型
usingCache是否使用缓存,默认true
priority优先级,1~1000,默认1
usingProtocol是否使用协议
usingProxy是否使用http代理
headerhttp请求头

请求方式支持列表

字段类型
GET请求指定的页面信息,并返回响应主体
POST请求会向指定资源提交数据,请求服务器进行处理
PUT请求会向指定资源位置上传其最新内容
CONNECTHTTP/1.1协议预留,能够将连接改为管道方式的代理服务器
HEAD类似GET请求,返回响应头信息,但不会返回响应主体
DELETE请求服务器删除所请求URI
TRACE请求服务器回显其收到的请求信息
OPTIONS请求用于客户端查看服务器的性能

处理响应

let promise = httpRequest.request()promise.then((data) => {if (data.responseCode === http.ResponseCode.OK) {}
})

data中包含以下字段

data包含的字段类型
responseCode响应结果状态码
result响应数据
resultType返回值类型
header响应头
cookies服务器返回的cookies

常见responseCode状态码

名称说明
OK200请求成功
CREATED201已创建新的资源
NOT_FOUND404找不到资源
VERSION505服务器请求的HTTP协议版本

取消订阅

httpRequest.off("headersReceive")

销毁http对象(可选)

httpRequest.destroy()

HTTP流式请求开发步骤

HTTP流式请求通常用于下载文件

前几步与前文HTTP请求相同

// 导入https模块
import { http } from '@kit.NetworkKit’;
// 创建请求
let httpRequest = http.createHttp()
// 订阅响应事件
httpRequest.on('headersReceive', (header) => {
// 返回请求头
});

订阅更多响应事件

let res = ""
httpRequest.on("dataReceive", (data: ArrayBuffer) => {// 累加数据res += data
})
httpRequest.on("dataEnd", () => {// 接收完毕
})

使用requestInStream发起请求

与前文不同的是,这里使用requestInStream发起请求

let promise = httpRequest.requestInStream(url,{method: http.RequestMethod.POST,extraData: {"param1": "value1","param2": "value2"},connectTimeout: 60000,readTimeout: 60000,expectDataType: http.HttpDataType.STRING,usingCache: true,priority: 1,usingProtocol: http.HttpProtocol.HTTP1_1,usingProxy: false,header: {'Content-Type': 'application/json'}});

请求字段如下

字段类型
method请求方式
extraData请求的额外数据
connectTimeout连接超时时间
readTimeout读取超时时间
expectDataType指定返回数据的类型
usingCache是否使用缓存,默认true
priority优先级,1~1000,默认1
usingProtocol是否使用协议
usingProxy是否使用http代理
headerhttp请求头

处理相应

let promise = httpRequest.requestInStream()promise.then((responseCode) => {if (responseCode === http.ResponseCode.OK) {}
})

取消订阅

httpRequest.off("headersReceive")
httpRequest.off("dataReceive")
httpRequest.off("dataReceiveProgress")
httpRequest.off("dataEnd")

销毁http对象(可选)

httpRequest.destroy()

案例:新闻加载

本章的知识有配套的工程源码,请参阅附件

本Demo将从网络api获取一个新闻列表,收到的数据为json格式,并将其显示到一个列表界面上面

我们将分这几个步骤来实现这个Demo

  1. 行布局
  2. ForEach实现列表
  3. 配置Http请求
  4. 发起请求处理响应
  5. 界面触发更新

在这里插入图片描述

行布局

我们简单做个行布局,横向排列一个文本和图片。

ListItem() {Row() {Text(item.title)Image(item.imgsrc)}
}

效果如下

在这里插入图片描述

ForEach实现列表

我们声明一个自定义类Item用于表达每行数据,包含title和imgsrc属性。声明一个@State属性newsList,类型为Item数组。在ForEach渲染的时候把newsList传入,每次循环的时候取得item实例,把其中的属性赋值给UI组件。

class Item {title?: stringimgsrc?: string
}
…
@State newsList: Item[] = new Array(10)ForEach(this.newsList, (item: Item) => {ListItem() {}
}, (item: Item) => item.title)

配置Http请求

参考上文,配置Http请求。请求的url可以使用https://v2.alapi.cn/api/new/toutiao?token=qlVquQZPYSeaCi6u。

let httpRequest = http.createHttp()
httpRequest.on('headersReceive', (header) => {console.info('header: ' + JSON.stringify(header))
})
let url = "https://v2.alapi.cn/api/new/toutiao?token=qlVquQZPYSeaCi6u"
let promise = httpRequest.request(url, // 请求url地址{// 请求方式method: http.RequestMethod.GET,// 开发者根据自身业务需要添加header字段header: {'Content-Type': 'application/json'}}
)

发起请求处理响应

用上文创建的promise任务发送请求,promise.then。在then回调里面拿到返回数据之后,赋值给newsList属性。

@State newsList: Item[] = new Array(10)
…
promise.then((data) => {if (data.responseCode === http.ResponseCode.OK) {console.info('Result:' + data.result)console.info('code:' + data.responseCode)this.newsList = JSON.parse(data.result as string)["data"]}
}).catch((err: BusinessError) => {console.info('error:' + JSON.stringify(err))
})

界面触发更新

newsList更新之后,由于被@State,会自定触发UI更新。在之前定义的ForEach循环中,再次使用newsList渲染,界面将显示相应信息。

@State newsList: Item[] = new Array(10)this.newsList = JSON.parse(data.result as string)["data"]List() {ForEach(this.newsList, (item: Item) => {ListItem() {Row() {Text(item.title)Image(item.imgsrc)}}}, (item: Item) => item.title)
}

案例:文件下载

本例将通过一个文件下载的Demo来学习Http流式请求。文件我们选择了一个常用磁盘工具DiskGenius,从其官网获得的下载链接,一共30m左右,大小和网络条件都比较合适。

分为以下步骤

  1. 简单界面布局
  2. 点击下载按钮设置保存文件
  3. 配置Http请求
  4. 开始下载
  5. 下载完成

简单界面布局

界面上我们需要这几个元素:下载链接输入框,进度条,下载按钮,下载完成的文字提示。同时,有几个@State修饰的属性。

@State progress用于更新Progress组件的进度显示。

@State downloadUrl用于设置下载链接。代码中可以填写好链接,通常不需要在界面上手动修改。

@State downloadFinished用于表示下载是否完成的状态。可以用于“下载完成”的文字显示与否。

@State progress: number = 0
@State downloadUrl: string = “…”
@State downloadFinished: boolean = falseColumn() {TextInput({ text: this.downloadUrl })Progress({ value: this.progress })Button("下载").onClick(() => {})Text("下载完成").visibility(this.downloadFinished ? Visibility.Visible : Visibility.Hidden)
}

大致效果图如下

在这里插入图片描述

点击下载按钮,设置保存文件

接下来,我们要配置点击按钮的动作。

当我们点击下载按钮的时候,会调起系统的文件管理器界面,我们会在界面上声明创建的文件名以及选择它所在的目录。

在这里插入图片描述

这里需要使用系统自带的DocumentViewPicker,调用实例的save方法,在异步回调then里面会获取到新文件的完整路径(包含文件名)。

在回调里面我们用获取到的文件路径来创建一个文件实例,保存在变量file里。

使用fs.openSync方法,打开文件,设定读写模式,并获取file实例。获取到file实例之后我们把它传到我们自己封装的download方法里。

Button("下载").onClick(() => {const documentViewPicker = new picker.DocumentViewPicker(); // 创建文件选择器实例documentViewPicker.save().then((documentSaveResult: Array<string>) => {let file = fs.openSync(documentSaveResult[0], fs.OpenMode.READ_WRITE);this.download(file)})})

配置Http请求

在download方法中,我们拿到了file实例,接下来我们看看怎么实现这个方法。

根据上文,我们同样先创建一个HttpRequest实例,然后注册几个事件监听:dataReceive,dataReceiveProgress和dataEnd。

在dataReceive中,我们会不停获取到文件的部分数据,每次获得数据的时候就用file实例写入磁盘。

在dataReceiveProgress中,我们会获取到文件下载进度。有两个数据,一个是已下载的大小,一个是总大小。我们可以利用这个数据,更新界面上进度条的显示。

在dataEnd中,我们可以关闭文件操作,并把@State修饰的progress属性置为0,让界面上的进度条回到初始显示状态。

download(file: fs.File): void {let httpRequest = http.createHttp()httpRequest.on('dataReceive', (data: ArrayBuffer) => {fs.writeSync(file.fd, data)})httpRequest.on('dataReceiveProgress', (info: http.DataReceiveProgressInfo) => {this.progress = info.receiveSize / info.totalSize * 100})httpRequest.on('dataEnd', () => {fs.closeSync(file)this.progress = 0})}

开始下载

创建完请求,注册完监听之后,我们就要触发请求了。不同于上文,我们这里使用httpRequest.requestInStream()方法来配置请求地址。获取到异步任务之后,调用promise.then()发起请求。在文件接收完之后,会触发此处的then回调。

download(file: fs.File): void {let httpRequest = http.createHttp()let promise = httpRequest.requestInStream(// 请求url地址this.downloadUrl,{// 请求方式method: http.RequestMethod.GET,header: {'Content-Type': 'application/json'}})promise.then((data) => {console.info('Result:' + data)})
}

在这里插入图片描述

下载完成

当下载完成时,会显示完成的提示。

案例:图片下载

本例将通过一个图片下载的Demo来学习Http流式请求。我们选择了百度首页的百度logo图片地址。

分为以下步骤

  1. 简单界面布局
  2. 点击下载按钮调用下载方法
  3. 配置Http请求
  4. 开始下载
  5. 下载完成

简单界面布局

界面上我们需要这几个元素:下载链接输入框,进度条,下载按钮,下载完成的文字提示。同时,有几个@State修饰的属性。

@State progress用于更新Progress组件的进度显示。

@State downloadUrl用于设置下载链接。代码中可以填写好链接,通常不需要在界面上手动修改。

@State downloadFinished用于表示下载是否完成的状态。可以用于“下载完成”的文字显示与否。

@State pixelMap用于设置图片组件的数据源。

@State progress: number = 0
@State downloadUrl: string = “…”
@State downloadFinished: boolean = false
@State pixelMap?: PixelMap = undefined
imageBuffer: ArrayBuffer = new ArrayBuffer(0)Column() {TextInput({ text: this.downloadUrl })Progress({ value: this.progress })Image(this.pixelMap)Button("下载").onClick(() => {})Text("下载完成").visibility(this.downloadFinished ? Visibility.Visible : Visibility.Hidden)
}

大致效果图如下

在这里插入图片描述

点击下载按钮,调用下载方法

Button("下载").onClick(() => {this.download()})

配置Http请求

在download方法中,我们拿到了file实例,接下来我们看看怎么实现这个方法。

根据上文,我们同样先创建一个HttpRequest实例,然后注册几个事件监听:dataReceive,dataReceiveProgress和dataEnd。

在dataReceive中,我们会不停获取到文件的部分数据,每次获得数据的时候就拼接到imageBuffer尾部。

在dataReceiveProgress中,我们会获取到文件下载进度。有两个数据,一个是已下载的大小,一个是总大小。我们可以利用这个数据,更新界面上进度条的显示。

在dataEnd中,我们可以调用createImageSource,createPixelMap方法,把收到的二进制数据转换为pixel map。

并把@State修饰的progress属性置为0,让界面上的进度条回到初始显示状态。

download(file: fs.File): void {let httpRequest = http.createHttp()httpRequest.on('dataReceive', (data: ArrayBuffer) => {this.imageBuffer = concatenateArrayBuffers(this.imageBuffer, data)})httpRequest.on('dataReceiveProgress', (info: http.DataReceiveProgressInfo) => {this.progress = info.receiveSize / info.totalSize * 100})httpRequest.on('dataEnd', () => {let imageSource: image.ImageSource = image.createImageSource(this.imageBuffer);imageSource.createPixelMap().then((pixelMap: PixelMap) => {this.pixelMap = pixelMap})this.progress = 0})}

开始下载

创建完请求,注册完监听之后,我们就要触发请求了。不同于上文,我们这里使用httpRequest.requestInStream()方法来配置请求地址。获取到异步任务之后,调用promise.then()发起请求。在文件接收完之后,会触发此处的then回调。

download(file: fs.File): void {let httpRequest = http.createHttp()let promise = httpRequest.requestInStream(// 请求url地址this.downloadUrl,{// 请求方式method: http.RequestMethod.GET,header: {'Content-Type': 'application/json'}})promise.then((data) => {console.info('Result:' + data)})
}

下载完成

当下载完成时,会显示完成的提示。

应用本地数据保存

什么是用户首选项

用户首选项为应用提供Key-Value键值型的数据存储能力,支持应用持久化轻量级数据,并对其进行增删除改查等。该存储对象中的数据会被缓存在内存中,因此它可以获得更快的存取速度,下面详细介绍下用户首选项的开发过程。

用户首选项运作机制

用户首选项的特点是:

1、以Key-Value形式存储数据

​ Key是不重复的关键字,Value是数据值。

2、非关系型数据库

​ 区别于关系型数据库,它不保证遵循ACID(Atomicity, Consistency, Isolation and Durability)特性,数据之间无关系。

进程中每个文件对应一个Preferences实例,应用获取到实例后,可以从中读取数据,或者将数据存入实例中。通过调用flush方法可以将实例中的数据回写到文件里。

与关系数据库的区别

分类关系型数据库用户首选项
数据库类型关系型非关系型
使用场景提供复杂场景下的本地数据库管理机制对Key-Value结构的数据进行存取和持久化操作
存储方式SQLite数据库文件
约束与限制1.连接池最大4个 2.同一时间只支持一个写操作1.建议数据不超一万条 2.Key为string型

接口介绍

常用接口有:保存数据(put)、获取数据(get)、是否包含指定的key(has)、数据持久化(flush)、删除数据(delete)等,后面依次详细介绍接口使用。

接口使用前提

1、需要导入preferences模块到开发环境中,同时定义一个常量KEY_APP_FONT_SIZE。相关代码实现如下:

// entryAbility.ets
import { preferences } from '@kit.ArkData';
const KEY_APP_FONT_SIZE = 'appFontSize';  // 用户首选项Key字段

2、需要在entryAbility的onCreate方法获取用户首选项实例,同时定义一个Preferences实例配置选项options,其中name表示Preferences实例的名称,以便后续能进行保存、读取、删除等操作,获取实例需要上下文context和文件名字PREFERENCES_NAME,相关代码实现如下:

// entryAbility.ets  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {Logger.info(TAG, 'onCreate');// 设置字体默认大小try {let options: preferences.Options = { name: 'myStore' };let promise = preferences.getPreferences(this.context, options);...} catch (err) {console.error("Failed to get preferences. code =" + err.code + ", message =" + err.message);}}

保存数据(put)

1、在entryAbility的onCreate方法,先用has方法判断当前key是否有存在,如果没有就通过put方法把用户数据保存起来,该方法通过key-value键值对方式保存,常量KEY_APP_FONT_SIZE作为key,用户数据fontSize作为value,再通过flush方法把数据保存到文件,相关代码实现如下:

// entryAbility.ets  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {...// 设置字体默认大小try {let options: preferences.Options = { name: 'myStore' };let promise = preferences.getPreferences(this.context, options);promise.then((object: preferences.Preferences) => {object.has(KEY_APP_FONT_SIZE).then(async (isExist: boolean) => {Logger.info(TAG, 'preferences has changeFontSize is ' + isExist);if (!isExist) {await object?.put(KEY_APP_FONT_SIZE, CommonConstants.SET_SIZE_NORMAL);await object?.flush();}}).catch((err: Error) => {Logger.error(TAG, 'Has the value failed with err: ' + err);});console.info("Succeeded in getting preferences.");}).catch((err: base.BusinessError) => {console.error("Failed to get preferences. code =" + err.code + ", message =" + err.message);})} catch (err) {console.error("Failed to get preferences. code =" + err.code + ", message =" + err.message);}}

2、在SetFontSizePage页面,当手指移动Slider滑动条时,通过onChange方法回调获取当前进度值,再通过flush方法把数据保存到文件,相关代码实现如下:

// SetFontSizePage.etsbuild() {Row() {Slider({...}).onChange(async (value: number) => {// 保存当前进度值if (this.changeFontSize === 0) {this.fontSizeText = SetViewModel.getTextByFontSize(value);return;}this.changeFontSize = (value === CommonConstants.SET_SLIDER_MAX ? CommonConstants.SET_SIZE_HUGE : value);this.fontSizeText = SetViewModel.getTextByFontSize(this.changeFontSize);let myPreferences: preferences.Preferences | null = null;preferences.getPreferences(getContext(this), 'myStore').then((object: preferences.Preferences) => {myPreferences = object;myPreferences.put(KEY_APP_FONT_SIZE, this.changeFontSize).then(() => {myPreferences?.flush();});})})}}

获取数据(get)

在HomePage的onPageShow方法,调用preferences.get方法获取用户数据,该方法通过key-value键值对方式读取,常量KEY_APP_FONT_SIZE作为key,默认数据defValue作为value,把得到的结果赋值给变量fontSize,相关代码实现如下:

// HomePage.etsonPageShow() {preferences.getPreferences(getContext(this), 'myStore').then((object: preferences.Preferences) => {object.get(KEY_APP_FONT_SIZE, 0).then((data) => {this.changeFontSize = Number(data);});})}

是否包含指定的key(has)

通过has方法判断用户首选项中是否包含指定的key,保证指定的key不会被重复保存,相关代码实现如下:

// 判断保存的key是否存在
...
preferences.has(KEY_APP_FONT_SIZE).then(async (isExist: boolean) => {Logger.info(TAG, 'preferences has changeFontSize is ' + isExist);
}).catch((err: Error) => {Logger.error(TAG, 'Has the value failed with err: ' + err);
});

数据持久化(flush)

通过flush方法把应用数据保存到文件中,使得应用数据保存期限变长,相关代码实现如下:

// SetFontSizePage.ets 
...
let myPreferences: preferences.Preferences | null = null;
preferences.getPreferences(getContext(this), 'myStore').then((object: preferences.Preferences) => {myPreferences = object;myPreferences.put(KEY_APP_FONT_SIZE, this.changeFontSize).then(() => {myPreferences?.flush();});
})

删除数据(delete)

删除用户首选项数据需要获取Preferences实例,用delete方法删除指定的key所对应的值,常量KEY_APP_FONT_SIZE作为key,通过Promise异步回调是否删除成功,相关代码实现如下:

...
let myPreferences: preferences.Preferences | null = null;
preferences.getPreferences(getContext(this), 'myStore').then((object: preferences.Preferences) => {myPreferences = object;myPreferences.delete(KEY_APP_FONT_SIZE).then(() => {console.info("Succeeded in deleting the key 'appFontSize'.");}).catch((err: BusinessError) => {console.error("Failed to delete the key 'appFontSize'. code =" + err.code +", message =" + err.message);});
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/17802.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

画 五边形 思路

1. 计算圆心 view 中心点 2.规定半径 R < view宽度 / 2 3.计算五边形五个顶点&#xff08;角度A 2π / 5&#xff09; 4. 五点相连 转载&#xff1a; Android自定义控件 芝麻信用分雷达图 - 简书

网络工程实验三:DHCP的配置

#实验仅供参考&#xff0c;勿直接粘贴复制&#xff0c;用以学习交流# #对于软件的使用&#xff0c;请移步到实验一观看# 1、实验目的&#xff1a; &#xff08;1&#xff09;掌握DHCP工作原理。 &#xff08;2&#xff09;配置路由器作为DHCP服务器。 &#xff08;3&#x…

手写体识别Tensorflow实现

简介&#xff1a;本文先讲解了手写体识别中涉及到的知识&#xff0c;然后分步讲解了代码的详细思路&#xff0c;完成了手写体识别案例的讲解&#xff0c;希望能给大家带来帮助&#xff0c;也希望大家多多关注我。本文是基于TensorFlow1.14.0的环境下运行的 手写体识别Tensorflo…

【SpringBoot】公共字段自动填充

问题引入 JavaEE开发的时候&#xff0c;新增字段&#xff0c;修改字段大都会涉及到创建时间(createTime)&#xff0c;更改时间(updateTime)&#xff0c;创建人(craeteUser)&#xff0c;更改人(updateUser)&#xff0c;如果每次都要自己去setter()&#xff0c;会比较麻烦&#…

【项目开发】为什么文件名要小写?

未经许可,不得转载。 文章目录 一、可移植性二、易读性三、易用性四、便捷性一、可移植性 Linux 系统对文件名大小写敏感,而 Windows 和 Mac 系统则不敏感。这种差异可能导致跨平台的问题。 例如,以下四个文件名: computerComPutercomPuterCOMPOTer在 Linux 系统上,它们…

ssm127基于SSM的乡镇篮球队管理系统+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;乡镇篮球队管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本乡镇篮球队管理…

C#获取视频第一帧_腾讯云媒体处理获取视频第一帧

一、 使用步骤&#xff1a; 第一步、腾讯云开启万象 第二步、安装Tencent.QCloud.Cos.Sdk 包 第三步、修改 腾讯云配置 图片存储目录配置 第四步、执行获取图片并保存 二、封装代码 using System.Text; using System.Threading.Tasks;using COSXML.Model.CI; using COSXML.A…

【数据分享】2003-2022年各省土地利用面积统计数据

数据介绍 2003-2022年各省土地利用面积统计数据数据时间2003-2008、2013、2015-2017、2019、2022数据类型excel数据指标土地调查面积/万公顷农用地面积/万公顷园林面积/万公顷牧草地面积/万公顷建设用地面积/万公顷居民点及工矿用地/万公顷交通用地/万公顷水利设施用地/万公顷…

任务调度工具Spring Test

Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 作用&#xff1a;定时自动执行某段Java代码 应用场景&#xff1a; 信用卡每月还款提醒 银行贷款每月还款提醒 火车票售票系统处理未支付订单 入职纪念日为用户发送通知 一.…

20 轮转数组

20 轮转数组 20.1 轮转数组解决方案 class Solution { public:void rotate(vector<int>& nums, int k) {int n nums.size();k k % n; // 如果 k 大于数组长度&#xff0c;取模减少不必要的旋转// 第一步&#xff1a;反转整个数组reverse(nums.begin(), nums.end(…

字符串相关题解

目录 字母异位词 最长公共前缀 博主主页&#xff1a;东洛的克莱斯韦克-CSDN博客 字母异位词 49. 字母异位词分组 - 力扣&#xff08;LeetCode&#xff09; 这道题更像一道语法题&#xff0c;考察对容器的掌握情况。如果按题目要求去模拟&#xff0c;不仅要分析每个字符串&am…

【微软:多模态基础模型】(3)视觉生成

欢迎关注【youcans的AGI学习笔记】原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微软&#xff1a;多模态基础模型】&#xff08;3&#xff09;视觉生成 【微…

CentOS8 启动错误,enter emergency mode ,开机直接进入紧急救援模式,报错 Failed to mount /home 解决方法

先看现场问题截图&#xff1a; 1.根据提示 按 ctrld 输入 root 密码&#xff0c;进入系统。 2. 在紧急模式下运行&#xff1a;journalctl -xe &#xff0c;查看相关日志&#xff0c;找到关键点&#xff1a; Failed to mount /home 3.接着执行修复命令&#xff1a; xfs_repa…

2024140读书笔记|《作家榜名著:生如夏花·泰戈尔经典诗选》——你从世界的生命的溪流浮泛而下,终于停泊在我的心头

2024140读书笔记|《作家榜名著&#xff1a;生如夏花泰戈尔经典诗选》——你从世界的生命的溪流浮泛而下&#xff0c;终于停泊在我的心头 《作家榜名著&#xff1a;生如夏花泰戈尔经典诗选》[印]泰戈尔&#xff0c;郑振铎译&#xff0c;泰戈尔的诗有的清丽&#xff0c;有的童真&…

lenovo联想ThinkBook 14 G5 ABP(21JE)原装出厂Windows11系统恢复镜像包下载

适用机型 &#xff1a;【21JE】 链接&#xff1a;https://pan.baidu.com/s/1FUjwN8ZeaQ9qr3kNalSkYg?pwdqasf 提取码&#xff1a;qasf 联想原装出厂系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想电脑管家、联想浏览…

MySQL 数据类型

数值类型 int类型 类型说明tinyint1字节&#xff0c;范围从-128到127&#xff08;有符号&#xff09;&#xff0c;0到255&#xff08;无符号&#xff09;smallint2字节&#xff0c;范围从-2^15到2^15-1&#xff08;有符号&#xff09;&#xff0c;0到2^16-1&#xff08;无符号…

【WPF】Prism学习(三)

Prism Commands 1.复合命令&#xff08;Composite Commanding&#xff09; 这段内容主要介绍了在应用程序中如何使用复合命令&#xff08;Composite Commands&#xff09;来实现多个视图模型&#xff08;ViewModels&#xff09;上的命令。以下是对这段内容的解释&#xff1a; …

用go语言后端开发速查

文章目录 一、发送请求和接收请求示例1.1 发送请求1.2 接收请求 二、发送form-data格式的数据示例 用go语言发送请求和接收请求的快速参考 一、发送请求和接收请求示例 1.1 发送请求 package mainimport ("bytes""encoding/json""fmt""ne…

SpringCloud Alibaba入门简介和Nacos服务注册和配置中心

前面已经把spring cloud相关的组件都一一学了个遍,现在有点小佩服自己…本来计划今天周末好好出去玩一圈,天气太热了,39了都,还是在办公室学习吧,进行下面的springCloud Alibaba 学习吧…不废话了赶快进入正体 1. SpringCloud Alibaba入门简介 1.1 why会出现SpringCloud alib…

如何让Excel公式中的参数实现动态引用

如果你想成为Excel函数高手&#xff0c;仅仅掌握VLOOKUP和Countif等函数是远远不够的&#xff0c;起码你得学会使用INDIRECT函数&#xff0c;熟练掌握INDIRECT函数能让你从一个初学者晋级为高手&#xff0c;学会它就好比孙悟空掌握了72般变化的基本功&#xff0c;你说厉不厉害。…