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 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…...
如果xml在mapper目录下,如何扫描到xml
如果xml在mapper目录下,如何扫描到xml 项目结构 src├── main│ ├── java│ │ └── com│ │ └── bg│ │ ├── Application.java│ │ ├── domain│ │ │ └── User.java│ │ …...

什么是无限铸币攻击?它是如何运作的?
一、无限铸币攻击解释 无限铸币攻击是指攻击者操纵合约代码不断铸造超出授权供应限制的新代币。 这种黑客行为在去中心化金融 (DeFi) 协议中最为常见。这种攻击通过创建无限数量的代币来损害加密货币或代币的完整性和价值。 例如,一名黑客利用了 Paid 网络的智能…...
【Android】怎么使APP进行开机启动
项目需求 在Android系统开启之后,目标app可以在系统开机之后启动。 项目实现 使用广播的方式 首先我们要创建一个广播(这里是启动了一个Service服务) public class BootReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, I…...

详细分析Element Plus的el-pagination基本知识(附Demo)
目录 前言1. 基本知识2. Demo3. 实战 前言 需求:从无到有做一个分页并且附带分页的导入导出增删改查等功能 前提一定是要先有分页,作为全栈玩家,先在前端部署一个分页的列表 相关后续的功能,是Java,推荐阅读&#x…...
ubuntu换镜像源方法
查看ubuntu的版本,不同的版本对应的不同的镜像源 cat /etc/issue Ubuntu 18.04.6 LTS \n \l 先备份一个,防止更改错误 cobol cp /etc/apt/sources.list /etc/apt/sources.list.backup 先进入清华源,搜索ubuntu,点击问号 点进来可以看到可以…...

python flask配置邮箱发送功能,使用flask_mail模块
🌈所属专栏:【Flask】✨作者主页: Mr.Zwq✔️个人简介:一个正在努力学技术的Python领域创作者,擅长爬虫,逆向,全栈方向,专注基础和实战分享,欢迎咨询! 您的点…...

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

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

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

【windows|004】BIOS 介绍及不同品牌电脑和服务器进入BIOS设置的方法
🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专家博主 💊交流社…...

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方法之后,Reduce方法之前的数据处理过程称。 二、图解说明 1、数据流向 map方法中context.write(outK, outV);开始,写入环形缓冲区,再进行分区排序,写到磁盘 reduce方法拉取磁盘上的数据,…...

从设计到实践:高速公路监控技术架构全剖析
随着高速公路网络的迅速扩展和交通流量的日益增加,高效的监控系统成为保障交通安全、提升管理效率的重要手段。本文将深入探讨高速公路监控技术架构,从设计理念到实际应用,全面解析这一关键技术的各个环节。 ### 一、系统设计理念 #### 1. 高…...
Go Context
Context 介绍 Context 代表了协程的上下文,用以在父子协程之间传递控制信号,共享变量等操作// context.Context 接口 type Context interface {// 当Context自动取消或者到了取消时间被取消后返回Deadline() (deadline time.Time, ok bool)// 当Contex…...

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

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

nginx+tomcat负载均衡、动静分离群集【☆☆☆☆☆】
Nginx是一款非常优秀的HTTP服务器软件,性能比tomcat更优秀,它支持高达50 000个并发连接数,拥有强大的静态资源处理能力,运行稳定,内存、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…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...