当前位置: 首页 > news >正文

HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)

系列文章目录

HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)
HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)


文章目录

  • 系列文章目录
  • 前言
  • 一、实现步骤总结
  • 二、代码实现
    • 1.媒体读写权限检查和申请
    • 2.从手机存储选择图片或拍照
    • 3.复制图片到缓存目录下
    • 4. 接口请求上传图片
  • 三、完整代码
    • 页面调用:


前言

HarmonyOS Next(基于API11)实现从手机选择图片或拍照上传功能,常用于头像上传等操作


一、实现步骤总结

1、媒体读写权限检查和申请
2、从手机存储选择图片或拍照
3、把图片复制到缓存目录
4、接口请求上传图片

分析说明:
图片上传使用API request.uploadFile 而该api上传文件的本地路径只支持internal协议

在这里插入图片描述

所以选择完图片/或拍照后需要把图片从内部存储复制到cache目录下,该操作需要外部存储设备媒体读写权限,且是用户级别的权限,因此每次复制图片前需要检查权限如果没权限需弹窗口让用户授权,最后在通过该api实现上传

在这里插入图片描述

二、代码实现

1.媒体读写权限检查和申请

(1)检查权限

工具类文件:

import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = 0;// 获取应用程序的accessTokenIDlet tokenId: number = 0;try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (err) {console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);}// 校验应用是否被授予权限try {grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (err) {console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);}return grantStatus;
}//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {try {let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED}catch (e) {return Promise.reject(e)}
}

调用:

      const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限let permissionList: Permissions[] = []; //需要申请选项列表let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限!readPermission && permissionList.push(READ_MEDIA_PERMISSION)let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限!writePermission && permissionList.push(READ_MEDIA_PERMISSION)

(2)申请权限
工具类文件:

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'interface rejectObj {code: numbermessage: string
}
/*** 申请权限* @params context:AblitiyContext* @params permissions:权限名称数组* @returns  Promise<boolean>:是否授权成功*/
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {let atManager = abilityAccessCtrl.createAtManager();return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;resolve(grantStatus.every(item => item === 0))}).catch((err: rejectObj) => {reject(err)})})
}

调用:

       private context = getContext(this) as common.UIAbilityContext; //UIAbilityContext...............//申请权限let res: boolean = await applyPermission(this.context, permissionList)if (!res) {//用户未同意授权AlertDialog.show({title: "提示",message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",alignment: DialogAlignment.Center,secondaryButton: {value: '关闭',action: () => {}}})}

2.从手机存储选择图片或拍照

(1)从手机存储选择图片

    import picker from '@ohos.file.picker';........//从相册选择let PhotoSelectOptions = new picker.PhotoSelectOptions();PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;PhotoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {if (PhotoSelectResult.photoUris.length) {console.log(`图片本地路径:${PhotoSelectResult.photoUris[0]}`)} })

(2)拍照

    import camera from '@ohos.multimedia.camera';import camerapicker from '@ohos.multimedia.cameraPicker';import { BusinessError } from '@ohos.base';........try{let pickerProfile: camerapicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK};let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,[camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);} catch (error) {let err = error as BusinessError;console.error(`the pick call failed. error code: ${err.code}`);}   

3.复制图片到缓存目录下

默认复制图片到缓存目录cache根路径下,移动后文件名前面加上当前时间戳区分:timestamep+原name.格式

