当前位置:   article > 正文

【HarmonyOS】网络数据请求连接与数据持久化操作_harmonyos 网络请求

harmonyos 网络请求

            从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是什么?鸿蒙仅仅是一个手机操作系统吗?它的出现能够和Android和IOS三分天下吗?它未来的潜力能否制霸整个手机市场呢?

抱着这样的疑问和对鸿蒙开发的好奇,让我们开始今天对网络连接和数据持久化的掌握吧!

目录

网络连接

HTTP数据请求

HTTP数据请求(第三方库axios)

ohpm安装使用教程

axios第三方库安装

axios的使用

数据持久化

用户首选项

关系型数据库


网络连接

在harmonyos中提供了三种不同的网络连接方式,如下图所示,接下来我们对这三种不同的网络连接方式进行一个简单的讲解,我们可以根据自身的需求去选择合适的方式,但事实上我们在开发过程中,最后两种使用的情况比较少,最常见的就是http的数据请求方式。我们这里也就拿http数据请求这个例子进行讲解使用:

HTTP数据请求

是由客户端向服务端发起的一种单向的连接方式,接下来就这种连接方式进行一个简单的讲解,如果我们想发送http请求服务,需要遵循以下的步骤来进行:

1)导入 http 模块:

import http from '@ohos.net.http';

2)使用http模块发送请求,处理响应:

  1. // 创建一个http的请求对象,不可复用
  2. let httpRequest = http.createHttp()
  3. // 发送网络请求
  4. httpRequest.request(
  5. 'http://localhost:3000/user', // 请求的URL路径
  6. { // 请求选项 HttpRequestOptions
  7. method: http.RequestMethod.GET,
  8. extraData: { 'param1': 'value1' },
  9. }
  10. )

关于 HttpRequestOptions 的选择,可以参考下面的表格:

名称类型描述
methodRequestMethod请求方式:GET、POST、PUT、DELETE等
extraDatastring|Object请求参数
headerObject请求头字段
connectTimeoutnumber连接超时时间,单位毫秒,默认是60000ms
readTimeoutnumber读取超时时间,单位毫秒,默认是60000ms

3)处理响应的结果

  1. // 创建一个http的请求对象,不可复用
  2. let httpRequest = http.createHttp()
  3. // 发送网络请求
  4. httpRequest.request(
  5. 'http://localhost:3000/user', // 请求的URL路径
  6. { // 请求选项 HttpRequestOptions
  7. method: http.RequestMethod.GET,
  8. extraData: { 'param1': 'value1' },
  9. }
  10. )
  11. // 处理响应结果
  12. .then((resp: http.HttpResponse) => {
  13. if(resp.responseCode === 200){
  14. // 请求成功
  15. }
  16. })
  17. .catch((err: Error) => {
  18. // 请求失败
  19. })

关于 HttpResponse 的选择,可以参考下面的表格:

名称类型描述
responseCodeResponseCode响应状态码
headerObject响应头
cookiesstring响应返回的cookies
resultstring | Object响应体,默认是JSON字符串
resultTypeHttpDataType返回值类型

ok,接下来我们通过上面给出的步骤来开始编写相应的接口来获取数据,接口地址就使用网上公共的接口地址吧,通过新建ts文件,将接口函数进行书写:

  1. import http from '@ohos.net.http';
  2. class getAPI {
  3. BaseCatURL = 'https://api.thecatapi.com/v1/images' // 猫图
  4. catNum = 2 // 猫数
  5. // 获取猫的图片
  6. getCat(){
  7. return new Promise((resolve, reject) => {
  8. // 创建一个http的请求对象,不可复用
  9. let httpRequest = http.createHttp()
  10. // 发送网络请求
  11. httpRequest.request(
  12. `${this.BaseCatURL}/search?limit=${this.catNum}`,// 请求的URL路径
  13. { // 请求选项 HttpRequestOptions
  14. method: http.RequestMethod.GET,
  15. }
  16. )
  17. // 处理响应结果
  18. .then((resp: http.HttpResponse) => {
  19. if(resp.responseCode === 200){
  20. // 请求成功
  21. resolve(JSON.parse(resp.result.toString()))
  22. }else{
  23. console.log('查询信息失败!', JSON.stringify(resp))
  24. reject('查询信息失败!')
  25. }
  26. })
  27. .catch((err: Error) => {
  28. // 请求失败
  29. console.log('查询信息失败!', JSON.stringify(err))
  30. reject('查询信息失败!')
  31. })
  32. })
  33. }
  34. // 获取猫的图片
  35. getWord(){
  36. return new Promise((resolve, reject) => {
  37. // 创建一个http的请求对象,不可复用
  38. let httpRequest = http.createHttp()
  39. // 发送网络请求
  40. httpRequest.request(
  41. 'http://api.uomg.com/api/rand.qinghua',// 请求的URL路径
  42. { // 请求选项 HttpRequestOptions
  43. method: http.RequestMethod.GET,
  44. }
  45. )
  46. // 处理响应结果
  47. .then((resp: http.HttpResponse) => {
  48. if(resp.responseCode === 200){
  49. console.log(resp.result.toString())
  50. // 请求成功
  51. resolve(JSON.parse(resp.result.toString()))
  52. }else{
  53. console.log('查询信息失败!', JSON.stringify(resp))
  54. reject('查询信息失败!')
  55. }
  56. })
  57. .catch((err: Error) => {
  58. // 请求失败
  59. console.log('查询信息失败!', JSON.stringify(err))
  60. reject('查询信息失败!')
  61. })
  62. })
  63. }
  64. }
  65. const getApi = new getAPI()
  66. export default getApi

