【Harmony】常用工具类封装
文章目录
- 一,简介
- 二,网络请求工具类
- 2.1、鸿蒙原生http封装
- 2.2、第三方axios封装(需提前下载依赖)
- 三、录音笔相关工具类
- 3.1、录音封装(录入)
- 3.2、录音封装(放音/渲染)
- 3.3、文件写入封装(针对录音/放音功能)
- 四、RDB关系型数据库
- 4.1、relationalStore简答的CRUD封装
- 4.2、relationalStore单例模式封装(待更新)
- 五、首选项
- 5.1、preferences简单封装
- 5.2、preferences单例模式封装
- 六、权限管理
- 6.1、权限管理封装
- 七、其他工具类
- 7.1、生成一个指定连续数值的数组
- 7.2、生成随机颜色(RGB)
- 7.3、生成随机颜色(16进制)
- 7.4、格式化日期
一,简介
本文工具类更新至2025年4月22日,后续有新内容也会持续更新。并且本文工具类为本人在学习过程中自己总结和封装,可能有不足的地方,欢迎大佬指正。
二,网络请求工具类
2.1、鸿蒙原生http封装
//【鸿蒙http】
// -http只提供底层核心代码功能,没有任何功能的封装,需要自己开发。
// -适配应用,采用泛型进行封装
import { http } from "@kit.NetworkKit";
import { BASE_URL, TOKEN_KEY } from "../constants";
import { promptAction, router } from "@kit.ArkUI";
import { UserSettingClass } from ".";
import { ResponseData } from "../models";//【网络请求过程】
// 当前模块私有方法,不导出,提供正式对外开放的功能使用
// 其中包括:请求拦截处理,头部处理,过程处理,响应结果处理
// -url:请求的路径:必填项
// -data:请求的参数对象:什么都可以,用object,可选的
// -method:请求方式,可选,默认是GET请求
async function requestHttp<T> (url: string,data?: object,method:http.RequestMethod = http.RequestMethod.GET
): Promise<T> {//创建请求对象const httpRequest = http.createHttp()//设置请求参数对象const options: http.HttpRequestOptions = {method,readTimeout: 10000,header: {//与后台匹配,提交的是json对象'Content-Type': 'application/json',//用户登录后,应用级数据对象获取用户令牌,拿不到就是空的'Authorization': AppStorage.get<string>(TOKEN_KEY) || ''},//设置除get请求之外的请求参数(因为get请求提交的数据是组合在地址中的)extraData: method === http.RequestMethod.GET ? '' : data}//组合正式请求的完整网址let urlStr = BASE_URL + url//处理get请求情况if(method === http.RequestMethod.GET){//需要将请求对象中的属性提取出来,组合到请求地址中//判断:是否提交了请求数据对象if(data){//调用Object的方法,自动获取对象中所有的属性名,返回字符串数组const allKeys:string[] = Object.keys(data)//是否有请求的参数属性if(allKeys){//创建一个数组,字符串的,里面是请求内容[key=value]const arr:string[] = []//循环key的数组for(let key of allKeys){//在数据中,按照key获取值,然后组合成要的格式,加入数组arr.push(`${key}=${data[key]}`)}//组合到请求地址中:按照指定字符将数组所有元素组合成一个字符串urlStr += '?' + arr.join('&')}}}//正式发送请求// -异常需要处理:这个数据代码错误了// -http请求操作是一次性的(鸿蒙固定的),用完了要销毁的// -需要对应好resolve和reject// 错误情况有多种,err是错误,服务器正常返回也有错误的// -采用Promise特性,async自动封装了Promise,内部可以直接对应resolve和rejecttry{//发起请求,获取响应结果const res = await httpRequest.request(urlStr, options)//解析响应结果:if(res.responseCode === 401){//服务器验证用户身份Authorization失败promptAction.showToast({message: '未授权或令牌失效!'})//清空本地令牌AppStorage.setOrCreate(TOKEN_KEY, '')new UserSettingClass(getContext()).setUserToken('')//跳转登录router.replaceUrl({ url: 'pages/Login/Login' })//返回错误return Promise.reject(new Error('未授权或令牌失效!'))}else if(res.responseCode === 404){//访问的地址已失效promptAction.showToast({message: '请求的地址无效!'})return Promise.reject(new Error('请求的地址无效!'))}else if(res.responseCode === 200){//正确响应,提取响应结果// -先将响应结果统一类型string// -然后转成json对象,它是object// -然后对应好类型约束:ResponseData:参考所有接口返回的统一格式const result = JSON.parse(res.result as string) as ResponseData<T>//校验结果:回发的数据中的编码if(result.code === 200){//返回结果:适配泛型,默认返回自动对应resolve,不用写了return result.data as T}else{//请求对的,也响应了,但是代码中说失败//请找后端开发人员了解具体情况:需要告知:请求方式、头部、参数promptAction.showToast({message: '请求失败!'})return Promise.reject(new Error('请求失败!'))}}else{return Promise.reject(new Error('服务器接口调用失败!'))}}catch(err){//错误return Promise.reject(new Error(JSON.stringify(err)))}finally {//对和错都执行:销毁请求对象httpRequest.destroy()}
}//【http接口请求工具类】
// -对外提供RestFul请求风格的四类请求:GET/POST/PUT/DELETE
// -采用静态方法,提供应用直接使用
export class Request {//方法格式统一,用方法名描述请求方式//参数只要路径和请求数据对象//响应结果是Promise<泛型>,你要什么返回什么static get<T>(url:string, data?:object):Promise<T> {return requestHttp<T>(url, data, http.RequestMethod.GET)}static post<T>(url:string, data?:object):Promise<T> {return requestHttp<T>(url, data, http.RequestMethod.POST)}static put<T>(url:string, data?:object):Promise<T> {return requestHttp<T>(url, data, http.RequestMethod.PUT)}static delete<T>(url:string, data?:object):Promise<T> {return requestHttp<T>(url, data, http.RequestMethod.DELETE)}
}
2.2、第三方axios封装(需提前下载依赖)
如果没有axios依赖,须在项目目录下,命令行执行如下命令
ohpm install @ohos/axios
出现绿色completed证明安装成功



