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

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

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

目录

网络连接

HTTP数据请求

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

ohpm安装使用教程

axios第三方库安装

axios的使用

数据持久化

用户首选项

关系型数据库


网络连接

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

HTTP数据请求

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

1)导入 http 模块:

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

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

// 创建一个http的请求对象,不可复用
let httpRequest = http.createHttp()
// 发送网络请求
httpRequest.request('http://localhost:3000/user', // 请求的URL路径{ // 请求选项 HttpRequestOptionsmethod: http.RequestMethod.GET,extraData: { 'param1': 'value1' },}
)

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

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

3)处理响应的结果

// 创建一个http的请求对象,不可复用
let httpRequest = http.createHttp()
// 发送网络请求
httpRequest.request('http://localhost:3000/user', // 请求的URL路径{ // 请求选项 HttpRequestOptionsmethod: http.RequestMethod.GET,extraData: { 'param1': 'value1' },}
)// 处理响应结果.then((resp: http.HttpResponse) => {if(resp.responseCode === 200){// 请求成功}}).catch((err: Error) => {// 请求失败})

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

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

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

import http from '@ohos.net.http';class getAPI {BaseCatURL = 'https://api.thecatapi.com/v1/images' // 猫图catNum = 2 // 猫数// 获取猫的图片getCat(){return new Promise((resolve, reject) => {// 创建一个http的请求对象,不可复用let httpRequest = http.createHttp()// 发送网络请求httpRequest.request(`${this.BaseCatURL}/search?limit=${this.catNum}`,// 请求的URL路径{ // 请求选项 HttpRequestOptionsmethod: http.RequestMethod.GET,})// 处理响应结果.then((resp: http.HttpResponse) => {if(resp.responseCode === 200){// 请求成功resolve(JSON.parse(resp.result.toString()))}else{console.log('查询信息失败!', JSON.stringify(resp))reject('查询信息失败!')}}).catch((err: Error) => {// 请求失败console.log('查询信息失败!', JSON.stringify(err))reject('查询信息失败!')})})}// 获取猫的图片getWord(){return new Promise((resolve, reject) => {// 创建一个http的请求对象,不可复用let httpRequest = http.createHttp()// 发送网络请求httpRequest.request('http://api.uomg.com/api/rand.qinghua',// 请求的URL路径{ // 请求选项 HttpRequestOptionsmethod: http.RequestMethod.GET,})// 处理响应结果.then((resp: http.HttpResponse) => {if(resp.responseCode === 200){console.log(resp.result.toString())// 请求成功resolve(JSON.parse(resp.result.toString()))}else{console.log('查询信息失败!', JSON.stringify(resp))reject('查询信息失败!')}}).catch((err: Error) => {// 请求失败console.log('查询信息失败!', JSON.stringify(err))reject('查询信息失败!')})})}
}const getApi = new getAPI()
export default getApi

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