接下来在ets文件调用接口函数,使用aboutToAppear函数,在页面还未加载完成获取相应的数据并渲染到界面上,如下:

  1. import getApi from '../api/test'
  2. @Entry
  3. @Component
  4. struct test {
  5. @State catInfo: any = []
  6. @State word: string = ''
  7. scroller: Scroller = new Scroller()
  8. aboutToAppear(){
  9. this.loadCatInfo()
  10. }
  11. build() {
  12. Column(){
  13. Text('猫猫的图片')
  14. .fontSize(30)
  15. .fontWeight(FontWeight.Bold)
  16. .margin(15)
  17. Text('今日情话:'+ this.word)
  18. .fontSize(20)
  19. .fontWeight(FontWeight.Bold)
  20. .margin(5)
  21. Divider()
  22. .margin(10)
  23. Grid(this.scroller){
  24. ForEach(this.catInfo, (item: any) => {
  25. GridItem(){
  26. Image(item.url)
  27. .width('100%')
  28. .objectFit(ImageFit.Auto)
  29. .height(120)
  30. }
  31. })
  32. }
  33. .width('100%')
  34. .columnsTemplate(`1fr 1fr`)
  35. .columnsGap(10)
  36. .rowsGap(10)
  37. .padding(5)
  38. .height(540)
  39. }
  40. .padding(10)
  41. .width('100%')
  42. .height('100%')
  43. }
  44. loadCatInfo() {
  45. // 加载数据
  46. getApi.getCat()
  47. .then((res: any) => {
  48. this.catInfo = res
  49. })
  50. getApi.getWord()
  51. .then((res: any) => {
  52. console.log('111',res.content)
  53. this.word = res.content
  54. })
  55. }
  56. }

最终呈现的效果如下:

HTTP数据请求(第三方库axios)

上面我们讲解了如何利用harmonyos提供的http模块实现http数据请求,接下来我们这里用第三方库来实现,如果做过前端开发的同学对于这个库应该不陌生,因为axios是前端开发中用来发送ajax请求的最流行的一个第三方库,ajax请求本质也属于http请求,因此在鸿蒙开发中也依然可以使用axios,接下来我们开始讲解如何在鸿蒙开发中使用axios。

因为axios并不是harmonyos官方提供的,所以我们并不能直接拿来就用,需要先安装ohpm,其就是鸿蒙开发中所有安装的包的一个管理工具,所以我们需要先安装它然后再利用它去安装axios,以下是ohpm的安装步骤:

ohpm安装使用教程

关于ohpm包管理工具,我们在下载DevEco Studio工具的时候,一般都已经下载好了,下面是我以前讲解该工具的安装教程,当时是装载工具的时候就已经顺便把ohpm工具下载好了:

如果你电脑没有过这个工具当然也可以重新下载,点击 下载链接 进行下载,根据自己电脑的系统配置选择不同的版本。

一般我们下载好,没有配置过环境变量是没法使用的,需要我们进行一些配置才能使用,找到我们之前下载好的工具,进入bin目录,打开该路径的cmd,输入init.bat进行初始化,然后输入如下命令可以看到ohpm的版本,但是ohpm只能在当前目录生效,并不是全局。