import fs from '@ohos.file.fs';/*** 复制文件到缓存目录下* @param path :文件路径* @param context :Context* @returns Promise<string> 移动后文件路径*/
export async function copyFileToCache(path: string,context:Context): Promise<string> {try {let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)if (file) {let fileDir: string = `${context.cacheDir}` //临时文件目录//时间戳生成随机文件名let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`let targetPath: string = `${fileDir}/${newPath}`fs.copyFileSync(file.fd, targetPath)return  newPath}else {return ''}} catch (e) {return Promise.resolve('')}
}

4. 接口请求上传图片

  //开始上传图片 path:图片路径后缀(图片名称)async uploadImage(path: string) {let uri=`internal://cache/${path}` //上传图片全路径let uploadConfig: request.UploadConfig = {url:"http://xxxxxxx",header:{},method: "POST",files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],data: [],};try {let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)//上传中回调uploadTask.on('progress', (size,total) => {console.log(size.toString(),total.toString(),'上传进度')})//上传完成回调uploadTask.on('complete', (taskStates: request.TaskState[]) => {console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));})//上传失败回调uploadTask.on('fail', (taskStates: request.TaskState[]) => {console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));})}catch (e){console.log( JSON.stringify(e),'e')}}

需要注意的是我们在复制图片步骤中通过context.cacheDir获取到的缓存目录路径如下所示:

"path":"/data/storage/el2/base/haps/entry/cache/1717854801890_IMG_20240603_170235.jpg"

需转换成internal协议路径,
前面 “/data/storage/el2/base/haps/entry/cache"实际等价于"internal://cache”
所以在上传接口拼接uri参数时候只需要知道图片名称+格式即可,最终上传参数拼接后路径为internal://cache/1717854801890_IMG_20240603_170235.jpg


三、完整代码

完整代码将封装一个完整的组件,自定义底部弹窗菜单选择拍照或从手机相册选择,选完自动上传。
在这里插入图片描述

代码目录结构
在这里插入图片描述

utils/index.ets(工具类):


import fs from '@ohos.file.fs';
import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'/*** 复制文件到缓存目录下* @param path :文件路径* @param context :Context* @returns Promise<string> 移动后文件路径*/
export async function copyFileToCache(path: string,context:Context): Promise<string> {try {let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)if (file) {let fileDir: string = `${context.cacheDir}` //临时文件目录//时间戳生成随机文件名let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`let targetPath: string = `${fileDir}/${newPath}`fs.copyFileSync(file.fd, targetPath)return  newPath}else {return ''}} catch (e) {return Promise.resolve('')}
}//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = 0;// 获取应用程序的accessTokenIDlet tokenId: number = 0;try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (err) {console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);}// 校验应用是否被授予权限try {grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (err) {console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);}return grantStatus;
}//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {try {let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED}catch (e) {return Promise.reject(e)}
}interface rejectObj {code: numbermessage: string
}
/*** 申请权限* @params context:AblitiyContext* @params permissions:权限名称数组* @returns  Promise<boolean>:是否授权成功*/
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {let atManager = abilityAccessCtrl.createAtManager();return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;resolve(grantStatus.every(item => item === 0))}).catch((err: rejectObj) => {reject(err)})})
}

ImageUploadDialog.ets(图片上传弹窗菜单选择组件):

