当前位置: 首页 > article >正文

鸿蒙OSUniApp 实现图片上传与压缩功能#三方框架 #Uniapp

UniApp 实现图片上传与压缩功能

前言

在移动应用开发中,图片上传是一个非常常见的需求。无论是用户头像、朋友圈图片还是商品图片,都需要上传到服务器。但移动设备拍摄的图片往往尺寸较大,直接上传会导致流量消耗过大、上传时间过长,影响用户体验。因此,图片压缩成为了移动应用开发中的必备技能。

通过 UniApp 实现图片上传与压缩功能,既能满足用户体验需求,又能减轻服务器负担。今天就来分享一下我在实际项目中使用的图片上传与压缩方案,希望能对大家有所帮助。

技术方案分析

在 UniApp 中实现图片上传与压缩,主要涉及以下几个方面:

  1. 图片选择:通过 uni.chooseImage() 实现
  2. 图片压缩:通过 canvas 实现
  3. 图片上传:通过 uni.uploadFile() 实现

这个方案的优点是:

  • 压缩在客户端进行,减轻了服务器压力
  • 减少了网络流量,提高了上传速度
  • 可以根据不同场景设置不同的压缩参数

具体实现

1. 图片选择

首先实现图片选择功能:

// 选择图片
chooseImage() {return new Promise((resolve, reject) => {uni.chooseImage({count: 9, // 最多可选择的图片张数sizeType: ['original', 'compressed'], // 可选择原图或压缩后的图片sourceType: ['album', 'camera'], // 从相册选择或使用相机拍摄success: (res) => {resolve(res.tempFilePaths);},fail: (err) => {reject(err);}});});
}

2. 图片压缩实现

压缩图片是整个功能的核心,我们使用 canvas 来实现:

/*** 图片压缩* @param {String} src 图片路径* @param {Number} quality 压缩质量(0-1)* @param {Number} maxWidth 最大宽度* @param {Number} maxHeight 最大高度*/
compressImage(src, quality = 0.8, maxWidth = 800, maxHeight = 800) {return new Promise((resolve, reject) => {// 获取图片信息uni.getImageInfo({src: src,success: (imgInfo) => {// 计算压缩后的尺寸let width = imgInfo.width;let height = imgInfo.height;// 等比例缩放if (width > maxWidth || height > maxHeight) {const ratio = Math.max(width / maxWidth, height / maxHeight);width = Math.floor(width / ratio);height = Math.floor(height / ratio);}// 创建canvas上下文const ctx = uni.createCanvasContext('compressCanvas', this);// 绘制图片到canvasctx.drawImage(src, 0, 0, width, height);// 将canvas转为图片ctx.draw(false, () => {setTimeout(() => {uni.canvasToTempFilePath({canvasId: 'compressCanvas',fileType: 'jpg',quality: quality,success: (res) => {// 获取压缩后的图片路径resolve(res.tempFilePath);},fail: (err) => {reject(err);}}, this);}, 300); // 延迟确保canvas绘制完成});},fail: (err) => {reject(err);}});});
}

在页面中需要添加对应的 canvas 元素:

<canvas canvas-id="compressCanvas" style="width: 0px; height: 0px; position: absolute; left: -1000px; top: -1000px;"></canvas>

3. 图片上传实现

图片上传时,我们往往需要添加额外的参数,比如表单字段、用户 token 等:

/*** 上传图片到服务器* @param {String} filePath 图片路径* @param {String} url 上传地址* @param {Object} formData 附加数据*/
uploadFile(filePath, url, formData = {}) {return new Promise((resolve, reject) => {uni.uploadFile({url: url,filePath: filePath,name: 'file', // 服务器接收的字段名formData: formData,header: {// 可以添加自定义 header,如 token'Authorization': 'Bearer ' + uni.getStorageSync('token')},success: (res) => {// 这里需要注意,返回的数据是字符串,需要手动转为 JSONlet data = JSON.parse(res.data);resolve(data);},fail: (err) => {reject(err);}});});
}

4. 完整的上传流程

将以上三个步骤组合,实现完整的图片上传流程:

// 实现完整的上传流程
async handleUpload() {try {// 显示加载提示uni.showLoading({title: '上传中...',mask: true});// 选择图片const imagePaths = await this.chooseImage();// 用于存储上传结果const uploadResults = [];// 循环处理每张图片for (let i = 0; i < imagePaths.length; i++) {// 压缩图片const compressedPath = await this.compressImage(imagePaths[i],0.7,  // 压缩质量800,  // 最大宽度800   // 最大高度);// 获取原图和压缩后的图片大小进行对比const originalInfo = await this.getFileInfo(imagePaths[i]);const compressedInfo = await this.getFileInfo(compressedPath);console.log(`原图大小: ${(originalInfo.size / 1024).toFixed(2)}KB, 压缩后: ${(compressedInfo.size / 1024).toFixed(2)}KB`);// 上传压缩后的图片const uploadResult = await this.uploadFile(compressedPath,'https://your-api.com/upload',{type: 'avatar', // 附加参数userId: this.userId});uploadResults.push(uploadResult);}// 隐藏加载提示uni.hideLoading();// 提示上传成功uni.showToast({title: '上传成功',icon: 'success'});// 返回上传结果return uploadResults;} catch (error) {uni.hideLoading();uni.showToast({title: '上传失败',icon: 'none'});console.error('上传错误:', error);}
}// 获取文件信息
getFileInfo(filePath) {return new Promise((resolve, reject) => {uni.getFileInfo({filePath: filePath,success: (res) => {resolve(res);},fail: (err) => {reject(err);}});});
}

进阶优化

以上代码已经可以基本满足图片上传与压缩需求,但在实际项目中,我们还可以进一步优化:

1. 添加图片预览功能

在上传前,通常需要让用户预览选择的图片:

// 预览图片
previewImage(current, urls) {uni.previewImage({current: current, // 当前显示图片的路径urls: urls, // 需要预览的图片路径列表indicator: 'number',loop: true});
}

2. 使用 uniCloud 上传

如果你使用 uniCloud 作为后端服务,可以利用其提供的云存储功能简化上传流程:

// 使用 uniCloud 上传
async uploadToUniCloud(filePath) {try {const result = await uniCloud.uploadFile({filePath: filePath,cloudPath: 'images/' + Date.now() + '.jpg'});return result.fileID; // 返回文件ID} catch (error) {throw error;}
}

3. 添加上传进度显示

对于大图片,添加上传进度能提升用户体验:

uploadFileWithProgress(filePath, url, formData = {}) {return new Promise((resolve, reject) => {const uploadTask = uni.uploadFile({url: url,filePath: filePath,name: 'file',formData: formData,success: (res) => {let data = JSON.parse(res.data);resolve(data);},fail: (err) => {reject(err);}});uploadTask.onProgressUpdate((res) => {console.log('上传进度', res.progress);// 更新进度条this.uploadProgress = res.progress;});});
}

4. 针对鸿蒙系统的适配

随着国产操作系统鸿蒙的普及,我们也需要考虑在鸿蒙系统上的兼容性。虽然目前 UniApp 官方还没有专门针对鸿蒙系统的适配文档,但我们可以通过一些方法来优化:

// 检测当前系统
checkSystem() {const systemInfo = uni.getSystemInfoSync();console.log('当前系统:', systemInfo.platform);// 鸿蒙系统目前会被识别为 android,可以通过 brand 和 model 辅助判断const isHarmonyOS = systemInfo.brand === 'HUAWEI' && /HarmonyOS/i.test(systemInfo.system);if (isHarmonyOS) {console.log('当前是鸿蒙系统');// 针对鸿蒙系统进行特殊处理// 例如:调整压缩参数、使用不同的 API 等}return systemInfo;
}

根据我的测试,在鸿蒙系统上,有时 canvas 绘制需要更长的延迟时间,可以适当调整:

// 针对鸿蒙系统的 canvas 延迟调整
const delay = isHarmonyOS ? 500 : 300;
setTimeout(() => {uni.canvasToTempFilePath({// 配置项...});
}, delay);

实际案例

下面是一个完整的实际案例,用于实现商品发布页面的图片上传功能:

<template><view class="container"><view class="image-list"><!-- 已选图片预览 --><view class="image-item" v-for="(item, index) in imageList" :key="index"><image :src="item.path" mode="aspectFill" @tap="previewImage(index)"></image><view class="delete-btn" @tap.stop="deleteImage(index)">×</view></view><!-- 添加图片按钮 --><view class="add-image" @tap="handleAddImage" v-if="imageList.length < 9"><text class="add-icon">+</text><text class="add-text">添加图片</text></view></view><!-- 上传按钮 --><button class="upload-btn" @tap="submitUpload" :disabled="imageList.length === 0">上传图片 ({{imageList.length}}/9)</button><!-- 压缩画布(隐藏) --><canvas canvas-id="compressCanvas" style="width: 0px; height: 0px; position: absolute; left: -1000px; top: -1000px;"></canvas><!-- 上传进度条 --><view class="progress-bar" v-if="isUploading"><view class="progress-inner" :style="{width: uploadProgress + '%'}"></view><text class="progress-text">{{uploadProgress}}%</text></view></view>
</template><script>
export default {data() {return {imageList: [], // 已选图片列表isUploading: false, // 是否正在上传uploadProgress: 0, // 上传进度isHarmonyOS: false // 是否鸿蒙系统};},onLoad() {// 检测系统const systemInfo = this.checkSystem();this.isHarmonyOS = systemInfo.brand === 'HUAWEI' && /HarmonyOS/i.test(systemInfo.system);},methods: {// 添加图片async handleAddImage() {try {const imagePaths = await this.chooseImage();// 添加到图片列表for (let path of imagePaths) {this.imageList.push({path: path,compressed: false,compressedPath: '',uploaded: false,fileID: ''});}} catch (error) {console.error('选择图片失败:', error);}},// 预览图片previewImage(index) {const urls = this.imageList.map(item => item.path);uni.previewImage({current: this.imageList[index].path,urls: urls});},// 删除图片deleteImage(index) {this.imageList.splice(index, 1);},// 提交上传async submitUpload() {if (this.imageList.length === 0) {uni.showToast({title: '请至少选择一张图片',icon: 'none'});return;}this.isUploading = true;this.uploadProgress = 0;uni.showLoading({title: '准备上传...',mask: true});try {// 上传结果const uploadResults = [];// 总进度let totalProgress = 0;// 遍历所有图片进行压缩和上传for (let i = 0; i < this.imageList.length; i++) {let item = this.imageList[i];// 如果还没压缩过,先压缩if (!item.compressed) {uni.showLoading({title: `压缩第 ${i+1}/${this.imageList.length} 张图片`,mask: true});try {const compressedPath = await this.compressImage(item.path,0.7,800,800);// 更新图片信息this.imageList[i].compressed = true;this.imageList[i].compressedPath = compressedPath;// 获取压缩前后的大小对比const originalInfo = await this.getFileInfo(item.path);const compressedInfo = await this.getFileInfo(compressedPath);console.log(`图片 ${i+1}: 原图 ${(originalInfo.size / 1024).toFixed(2)}KB, 压缩后 ${(compressedInfo.size / 1024).toFixed(2)}KB, 压缩率 ${((1 - compressedInfo.size / originalInfo.size) * 100).toFixed(2)}%`);} catch (error) {console.error(`压缩第 ${i+1} 张图片失败:`, error);// 如果压缩失败,使用原图this.imageList[i].compressedPath = item.path;this.imageList[i].compressed = true;}}// 准备上传uni.showLoading({title: `上传第 ${i+1}/${this.imageList.length} 张图片`,mask: true});try {// 使用压缩后的图片路径,如果没有则使用原图const fileToUpload = item.compressedPath || item.path;// 上传图片const result = await this.uploadFileWithProgress(fileToUpload,'https://your-api.com/upload',{type: 'product',index: i});// 更新图片信息this.imageList[i].uploaded = true;this.imageList[i].fileID = result.fileID || result.url;uploadResults.push(result);// 更新总进度totalProgress = Math.floor((i + 1) / this.imageList.length * 100);this.uploadProgress = totalProgress;} catch (error) {console.error(`上传第 ${i+1} 张图片失败:`, error);uni.showToast({title: `第 ${i+1} 张图片上传失败`,icon: 'none'});}}uni.hideLoading();this.isUploading = false;uni.showToast({title: '所有图片上传完成',icon: 'success'});// 返回上传结果,可以传给父组件或进行后续处理this.$emit('uploadComplete', uploadResults);} catch (error) {uni.hideLoading();this.isUploading = false;console.error('上传过程出错:', error);uni.showToast({title: '上传失败,请重试',icon: 'none'});}},// 其他方法实现(chooseImage, compressImage, uploadFile等,同前面的实现)}
};
</script><style lang="scss">
.container {padding: 20rpx;
}.image-list {display: flex;flex-wrap: wrap;
}.image-item {width: 220rpx;height: 220rpx;margin: 10rpx;position: relative;border-radius: 8rpx;overflow: hidden;image {width: 100%;height: 100%;}.delete-btn {position: absolute;top: 0;right: 0;width: 44rpx;height: 44rpx;background-color: rgba(0, 0, 0, 0.5);color: #ffffff;text-align: center;line-height: 44rpx;font-size: 32rpx;z-index: 10;}
}.add-image {width: 220rpx;height: 220rpx;margin: 10rpx;background-color: #f5f5f5;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 8rpx;border: 1px dashed #dddddd;.add-icon {font-size: 60rpx;color: #999999;}.add-text {font-size: 24rpx;color: #999999;margin-top: 10rpx;}
}.upload-btn {margin-top: 40rpx;background-color: #007aff;color: #ffffff;border-radius: 8rpx;&:disabled {background-color: #cccccc;}
}.progress-bar {margin-top: 30rpx;height: 40rpx;background-color: #f5f5f5;border-radius: 20rpx;overflow: hidden;position: relative;.progress-inner {height: 100%;background-color: #007aff;transition: width 0.3s;}.progress-text {position: absolute;top: 0;left: 0;right: 0;bottom: 0;display: flex;justify-content: center;align-items: center;font-size: 24rpx;color: #ffffff;}
}
</style>

鸿蒙系统适配经验

前面已经简单提到了鸿蒙系统的适配,下面来详细说一下我在实际项目中遇到的问题和解决方案:

  1. 画布延迟问题:在鸿蒙系统上,canvas 绘制后转图片需要更长的延迟时间,建议延长 setTimeout 时间。

  2. 文件系统差异:有些文件路径的处理方式可能与 Android 有所不同,建议使用 UniApp 提供的 API 进行文件操作,而不要直接操作路径。

  3. 图片格式支持:在鸿蒙系统上,对 WebP 等格式的支持可能有限,建议统一使用 JPG 或 PNG 格式。

  4. 内存管理:鸿蒙系统对内存的管理略有不同,处理大图片时需要注意内存释放。可以在完成上传后,主动清空临时图片:

// 清空临时文件
clearTempFiles() {for (let item of this.imageList) {// 如果存在压缩后的临时文件,尝试删除if (item.compressedPath && item.compressedPath !== item.path) {uni.removeSavedFile({filePath: item.compressedPath,complete: () => {console.log('清理临时文件');}});}}
}

总结

通过本文介绍的方法,我们可以在 UniApp 中实现图片上传与压缩功能,主要包括以下几个步骤:

  1. 使用 uni.chooseImage() 选择图片
  2. 使用 canvas 进行图片压缩
  3. 使用 uni.uploadFile() 上传图片
  4. 添加进度显示和预览功能
  5. 针对鸿蒙系统做特殊适配

在实际项目中,可以根据需求调整压缩参数,比如对头像类图片可以压缩得更小,而对需要展示细节的商品图片,可以保留更高的质量。

希望本文能够帮助大家更好地实现 UniApp 中的图片上传与压缩功能。如果有任何问题或建议,欢迎在评论区交流讨论!

参考资料

  1. UniApp 官方文档:https://uniapp.dcloud.io/
  2. Canvas API 参考:https://uniapp.dcloud.io/api/canvas/CanvasContext

相关文章:

鸿蒙OSUniApp 实现图片上传与压缩功能#三方框架 #Uniapp

UniApp 实现图片上传与压缩功能 前言 在移动应用开发中&#xff0c;图片上传是一个非常常见的需求。无论是用户头像、朋友圈图片还是商品图片&#xff0c;都需要上传到服务器。但移动设备拍摄的图片往往尺寸较大&#xff0c;直接上传会导致流量消耗过大、上传时间过长&#x…...

科技项目验收测试对软件产品和企业分别有哪些好处?

科技项目验收测试是指在项目的开发周期结束后&#xff0c;针对项目成果进行的一系列验证和确认活动。其目的是确保终交付的产品或系统符合预先设定的需求和标准。验收测试通常包括功能测试、性能测试、安全测试等多个方面&#xff0c;帮助企业评估软件在实际应用中的表现。 科…...

javascript和vue的不同

1. 数据绑定方式 JavaScript&#xff08;原生&#xff09; 手动操作 DOM&#xff1a;通过document.querySelector()等方法获取 DOM 元素&#xff0c;然后直接修改其属性或内容。 示例&#xff1a; <div id"counter">0</div> <button onclick"i…...

duxapp 2025-01-06更新 CLI新增帮助支持,优化基础模块结构

CLI 新增帮助命令 yarn duxapp -h yarn duxapp --helpyarn duxapp icon -h yarn duxapp icon create -h基础库 完善所有函数和组件的Types移除 Detail 组件移除 checkLocationPermission 方法移除 duxapp/utils/app.js 有关于模块的方法移除 Queue 队列功能移除 recursionSe…...

汽车零部件冲压车间MES一体机解决方案

在当前制造业升级的大背景下&#xff0c;提升生产效率、实现精细化管理已成为企业竞争力的关键。特别是在汽车零部件制造领域&#xff0c;冲压车间作为生产流程中的重要一环&#xff0c;其生产数据的实时采集与分析对于确保产品质量、优化生产节拍、降低运营成本至关重要。今天…...

hysAnalyser 从MPEG-TS导出ES功能说明

摘要 hysAnalyser 是一款特色的 MPEG-TS 数据分析工具。本文主要介绍了 hysAnalyser 从MPEG-TS 中导出选定的 ES 或 PES 功能(版本v1.0.003)&#xff0c;以便用户知悉和掌握这些功能&#xff0c;帮助分析和解决各种遇到ES或PES相关的实际问题。hysAnalyser 支持主流的MP1/MP2/…...

家里wifi不能上网或莫名跳转到赌博及色情网站就是域名被劫持、DNS被污染了

文章目录 定义上网过程域名被劫持可能阶段案例排查工具 解决方法清除系统DNS缓存查看DNS缓存清除DNS缓存 登录路由器&#xff0c;设置DNS可用的DNS地址&#xff1a; 找网络运营商报警 定义 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;劫持&#xff0c…...

基于SSM实现的健身房系统功能实现十六

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人们健康意识的不断提升&#xff0c;健身行业也在迅速扩展。越来越多的人加入到健身行列&#xff0c;健身房的数量也在不断增加。这种趋势使得健身房的管理变得越来越复杂&#xff0c;传统的手工或部分自动化的管…...

【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。 目录 引言设计一个共享数据中心选择数据模型键值对设计 数据可靠性设计持久化快照 &#xff08…...

[Harmony]大文件持久化

1.添加权限 在module.json5文件中添加权限 "requestPermissions": [{"name": "ohos.permission.READ_WRITE_USER_FILE", // 读写用户数据"reason": "$string:read_write_user_file_reason","usedScene": {"…...

pgsql14自动创建表分区

最近有pgsql的分区表功能需求&#xff0c;没想到都2025年了&#xff0c;pgsql和mysql还是没有自身支持自动创建分区表的功能 现在pgsql数据库层面还是只能用老三样的办法来处理这个问题&#xff0c;每个方法各有优劣 1. 触发器 这是最传统的方法&#xff0c;通过创建一个触发…...

cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx

现象&#xff1a; 上午正常使用cursor/vscode&#xff0c;因为需要写前端安装了nodejs16.20和vue2&#xff0c;结果下午启动前端服务无法访问&#xff0c;浏览器一直转圈。接着测试运行最简单的flask服务&#xff0c;vscode报错connect ETIMEDOUT 127.0.0.1:xx&#xff0c;要么…...

Leetcode 3553. Minimum Weighted Subgraph With the Required Paths II

Leetcode 3553. Minimum Weighted Subgraph With the Required Paths II 1. 解题思路2. 代码实现 题目链接&#xff1a;3553. Minimum Weighted Subgraph With the Required Paths II 1. 解题思路 这一题很惭愧&#xff0c;并没有自力搞定&#xff0c;是看了大佬们的解答才有…...

兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统

作者&#xff1a;Fei Lin 1 ^{1} 1, Yonglin Tian 2 ^{2} 2, Tengchao Zhang 1 ^{1} 1, Jun Huang 1 ^{1} 1, Sangtian Guan 1 ^{1} 1, and Fei-Yue Wang 2 , 1 ^{2,1} 2,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0c; 2 ^{2} 2中科院自动化研究所…...

springboot踩坑记录

之前运行好端端的项目&#xff0c;今天下午打开只是添加了一个文件之后 再运行都报Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver class Action: Conside…...

SparkSQL基本操作

以下是 Spark SQL 的基本操作总结&#xff0c;涵盖数据读取、转换、查询、写入等核心功能&#xff1a; 一、初始化 SparkSession scala import org.apache.spark.sql.SparkSession val spark SparkSession.builder() .appName("Spark SQL Demo") .master("…...

Web 架构之动静分离

文章目录 一、引言二、动静分离的原理2.1 什么是动静分离2.2 为什么要进行动静分离 三、动静分离的实现方式3.1 基于 Nginx 的动静分离3.2 基于 CDN 的动静分离 四、常见问题及解决方法4.1 缓存问题4.2 跨域问题4.3 性能监控问题 五、思维导图六、总结 一、引言 在当今的 Web 应…...

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤

20250515配置联想笔记本电脑IdeaPad总是使用独立显卡的步骤 2025/5/15 19:55 百度&#xff1a;intel 集成显卡 NVIDIA 配置成为 总是用独立显卡 百度为您找到以下结果 ?要将Intel集成显卡和NVIDIA独立显卡配置为总是使用独立显卡&#xff0c;可以通过以下步骤实现?&#xff…...

sparkSQL读入csv文件写入mysql

思路 示例 &#xff08;年龄>18改成>20) mysql的字符集问题 把user改成person “让字符集认识中文”...

大涡模拟实战:从区域尺度到街区尺度的大气环境模拟

前言&#xff1a; 随着低空经济的蓬勃发展&#xff0c;无人机、空中出租车等新型交通工具正在重塑我们的城市空间。这场静默的革命不仅带来了经济机遇&#xff0c;更对城市大气环境提出了全新挑战。在距离地面200米以下的城市冠层中&#xff0c;建筑物与大气的复杂相互作用、人…...

centos安装方式的aarch64架构下的kylinv10安装docker23.0.0

以下通过压缩包方式安装docker 因为yum方式配置各种依赖仓库太麻烦了&#xff0c;如果你不想执行 yum repolist yum clean all yum makecache那可以按照以下压缩包的方式安装任何版本的docker 1.查看glibc版本 ldd --version我这里显示2.28&#xff0c;安装docker23.0.0没问…...

单目测距和双目测距 bev 3D车道线

单目视觉测距原理 单目视觉测距有两种方式。 第一种&#xff0c;是通过深度神经网络来预测深度&#xff0c;这需要大量的训练数据。训练后的单目视觉摄像头可以认识道路上最典型的参与者——人、汽车、卡车、摩托车&#xff0c;或是其他障碍物&#xff08;雪糕桶之类&#xf…...

鸿蒙OSUniApp 实现一个精致的日历组件#三方框架 #Uniapp

使用 UniApp 实现一个精致的日历组件 前言 最近在开发一个约会小程序时&#xff0c;需要实现一个既美观又实用的日历组件。市面上虽然有不少现成的组件库&#xff0c;但都不太符合我们的设计需求。于是&#xff0c;我决定从零开始&#xff0c;基于 UniApp 自己实现一个功能完…...

【爬虫】DrissionPage-3

安装&#xff1a;4.1最新版本 pip install drissionpage --upgrade 官方文档&#xff1a;&#x1f6f0;️ 连接浏览器 | DrissionPage官网 1 Chromium对象 Chromium对象用于连接和管理浏览器。标签页的开关和获取、整体运行参数配置、浏览器信息获取等都由它进行。 1.1 默认…...

Web开发-JavaEE应用SpringBoot栈SnakeYaml反序列化链JARWAR构建打包

知识点&#xff1a; 1、安全开发-JavaEE-WAR&JAR打包&反编译 2、安全开发-JavaEE-SnakeYaml反序列化&链 一、演示案例-WEB开发-JavaEE-项目-SnakeYaml序列化 常见的创建的序列化和反序列化协议 • &#xff08;已讲&#xff09;JAVA内置的writeObject()/readObje…...

项目复习(2)

第四天 高并发优化 前端每隔15秒就发起一次请求&#xff0c;将播放记录写入数据库。 但问题是&#xff0c;提交播放记录的业务太复杂了&#xff0c;其中涉及到大量的数据库操作&#xff1a;在并发较高的情况下&#xff0c;会给数据库带来非常大的压力 使用Redis合并写请求 一…...

UE 材质基础 第一天

课程&#xff1a;虚幻引擎【UE5】材质宝典【初学者材质基础入门系列】-北冥没有鱼啊_-稍后再看-哔哩哔哩视频 随便记录一些 黑色是0到负无穷&#xff0c;白色是1到无穷 各向异性 有点类似于高光&#xff0c;可以配合切线来使用&#xff0c;R G B 相当于 X Y Z轴&#xff0c;切…...

短剧小程序系统开发源码上架,短剧项目市场分析

引言 随着短视频内容消费的爆发式增长&#xff0c;短剧小程序凭借其碎片化、强互动、低成本的特点&#xff0c;成为内容创业与资本布局的新风口。2024年以来&#xff0c;行业规模突破500亿元&#xff0c;预计2027年将超千亿17。本文将深度解析短剧小程序系统开发的技术优势、市…...

学习FineBI

FineBI 第一章 FineBI 介绍 1.1. FineBI 概述 FineBI 是帆软软件有限公司推出的一款商业智能 &#xff08;Business Intelligence&#xff09; 产品 。 FineBI 是新一代大数据分析的 BI 工具 &#xff0c; 旨在帮助企业的业务人员充分了解和利用他们的数据 。FineBI 凭借强…...

Oracle日期计算跟Mysql计算日期差距问题-导致两边计算不一致

Oracle数据库对日期做加法时&#xff0c;得到的时间是某天的12:00:00 例&#xff1a; Oracle计算 select (TO_DATE(2025-04-14, YYYY-MM-DD)1.5*365) from dual; 结果&#xff1a;2026/10/13 12:00:00Mysql计算 select DATE_ADD( str_to_date( 2025-04-14, %Y-%m-%d ), INTER…...