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;

  // 获取应用程序的accessTokenID
  let 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: number
  message: 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;

  // 获取应用程序的accessTokenID
  let 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: number
  message: 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; //UIAbilityContext
  private 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) return
        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);
          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": "上传头像"
    }
  ]
}

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

践行国产化替代,优刻得私有云勇当先锋

编辑&#xff1a;阿冒 设计&#xff1a;沐由 阳泉&#xff0c;十万火急&#xff01; 位于太行山西麓的山西省阳泉市&#xff0c;是一座历史悠久、底蕴深厚、资源丰富的名城&#xff0c;拥有超百万常住人口&#xff0c;国内生产总值在2022年成功跨越千亿元大关。然而&#xff0c…

IDEA上MySQL的jar包导入教程

jar包下载网址——》https://mvnrepository.com/ 1.进入界面&#xff0c;点击搜索框&#xff0c;搜索mysql&#xff1a; 外国网站&#xff0c;可能有点慢,耐心等待即可。 2.点击查询结果&#xff1a; 进入界面&#xff0c;点击前两个结果的其中一个&#xff0c;两个都可以 …

tp6+swoole+mysql+nginx+redis高并发优化

1.服务器 IDC机房提供的物理机&#xff1a;单机 40核&#xff0c;64G内存&#xff0c;带宽100M&#xff0c;最后带宽增加至300M 2.redis 7.2配置 timeout600 #空闲连接超时时间,0表示不断开 maxclients100000 #最大连接数 3.Mysql 5.7配置&#xff0c;按宝塔16-32G优化方案…

经验分享,如何去除文本中的空格

有时候我们需要去掉一窜文本中的空格&#xff0c;这里分享一个好用的免费网站&#xff0c;可实现在线去除 网址&#xff1a;http://www.txttool.com/t/?idMzM4 使用截图&#xff1a;

Vue53-Todo-list案例

一、需求&#xff1a; 二、组件的划分&#xff1a;按照功能划分 组件起名&#xff0c;不要和html内置元素重名&#xff01; Vue鼓励组件名用多个单词。 三、组件化编码流程 3-1、实现静态组件 将各个组件的基本框架写好&#xff0c;并在App.vue文件中进行引入和注册。 将已有…

sslh一键在一个端口上运行多个服务(KALI工具系列二十三)

目录 1、KALI LINUX 简介 2、sslh工具简介 3、信息收集 3.1 目标主机IP&#xff08;win&#xff09; 3.2 KALI的IP 4、操作示例 4.1 监听特定端口 4.2 配置SSH 4.3 配置apache 4.4 配置sshl 4.5 验证配置 5、总结 1、KALI LINUX 简介 Kali Linux 是一个功能强大、…

.net 调用海康SDK的常用操作封装

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

滚动轴承数字孪生模拟信号(Python)

以SKF6312轴承型号为例 class SKF6312:def __init__(self, Fs, f_n, B, m50.0, g9.8, e50 * 1e-06, rho1e-3):# element parametersBearingParameter {d: 22.2, Dm: 96.987, alpha: 0, z: 8}self.d BearingParameter[d] # ball diameterself.Dm BearingParameter[Dm] # p…

第二篇: 掌握Docker的艺术:深入理解镜像、容器和仓库

掌握Docker的艺术&#xff1a;深入理解镜像、容器和仓库 1. 引言 1.1 简要介绍Docker的重要性 在当今快速发展的技术世界中&#xff0c;软件开发和部署的效率和可靠性是衡量成功的关键因素。Docker&#xff0c;作为一个开源的容器化平台&#xff0c;革新了软件的打包、分发和…

1970python高校教室管理系统mysql数据库Django框架bootstrap布局计算机软件工程网页

一、源码特点 python Django 高校教室管理系统是一套完善的web设计系统mysql数据库 &#xff0c;对理解python编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 python Django 高校教室管理系统 开发环境pycharm mys…

勾八头歌网安之标准ACL、扩展ACL

标准ACL vs 扩展ACL 我是分享我的快乐的终于写完啦&#xff01;&#xff01;&#xff01;&#xff01;我有时间会把步骤写上来的 也不知有人需要吗哈哈哈 vs

深入了解RSA加密算法

目录 前言 一、什么是RSA&#xff1f; 二、RSA加密的基本概念 1.非对称加密 2.密钥生成 3.加密和解密 三、RSA加密的工作原理 四、RSA的应用场景 五、RSA加密解密的实现 六、RSA算法的局限性及改进措施 前言 在当今的数字化时代&#xff0c;信息的安全性成为了人们关注…

VUE3脚手架工具cli配置搭建及创建VUE工程

1、VUE的脚手架工具(CLI&#xff09; 开发大型vue的时候&#xff0c;不能通过html编写一个大型的项目&#xff0c;这个时候需要用到vue的脚手架工具 通过vue的脚手架&#xff0c;可以快速的生成vue工程 1.1、安装nodejs和npm 【下载nodejs】 https://nodejs.org/en 【安装…

厂里资讯之自媒体文章自动审核

自媒体文章-自动审核 1)自媒体文章自动审核流程 1 自媒体端发布文章后&#xff0c;开始审核文章 2 审核的主要是审核文章的内容&#xff08;文本内容和图片&#xff09; 3 借助第三方提供的接口审核文本 4 借助第三方提供的接口审核图片&#xff0c;由于图片存储到minIO中&…

Caffe、PyTorch、Scikit-learn、Spark MLlib 和 TensorFlowOnSpark 概述

在 AI 框架方面,有几种工具可用于图像分类、视觉和语音等任务。有些很受欢迎,如 PyTorch 和 Caffe,而另一些则更受限制。以下是四种流行的 AI 工具的亮点。 Caffee Caffee是贾扬青在加州大学伯克利分校(UC Berkeley)时开发的深度学习框架。该工具可用于图像分类、语音和…

UniVue更新日志:SuperGrid组件的使用

github仓库 稳定版本仓库&#xff1a;https://github.com/Avalon712/UniVue 开发版本仓库&#xff1a;https://github.com/Avalon712/UniVue-Develop UniVue扩展框架-UniVue源生成器仓库&#xff1a;https://github.com/Avalon712/UniVue-SourceGenerator SuperGrid组件的实现…

docker和docker compose 部署

一. 将微服务运行在docker上&#xff1a; 1.新建一个空文件夹docker-demo&#xff0c;在里面再新建文件夹app&#xff0c;在app目录下新建一个名为Dockerfile的文件。 2.编写Dockerfile文件 3.构建镜像 4.启动镜像 5.可以访问了。 二使用Dockerfile构建微服务镜像 1.将j…

UniVue更新日志:使用ObservableList优化LoopList/LoopGrid组件的使用

github仓库 稳定版本仓库&#xff1a;https://github.com/Avalon712/UniVue 开发版本仓库&#xff1a;https://github.com/Avalon712/UniVue-Develop UniVue扩展框架-UniVue源生成器仓库&#xff1a;https://github.com/Avalon712/UniVue-SourceGenerator 更新说明 如果大家…

C++ | Leetcode C++题解之第160题相交链表

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {if (headA nullptr || headB nullptr) {return nullptr;}ListNode *pA headA, *pB headB;while (pA ! pB) {pA pA nullptr ? headB : p…

Axios进阶

目录 axios实例 axios请求配置 拦截器 请求拦截器 响应拦截器 取消请求 axios不仅仅是简单的用基础请求用法的形式向服务器请求数据&#xff0c;一旦请求的端口与次数变多之后&#xff0c;简单的请求用法会有些许麻烦。所以&#xff0c;axios允许我们进行创建axios实例、ax…