//【第三方axios】
import axios,{InternalAxiosRequestConfig,AxiosError,AxiosResponse,AxiosRequestConfig,AxiosInstance} from "@ohos/axios"
import { UserSettingClass } from "."
import { BASE_URL, TOKEN_KEY } from "../constants"
import { router } from "@kit.ArkUI"const instance = axios.create({baseURL:BASE_URL,//自动组合到请求路径readTimeout:10000
})//请求拦截配置,发起请求时,先执行这里追加令牌
instance.interceptors.request.use((config:InternalAxiosRequestConfig)=>{//config就是配置,我们在头部追加用户令牌config.headers.Authorization = AppStorage.get(TOKEN_KEY) || ""return config},(err:AxiosError)=>{return Promise.reject(err)
})//响应拦截,接收到响应结果后,执行这里的操作
instance.interceptors.response.use((response:AxiosResponse)=>{//data:{code,meg,data}//判断结果:if(response.data && response.data.code ===200){return response.data.data}//TODO:如果response.data.code ===401等自行处理//默认返回响应,调用者处理return response
},(err:AxiosError)=>{//是否是401,身份验证不通过if(err.response?.status===401){//说明令牌无效AppStorage.setOrCreate(TOKEN_KEY,"")//删除应用中的token记录new UserSettingClass(getContext()).setUserToken("")//删除首选项中的token//跳转登录router.replaceUrl({ url: 'pages/Login/Login' })}return Promise.reject(err)
})//提供执行操作对象,适配泛型
//R是返回类型,D是请求类型
//支持调用时,自定义配置
function request<R=null,D=null>(config:AxiosRequestConfig){//返回操作实例return instance<null,R,D>(config)
}export class RequestAxios{static get<T>(url:string, data?:object):Promise<T> {return request<T,null>({url,params:data,method:"GET"})}static post<T>(url:string, data?:object):Promise<T> {return request<T,object>({url,data,method:"POST"})}static put<T>(url:string, data?:object):Promise<T> {return request<T,object>({url,data,method:"PUT"})}static delete<T>(url:string, data?:object):Promise<T> {return request<T,object>({url,data,method:"DELETE"})}
}
三、录音笔相关工具类
3.1、录音封装(录入)
//音频工具
//官方称之为录音笔
//需要集成audio和fileIo
import { audio } from "@kit.AudioKit";
import { fileIo } from "@kit.CoreFileKit";
import { emitter } from "@kit.BasicServicesKit";export class AudioCapturer{//录音笔对象static audioCapture:audio.AudioCapturer//音频流配置static audioStreamInfo:audio.AudioStreamInfo = {samplingRate:audio.AudioSamplingRate.SAMPLE_RATE_16000,//音频的采样率:帧数sampleFormat:audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,//音频文件的转码格式--音频播放解析encodingType:audio.AudioEncodingType.ENCODING_TYPE_RAW,//文件编码格式--读写文件channels:audio.AudioChannel.CHANNEL_1 //等级} as audio.AudioStreamInfo//录音笔配置static audioCapturerInfo:audio.AudioCapturerInfo = {source:audio.SourceType.SOURCE_TYPE_MIC,//资源的来源:麦克风capturerFlags:0//功能启动标识}//控制变量:是否进行录制static recordIng:boolean =false//初始化static async init(){//创建录音笔实例AudioCapturer.audioCapture = await audio.createAudioCapturer({streamInfo:AudioCapturer.audioStreamInfo,capturerInfo:AudioCapturer.audioCapturerInfo})}//开始录制static async start(filePath:string){try {//打开目标文件,得到文件对象,只写,读不在这块const file=fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE|fileIo.OpenMode.CREATE)//文件大小:字节const fd = file.fdlet bufferSize = fileIo.statSync(fd).size//开始采集,状态转换AudioCapturer.recordIng = true//开启录音笔能力await AudioCapturer.audioCapture.start()//采集音频:循环执行,由状态变量AudioCapturer.recordIng决定是否录制while (AudioCapturer.recordIng){//获取采集音频已经录下的在缓冲区内容的大小,他是一段一段读的const size = AudioCapturer.audioCapture.getBufferSizeSync()//从缓冲区中读取一段const buffer = await AudioCapturer.audioCapture.read(size,true)//如果可以读到if(buffer){//追加写入fileIo.writeSync(fd,buffer,{offset:bufferSize,length:buffer.byteLength})//通知页面emitter.emit("caleVoice",{data:{buffer}})//下一段bufferSize+=buffer.byteLength}}}catch (err) {console.log(JSON.stringify(err));AlertDialog.show({message:"当前设备不支持录音"})}}//结束录制static async stop(){//只有在录制才可以结束根据状态变量判断if(AudioCapturer.recordIng && AudioCapturer.audioCapture){//结束音频录制AudioCapturer.recordIng = false//关闭录音功能await AudioCapturer.audioCapture.stop()}}//释放资源static async close(){//只要对象存在都可以执行if(AudioCapturer.audioCapture){//释放缓冲区await AudioCapturer.audioCapture.release()}}}
3.2、录音封装(放音/渲染)
//音频渲染/播放工具
//主要集中于本地文件,先下载
import { audio } from "@kit.AudioKit";
import { fileIo } from "@kit.CoreFileKit";export class AudioRender {//播放器对象static audioRenderer:audio.AudioRenderer//音频流的配置static audioStreamInfo:audio.AudioStreamInfo = {samplingRate:audio.AudioSamplingRate.SAMPLE_RATE_16000,sampleFormat:audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,channels:audio.AudioChannel.CHANNEL_1,encodingType:audio.AudioEncodingType.ENCODING_TYPE_RAW} as audio.AudioStreamInfo//渲染器的配置static audioRenderInfo:audio.AudioRendererInfo = {rendererFlags:0,//标记usage:audio.StreamUsage.STREAM_USAGE_VOICE_ASSISTANT //语音助手的} as audio.AudioRendererInfo//渲染器的配置对象,将上面两个配置合在一起static audioRenderOptions:audio.AudioRendererOptions = {streamInfo:AudioRender.audioStreamInfo,rendererInfo:AudioRender.audioRenderInfo}//文件static renderFile:fileIo.File//文件大小static maxSize:number = 0//已经播放的字节数static renderSize:number = 0//播放完的回调static callBack=()=>{}//初始化static async init(){//创建渲染器实例AudioRender.audioRenderer = await audio.createAudioRenderer(AudioRender.audioRenderOptions)//注册(监听)数据写入事件操作AudioRender.audioRenderer.on("writeData",//当有数据写入时(buffer:ArrayBuffer)=>{//是否有文件if(AudioRender.renderFile){//有,从文件中读取,文件大小必须保持一致fileIo.readSync(AudioRender.renderFile.fd,buffer,{offset:AudioRender.renderSize,length:buffer.byteLength})//更新字节数AudioRender.renderSize += buffer.byteLength}//前面的内容是否播放完毕if(AudioRender.renderSize>=AudioRender.maxSize){//关闭文件fileIo.closeSync(AudioRender.renderFile.fd)//停止播放//TODO:AudioRender.stop()}})}//播放static async start(filePath:string,callBack1?:()=>void,callBack2?:()=>void){//播放之前,停止之前播放,确保同时只播放一个await AudioRender.stop()//打开需要播放的文件AudioRender.renderFile= fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE)//获取文件大小AudioRender.maxSize= fileIo.statSync(AudioRender.renderFile.fd).size//文件有内容时if(AudioRender.maxSize>0){//如果有回调1:作为当前播放之前的方法调用callBack1 && callBack1()//如果有回调2:作为当前停止之后的方法调用,通过引用传递if(callBack2){AudioRender.callBack = callBack2}//正式播放AudioRender.audioRenderer.start()}else {AlertDialog.show({message:`文件为空`})}}//停止static async stop(){//必须播放状态下才可以停止if(AudioRender.audioRenderer && AudioRender.audioRenderer.state=== audio.AudioState.STATE_RUNNING){//停止await AudioRender.audioRenderer.stop()//重置信息AudioRender.maxSize = 0AudioRender.renderSize = 0//调用回调,告知外部AudioRender.callBack && AudioRender.callBack()}}}
3.3、文件写入封装(针对录音/放音功能)
//文件处理工具
//用于处理物理文件,针对files/目录
//针对录音功能,音频文件后缀.wav
import {fileIo} from "@kit.CoreFileKit"export class FileOperate{//创建空文件,返回路径static createAudioFile(userId:string){//判断有没有路径,没有就创建const dirPath = getContext().filesDir+"/"+userIdif(!fileIo.accessSync(dirPath)){fileIo.mkdirSync(dirPath)}//文件不能重名,利用时间戳作为文件名const filePath = dirPath+"/"+Date.now()+".wav"//打开并创建文件const file = fileIo.openSync(filePath,fileIo.OpenMode.CREATE)//关闭文件,防止挂起fileIo.closeSync(file)return filePath}//删除指定文件static deleteFile(path:string){fileIo.unlinkSync(path)}//删除整个个人目录static deleteUser(userId:string){const dirPath = getContext().filesDir+"/"+userIdif(fileIo.accessSync(dirPath)){fileIo.rmdirSync(dirPath)}}}
四、RDB关系型数据库
4.1、relationalStore简答的CRUD封装
补充:
1.这个工具类关闭数据库那里有点问题,我加了延时器关闭。因为store.close()是异步操作,如果不加,查询操作可能会出现数据库连接关闭了,返回的结果为空这种情况。所以手动延迟2秒关闭,造成这种情况原因还没完全搞明白,后续搞懂了再更新。
2.resultSet结果集需要在调用处自行关闭释放。
import { relationalStore } from "@kit.ArkData"export class DBHelper{//TODO:这里数据库名需要替换为自己的,注意不要忘了.db后缀private DB_NAME:string = "Test.db"//TODO:这里数据库安全等级需要替换为自己的private DB_SECURITY_LEVEL = relationalStore.SecurityLevel.S1private store:relationalStore.RdbStore = {} as relationalStore.RdbStoreprivate config:relationalStore.StoreConfig = {name:this.DB_NAME,securityLevel:this.DB_SECURITY_LEVEL}//创建链接,需要传入上下文对象private async createDB(context:Context){try {this.store = await relationalStore.getRdbStore(context,this.config)}catch (e){console.log("createDB执行异常",e);}}//增删改操作,由调用处决定上下文对象async execDML(context:Context,sql:string,params?:Array<relationalStore.ValueType>){try {await this.createDB(context)await this.store.executeSql(sql,params)} catch (e) {console.log("execDML执行异常",e)} finally {if(this.store){setTimeout(async ()=>{await this.store.close()},2000)}}}//查询操作,由调用处决定上下文对象async execDQL(context:Context,sql:string,params?:Array<relationalStore.ValueType>){try {await this.createDB(context)let res = await this.store.querySql(sql,params)return res}catch (e){console.log("execDQL执行异常",e);return {} as relationalStore.ResultSet} finally {if(this.store){setTimeout(async ()=>{await this.store.close()},2000)}}}
}
4.2、relationalStore单例模式封装(待更新)
五、首选项
5.1、preferences简单封装
import { preferences } from "@kit.ArkData"export class UserSettingClass{private context:Contextconstructor(context:Context) {this.context=context}//获取首选项仓库private getStore():Promise<preferences.Preferences>{//TODO:这里USER_SETTING需要替换为你的首选项文件存储时的名字return preferences.getPreferences(this.context,USER_SETTING)}//TODO:通过getStore()获取首选项仓库,然后定义对应方法//TODO:以下是两个案例:1.广告数据的存取,用户令牌的存取// //广告的数据存取// async setUserAd(ad:AdvertClass):Promise<void>{// const store = await this.getStore()// await store.put(USER_SETTING_AD,JSON.stringify(ad))// await store.flush()// }//// async getUserAd():Promise<AdvertClass>{// const store = await this.getStore()// const result = await store.get(USER_SETTING_AD,JSON.stringify(defaultAd))// return JSON.parse(result as string) as AdvertClass// }//// //用户的令牌存取// async setUserToken(token:string):Promise<void>{// const store = await this.getStore()// await store.put(TOKEN_KEY,token)// await store.flush()// }//// async getUserToken():Promise<string>{// const store = await this.getStore()// const result = await store.get(TOKEN_KEY,"")// return result as string// }}
5.2、preferences单例模式封装
//首选项功能类
import { preferences } from "@kit.ArkData"
import { MessageInfoModel } from "../models/message"
import { emitter } from "@kit.BasicServicesKit"
import { DefaultUserList } from "../models/users"export class StoreClass{static context:Context //上下文static KEY:string = "Ding" //标识//初始化方法,固定好上下文对象,全局都用这一个//TODO:这里推荐在entryAbility中进行初始化,固定上下文static init(context:Context){StoreClass.context = context}//每一个聊天用户一个文件,而不是所有人都存在一个地方//通过用户id获取指定用户的首选项仓库//TODO:核心就是这个方法,如果不想所有东西保存在一个位置,那么就用参数+key(随便什么字符串)拼接private static getUserStoreById(userId:string):preferences.Preferences{return preferences.getPreferencesSync(StoreClass.context,{name:`${StoreClass.KEY}_${userId}`})}//TODO:下面的方法是一些案例,可以参考。不需要就删掉自行定义相关方法// //给指定用户添加一条消息// static async addChatMessage(userId:string,message:MessageInfoModel){// //获取用户仓库// const store = StoreClass.getUserStoreById(userId)// //添加(按照消息id,转字符串)// store.putSync(message.id,JSON.stringify(message))// //更新// store.flushSync()// //【发布通知,告知消息放好了】给对方说有新内容,你可以读了,不然对方不知道有新的消息需要更新// //利用线程通讯,告知应用,消息发送好了// emitter.emit(StoreClass.KEY)//// }//// //删除指定用户的消息// static async removeChatMessage(userId:string,messageId:string){// //获取用户仓库// const store = StoreClass.getUserStoreById(userId)// //删除// store.deleteSync(messageId)// //更新// store.flushSync()// //【发布通知】// emitter.emit(StoreClass.KEY)// }//// //删除指定用户的所有信息// static async removeChatAllMessage(userId:string){// //删除用户仓库// preferences.deletePreferences(StoreClass.context,{name:`${StoreClass.KEY}_${userId}`})// //【发布通知】// emitter.emit(StoreClass.KEY)// }//// //获取指定用户的所有信息// static getChatAllMessage(userId:string):MessageInfoModel[]{// //获取用户仓库// const store = StoreClass.getUserStoreById(userId)// //获取所有// const all = store.getAllSync() as object// //有吗?// if(all){// //系统方法,通过字符串内容实现数据集合// const list: MessageInfoModel[] = Object.values(all).map((item:string)=>{// return JSON.parse(item) as MessageInfoModel// })// //按照时间进行数据排序// list.sort((a,b)=>{return a.sendTime-b.sendTime})// return list// }else {// return []// }//// }//// //获取所有用户最后一条消息【不需要参数】// //针对接收到新消息,只要有发布,我就获取所有// static async getAllChatLastMessage(){// const lastList:MessageInfoModel[] = []// //从默认用户列表,提取所有用户信息// DefaultUserList.forEach((user)=>{// //按照用户id提取他所有的消息// const chatList = StoreClass.getChatAllMessage(user.user_id)// //是否存在// if(chatList.length>0){// //最后一个消息,放入数组// lastList.push(chatList[chatList.length-1])// }// //按照时间进行数据排序// lastList.sort((a,b)=>{return a.sendTime-b.sendTime})// })// return lastList// }}
六、权限管理
6.1、权限管理封装
此工具类包含:检查权限\拉起权限弹窗\跳转系统权限设置
//之前需要授权管理,每次都要重新写代码
//所以我们先封装一个工具,后续可以一直使用
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';class PermissionManager{/*** 检查有没有指定的权限* @param permissions 指定的权限的列表*/checkPermissions(permissions:Permissions[]){//权限管理器let manager = abilityAccessCtrl.createAtManager();//获取应用信息(通过系统方法获取)let appInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)//获取应用唯一标识let tokenId = appInfo.appInfo.accessTokenId//校验这个token是否拥有权限let authResults = permissions.map((permission:Permissions)=>{return manager.checkAccessTokenSync(tokenId,permission)})//返回是否拥有权限return authResults.every((authResult:abilityAccessCtrl.GrantStatus)=>{return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED})}/*** 动态弹窗申请权限* @param permissions* @returns*/async requestPermissions(permissions:Permissions[]):Promise<boolean>{let mangager = abilityAccessCtrl.createAtManager();let res = await mangager.requestPermissionsFromUser(getContext(),permissions)//选择结果let isAuth = res.authResults.every((authResult:abilityAccessCtrl.GrantStatus)=>{return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED})return isAuth}//如果出问题需要打开系统设置手动给权限//打开系统设置:权限管理页面openPermissionSettingPage() {//获取UIAbility上下文对象const context = getContext() as common.UIAbilityContext//应用信息(通过系统方法设置为当前本地应用对象)const appInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)//打开系统设置窗口,进行配置context.startAbility({bundleName: 'com.huawei.hmos.settings',abilityName: 'com.huawei.hmos.settings.MainAbility',uri: 'application_info_entry',parameters: {pushParams: appInfo.name}})}
}export let permissionManager = new PermissionManager()
七、其他工具类
7.1、生成一个指定连续数值的数组
/*生成一个指定连续数值的数组* startNum:number 开始参数* endNum:number 结束参数* step:number=1 步长参数(默认为1)* */
export function range(startNum:number,endNum:number,step:number=1){let arr:number[]=[];for(let i=startNum;i<=endNum;i+=step){arr.push(i)}return arr;
}
7.2、生成随机颜色(RGB)
export function getRandColorRGB(){const red = Math.floor(Math.random()*256) //0~255的随机数const green = Math.floor(Math.random()*256) //0~255的随机数const blue = Math.floor(Math.random()*256) //0~255的随机数return `rgb(${red},${green},${blue})`
}
7.3、生成随机颜色(16进制)
export function getRandColorHEX(){const result = Math.floor(Math.random()*16777216).toString(16) //16777216=256*256*256return "#"+result
}
7.4、格式化日期
export function formatDate(date:Date):string{let year= date.getFullYear()let month= date.getMonth()+1let day= date.getDate()let hour= date.getHours()let minter= date.getMinutes()let seconds= date.getSeconds()let monthStr = month<10?"0"+month:month.toString()let dayStr = day<10?"0"+day:day.toString()let hourStr = hour<10?"0"+hour:hour.toString()let minterStr = minter<10?"0"+minter:minter.toString()let secondsStr = seconds<10?"0"+seconds:seconds.toString()return `${year}-${monthStr}-${dayStr} ${hourStr}:${minterStr}:${secondsStr}`}
相关文章:
【Harmony】常用工具类封装
文章目录 一,简介二,网络请求工具类2.1、鸿蒙原生http封装2.2、第三方axios封装(需提前下载依赖) 三、录音笔相关工具类3.1、录音封装(录入)3.2、录音封装(放音/渲染)3.3、文件写入封装(针对录音/放音功能) 四、RDB关系型数据库4.1、relationalStore简答…...
DCDC芯片,boost升压电路设计,MT3608 芯片深度解析:从架构到设计的全维度技术手册
一、硬件架构解析:电流模式升压 converter 的核心设计 (一)电路拓扑与核心组件 MT3608 采用恒定频率峰值电流模式升压(Boost)转换器架构,核心由以下模块构成: 集成功率 MOSFET 内置 80mΩ 导通电阻的 N 沟道 MOSFET,漏极(Drain)对应引脚 SW,源极(Source)内部接…...
Cline 之Plan和Act模式
Cline 提供了 "Plan & Act"双模式开发框架。适用在不同的场景。 一、核心模式理念 通过结构化开发流程提升AI编程效率,采用"先规划后执行"的核心理念。 该框架旨在帮助开发者构建更易维护、准确性更高的代码,同时显著缩短开发…...
深入了解 WebGIS 系统:构建地理空间信息的网络桥梁
一、引言 在当今数字化时代,地理空间信息的获取、分析和共享变得越来越重要。WebGIS(网络地理信息系统,Web - based Geographic Information System)应运而生,它将地理信息系统(GIS)的强大功能…...
【中级软件设计师】程序设计语言基础成分
【中级软件设计师】程序设计语言基础成分 目录 【中级软件设计师】程序设计语言基础成分一、历年真题二、考点:程序设计语言基础成分1、基本成分2、数据成分3、控制成分 三、真题的答案与解析答案解析 复习技巧: 若已掌握【程序设计语言基础成分】相关知…...
C++项目 —— 基于多设计模式下的同步异步日志系统(3)(日志器类)
C项目 —— 基于多设计模式下的同步&异步日志系统(3)(日志器类) 整体思想设计日志消息的构造C语言式的不定参函数的作用函数的具体实现逻辑1. 日志等级检查2. 初始化可变参数列表3. 格式化日志消息4. 释放参数列表5. 序列化和…...
【数学建模】随机森林算法详解:原理、优缺点及应用
随机森林算法详解:原理、优缺点及应用 文章目录 随机森林算法详解:原理、优缺点及应用引言随机森林的基本原理随机森林算法步骤随机森林的优点随机森林的缺点随机森林的应用场景Python实现示例超参数调优结论参考文献 引言 随机森林是机器学习领域中一种…...
蓝桥杯 19.合根植物
合根植物 原题目链接 题目描述 W 星球的一个种植园被分成 m n 个小格子(东西方向 m 行,南北方向 n 列)。每个格子里种了一株合根植物。 这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的…...
Linux环境MySQL出现无法启动的问题解决 [InnoDB] InnoDB initialization has started.
目录 起因 强制启用恢复模式 备份数据 起因 服务器重启了,然后服务器启动完成之后我发现MySQL程序没有启动,错误信息如下: 2025-04-19T12:46:47.648559Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started. 2025-04-1…...
高性能服务器配置经验指南1——刚配置好服务器应该做哪些事
文章目录 安装ubuntu安装必要软件设置用户远程连接安全问题ClamAV安装教程步骤 1:更新系统软件源步骤 2:升级系统(可选但推荐)步骤 3:安装 ClamAV步骤 4:更新病毒库步骤 5:验证安装ClamAV 常用命…...
DePIN驱动的分布式AI资源网络
GAEA通过通证经济模型激励全球用户共享闲置带宽、算力、存储资源,构建覆盖150多个国家/地区的分布式AI基础设施网络。相比传统云服务,GAEA具有显著优势: 成本降低70%:通过利用边缘设备资源,避免了集中式数据中心所需…...
徐州服务器租用:虚拟主机的应用场景
虚拟主机也可以被称为网站空间或者是共享主机,主要是通过软硬件技术将一台物理服务器分割成多个逻辑单元的技术,让每一个单元都拥有着独立的IP地址和完整的网络服务功能,那么虚拟主机的应用场景都有哪些呢? 许多中小型企业会选择租…...
Centos7安装Jenkins(图文教程)
本章教程,主要记录在centos7安装部署Jenkins 的详细过程。 [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) 一、基础环境安装 内存大小要求:256 MB 内存以上 硬盘大小要求:10 GB 及以上 安装基础java环境:Java 17 ( JRE 或者 JDK 都可…...
【JAVA】十三、基础知识“接口”精细讲解!(二)(新手友好版~)
哈喽大家好呀qvq,这里是乎里陈,接口这一知识点博主分为三篇博客为大家进行讲解,今天为大家讲解第二篇java中实现多个接口,接口间的继承,抽象类和接口的区别知识点,更适合新手宝宝们阅读~更多内容持续更新中…...
边缘计算盒子是什么?
边缘计算盒子是一种小型的硬件设备,通常集成了处理器、存储器和网络接口等关键组件,具备一定的计算能力和存储资源,并能够连接到网络。它与传统的云计算不同,数据处理和分析直接在设备本地完成,而不是上传到云端&#…...
量子计算在密码学中的应用与挑战:重塑信息安全的未来
在当今数字化时代,信息安全已成为全球关注的焦点。随着量子计算技术的飞速发展,密码学领域正面临着前所未有的机遇与挑战。量子计算的强大计算能力为密码学带来了新的应用场景,同时也对传统密码体系构成了潜在威胁。本文将深入探讨量子计算在…...
大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署--完结
大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署 1. ClickHouse与MySQL的区别2. 在群集的所有机器上安装ClickHouse服务端2.1. 在线安装clickhouse2.2. 离线安装clickhouse 3. ClickHouse Keeper/Zookeeper集群安装4. 在配置文件中设置集群配置5. 在每…...
【C++游戏引擎开发】第20篇:基于物理渲染(PBR)——辐射度量学
引言 在基于物理渲染(PBR)中,辐射度量学是描述光与物质交互的核心数学框架。本文将深入解析辐射度量学的四大基础量,双向反射分布函数(BRDF)的物理本质,以及如何通过积分形式推导出渲染方程。最后,通过OpenGL实践,直观展示辐射率(Radiance)在三维场景中的分布规律。…...
19Linux自带按键驱动程序的使用_csdn
1、自带按键驱动程序源码简析 2、自带按键驱动程序的使用 设备节点信息: gpio-keys {compatible "gpio-keys";pinctrl-names "default";pinctrl-0 <&key_pins_a>;autorepeat;key0 {label "GPIO Key L";linux,code &l…...
用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置
原文链接:用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置 Hello,大家好啊!今天给大家带来一篇在银河麒麟操作系统的 LiveCD 或系统试用镜像环境下,如何查看原系统中电脑的 IP 地址与网络打印机 IP 地址的实用教程。在系统损坏…...
.net core 项目快速接入Coze智能体-开箱即用-第2节
目录 一、Coze智能体的核心价值 二、开箱即用-效果如下 三 流程与交互设计 本节内容调用自有或第三方的服务 实现语音转文字 四:代码实现----自行实现 STT 【语音转文字】 五:代码实现--调用字节API实现语音转文字 .net core 项目快速接入Coze智能…...
win10中打开python的交互模式
不是输入python3,输入python,不知道和安装python版本有没有关系。做个简单记录,不想记笔记了...
时序逻辑电路——序列检测器
文章目录 一、序列检测二、牛客真题1. 输入序列连续的序列检测(输入连续、重叠、不含无关项、串行输入)写法一:移位寄存器写法二:Moore状态机写法三:Mealy状态机 一、序列检测 序列检测器指的就是将一个指定的序列&…...
SVT-AV1编码器中的模块
一 模块列表 1 svt_input_cmd_creator 2 svt_input_buffer_header_creator 3 svt_input_y8b_creator 4 svt_output_buffer_header_creator 5 svt_output_recon_buffer_header_creator 6 svt_aom_resource_coordination_result_creator 7 svt_aom_picture_analysis_result_creat…...
TikTok X-Gnarly纯算分享
TK核心签名校验:X-Bougs 比较简单 X-Gnarly已经替代了_signature参数(不好校验数据) 主要围绕query body ua进行加密验证 伴随着时间戳 浏览器指纹 随机值 特征值 秘钥转换 自写算法 魔改base64编码 与X-bougs 长a-Bougs流程一致。 视频…...
LPDDR5协议新增特性
文章目录 一、BL/n_min参数含义二、RDQS_t/RDQS_c引脚的功能三、DMI引脚的功能3.1、Write操作时的Data Mask数据掩码操作3.2、Write/Read操作时的Data Bus Inversion操作四、CAS命令针对WR/RD/Mask WR命令的低功耗组合配置4.1、Write/Read操作前的WCK2CK同步操作4.2、Write/Rea…...
python数据分析(二):Python Pandas索引技术详解
Python Pandas索引技术详解:从基础到多层索引 1. 引言 Pandas是Python数据分析的核心库,而索引技术是Pandas高效数据操作的关键。良好的索引使用可以显著提高数据查询和操作的效率。本文将系统介绍Pandas中的各种索引技术,包括基础索引、位…...
【深度学习】#8 循环神经网络
主要参考学习资料: 《动手学深度学习》阿斯顿张 等 著 【动手学深度学习 PyTorch版】哔哩哔哩跟李牧学AI 为了进一步提高长线学习的效率,该系列从本章开始将舍弃原始教材的代码部分,专注于理论和思维的提炼,系列名也改为“深度学习…...
开源状态机引擎,在实战中可以放心使用
### Squirrel-Foundation 状态机开源项目介绍 **Squirrel-Foundation** 是一个轻量级、灵活、可扩展、易于使用且类型安全的 Java 状态机实现,适用于企业级应用。它提供了多种方式来定义状态机,包括注解声明和 Fluent API,并且支持状态转换、…...
机器学习超参数优化全解析
机器学习超参数优化全解析 摘要 本文全面深入地剖析了机器学习模型中的超参数优化策略,涵盖了从参数与超参数的本质区别,到核心超参数(如学习率、批量大小、训练周期)的动态调整方法;从自动化超参数优化技术…...