import picker from '@ohos.file.picker';
import { checkPermissions, applyPermission, copyFileToCache } from '../../utils/index'
import { request } from '@kit.BasicServicesKit';
import { Permissions } from '@ohos.abilityAccessCtrl';
import camera from '@ohos.multimedia.camera';
import camerapicker from '@ohos.multimedia.cameraPicker';
import { BusinessError } from '@ohos.base';
import { common } from '@kit.AbilityKit';@Extend(Text)
function custText() {.width('100%').height('48')    .fontColor('#39364D').textAlign(TextAlign.Center)
}@CustomDialog
export default struct ImageUploadDialog {dialogController: CustomDialogController@Prop uploadURL:string='';//上传接口地址private context = getContext(this) as common.UIAbilityContext; //UIAbilityContextprivate success:(res: request.TaskState[])=>void=()=>{}//上传成功回调private fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调//检查权限async checkAppPermission(): Promise<boolean> {try {const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限let permissionList: Permissions[] = []; //需要申请选项列表let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限!readPermission && permissionList.push(READ_MEDIA_PERMISSION)let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限!writePermission && permissionList.push(READ_MEDIA_PERMISSION)if (permissionList.length) {//申请权限let res: boolean = await applyPermission(this.context, permissionList)if (!res) {//用户未同意授权AlertDialog.show({title: "提示",message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",alignment: DialogAlignment.Center,secondaryButton: {value: '关闭',action: () => {}}})}return res}return true}catch (e) {return Promise.reject(e)}}//开始上传图片 path:图片路径后缀(图片名称)async uploadImage(path: string) {console.log(path, 'path')let uri=`internal://cache/${path}` //上传图片全路径let uploadConfig: request.UploadConfig = {url:this.uploadURL,header:{},method: "POST",files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],data: [],};try {let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)//上传中回调uploadTask.on('progress', (size,total) => {console.log(size.toString(),total.toString(),'上传进度')})//上传完成回调uploadTask.on('complete', (taskStates: request.TaskState[]) => {console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));if(taskStates&&taskStates.length&& taskStates[0].responseCode===0){this.success&&this.success(taskStates)}})//上传失败回调uploadTask.on('fail', (taskStates: request.TaskState[]) => {console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));this.fail&&this.fail(taskStates)})}catch (e){console.log( JSON.stringify(e),'e')}}build() {Column() {//拍照Text('拍照').custText().onClick(async()=>{//检查是否有读写外部媒体权限let res: boolean = await this.checkAppPermission()//无权限返回if (!res) returntry {let pickerProfile: camerapicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK};let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,[camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);if(pickerResult?.resultUri){//关闭弹窗this.dialogController.close()//复制图片到缓存目录(缓存目录才有读写权限)let filePath = await copyFileToCache(pickerResult.resultUri, this.context)if (filePath) {//上传头像并设置this.uploadImage(filePath)}}} catch (error) {let err = error as BusinessError;console.error(`the pick call failed. error code: ${err.code}`);}})Divider().color('#F7F9FA').width('100%').strokeWidth(1)//从手机相册选择Text('从手机相册选择').custText().onClick(async () => {//检查是否有读写外部媒体权限let res: boolean = await this.checkAppPermission()//无权限返回if (!res) return//关闭弹窗this.dialogController.close()//从相册选择let PhotoSelectOptions = new picker.PhotoSelectOptions();PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;PhotoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {if (PhotoSelectResult.photoUris.length) {//复制图片到缓存目录(缓存目录才有读写权限)let filePath = await copyFileToCache(PhotoSelectResult.photoUris[0],this.context)if (filePath) {this.uploadImage(filePath)}}})})Button('取消', { type: ButtonType.Capsule }).backgroundColor('#F7F7F7').fontSize('16fp').fontColor('#333333').width('100%').margin({ top: '30' }).onClick(() => {this.dialogController.close()})}.width('100%').padding({ left: '16', top: '11', right: '16', bottom: '16' }).backgroundColor(Color.White).borderRadius({topLeft: '24',topRight: '24'})}
}

组件入参 说明:

uploadURL:上传接口url
success:(res: request.TaskState[])=>void 上传成功回调函数
fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调

