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…...
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的错误,原因是两个仓库不同而导致的,需要在后面加上--allow-unrelated-histories进行允许合并,即可解决问题。 git push origin …...
构建稳定高效的消息传递中间件:消息队列系统的设计与实现
✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 🎈🎈作者主页: 喔的嘛呀🎈🎈 目录 一、引言 二、设计目标 2.1、高可用性 1. 集群搭建 1.1 …...
支持 MKV、MP4、AVI、MPG 等格式视频转码器
一、简介 1、一款开源的视频转码器,适用于 Linux、Mac 和 Windows。它是一个免费的工具,由志愿者们开发,可以将几乎所有格式的视频转换为现代、广泛支持的编码格式。你可以在官网上下载该应用或源代码。该软件支持 MKV、MP4、AVI、MPG 等格式…...
yum
文章目录 本地源配置本地yum源仓库yum常用的操作命令 网络源阿里云当yum 安装源代码软件包需要编译安装,需要安装支持c和c程序语言的编译器,如gcc、gcc-c、make 如果使用rpm方式安装,则需要先安装多个依赖包,这样会很繁琐。可以使…...
【单片机毕业设计选题24016】-基于STM32和阿里云的采空区环境监测系统设计
系统功能: 系统分为主机端和从机端,主机端主动向从机端发送信息和命令,从机端 收到主机端的信息后回复温度,甲烷,一氧化碳,氧气和系统状态等信息。 同时主机端将这些信息上传至阿里云服务器。 主要功能模块原理图: 电源时钟烧…...
Leetcode3179. K 秒后第 N 个元素的值
Every day a Leetcode 题目来源:3179. K 秒后第 N 个元素的值 解法1:模拟 模拟 k 轮,数组保存上一次结果,然后计算当前轮次的结果。 代码: /** lc appleetcode.cn id3179 langcpp** [3179] K 秒后第 N 个元素的值…...
vue3第二阶段的开发文档
1 2.1 案例——学习计划表 2.1.1 准备工作 在开发“学习计划表”案例之前,需要先完成一些准备工作,具体步骤如下。 ① 打开命令提示符,切换到 D:\vue\chapter02 目录,在该目录下执行如下命令,创建 项目。 np…...
杨凌住房和城乡建设局网站/网络推广是什么
logback日志深入使用在之前的博文中,博主已经简单的介绍了logback的配置文件以及简单的使用。下面,博主将介绍一下logback的一些其它用法。格式化输出logback的方法可以支持我们进行格式化输出,我们再也不用手动进行字符串的拼接了。logger.i…...
网站怎么建设?/怎么样建一个网站
想象一下,您想用Python开发一个平凡的最终用户桌面(非Web)应用程序。 构造项目文件夹层次结构的最佳方法是什么?理想的功能是易于维护,IDE友好,适用于源代码控制分支/合并以及易于生成安装软件包。尤其是:您将源放在哪…...
自己做的网站怎么上传网络/抖音推广
今天导入老师上周发的结束项目,发现需要下载最新版本的 tomcat , 然后百度了一下,发现有广告,所以我打算自己操作一下,发个图文教程。 因为之前学校使用的是 eclipse ,版本是8.5的。所以需要重新下载。 说实话&#…...
网站换ip影响 百度/搜外网 seo教程
windbg附加IE后,设置flash模块加载断点 sxe ld Flash32_30_0_0_113.ocx内存访问断点,Flash漏洞利用代码,通过任意地址读写,泄露一个Flash Object 虚表函数地址, 通过计算虚表函数地址,可以定位到Flash模块…...
西安专业建网站/电脑培训学校能学什么
原标题:盘点:简单好用的录音APP有哪些?本文为「智活范」原创作品,欢迎关注我们!前段时间去跟一个采访,因为过程中要录音,遂找人介绍了一款录音APP来用。当时用下来觉得录音体验没问题࿰…...
承德做网站/友情链接英文
1.首先安装好LAMP这一个组合,在安装的过程中重点关注PHP的安装./configure --prefix/usr/local/php5 --enable-mbstring--with-apxs2/usr/local/apache2/bin/apxs--with-mysql/usr/local/mysql--with-config-file-path/usr/local/php5--with-zlibmake ;make install…...