import getApi from '../api/test'@Entry
@Component
struct test {@State catInfo: any = []@State word: string = ''scroller: Scroller = new Scroller()aboutToAppear(){this.loadCatInfo()}build() {Column(){Text('猫猫的图片').fontSize(30).fontWeight(FontWeight.Bold).margin(15)Text('今日情话:'+ this.word).fontSize(20).fontWeight(FontWeight.Bold).margin(5)Divider().margin(10)Grid(this.scroller){ForEach(this.catInfo, (item: any) => {GridItem(){Image(item.url).width('100%').objectFit(ImageFit.Auto).height(120)}})}.width('100%').columnsTemplate(`1fr 1fr`).columnsGap(10).rowsGap(10).padding(5).height(540)}.padding(10).width('100%').height('100%')}loadCatInfo() {// 加载数据getApi.getCat().then((res: any) => {this.catInfo = res})getApi.getWord().then((res: any) => {console.log('111',res.content)this.word = res.content})}
}

最终呈现的效果如下:

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进行如下编写,如下:

import axios from '@ohos/axios'class getAPI {// 获取猫的图片getCat(){return new Promise((resolve, reject) => {axios.get('https://api.thecatapi.com/v1/images/search?limit=2').then((resp) => {if(resp.status === 200){// 请求成功resolve(resp.data)}else{console.log('查询信息失败!', JSON.stringify(resp))reject('查询信息失败!')}}).catch((err: Error) => {// 请求失败console.log('查询信息失败!', JSON.stringify(err))reject('查询信息失败!')})})}// 获取猫的图片getWord(){return new Promise((resolve, reject) => {axios.get('http://api.uomg.com/api/rand.qinghua').then((resp) => {if(resp.status === 200){// 请求成功resolve(resp.data)}else{console.log('查询信息失败!', JSON.stringify(resp))reject('查询信息失败!')}}).catch((err: Error) => {// 请求失败console.log('查询信息失败!', JSON.stringify(err))reject('查询信息失败!')})})}
}const getApi = new getAPI()
export default getApi

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

数据持久化

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

用户首选项

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

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

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

import dataPreference from '@ohos.data.preferences'

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

dataPreference.getPreferences(this.content, 'MyAppPreferences').then(preferences => {// 获取成功}).catch(reason => {// 获取失败})

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

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

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

import preferences from '@ohos.data.preferences';class PreferencesUtil {prefMap: Map<string, preferences.Preferences> = new Map()// 加载preferences实例async loadPreference(content, name: string){try {let pref = await preferences.getPreferences(content, name)this.prefMap.set(name, pref)console.log('testTag', `加载Preferences[${name}]成功`)}catch (e){console.log('testTag', `加载Preferences[${name}]失败`, JSON.stringify(e))}}// 新增数据async putPreferencesValue(name: string, key: string, value: preferences.ValueType){if (!this.prefMap.has(name)) {console.log('testTag', `Preferences[${name}]尚未初始化`)return}try {let pref = this.prefMap.get(name)// 写入数据await pref.put(key, value)// 刷盘await pref.flush()console.log('testTag', `保存Preferences[${name}.${key} = ${value}]成功`)} catch (e){console.log('testTag', `保存Preferences[${name}.${key} = ${value}]失败`, JSON.stringify(e))}}// 读取数据async getPreferencesValue(name: string, key: string, defaultValue: preferences.ValueType){if (!this.prefMap.has(name)) {console.log('testTag', `Preferences[${name}]尚未初始化`)return}try {let pref = this.prefMap.get(name)// 读取数据let value = await pref.get(key, defaultValue)console.log('testTag', `读取Preferences[${name}.${key} = ${value}]成功`)return value} catch (e){console.log('testTag', `读取Preferences[${name}.${key}]失败`, JSON.stringify(e))}}// 删除数据async deletePreferencesValue(name: string, key: string){if (!this.prefMap.has(name)) {console.log('testTag', `Preferences[${name}]尚未初始化`)return}try {let pref = this.prefMap.get(name)// 删除数据await pref.delete(key)// 刷盘await pref.flush()console.log('testTag', `删除Preferences[${name}.${key}]成功`)} catch (e){console.log('testTag', `删除Preferences[${name}.${key}]失败`, JSON.stringify(e))}}
}const  preferencesUtil = new PreferencesUtil()
export default preferencesUtil as PreferencesUtil

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

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

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

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

关系型数据库

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

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

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

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

2)初始化数据库表:

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

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

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

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

import relationalStore from '@ohos.data.relationalStore';class TaskModel {private rdbStore: relationalStore.RdbStoreprivate tableName: string = 'TASK'// 初始化任务列表initTaskDB(context){// rdb配置const config = {name: 'MyApplication.db',securityLevel: relationalStore.SecurityLevel.S1 // 安全级别}// 初始化SQL语句const sql = `CREATE TABLE IF NOT EXISTS TASK (ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT NOT NULL,FINISHED bit)`// 获取rdbrelationalStore.getRdbStore(context, config, (err, rdbStore) => {if(err) {console.log('testTag', '获取rdbStore失败!')return}// 执行sqlrdbStore.executeSql(sql)console.log('testTag', '创建task表成功!')// 保存rdbStorethis.rdbStore = rdbStore})}// 查询任务列表async getTaskList() {// 构建查询条件let predicates = new relationalStore.RdbPredicates(this.tableName)// 查询let result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED'])// 解析查询结果let tasks: any[] = [] // 准备数组保存结果while(!result.isAtLastRow) { // 循环遍历结果集,判断是否结果是否遍历到最后一行result.goToNextRow() // 指针移动到下一行数据// 根据字段名获取字段index,从而获取字段值let id = result.getLong(result.getColumnIndex('ID'))let name = result.getString(result.getColumnIndex('NAME'))let finished = result.getLong(result.getColumnIndex('FINISHED'))tasks.push({id, name, finished})}console.log('testTag', '查询到数据:', JSON.stringify(tasks))return tasks}/** 添加任务列表* @param name 任务名称* @returns 任务id* */addTask(name: string): Promise<number> {return this.rdbStore.insert(this.tableName, {name, finished: false})}/** 根据id更新任务列表* @param id 任务id* @param finished 任务是否完成* */updateTaskStatus(id: number, finished: boolean) {// 要更新的数据let data = {finished}// 更新的条件let predicates = new relationalStore.RdbPredicates(this.tableName)predicates.equalTo('ID', id)// 更新操作return this.rdbStore.update(data, predicates)}/** 根据id删除任务列表* @param id 任务id* */deleteTaskId(id: number, finished: boolean) {// 删除的条件let predicates = new relationalStore.RdbPredicates(this.tableName)predicates.equalTo('ID', id)// 删除操作return this.rdbStore.delete(predicates)}
}let taskModel = new TaskModel()
export default taskModel as TaskModel

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

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

删除的位置进行引用:

更新的位置进行引用:

最终呈现的效果如下:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot实战专题】「开发实战系列」深入迁出探索剖析SpringBoot服务容器特性的利器之Actuator(Web端点)

深入迁出探索剖析SpringBoot服务容器特性的利器之Actuator 内容简介内容大纲Actuator Web端点洞察应用程序内部状况的关键Actuator提供了13个端点启用ActuatorMaven依赖Gradle依赖 Actuator透视组件装配过程获得Bean装配报告&#xff08;/beans&#xff09;Bean属性概览Bean报告…

目标跟踪算法的目标丢失与遮挡处理 - 注意力机制

目标跟踪算法在处理目标遮挡和丢失情况时&#xff0c;采用了多种技术和策略。这些技术主要集中在提高算法的鲁棒性和适应性上&#xff0c;使其能够在复杂环境中有效跟踪目标。以下是一些常见的处理方法&#xff1a; 多模型融合&#xff1a;通过结合多个跟踪模型或特征表示&…

centos docker-compose安装教程-2024最新版 亲测可用

目录 长时间不安装,生疏了,再次记录下 1.下载 2.修改名称 3.提权 4.测试验证 长时间不安装,生疏了,再次记录下 1.下载 官网地址 docker-compose官网地址&#xff1a;https://docs.docker.com/compose/compose-file/compose-file-v3/ #进入目录 cd /usr/local/bin#下载 wg…

NI PXIe-6386国产替代,8路AI(16位,14 MS/s/ch),2路A​O,24路DIO,PXI多功能I/O模块

PXIe-6386 PXIe&#xff0c;8路AI&#xff08;16位&#xff0c;14 MS/s/ch&#xff09;&#xff0c;2路A​O&#xff0c;24路DIO&#xff0c;PXI多功能I/O模块 PXIe-6386是一款同步采样的多功能DAQ设备。该模块提供了模拟 I/O、数字I/O、四个32位计数器和模拟和数字触发。板载N…

Qat++,轻量级开源C++ Web框架

目录 一.简介 二.编译Oat 1.环境 2.编译/安装 三.试用 1.创建一个 CMake 项目 2.自定义客户端请求响应 3.将请求Router到服务器 4.用浏览器验证 一.简介 Oat是一个面向C的现代Web框架 官网地址&#xff1a;https://oatpp.io github地址&#xff1a;https://github.co…

15个为你的品牌增加曝光的维基百科推广方法-华媒舍

维基百科是全球最大的免费在线百科全书&#xff0c;拥有庞大的用户群体和高质量的内容。在如今竞争激烈的市场中&#xff0c;利用维基百科推广品牌和增加曝光度已成为许多企业的重要策略。本文将介绍15种方法&#xff0c;帮助你有效地利用维基百科推广品牌&#xff0c;提升曝光…

八. 实战:CUDA-BEVFusion部署分析-学习spconv的优化方案(Explicit GEMM conv)

目录 前言0. 简述1. 什么是Explicit GEMM Conv2. im2col3. spconv是如何使用Explicit GEMM Conv的4. 使用Explicit GEMM Conv处理spconv的优缺点5. 拓展-conv加速5.1 Introduction5.2 im2col5.3 Forward graph5.4 Backward graph5.5 Python example for forward propagation5.6…

【Proteus仿真】【Arduino单片机】智能感应温控风扇

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用LCD1602液晶显示模块、DS18B20温度、按键、声光报警、L293D电机驱动等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传感器检…

高级JavaScript。同步和异步,阻塞和非阻塞

同步阻塞 同步非阻塞 异步阻塞 异步非阻塞 在当什么是同步和异步&#xff0c;阻塞与非阻塞的概念还没弄清楚之前&#xff0c;更别提上面这些组合术语了&#xff0c;只会让你更加困惑。 同步和异步 同步和异步其实指的是&#xff0c;请求发起方对消息结果的获取是主动发起…

uniCloud - 云函数 的基本使用

目录 基本概念 简介 快速上手 1.新建云函数 2.使用云函数 callFunction方法 云函数的入参 获取云函数调用来源 云函数的返回格式 uniCloud响应体规范 总结案例 新建云函数 使用云函数 展示 基本概念 云函数即在云端&#xff08;服务器端&#xff09;运行的函数。…

SpringFramework实战指南(二)

SpringFramework实战指南&#xff08;二&#xff09; 2.1 Spring 和 SpringFramework概念2.2 SpringFramework主要功能模块2.3 SpringFramework 主要优势 2.1 Spring 和 SpringFramework概念 Spring-ioc 广义的 Spring&#xff1a;Spring 技术栈&#xff08;全家桶&#xff0…

odoo17基础培训1-odoo开发基础知识准备以及odoo17开发环境安装

odoo17基础培训 一、odoo开发基础知识准备以及odoo17开发环境安装 1、odoo是什么&#xff1f; 当我介绍客户使用odoo系统作为业务管理平台时&#xff0c;有时会被问到Odoo是什么&#xff1f; 简单点&#xff0c;可以这么说&#xff1a; Odoo是一套完整的系统&#xff0c;是…

ssm基于web的电影购票系统+vue论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统电影购票信息管理难度大&#xff0c;容错率低&#xff0c…

Python基础知识:整理14 利用pyecharts生成地图

1 地图可视化的基本使用 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts # 准备地图对象 map Map()# 准备数据 data [("北京市", 8), ("上海市", 99), ("广州省", 199), ("重庆市", 400), ("…

DSL查询文档--各种查询

DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1查询所有 结果&#xff1a; 2全文检索&#xff08;full text&#xff09;查询 常见的全文检索查询包括&#xff1a; match查询&#xff1a;单字段查询 multi_match查询&#xff1a;多字段查询&#xff…

.NET开源免费、企业级、可商用内容管理系统 - SSCMS

前言 今天给大家推荐一款基于.NET Core开源、企业级、可商用、能够以最低的成本、最少的人力投入在最短的时间内架设一个功能齐全、性能优异、规模庞大并易于维护的内容管理系统&#xff1a;SSCMS。 系统官方介绍 SSCMS 内容管理系统基于微软 .NET Core 平台开发&#xff0c…

黑马程序员SpringBoot2-开发实用篇

视频连接&#xff1a;开发实用篇-67-手工启动热部署_哔哩哔哩_bilibili 热部署 手动启动热部署 热部署仅包含restart的过程。 自动启动热部署 按CtrlAltShift/打开下列界面。 禁用热部署 配置高级 ConfigurationProperties 宽松绑定/松散绑定 常用计量单位绑定 数据校验 设置…

Android音视频编码(2)

Android本身提供了音视频编解码工具&#xff0c;很多时候是不需要第三方工具的&#xff0c;比如ffmpeg, OpenCV等&#xff0c;在android中引入第三库比较复杂&#xff0c;在Android音视频编码中介绍了如何引入第三方库libpng来进行进行图片处理&#xff0c;同时引入这些第三方库…

JVM内存区域详解,一文弄懂JVM内存【内存分布、回收算法、垃圾回收器】

视频讲解地址 学习文档 一、内存区域 区域描述线程私有如何溢出程序计数器为了线程切换后能恢复到正确的执行位置&#xff0c;每个线程都要有一个独立的程序计数器。✅唯一一个不会内存溢出的地方虚拟机栈1. 每个方法执行的时候&#xff0c;Java虚拟机都会同步创建一个栈帧用于…

获取当前设备的IP

背景&#xff1a; 在本地使用自带webUI的项目时&#xff0c;需要制定webUI的访问地址。 一般本地访问使用&#xff1a;127.0.0.1&#xff0c;配置为可以从其他设备访问时&#xff0c;需要指定当前设备的IP&#xff0c;或者指定为0.0.0.0。 例如&#xff1a;使用locust的时候&a…