UNIAPP項目記錄

一、通過?vue-cli?創建?uni-app?項目

  • 創建 vue3 項目

    • 創建以 javascript 開發的工程(如命令行創建失敗,請直接訪問?gitee?下載模板)
      npx degit dcloudio/uni-preset-vue#vite my-vue3-project
      
      復制代碼
      npx degit dcloudio/uni-preset-vue#vite-alpha my-vue3-project
      
      復制代碼
    • 創建以 typescript 開發的工程(如命令行創建失敗,請直接訪問?gitee?下載模板)
      npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project

?二、通過命令腳本打wgt文件

官網提示:目前使用npm run build:app-plus會在/dist/build/app-plus下生成app打包資源。如需制作wgt包,將app-plus中的文件壓縮成zip(注意:不要包含app-plus目錄),再重命名為${appid}.wgt,?appidmanifest.json文件中的appid

實際項目中package.json 文件中未找到build:app-plus命令,且發現執行以下倆條命令效果相同,在項目目錄下找到dist/build/app文件夾

"build:app-plus": "uni build -p app-plus"
"build:app": "uni build -p app"

制作wgt包,將dist/build/app中的文件壓縮成zip(注意:不要包含app目錄),再重命名為xxx.wgt

三、通過自定義命令腳本自動打wgt文件

1.在package.json中注冊腳本

"scripts": { "build:wgt": "node wgtScripts.js" }

2. 安裝archiver

yarn add archiver

3.在項目根目錄下增加wgtScripts.js文件

注意manifest.json文件不要有注釋,否則會報錯
// 腳本執行命令  yarn run build:wgt
const { exec } = require("child_process");
const fs = require("fs");
const archiver = require("archiver"); // 用于壓縮文件
const path = require("path");// 獲取項目根目錄路徑
const projectRoot = path.resolve(__dirname);
// 定義要執行的命令,打包 uniapp wgt 資源
const command = "uni build -p app";// 讀取 manifest.json
const getManifestJSON = () => {const manifestPath = path.resolve(__dirname, "src/manifest.json");return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
};// 將資源文件打壓縮包
const compress = (manifest) => {console.log("編譯成功!!!");const outputDirectory = path.resolve(__dirname, "dist/build/app");const wgtFolderPath = path.resolve(__dirname, "dist/wgt");// 創建 wgt 文件夾if (!fs.existsSync(wgtFolderPath)) {fs.mkdirSync(wgtFolderPath);}const outputZip = path.resolve(__dirname,`dist/wgt/${manifest.versionCode}.wgt`);console.log("正在壓縮中...");const output = fs.createWriteStream(outputZip);const archive = archiver("zip", { zlib: { level: 9 } });// 監聽輸出流關閉事件output.on("close", () => {const wgtPath = path.resolve(__dirname,`dist/wgt/${manifest.name}_${manifest.versionCode}.wgt`);console.log(`壓縮成功!!!`);console.log(`${manifest.name}的wgt導出路徑 ${wgtPath}`);});// 監聽警告事件archive.on("warning", (err) => {err.code === "ENOENT" ? console.warn(err) : console.error(err);});// 監聽錯誤事件archive.on("error", (err) => {console.error(err);});archive.pipe(output);archive.directory(outputDirectory, false);archive.finalize();
};const build = () => {console.log("正在編譯中...");exec(command, { cwd: projectRoot }, (error) => {if (error) {console.error(`執行命令時出錯: ${error}`);return;}const manifest = getManifestJSON();compress(manifest);});
};build();

4.執行yarn run build:wgt即可獲得wgt文件

5.后續優化可以增加上傳文件服務器功能

四、Android/IOS權限判斷文件