如果想在任意路径输入ohpm -v有效果的话,需要配置一下环境变量,如下:

接下来我们在任意路径访问ohpm都有效果了:

axios第三方库安装

接下来我们借助ohpm进行安装axios第三方库,关于harmonyos的第三方库可以参考 网站 ,里面罗列了harmonyos所有支持的第三方库的信息及其说明:

比如说我们想安装axios的话只需要找到对应的包名点击进去,里面就有详细的安装使用介绍:

复制安装命令,回到我们的编辑工具(记得要先重新一下开发者工具),找到编辑器下方菜单中的终端选项,输入如下命令进行安装:

安装完成之后我们的包就下载到 oh_modules 中,然后包的信息就存储到oh_package.json5中:

axios的使用

安装好axios包之后,接下来就开始正式使用axios,将上面的按钮编写接口的代码换成axios进行如下编写,如下:

  1. import axios from '@ohos/axios'
  2. class getAPI {
  3. // 获取猫的图片
  4. getCat(){
  5. return new Promise((resolve, reject) => {
  6. axios.get('https://api.thecatapi.com/v1/images/search?limit=2')
  7. .then((resp) => {
  8. if(resp.status === 200){
  9. // 请求成功
  10. resolve(resp.data)
  11. }else{
  12. console.log('查询信息失败!', JSON.stringify(resp))
  13. reject('查询信息失败!')
  14. }
  15. })
  16. .catch((err: Error) => {
  17. // 请求失败
  18. console.log('查询信息失败!', JSON.stringify(err))
  19. reject('查询信息失败!')
  20. })
  21. })
  22. }
  23. // 获取猫的图片
  24. getWord(){
  25. return new Promise((resolve, reject) => {
  26. axios.get('http://api.uomg.com/api/rand.qinghua')
  27. .then((resp) => {
  28. if(resp.status === 200){
  29. // 请求成功
  30. resolve(resp.data)
  31. }else{
  32. console.log('查询信息失败!', JSON.stringify(resp))
  33. reject('查询信息失败!')
  34. }
  35. })
  36. .catch((err: Error) => {
  37. // 请求失败
  38. console.log('查询信息失败!', JSON.stringify(err))
  39. reject('查询信息失败!')
  40. })
  41. })
  42. }
  43. }
  44. const getApi = new getAPI()
  45. export default getApi

达到的效果是一致的,说明我们使用axios发送请求完全没问题,了解更多axios也可以参考文档:

数据持久化

应用在使用过程中会产生各种各样的数据,如果没有对数据进行持久化处理,一旦应用进行重启这些数据就会全部丢失,那它肯定是不符合用户使用的一个需求,所以我们必须对这些数据进行持久化处理,在harmonyos中实现数据持久化主要有以下两种常用方式:

用户首选项

用户首选项 (Preference) 为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,以下是使用用户首选项的基本流程图:

以下是 用户首选项 使用的基本步骤:

1)导入用户首选项模块:

import dataPreference from '@ohos.data.preferences'

2)获取首选项实例,读取指定文件:

  1. dataPreference.getPreferences(this.content, 'MyAppPreferences')
  2. .then(preferences => {
  3. // 获取成功
  4. })
  5. .catch(reason => {
  6. // 获取失败
  7. })

3)数据操作:(key为string,要求非空且长度不超80字节,数据量建议不超1w条,轻量级)

  1. // 3.1.写入数据,如果已经存在则会覆盖,可利用.has()判断是否存在
  2. preferences.put('key', val)
  3. .then(() => preferences.flush()) // 刷到磁盘
  4. .catch(reason => J) // 处理异常
  5. //3.2.删除数据
  6. preferences.delete('key')
  7. .then(() => ).catch(reason => [])
  8. //3.3.查询数据
  9. preferences.get('key', 'defaultValue')
  10. .then(value => console.log('查询成功'))
  11. .catch(reason => console.log('查询失败'))