成功或失败回调参数说明

 request.TaskState[]: {path:string //图片在本地路径message:string //上传结果信息responseCode //上传结果状态码 0:成功,其他值失败}[]

从 request.TaskState字段描述可以看出request.uploadFile无法返回接口返回的数据,这也是最大的坑,期待官方解决,如果需要获取上传成功后返回的url,可以在设计个接口上传完再调用该接口获取图片url,如果像头像设置这种功能也可以把图片上传和头像设置整合成一个接口,上传完也即设置完成。

页面调用:

pages/Index

import ImageUploadDialog from '../components/ImageUploadDialog/ImageUploadDialog'
import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct Index {@State dialogController: CustomDialogController | null = null //选择上传类型弹窗控制器aboutToAppear(): void {this.dialogController= new CustomDialogController({builder: ImageUploadDialog({uploadURL: 'http://xxxxxxxxx',//上传地址success:e=>{//上传成功回调console.log(JSON.stringify(e))promptAction.showToast({message:'上传成功'})},fail:e=>{//上传失败回调console.log(JSON.stringify(e))promptAction.showToast({message:'上传失败'})}}),alignment: DialogAlignment.Bottom,//弹窗居于底部customStyle: true,//自定义样式})}build() {Column(){Button('上传').onClick(()=>{this.dialogController?.open()})}.width('100%')}
}

最后不要忘记添加权限
三个:

  "ohos.permission.INTERNET":网访问权限"ohos.permission.READ_MEDIA":外部存储设备媒体读取权限"ohos.permission.WRITE_MEDIA":外部存储设备媒体写入权限

module.json5:

 //权限requestPermissions: [{"name": "ohos.permission.INTERNET",},{"name": "ohos.permission.READ_MEDIA","reason": "$string:reasonReadWriteMedia",//使用权限原因"usedScene": {"abilities": [//使用的该权限的EntryAbility名称数组"EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.WRITE_MEDIA","reason": "$string:reasonReadWriteMedia","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]

entry\src\main\resources\base\element\string.json

{"string": [,{"name":"reasonReadWriteMedia","value": "上传头像"}]
}

效果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

相关文章:

HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…...

如果xml在mapper目录下,如何扫描到xml

如果xml在mapper目录下,如何扫描到xml 项目结构 src├── main│ ├── java│ │ └── com│ │ └── bg│ │ ├── Application.java│ │ ├── domain│ │ │ └── User.java│ │ …...

什么是无限铸币攻击?它是如何运作的?

一、无限铸币攻击解释 无限铸币攻击是指攻击者操纵合约代码不断铸造超出授权供应限制的新代币。 这种黑客行为在去中心化金融 (DeFi) 协议中最为常见。这种攻击通过创建无限数量的代币来损害加密货币或代币的完整性和价值。 例如&#xff0c;一名黑客利用了 Paid 网络的智能…...

【Android】怎么使APP进行开机启动

项目需求 在Android系统开启之后&#xff0c;目标app可以在系统开机之后启动。 项目实现 使用广播的方式 首先我们要创建一个广播(这里是启动了一个Service服务) public class BootReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, I…...

详细分析Element Plus的el-pagination基本知识(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 需求&#xff1a;从无到有做一个分页并且附带分页的导入导出增删改查等功能 前提一定是要先有分页&#xff0c;作为全栈玩家&#xff0c;先在前端部署一个分页的列表 相关后续的功能&#xff0c;是Java&#xff0c;推荐阅读&#x…...

ubuntu换镜像源方法

查看ubuntu的版本&#xff0c;不同的版本对应的不同的镜像源 cat /etc/issue Ubuntu 18.04.6 LTS \n \l 先备份一个&#xff0c;防止更改错误 cobol cp /etc/apt/sources.list /etc/apt/sources.list.backup 先进入清华源,搜索ubuntu&#xff0c;点击问号 点进来可以看到可以…...

python flask配置邮箱发送功能,使用flask_mail模块

&#x1f308;所属专栏&#xff1a;【Flask】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…...

Flask快速入门(路由、CBV、请求和响应、session)

Flask快速入门&#xff08;路由、CBV、请求和响应、session&#xff09; 目录 Flask快速入门&#xff08;路由、CBV、请求和响应、session&#xff09;安装创建页面Debug模式快速使用Werkzeug介绍watchdog介绍快速体验 路由系统源码分析手动配置路由动态路由-转换器 Flask的CBV…...

人工智能指数报告

2024人工智能指数报告&#xff08;一&#xff09;&#xff1a;研发 前言 全面分析人工智能的发展现状。 从2017年开始&#xff0c;斯坦福大学人工智能研究所&#xff08;HAI&#xff09;每年都会发布一份人工智能的研究报告&#xff0c;人工智能指数报告&#xff08;AII&…...

聊聊 Mybatis 动态 SQL

这篇文章&#xff0c;我们聊聊 Mybatis 动态 SQL &#xff0c;以及我对于编程技巧的几点思考 &#xff0c;希望对大家有所启发。 1 什么是 Mybatis 动态SQL 如果你使用过 JDBC 或其它类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQL 语句有多痛苦&#xff0c;例如拼…...

【windows|004】BIOS 介绍及不同品牌电脑和服务器进入BIOS设置的方法

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 ​ &#x1f3c5;阿里云ACE认证高级工程师 ​ &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社…...

lvgl的应用:移植MusicPlayer(基于STM32F407)

目录 概述 1 软硬件环境 1.1 UI开发版本 1.2 MCU开发环境 1.3 注意点 2 GUI Guider开发UI 2.1 使用GUI Guider创建UI 2.2 GUI Guider编译项目和测试 2.2.1 GUI Guider编译项目 2.2.2 编译 2.3 了解GUI Guider生成代码 3 移植项目 3.1 Keil中加载代码 3.2 调用G…...

Hadoop3:MapReduce中的Shuffle机制

一、流程图 Shuffle是Map方法之后&#xff0c;Reduce方法之前的数据处理过程称。 二、图解说明 1、数据流向 map方法中context.write(outK, outV);开始&#xff0c;写入环形缓冲区&#xff0c;再进行分区排序&#xff0c;写到磁盘 reduce方法拉取磁盘上的数据&#xff0c;…...

从设计到实践:高速公路监控技术架构全剖析

随着高速公路网络的迅速扩展和交通流量的日益增加&#xff0c;高效的监控系统成为保障交通安全、提升管理效率的重要手段。本文将深入探讨高速公路监控技术架构&#xff0c;从设计理念到实际应用&#xff0c;全面解析这一关键技术的各个环节。 ### 一、系统设计理念 #### 1. 高…...

Go Context

Context 介绍 Context 代表了协程的上下文&#xff0c;用以在父子协程之间传递控制信号&#xff0c;共享变量等操作// context.Context 接口 type Context interface {// 当Context自动取消或者到了取消时间被取消后返回Deadline() (deadline time.Time, ok bool)// 当Contex…...

centOS Stream9配置NAT8网络

首先将VMware关机&#xff0c;添加网络适配器 启动虚拟机&#xff0c;查看ens192是否打开连接 安装的图形化需要查看右上角电源处网卡是否连接 最小化安装一般不会出现未连接的状态 使用ip a 查看 配置网卡文件 cd /etc/NetworkManager/system-connections/cd到当前目录下…...

Linux - 进程

一、什么是进程 首先&#xff0c;Linux是一个多用户多进程的操作系统&#xff0c;系统上可以同时运行多个进程。 进程的产生&#xff1a;①是在执行程序或者命令时产生的&#xff1b;②定时任务进程 进程的类型&#xff1a;前台进程/后台进程 前台进程&#xff1a;一个终端…...

nginx+tomcat负载均衡、动静分离群集【☆☆☆☆☆】

Nginx是一款非常优秀的HTTP服务器软件&#xff0c;性能比tomcat更优秀&#xff0c;它支持高达50 000个并发连接数&#xff0c;拥有强大的静态资源处理能力&#xff0c;运行稳定&#xff0c;内存、CPU等系统资源消耗非常低。目前很多大型网站都应用Nginx服务器作为后端网站程序的…...

MySQL容器部署步骤

1、拉取MySQL镜像 docker pull mysql # 默认拉取最新版本docker pull mysql:5.7 # 拉取5.7版本docker pull mysql:8.0 # 拉取8.0版本 2、创建挂载目录 # 创建挂载目录 mkdir -p /home/mysql/conf/ # -p: 多级创建mkdir -p /home/mysql/log/mkdir -p /home/mysql/data/ 3…...

在 Ubuntu 18.04.4 LTS上安装 netmap

文章目录 步骤运行配置文件编译安装使用netmap 步骤 sudo su sudo apt-get update sudo apt install build-essential sudo apt-get install -y git sudo apt-get install -y linux-headers-$(uname -r)rootVM-20-6-ubuntu:/home/ubuntu/netmap/LINUX# git clone https://gith…...

spark 整合 yarn

spark 整合 yarn 1、在master节点上停止spark集群 cd /usr/local/soft/spark-2.4.5/sbin ./stop-all.sh 2、spark整合yarn只需要在一个节点整合, 可以删除node1 和node2中所有的spark文件 分别在node1、node2 的/usr/local/soft目录运行 rm -rf spark-2.4.…...

蓝桥杯十五届国赛模拟题1答案

1、bug缺陷报告 功能名称缺陷描述操作步骤预期结果实际结果缺陷级别销售订单列表...

分布式之日志系统平台ELK

ELK解决了什么问题 我们开发完成后发布到线上的项目出现问题时(中小型公司),我们可能需要获取服务器中的日志文件进行定位分析问题。但在规模较大或者更加复杂的分布式场景下就显得力不从心。因此急需通过集中化的日志管理,将所有服务器上的日志进行收集汇总。所以ELK应运而生…...

git常见错误

refusing to merge unrelated histories 如果git merge合并的时候出现refusing to merge unrelated histories的错误&#xff0c;原因是两个仓库不同而导致的&#xff0c;需要在后面加上--allow-unrelated-histories进行允许合并&#xff0c;即可解决问题。 git push origin …...

构建稳定高效的消息传递中间件:消息队列系统的设计与实现

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 一、引言 二、设计目标 2.1、高可用性 1. 集群搭建 1.1 …...

支持 MKV、MP4、AVI、MPG 等格式视频转码器

一、简介 1、一款开源的视频转码器&#xff0c;适用于 Linux、Mac 和 Windows。它是一个免费的工具&#xff0c;由志愿者们开发&#xff0c;可以将几乎所有格式的视频转换为现代、广泛支持的编码格式。你可以在官网上下载该应用或源代码。该软件支持 MKV、MP4、AVI、MPG 等格式…...

yum

文章目录 本地源配置本地yum源仓库yum常用的操作命令 网络源阿里云当yum 安装源代码软件包需要编译安装&#xff0c;需要安装支持c和c程序语言的编译器&#xff0c;如gcc、gcc-c、make 如果使用rpm方式安装&#xff0c;则需要先安装多个依赖包&#xff0c;这样会很繁琐。可以使…...

【单片机毕业设计选题24016】-基于STM32和阿里云的采空区环境监测系统设计

系统功能: 系统分为主机端和从机端&#xff0c;主机端主动向从机端发送信息和命令&#xff0c;从机端 收到主机端的信息后回复温度,甲烷&#xff0c;一氧化碳&#xff0c;氧气和系统状态等信息。 同时主机端将这些信息上传至阿里云服务器。 主要功能模块原理图: 电源时钟烧…...

Leetcode3179. K 秒后第 N 个元素的值

Every day a Leetcode 题目来源&#xff1a;3179. K 秒后第 N 个元素的值 解法1&#xff1a;模拟 模拟 k 轮&#xff0c;数组保存上一次结果&#xff0c;然后计算当前轮次的结果。 代码&#xff1a; /** lc appleetcode.cn id3179 langcpp** [3179] K 秒后第 N 个元素的值…...

vue3第二阶段的开发文档

1 2.1 案例——学习计划表 2.1.1 准备工作 在开发“学习计划表”案例之前&#xff0c;需要先完成一些准备工作&#xff0c;具体步骤如下。 ① 打开命令提示符&#xff0c;切换到 D:\vue\chapter02 目录&#xff0c;在该目录下执行如下命令&#xff0c;创建 项目。 np…...

眉山营销型网站建设/怎样把广告放到百度

ASP.NET MVC框架开发系列课程(视频课程讲师&#xff1a;赵劼) ASP.NET 2.0入门与提高系列课程(视频课程讲师&#xff1a;徐栋) ASP.NET AJAX深入浅出系列课程(视频课程讲师&#xff1a;赵劼)面向开发人员之ASP.NET开发技术系列课程(视频课程讲师&#xff1a;徐栋) 实战ASP.NET…...

做百度网站还是安居客网站/腾讯广告推广平台入口

一、命令详解 在使用VC时&#xff0c;可以用DUMPBIN。EXE来得到某个DLL中所输出的符号的清单。如下面的命令&#xff1a;dumpbin -exports Cmpnt1.dll如&#xff1a;C:/WINDOWS/system32>dumpbin -exports msgsvc.dllMicrosoft (R) COFF Binary File Dumper Version 6.00.8…...

主流网站编程语言/西安seo关键词排名优化

微软今年四月宣布了一个新项目“Project Astoria”&#xff0c;开发者可以直接将它们的Android、iOS、Web、Win32应用移植到Windows 10 Mobile移动平台&#xff0c;以兼容模式运行&#xff0c;从而大大降低开发难度。Re/Code报道称&#xff0c;微软确认Android版的Project Asto…...

两个人能用的一个公司做网站吗/服装品牌策划方案

Mysql部署文档操作系统&#xff1a;CentOS Linux release 7.4.1708内核版本&#xff1a;3.10.0# 手动安装1> 将mysql-5.5.54-linux2.6-x86_64.tar.gz上传至CentOS服务器/tmp目录下2> 解压压缩包至/usr/local/[rootlocalhost local]# tar -zxvf /tmp/mysql-5.5.54-linux2.…...

三金网手机网站/公司网站如何seo

1、什么是类集框架 1.1 类集框架是一组类和接口 1.2 位于java.util 包中 1.3 主要用于存储和管理对象 1.4 主要分为三类及&#xff1a;集合&#xff08;set&#xff09;、列表&#xff08;list&#xff09;和映射&#xff08;map&#xff09; 2、类集框架的层次结构 collection…...

网站备案主体/seo技术学院

游戏中的矿车要想跑起来就必须要铁轨,这就给了矿车许多限制,不能非常自由地驾驶,所以我们今天就教大家怎么在游戏里做一个超自由的飞行矿车~超自由飞行矿车要做出超自由飞行矿车其实非常简单~只需要一个命令方块即可&#xff0c;在聊天栏输入/give s command_block就可以得到啦…...