var isIos
// #ifdef APP-PLUS  
isIos = (plus.os.name == "iOS")
// #endif  // 判斷推送權限是否開啟  
function judgeIosPermissionPush() {var result = false;var UIApplication = plus.ios.import("UIApplication");var app = UIApplication.sharedApplication();var enabledTypes = 0;if (app.currentUserNotificationSettings) {var settings = app.currentUserNotificationSettings();enabledTypes = settings.plusGetAttribute("types");console.log("enabledTypes1:" + enabledTypes);if (enabledTypes == 0) {console.log("推送權限沒有開啟");} else {result = true;console.log("已經開啟推送功能!")}plus.ios.deleteObject(settings);} else {enabledTypes = app.enabledRemoteNotificationTypes();if (enabledTypes == 0) {console.log("推送權限沒有開啟!");} else {result = true;console.log("已經開啟推送功能!")}console.log("enabledTypes2:" + enabledTypes);}plus.ios.deleteObject(app);plus.ios.deleteObject(UIApplication);return result;
}// 判斷定位權限是否開啟  
function judgeIosPermissionLocation() {var result = false;var cllocationManger = plus.ios.import("CLLocationManager");var status = cllocationManger.authorizationStatus();result = (status != 2)console.log("定位權限開啟:" + result);// 以下代碼判斷了手機設備的定位是否關閉,推薦另行使用方法 checkSystemEnableLocation  /* var enable = cllocationManger.locationServicesEnabled();  var status = cllocationManger.authorizationStatus();  console.log("enable:" + enable);  console.log("status:" + status);  if (enable && status != 2) {  result = true;  console.log("手機定位服務已開啟且已授予定位權限");  } else {  console.log("手機系統的定位沒有打開或未給予定位權限");  } */plus.ios.deleteObject(cllocationManger);return result;
}// 判斷麥克風權限是否開啟  
function judgeIosPermissionRecord() {var result = false;var avaudiosession = plus.ios.import("AVAudioSession");var avaudio = avaudiosession.sharedInstance();var permissionStatus = avaudio.recordPermission();console.log("permissionStatus:" + permissionStatus);if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {console.log("麥克風權限沒有開啟");} else {result = true;console.log("麥克風權限已經開啟");}plus.ios.deleteObject(avaudiosession);return result;
}// 判斷相機權限是否開啟  
function judgeIosPermissionCamera() {var result = false;var AVCaptureDevice = plus.ios.import("AVCaptureDevice");var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');console.log("authStatus:" + authStatus);if (authStatus == 3) {result = true;console.log("相機權限已經開啟");} else {console.log("相機權限沒有開啟");}plus.ios.deleteObject(AVCaptureDevice);return result;
}// 判斷相冊權限是否開啟  
function judgeIosPermissionPhotoLibrary() {var result = false;var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");var authStatus = PHPhotoLibrary.authorizationStatus();console.log("authStatus:" + authStatus);if (authStatus == 3) {result = true;console.log("相冊權限已經開啟");} else {console.log("相冊權限沒有開啟");}plus.ios.deleteObject(PHPhotoLibrary);return result;
}// 判斷通訊錄權限是否開啟  
function judgeIosPermissionContact() {var result = false;var CNContactStore = plus.ios.import("CNContactStore");var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);if (cnAuthStatus == 3) {result = true;console.log("通訊錄權限已經開啟");} else {console.log("通訊錄權限沒有開啟");}plus.ios.deleteObject(CNContactStore);return result;
}// 判斷日歷權限是否開啟  
function judgeIosPermissionCalendar() {var result = false;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);if (ekAuthStatus == 3) {result = true;console.log("日歷權限已經開啟");} else {console.log("日歷權限沒有開啟");}plus.ios.deleteObject(EKEventStore);return result;
}// 判斷備忘錄權限是否開啟  
function judgeIosPermissionMemo() {var result = false;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);if (ekAuthStatus == 3) {result = true;console.log("備忘錄權限已經開啟");} else {console.log("備忘錄權限沒有開啟");}plus.ios.deleteObject(EKEventStore);return result;
}// Android權限查詢  
function requestAndroidPermission(permissionID) {return new Promise((resolve, reject) => {plus.android.requestPermissions(permissionID.split(","),// [permissionID], // 理論上支持多個權限同時查詢,但實際上本函數封裝只處理了一個權限的情況。有需要的可自行擴展封裝  function(resultObj) {var result = 0;for (var i = 0; i < resultObj.granted.length; i++) {var grantedPermission = resultObj.granted[i];console.log('已獲取的權限:' + grantedPermission);result = 1}for (var i = 0; i < resultObj.deniedPresent.length; i++) {var deniedPresentPermission = resultObj.deniedPresent[i];console.log('拒絕本次申請的權限:' + deniedPresentPermission);result = 0}for (var i = 0; i < resultObj.deniedAlways.length; i++) {var deniedAlwaysPermission = resultObj.deniedAlways[i];console.log('永久拒絕申請的權限:' + deniedAlwaysPermission);result = -1}resolve(result);// 若所需權限被拒絕,則打開APP設置界面,可以在APP設置界面打開相應權限  // if (result != 1) {  // gotoAppPermissionSetting()  // }  },function(error) {console.log('申請權限錯誤:' + error.code + " = " + error.message);resolve({code: error.code,message: error.message});});});
}// 使用一個方法,根據參數判斷權限  
function judgeIosPermission(permissionID) {if (permissionID == "location") {return judgeIosPermissionLocation()} else if (permissionID == "camera") {return judgeIosPermissionCamera()} else if (permissionID == "photoLibrary") {return judgeIosPermissionPhotoLibrary()} else if (permissionID == "record") {return judgeIosPermissionRecord()} else if (permissionID == "push") {return judgeIosPermissionPush()} else if (permissionID == "contact") {return judgeIosPermissionContact()} else if (permissionID == "calendar") {return judgeIosPermissionCalendar()} else if (permissionID == "memo") {return judgeIosPermissionMemo()}return false;
}// 跳轉到**應用**的權限頁面  
function gotoAppPermissionSetting() {if (isIos) {var UIApplication = plus.ios.import("UIApplication");var application2 = UIApplication.sharedApplication();var NSURL2 = plus.ios.import("NSURL");// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");       var setting2 = NSURL2.URLWithString("app-settings:");application2.openURL(setting2);plus.ios.deleteObject(setting2);plus.ios.deleteObject(NSURL2);plus.ios.deleteObject(application2);} else {// console.log(plus.device.vendor);  var Intent = plus.android.importClass("android.content.Intent");var Settings = plus.android.importClass("android.provider.Settings");var Uri = plus.android.importClass("android.net.Uri");var mainActivity = plus.android.runtimeMainActivity();var intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);intent.setData(uri);mainActivity.startActivity(intent);}
}// 檢查系統的設備服務是否開啟  
// var checkSystemEnableLocation = async function () {  
function checkSystemEnableLocation() {if (isIos) {var result = false;var cllocationManger = plus.ios.import("CLLocationManager");var result = cllocationManger.locationServicesEnabled();console.log("系統定位開啟:" + result);plus.ios.deleteObject(cllocationManger);return result;} else {var context = plus.android.importClass("android.content.Context");var locationManager = plus.android.importClass("android.location.LocationManager");var main = plus.android.runtimeMainActivity();var mainSvr = main.getSystemService(context.LOCATION_SERVICE);var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);console.log("系統定位開啟:" + result);return result}
}let permissionMap = {"android": {"CALL_PHONE": {"name": "android.permission.CALL_PHONE","title": "撥打電話權限說明","mtitle": "撥打電話權限","content": "向您獲取撥打電話權限,便于聯系客服等"},"CAMERA&STORAGE": {"name": "android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA","title": "相機/相冊權限說明","mtitle": "相機/相冊權限","content": "便于您使用該功能上傳您的照片/圖片,用于上傳證件等場景中讀取和寫入相冊和文件內容"},"CAMERA": {"name": "android.permission.CAMERA","title": "相機權限說明","mtitle": "相機權限","content": "便于您使用該功能上傳您的照片/圖片,用于上傳證件等場景中拍攝內容"},"PHOTO": {"name": "android.permission.READ_EXTERNAL_STORAGE","title": "相冊權限說明","mtitle": "相冊權限","content": "便于您使用該功能上傳您的照片/圖片,用于上傳證件等場景中選擇相冊內容"},"Location": {"name": "android.permission.ACCESS_COARSE_LOCATION,android.permission.ACCESS_FINE_LOCATION","title": "獲取當前定位權限說明","mtitle": "獲取當前定位權限","content": "向您獲取當前的地理位置信息,便于查看位置、地圖選點與導航等功能"},"STORAGE": {"name": "android.permission.WRITE_EXTERNAL_STORAGE","title": "存儲權限申請說明","mtitle": "存儲權限","content": "為了將圖片保存到手機,我們需要向您申請存儲權限。"}},"ios": {}
}let view = null;function showViewDesc(permission) {let plat = isIos ? "ios" : "android";view = new plus.nativeObj.View('per-modal', {top: '0px',left: '0px',width: '100%',backgroundColor: 'rgba(0,0,0,0.2)',//opacity: '.9'     })view.drawRect({color: '#fff',radius: '5px'}, {top: '30px',left: '5%',width: '90%',height: "100px",})view.drawText(permissionMap[plat][permission]["title"], {top: '40px',left: "8%",height: "30px"}, {align: "left",color: "#000",}, {onClick: function(e) {console.log(e);}})view.drawText(permissionMap[plat][permission]["content"], {top: '65px',height: "60px",left: "8%",width: "84%"}, {whiteSpace: 'normal',size: "14px",align: "left",color: "#656563"})view.show()
}function premissionCheck(permission) {console.log('premissionCheck')return new Promise(async (resolve, reject) => {let plat = isIos ? "ios" : "android";if (isIos) { // ios  // const camera = permission.judgeIosPermission("camera");//判斷ios是否給予攝像頭權限  // //ios相冊沒權限,系統會自動彈出授權框  // //let photoLibrary = permission.judgeIosPermission("photoLibrary");//判斷ios是否給予相冊權限  // if(camera){  //     resolve();  // }else{  //     reject('需要開啟相機使用權限');  // }  resolve(1)} else { // android  console.log('android')let permission_arr = permissionMap[plat][permission]["name"].split(",");let flag = true;for (let i = 0; i < permission_arr.length; i++) {let status = plus.navigator.checkPermission(permission_arr[i]);if (status == "undetermined") {flag = false;}}console.log("flag", flag)if (flag == false) { // 未完全授權  showViewDesc(permission);requestAndroidPermission(permissionMap[plat][permission]["name"]).then((res) => {view.close();if (res == -1) {uni.showModal({title: '提示',content: permissionMap[plat][permission]["mtitle"] + '已被拒絕,請手動前往設置',confirmText: "立即設置",success: (res) => {if (res.confirm) {gotoAppPermissionSetting()}}})}resolve(res)})} else {resolve(1)}}})
}export default {judgeIosPermission: judgeIosPermission,requestAndroidPermission: requestAndroidPermission,checkSystemEnableLocation: checkSystemEnableLocation,gotoAppPermissionSetting: gotoAppPermissionSetting,premissionCheck: premissionCheck
}

五、熱更新wgt

1.下載彈窗

<template><view class="mask flex-center"><view class="content"><view style="position: relative;"><image class="content-img" src="./card.png" /><view class="content-version" v-if="data?.edition_name">版本號:{{data?.edition_name}}</view></view><view class="content-body"><view class="content-body-row" v-for="(item,index) of data.describe.split(';')" :key="new Date().getTime()"><view class="dot" /><view class="content-body-lable">{{item}}</view></view><view v-if="showProgress"><u-line-progress :striped="true" :percent="percent" active-color="#E80A1E" :striped-active="true" /><view>正在下載,請稍后</view></view><view v-else><view v-if="!cancleBtn"><view class="content-button-now content-button" @click="confirm">立即更新</view></view><view class="content-button-row" v-else><view class="content-button-cancel content-button" @click="cancel">以后再說</view><view class="content-button-confirm content-button" @click="confirm">立即更新</view></view></view></view></view></view>
</template><script setup>import {ref,reactive,toRefs} from 'vue'import {onLoad,onBackPress} from '@dcloudio/uni-app'const dataMap = reactive({percent: 0, //進度條百分比cancleBtn: true, //是否強制立即更新showProgress: false, //是否顯示按鈕data: {describe: '1. 修復已知問題;2. 優化用戶體驗',edition_url: 'http://download.rongtongkeji.com/榮煤寶.apk', //安裝包下載地址或者通用應用市場地址edition_force: 1, //是否強制更新 0代表否 1代表是package_type: 1 //0是整包升級 1是wgt升級}})const {percent,cancleBtn,data,showProgress} = toRefs(dataMap)onLoad((e) => {if (e?.obj) {dataMap.data = JSON.parse(e.obj);}dataMap.cancleBtn = !dataMap.data.edition_force;})onBackPress((e) => {// 強制更新不允許返回if (dataMap.data.edition_force || dataMap.percent > 0) {return true;}})const cancel = () => {//取消升級 返回上一頁uni.navigateBack({delta: 1});}const confirm = () => {// const packageName = ''// let url = ''// let deviceBrand = uni.getSystemInfoSync()?.deviceBrand?.toLowerCase() || ''// if (dataMap.data.package_type == 0) {// 	if (uni.getSystemInfoSync().platform != 'android') {// 		url = "https://apps.apple.com/cn/app/xxx"// 	} else {// 		if (deviceBrand.indexOf("huawei") > -1) {// 			url = "appmarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("oppo") > -1) {// 			url = "market://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("vivo") > -1) {// 			url = "vivoMarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("mi") > -1) {// 			url = "mimarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("samsung") > -1) {// 			url = "samsungapps://ProductDetail/" + packageName;// 		} else if (deviceBrand.indexOf("lenovo") > -1) {// 			url = "http://market.lenovomm.com/details?id=" + packageName;// 		} else {// 			// url = "https://a.app.qq.com/o/simple.jsp?pkgname="+packageName;// 			url = "http://download/xx.apk";// 		}// 	}// 	//apk整包升級// 	if (url.includes('.apk')) {// 		download();// 	} else {// 		plus.runtime.openURL(url);// 	}// } else {// 	//wgt資源包升級// 	download();// }download();}const download = () => {dataMap.data.edition_force = 0dataMap.showProgress = trueconst downloadTask = uni.downloadFile({url: dataMap.data.edition_url,success: res => {if (res.statusCode === 200) {plus.runtime.install(res.tempFilePath, {force: true //true表示強制安裝,不進行版本號的校驗;false則需要版本號校驗,},function() {if (dataMap.data.package_type == 1) {// wgt升級需要重啟plus.runtime.restart();}else {plus.runtime.quit();}},function(e) {console.error('install fail...');});}}});downloadTask.onProgressUpdate(res => {dataMap.percent = res.progress;});}
</script><style lang="scss">page {background: transparent;}.flex-center {display: flex;justify-content: center;align-items: center;}.mask {position: fixed;left: 0;top: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.65);}.content {width: 600rpx;background: #FFFFFF;border-radius: 32rpx;.content-img {width: 600rpx;height: 344rpx;}.content-version {position: absolute;bottom: 22rpx;left: 70rpx;font-size: 28rpx;font-family: PingFangSC-Medium, PingFang SC;font-weight: 500;color: #E90F21;}.content-body {padding: 0 40rpx 40rpx 40rpx;.content-body-row {display: flex;.dot {width: 14rpx;height: 14rpx;background-color: #E90D20;border-radius: 50px;margin-top: 16rpx;margin-right: 16rpx;}.content-body-lable {width: 506rpx;font-size: 28rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #333333;}}.content-button-now {width: 520rpx;color: #FFFFFF;background: linear-gradient(90deg, #FF775B 0%, #E80A1E 100%);margin-top: 32rpx;}.content-button-row {display: flex;justify-content: space-between;margin-top: 32rpx;.content-button-confirm {width: 244rpx;background: linear-gradient(90deg, #FF775B 0%, #E80A1E 100%);color: #FFFFFF;}.content-button-cancel {width: 244rpx;border: 2rpx solid #999999;color: #999999;}}.content-button {height: 80rpx;border-radius: 40rpx;font-size: 28rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;display: flex;justify-content: center;align-items: center;}}}
</style>

2.silence-update文件從服務器判斷是否需要更新

import { config } from '@/config/config';
export const silenceUpdate = (url) => {uni.downloadFile({url,success: res => {if (res.statusCode === 200) {plus.runtime.install(res.tempFilePath, {force: true //true表示強制安裝,不進行版本號的校驗;false則需要版本號校驗,},function() {uni.showModal({title: '更新提示',content: '新版本已經準備好,請重啟應用',showCancel: false,success: function(res) {if (res.confirm) {plus.runtime.restart()}}});// console.log('install success...');},function(e) {console.error('install fail...');});}}});
}export const checkVersion = (appid, platform, version_code, loadding) => {loadding && uni.showLoading({title: '加載中',mask: true})let url = config.baseUrl + '/edition/get_renew_edition'//獲取服務器的版本號uni.request({url: url,method: 'POST',data: {edition_type: appid,version_type: platform,edition_number: version_code,},header: {"content-type": "application/json",},success: (res) => {console.log(res, 'res')if (res.statusCode == 200 && res.data.ok) {//判斷后臺返回版本號是否大于當前應用版本號 && 是否發行if (Number(res.data.data.edition_number) == version_code && res.data.data.edition_issue && loadding) {uni.showToast({title: '已是最新版本',icon: 'none',mask: true})return}if (Number(res.data.data.edition_number) > version_code && res.data.data.edition_issue) {//注意 這里obj盡量不要修改,如果非要修改,rt-uni-update里的onload的obj也得改if (res.data.data.package_type == '1' && res.data.data.edition_silence) {//調用靜默更新方法 傳入下載地址silenceUpdate(res.data.data.edition_url)} else {const pages = getCurrentPages()let flag = falsefor (let s of pages) {if(s.route == 'components/hot-update-gc/index') flag = true}!flag && uni.navigateTo({url: '/components/hot-update-gc/index?obj=' + JSON.stringify(res.data.data)})}}}},fail: (err) => {console.log(err, 'err')},complete: () => {loadding && uni.hideLoading()}})
}

3.調用checkVersion?

import { checkVersion } from "@/xxx/silence-update.js"
plus.runtime.getProperty(plus.runtime.appid!, async (inf) => {let version_code = +inf.versionCode!checkVersion(plus.runtime.appid, uni.getSystemInfoSync().platform, version_code, false)
})

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81104.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81104.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81104.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華為發布全球首個L3商用智駕ADS4.0

2024年10月2024世界智能網聯汽車大會上&#xff0c;余承東講到&#xff1a;“華為ADS 4.0將于2025年推出高速L3級自動駕駛商用及城區L3級自動駕駛試點&#xff0c;希望加快L3級自動駕駛標準的進程&#xff0c;推動L3級自動駕駛技術的普及。” 世界智能網聯汽車大會演講PPT 所以…

【Python學習路線】零基礎到項目實戰

目錄 &#x1f31f; 前言技術背景與價值當前技術痛點解決方案概述目標讀者說明 &#x1f9e0; 一、技術原理剖析核心概念圖解核心作用講解關鍵技術模塊說明技術選型對比 &#x1f4bb; 二、實戰演示環境配置要求核心代碼實現運行結果驗證 ? 三、性能對比測試方法論量化數據對比…

解決redis序列號和反序列化問題

最近遇到了一個問題,將 List<Map<String, Object>> 類型數據以list形式存入到redis之后,發現取出來時數據格式完全不對,根據報錯信息發現是反序列化問題,遇到類似問題,主要有兩種解決方案1.使用序列號工具 例如&#xff0c;Java中常用的序列化工具有Jackson、Gso…

Android學習總結之設計場景題

設計圖片請求框架的緩存模塊 核心目標是通過分層緩存策略&#xff08;內存緩存 磁盤緩存&#xff09;提升圖片加載效率&#xff0c;同時兼顧內存占用和存儲性能。以下是針對 Android 面試官的回答思路&#xff0c;結合代碼注釋說明關鍵設計點&#xff1a; 一、緩存架構設計&…

Webug3.0通關筆記14 第十四關:存儲型XSS

目錄 第十四關:存儲型XSS 1.打開靶場 2.源碼分析 3.滲透實戰 第十四關:存儲型XSS 本文通過《webug3靶場第十四關 存儲型XSS》來進行存儲型XSS關卡的滲透實戰。 存儲型 XSS&#xff08;Stored Cross - Site Scripting&#xff09;&#xff0c;也被稱為持久型 XSS&#xff…

Java父類、子類實例初始化順序詳解

1、完整的初始化順序&#xff08;含繼承&#xff09; 1、父類的靜態初始化 父類靜態變量默認值 → 父類靜態變量顯式賦值 父類靜態代碼塊&#xff08;按代碼順序執行&#xff09;。 2、子類的靜態初始化 子類靜態變量默認值 → 子類靜態變量顯式賦值 子類靜態代碼塊&…

13.組合模式:思考與解讀

原文地址:組合模式&#xff1a;思考與解讀 更多內容請關注&#xff1a;7.深入思考與解讀設計模式 引言 在軟件開發中&#xff0c;是否曾經遇到過這樣一種情況&#xff1a;你有一個對象&#xff0c;它本身很簡單&#xff0c;但是它包含了其他類似的對象。隨著系統變得越來越復…

OpenCV實戰教程 第一部分:基礎入門

第一部分&#xff1a;基礎入門 1. OpenCV簡介 什么是OpenCV及其應用領域 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一個開源的計算機視覺和機器學習軟件庫&#xff0c;于1999年由Intel公司發起&#xff0c;現在由非營利組織OpenCV.org維護。Ope…

虛幻商城 Quixel 免費資產自動化入庫(2025年版)

文章目錄 一、背景二、問題講解1. Quixel 免費資產是否還能一鍵入庫?2. 是不是使用了一鍵入庫功能 Quixel 的所有資產就能入庫了?3. 一鍵入庫會入庫哪些資產?三、實現效果展示四、實現自動化入庫五、常見問題1. 出現401報錯2. 出現429報錯3. 入庫過于緩慢4. 入庫 0 個資產一…

uni-app - 小程序使用高德地圖完整版

文章目錄 ??功能描述??效果??開發環境??代碼部分??功能描述 頁面自動通過定位獲取用戶位置并展示周邊POI數據,同時支持關鍵詞輸入實時聯想推薦關聯地點信息, 實現精準智能的地點發現與檢索功能。 ??效果 ??開發環境 unibest2.5.4nodev18.20.5pnpm9.14.2wot-des…

牛客:AB4 逆波蘭表達式求值

鏈接&#xff1a;逆波蘭表達式求值_牛客題霸_牛客網 題解&#xff1a; 利用棧&#xff0c;遍歷字符串數組&#xff0c;遇到運算數則入棧&#xff0c;遇到運算符則取出棧頂兩個運算數進行運算&#xff0c;并將運算結果入棧。 class Solution { public:/*** 代碼中的類名、方法…

Ant(Ubuntu 18.04.6 LTS)安裝筆記

一、前言 本文與【MySQL 8&#xff08;Ubuntu 18.04.6 LTS&#xff09;安裝筆記】同批次&#xff1a;先搭建數據庫&#xff0c;再安裝JDK&#xff0c;后面肯定就是部署Web應用。其中Web應用的部署使用 Ant 方式&#xff0c;善始善終&#xff0c;特以筆記。 二、準備 &#xf…

ultralytics 目標檢測 混淆矩陣 背景圖像 沒被記錄

修改 utils/metrics.py ConfusionMatrix def process_batch(self, detections, gt_bboxes, gt_cls):"""Update confusion matrix for object detection task.Args:detections (Array[N, 6] | Array[N, 7]): Detected bounding boxes and their associated inf…

iview 如何設置sider寬度

iview layout組件中&#xff0c;sider設置了默認寬度和最大寬度&#xff0c;在css樣式文件中修改無效&#xff0c;原因是iview默認樣式設置在了element.style中&#xff0c;只能通過行內樣式修改 樣式如下&#xff1a; image.png image.png 修改方式&#xff1a; 1.官方文檔中寫…

go-zero(十七)結合DTM :實現分布式事務

1. 基礎概念介紹 1.1 什么是分布式事務 在微服務架構中&#xff0c;一個業務操作常常需要調用多個服務來完成。例如&#xff0c;在電商系統中下單時&#xff0c;需要同時操作訂單服務和庫存服務。這種跨服務的操作就需要分布式事務來保證數據一致性。 分布式事務面臨以下挑戰…

2025 簡易Scrum指南(簡體中文版)

Scrum是一個輕量級的、以團隊為中心的框架&#xff0c;用于解決復雜的問題并創造價值。Scrum有意保持非完整性&#xff0c;Scrum的設計初衷旨在依靠使用者的集體智慧來不斷演進構建。 Scrum建立在實驗主義和精益思想的基礎上&#xff0c;它賦能團隊靈活巧妙地工作&#xff0c;…

2025最新福昕PDF編輯器,PDF萬能處理工具

軟件介紹 Foxit PDF Editor Pro 2025 中文特別版&#xff08;以前稱為 Foxit PhantomPDF Business&#xff09;是一款專為滿足各種辦公需求而設計的業務就緒的PDF工具包。 軟件特點 1. 強大的PDF編輯能力 創建新文檔&#xff1a;用戶可以從無到有地構建PDF文檔&#xff0c;添…

ollama的若干實踐

1. 本地ollama 1.1 本地安裝ollama 方法 1&#xff1a;手動檢查最新版本并下載 訪問 Ollama 的 GitHub Releases 頁面&#xff1a; 打開 https://github.com/ollama/ollama/releases 查看最新的穩定版本&#xff08;如 v0.7.0 或更高&#xff09; 手動下載最新版本&#xff08…

Spring Security源碼解析

秒懂SpringBoot之全網最易懂的Spring Security教程 SpringBoot整合Spring-Security 認證篇&#xff08;保姆級教程&#xff09; SpringBoot整合Spring Security【超詳細教程】 spring security 超詳細使用教程&#xff08;接入springboot、前后端分離&#xff09; Security 自…

LeetCode 3392.統計符合條件長度為 3 的子數組數目:一次遍歷模擬

【LetMeFly】3392.統計符合條件長度為 3 的子數組數目&#xff1a;一次遍歷模擬 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/count-subarrays-of-length-three-with-a-condition/ 給你一個整數數組 nums &#xff0c;請你返回長度為 3 的 子數組&#xff0c;滿足…