接下来对用户的首选项数据持久化进行一个简单的操作,首先我们先定义一个实例用来增删改查数据:

  1. import preferences from '@ohos.data.preferences';
  2. class PreferencesUtil {
  3. prefMap: Map<string, preferences.Preferences> = new Map()
  4. // 加载preferences实例
  5. async loadPreference(content, name: string){
  6. try {
  7. let pref = await preferences.getPreferences(content, name)
  8. this.prefMap.set(name, pref)
  9. console.log('testTag', `加载Preferences[${name}]成功`)
  10. }catch (e){
  11. console.log('testTag', `加载Preferences[${name}]失败`, JSON.stringify(e))
  12. }
  13. }
  14. // 新增数据
  15. async putPreferencesValue(name: string, key: string, value: preferences.ValueType){
  16. if (!this.prefMap.has(name)) {
  17. console.log('testTag', `Preferences[${name}]尚未初始化`)
  18. return
  19. }
  20. try {
  21. let pref = this.prefMap.get(name)
  22. // 写入数据
  23. await pref.put(key, value)
  24. // 刷盘
  25. await pref.flush()
  26. console.log('testTag', `保存Preferences[${name}.${key} = ${value}]成功`)
  27. } catch (e){
  28. console.log('testTag', `保存Preferences[${name}.${key} = ${value}]失败`, JSON.stringify(e))
  29. }
  30. }
  31. // 读取数据
  32. async getPreferencesValue(name: string, key: string, defaultValue: preferences.ValueType){
  33. if (!this.prefMap.has(name)) {
  34. console.log('testTag', `Preferences[${name}]尚未初始化`)
  35. return
  36. }
  37. try {
  38. let pref = this.prefMap.get(name)
  39. // 读取数据
  40. let value = await pref.get(key, defaultValue)
  41. console.log('testTag', `读取Preferences[${name}.${key} = ${value}]成功`)
  42. return value
  43. } catch (e){
  44. console.log('testTag', `读取Preferences[${name}.${key}]失败`, JSON.stringify(e))
  45. }
  46. }
  47. // 删除数据
  48. async deletePreferencesValue(name: string, key: string){
  49. if (!this.prefMap.has(name)) {
  50. console.log('testTag', `Preferences[${name}]尚未初始化`)
  51. return
  52. }
  53. try {
  54. let pref = this.prefMap.get(name)
  55. // 删除数据
  56. await pref.delete(key)
  57. // 刷盘
  58. await pref.flush()
  59. console.log('testTag', `删除Preferences[${name}.${key}]成功`)
  60. } catch (e){
  61. console.log('testTag', `删除Preferences[${name}.${key}]失败`, JSON.stringify(e))
  62. }
  63. }
  64. }
  65. const preferencesUtil = new PreferencesUtil()
  66. export default preferencesUtil as PreferencesUtil

在创建ability实例的文件中,在onCreate函数出进行一个调用:

在调用完成之后,我们进入到要持久化存储数据的界面,然后调用aboutToAppear函数在页面加载前读取数据,没有数据选择默认数据:

在修改数据后,对修改后的数据进行一个新增:

最后在真机中进行数据模仿,本地预览器是没有任何效果的,结果如下:

关系型数据库

关系型数据库(RDB)是基于SQLite组件提供的本地数据库,用于管理应用中的结构化数据。例如: 记账本、备忘录。以下是关系型数据库的运行流程图:

以下是 关系型数据库 使用的基本步骤:

1)导入关系型数据库模块:

import relationalStore from '@ohos.data.relationalStore';

2)初始化数据库表:

  1. // 2.1.rdb配置
  2. const config = {
  3. name: 'MyApplication.db'// 数据库文件名
  4. securityLevel: relationalstore.SecurityLevel.S1 // 数据库安全级别
  5. }
  6. // 2.2.初始化表的SQL
  7. const sql = `CREATE TABLE IF NOT EXISTS TASK (
  8. ID INTEGER PRIMARY KEY AUTOINCREMENT,
  9. NAME TEXT NOT NULL,
  10. FINISHED bit
  11. )`
  12. // 2.3获取rdb
  13. relationalStore.getRdbStore(this.context, config,(err,rdbStore) => {
  14. // 2.4执行Sql,后续的所有增删改查都是使用rdbstore对象
  15. rdbStore.executeSql(sql)
  16. })

3)增删改查的数据操作:

  1. // 新增数据
  2. let task = {id: 1, name: '任务', finished: false}; // 准备数据
  3. this.rdbStore.insert(this.tableName, task) // 新增
  4. // 修改数据
  5. let task = {'finished': true}; // 要更新的数据
  6. let predicates = new relationalStore.RdbPredicates(this.tableName) // 查询条件,RdbPredicates为条件谓词
  7. predicates.equalTo('ID', id)
  8. this.rdbStore.update(task, predicates) // 执行更新
  9. // 删除数据
  10. let predicates = new relationalStore.RdbPredicates(this.tableName) // 查询条件
  11. predicates.equalTo('ID', id)
  12. this.rdbStore.delete(predicates) // 执行删除
  13. // 查询数据
  14. let predicates = new relationalStore.RdbPredicates(this.tableName) // 查询条件
  15. let result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED']) // 执行查询
  16. let tasks: any[] = [] // 准备数组保存结果
  17. while(!result.isAtLastRow) { // 循环遍历结果集,判断是否结果是否遍历到最后一行
  18. result.goToNextRow() // 指针移动到下一行数据
  19. // 根据字段名获取字段index,从而获取字段值
  20. let id = result.getLong(result.getColumnIndex('ID'))
  21. let name = result.getString(result.getColumnIndex('NAME'))
  22. tasks.push({id, name})
  23. }

接下来对 关系型数据库 数据持久化进行一个简单的操作,首先我们先定义一个实例用来增删改查数据: 

  1. import relationalStore from '@ohos.data.relationalStore';
  2. class TaskModel {
  3. private rdbStore: relationalStore.RdbStore
  4. private tableName: string = 'TASK'
  5. // 初始化任务列表
  6. initTaskDB(context){
  7. // rdb配置
  8. const config = {
  9. name: 'MyApplication.db',
  10. securityLevel: relationalStore.SecurityLevel.S1 // 安全级别
  11. }
  12. // 初始化SQL语句
  13. const sql = `CREATE TABLE IF NOT EXISTS TASK (
  14. ID INTEGER PRIMARY KEY AUTOINCREMENT,
  15. NAME TEXT NOT NULL,
  16. FINISHED bit
  17. )`
  18. // 获取rdb
  19. relationalStore.getRdbStore(context, config, (err, rdbStore) => {
  20. if(err) {
  21. console.log('testTag', '获取rdbStore失败!')
  22. return
  23. }
  24. // 执行sql
  25. rdbStore.executeSql(sql)
  26. console.log('testTag', '创建task表成功!')
  27. // 保存rdbStore
  28. this.rdbStore = rdbStore
  29. })
  30. }
  31. // 查询任务列表
  32. async getTaskList() {
  33. // 构建查询条件
  34. let predicates = new relationalStore.RdbPredicates(this.tableName)
  35. // 查询
  36. let result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED'])
  37. // 解析查询结果
  38. let tasks: any[] = [] // 准备数组保存结果
  39. while(!result.isAtLastRow) { // 循环遍历结果集,判断是否结果是否遍历到最后一行
  40. result.goToNextRow() // 指针移动到下一行数据
  41. // 根据字段名获取字段index,从而获取字段值
  42. let id = result.getLong(result.getColumnIndex('ID'))
  43. let name = result.getString(result.getColumnIndex('NAME'))
  44. let finished = result.getLong(result.getColumnIndex('FINISHED'))
  45. tasks.push({id, name, finished})
  46. }
  47. console.log('testTag', '查询到数据:', JSON.stringify(tasks))
  48. return tasks
  49. }
  50. /*
  51. * 添加任务列表
  52. * @param name 任务名称
  53. * @returns 任务id
  54. * */
  55. addTask(name: string): Promise<number> {
  56. return this.rdbStore.insert(this.tableName, {name, finished: false})
  57. }
  58. /*
  59. * 根据id更新任务列表
  60. * @param id 任务id
  61. * @param finished 任务是否完成
  62. * */
  63. updateTaskStatus(id: number, finished: boolean) {
  64. // 要更新的数据
  65. let data = {finished}
  66. // 更新的条件
  67. let predicates = new relationalStore.RdbPredicates(this.tableName)
  68. predicates.equalTo('ID', id)
  69. // 更新操作
  70. return this.rdbStore.update(data, predicates)
  71. }
  72. /*
  73. * 根据id删除任务列表
  74. * @param id 任务id
  75. * */
  76. deleteTaskId(id: number, finished: boolean) {
  77. // 删除的条件
  78. let predicates = new relationalStore.RdbPredicates(this.tableName)
  79. predicates.equalTo('ID', id)
  80. // 删除操作
  81. return this.rdbStore.delete(predicates)
  82. }
  83. }
  84. let taskModel = new TaskModel()
  85. export default taskModel as TaskModel

然后在页面加载的时候进行调用:

新增任务的位置进行引用:

删除的位置进行引用:

更新的位置进行引用:

最终呈现的效果如下:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/651568
推荐阅读
相关标签
  

闽ICP备14008679号