Flutter鸿蒙化中的Plugin
Flutter鸿蒙化中的Plugin
- 前言
- 鸿蒙项目内Plugin
- Flutter端实现
- 鸿蒙端实现
- 创建Plugin的插件类
- 注册Plugin
- 开发纯Dart的package
- 为现有插件项目添加ohos平台支持
- 创建插件
- 配置插件
- 编写插件内容
- 参考资料
前言
大家知道Flutter和鸿蒙通信方式和Flutter和其他平台通信方式都是一样的, 都是使用Platform Channel API来通信。
那么鸿蒙中这些通信的代码是写在哪里? 如何编写的了?
下面我们简单的学习下。
鸿蒙项目内Plugin
在我们开发App的过程中,可能有这样的需求:
在鸿蒙平台上特有的,并且需要调用鸿蒙原生的API来完成的。那么我们可以在在ohos平台上创建一个Plugin的方式来支持这个功能。
示例的通信方式使用:MethodChannel
的方式。
Flutter端实现
// flutter端创建一个MethodChannel的通道,通道名称必须和鸿蒙指定, 如果创建的名称不一致,会导致无法通信
final channel = const MethodChannel("com.test.channel");
// flutter给鸿蒙端发送消息
channel.invokeMapMethod("testData");
鸿蒙端实现
创建Plugin的插件类
首先我们需要创建一个插件类, 继承自FlutterPlugin
类, 并实现其中的方法
export default class TestPlugin implements FlutterPlugin {
// 通道private channel?: MethodChannel;
//获取唯一的类名 类似安卓的Class<? extends FlutterPlugin ts无法实现只能用户自定义getUniqueClassName(): string {return 'TestPlugin'}// 当插件从engine上分离的时候调用onDetachedFromEngine(binding: FlutterPluginBinding): void {this.channel?.setMethodCallHandler(null);}// 当插件挂载到engine上的时候调用onAttachedToEngine(binding: FlutterPluginBinding): void {this.channel = new MethodChannel(binding.getBinaryMessenger(), "com.test.channel");// 给通道设置回调监听 this.channel.setMethodCallHandler({onMethodCall(call: MethodCall, result: MethodResult) {switch (call.method) {case "testData":console.log(`接收到flutter传递过来的参shu ===================`)break;default:result.notImplemented();break;}}})}
}
注册Plugin
我们创建完Plugin了, 我们还需要再EntryAbility
中去注册我们的插件
export default class EntryAbility extends FlutterAbility {configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)this.addPlugin(new TestPlugin());}
}
完成上述两步之后,我们就可以使用这个专属鸿蒙的插件来完成鸿蒙上特有的功能了。
开发纯Dart的package
我们知道,flutter_flutter的仓库对于纯Dart开发的package是完全支持的, 对于纯Dart的package我们主要关注Dart的版本支持。
开发纯Dart的命令:flutter create --template=package hello
对于具体如何开发纯Dart的package,Flutter官方已经讲的非常详细, 开发,集成详细 可以参考官方文档。Flutter中的Package开发
为现有插件项目添加ohos平台支持
在我们开发Flutter项目适配鸿蒙平台的时候,会有些插件还没有适配ohos平台, 这个时候我们等华为适配, 或者我们自己下载插件的源码, 然后我们自己在源码中编写适配ohos平台的代码
下面以image_picker
插件为示例,来学习下如何为已有插件项目添加ohos的平台支持
创建插件
首先我们需要下载image_picker
源码, 然后使用Android studio打开flutter项目。 可以查看到项目的结构
然后通过命令行进入到项目根目录, 执行命令:flutter create . --template=plugin --platforms=ohos
执行完后的目录结构如下:
配置插件
我们创建完ohos平台的插件之后, 我们需要再Plugin工程的pubspec.yaml
配置文件中配置ohos平台的插件。
当我们配置完成之后, 我们接下来就可以开始编写ohos平台插件相关内容了。
编写插件内容
在我们编写ohos平台的插件内容时, 我们首先需要知道这个插件是通过什么通道, 调用什么方法来和个个平台通信的。 ohos平台的通道名称、调用方法尽量和原来保持一致,有助于理解。
// 执行flutter指令创建plugin插件时, 会自动创建这个类
export default class ImagesPickerPlugin implements FlutterPlugin, MethodCallHandler, AbilityAware {private channel: MethodChannel | null = null;private pluginBinding: FlutterPluginBinding | null = null;// 当前处理代理对象private delegate: ImagePickerDelegate | null = nullconstructor() {}getUniqueClassName(): string {return "ImagesPickerPlugin"}onAttachedToEngine(binding: FlutterPluginBinding): void {// 后续用到的页面context,都是需要重binding对象中获取, 如果你直接this.getcontext 等方法获取, 可能不是页面的contextthis.pluginBinding = binding;this.channel = new MethodChannel(binding.getBinaryMessenger(), "chavesgu/images_picker");this.channel.setMethodCallHandler(this)}onDetachedFromEngine(binding: FlutterPluginBinding): void {this.pluginBinding = null;if (this.channel != null) {this.channel.setMethodCallHandler(null)}}// 插件挂载到ablitity上的时候onAttachedToAbility(binding: AbilityPluginBinding): void {if (!this.pluginBinding) {return}this.delegate = new ImagePickerDelegate(binding.getAbility().context, this.pluginBinding.getApplicationContext());}onDetachedFromAbility() {}onMethodCall(call: MethodCall, result: MethodResult): void {if (call.method === "pick") {// 解析参数let count = call.argument("count") as number;// let language = call.argument("language") as string;let pickType = call.argument("pickType") as string;// let supportGif = call.argument("gif") as boolean;// let maxTime = call.argument("maxTime") as number;let maxSize = call.argument("maxSize") as number;if (this.delegate !== null) {this.delegate.pick(count, pickType, maxSize, result)}} else if (call.method === "saveImageToAlbum" || call.method === "saveVideoToAlbum") {// 保存图片let filePath = call.argument("path") as string; // 图片路径if (this.delegate !== null) {this.delegate.saveImageOrVideo(filePath, call.method === "saveImageToAlbum", result)}} else if (call.method === "openCamera") {let pickType = call.argument("pickType") as string;let maxSize = call.argument("maxSize") as number;if (this.delegate !== null) {this.delegate.openCamear(pickType, maxSize, result)}} else {result.notImplemented()}}
}
注意:这个插件内开发代码是没有代码提示的, 也不会自动检车报错, 只有你运行测试demo时, 编译时才会报错,所以建议大家把插件的功能在一个demo中完成,在把代码拷贝过来。
逻辑实现代码:
import ArrayList from '@ohos.util.ArrayList';
import common from '@ohos.app.ability.common';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
import { BusinessError } from '@kit.BasicServicesKit';
import picker from '@ohos.multimedia.cameraPicker';
import camera from '@ohos.multimedia.camera';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import { fileUri } from '@kit.CoreFileKit';
import FileUtils from './FileUtils'
import fs from '@ohos.file.fs';
import {MethodResult,
} from '@ohos/flutter_ohos';
import abilityAccessCtrl, { PermissionRequestResult } from '@ohos.abilityAccessCtrl';export default class ImagePickerDelegate {// 当前UIAblitity的contextprivate context: common.Context// 插件绑定的contextprivate bindContext: common.Context// 构造方法constructor(context: common.Context, bindContext: common.Context) {this.context = contextthis.bindContext = bindContext}// 选择相册图片和视频pick(count: number, pickType: string, maxSize: number, callback: MethodResult) {// 创建一个选择配置const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();// 媒体选择类型let mineType: photoAccessHelper.PhotoViewMIMETypes = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;if (pickType === "PickType.all") {mineType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;} else if (pickType === "PickType.video") {mineType = photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE;}photoSelectOptions.MIMEType = mineTypephotoSelectOptions.maxSelectNumber = count; // 选择媒体文件的最大数目let uris: Array<string> = [];const photoViewPicker = new photoAccessHelper.PhotoViewPicker();// 通过photoViewPicker对象来打开相册图片photoViewPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {uris = photoSelectResult.photoUris;console.info('photoViewPicker.select to file succeed and uris are:' + uris);this.hanlderSelectResult(uris, callback)}).catch((err: BusinessError) => {console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);})}// 处理打开相机照相/录制async openCamear(type: string, maxSize: number, callback: MethodResult) {// 定义一个媒体类型数组let mediaTypes: Array<picker.PickerMediaType> = [picker.PickerMediaType.PHOTO];if (type === "PickType.all") {mediaTypes = [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO]} else if (type === "PickType.video") {mediaTypes = [picker.PickerMediaType.VIDEO]}try {let pickerProfile: picker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK};let pickerResult: picker.PickerResult = await picker.pick(this.context,mediaTypes, pickerProfile);console.log("the pick pickerResult is:" + JSON.stringify(pickerResult));// 获取uri的路径和媒体类型let resultUri = pickerResult["resultUri"] as stringlet mediaTypeTemp = pickerResult["mediaType"] as string// 需要把uri转换成沙河路径let realPath = FileUtils.getPathFromUri(this.bindContext, resultUri);if (mediaTypeTemp === "video") {// 需要获取缩略图callback.success([{thumbPath: realPath, path: realPath, size: maxSize}])} else {// 图片无需设置缩略图callback.success([{thumbPath: realPath, path: realPath, size: maxSize}])}} catch (error) {let err = error as BusinessError;console.error(`the pick call failed. error code: ${err.code}`);}}// 处理保存图片async saveImageOrVideo(path: string, isImage: boolean, callback: MethodResult) {let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(this.context,['ohos.permission.WRITE_IMAGEVIDEO', 'ohos.permission.READ_IMAGEVIDEO'],async (err: BusinessError, data: PermissionRequestResult) => {if (err) {console.log(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);} else {console.info('data:' + JSON.stringify(data));console.info('data permissions:' + data.permissions);console.info('data authResults:' + data.authResults);//转换成urilet uriTemp = fileUri.getUriFromPath(path);//打开文件let fileTemp = fs.openSync(uriTemp, fs.OpenMode.READ_ONLY);//读取文件大小let info = fs.statSync(fileTemp.fd);//缓存照片数据let bufferImg: ArrayBuffer = new ArrayBuffer(info.size);//写入缓存fs.readSync(fileTemp.fd, bufferImg);//关闭文件流fs.closeSync(fileTemp);let phHelper = photoAccessHelper.getPhotoAccessHelper(this.context);try {const uritemp = await phHelper.createAsset(isImage ? photoAccessHelper.PhotoType.IMAGE :photoAccessHelper.PhotoType.VIDEO, isImage ? 'jpg' : "mp4"); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源const file = await fs.open(uritemp, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);await fs.write(file.fd, bufferImg);await fs.close(file.fd);callback.success(true);} catch (error) {console.error(`error=========${JSON.stringify(error)}`)callback.success(false);}}});}// 处理选中结果hanlderSelectResult(uris: Array<string>, callback: MethodResult) {// 定义一个path数组let pathList: ArrayList<string> = new ArrayList();for (let path of uris) {// if (path.search("video") < 0) {// path = await this.getResizedImagePath(path, this.pendingCallState.imageOptions);// }this.getVideoThumbnail(path)let realPath = FileUtils.getPathFromUri(this.bindContext, path);pathList.add(realPath);}let uriModels: UriModel[] = [];pathList.forEach(element => {uriModels.push({thumbPath: element,path: element,size: 500})});callback.success(uriModels)}// 获取视频的缩略图async getVideoThumbnail(uri: string) {//建立视频检索条件,用于获取视频console.log("开始获取缩略图==========")let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();predicates.equalTo(photoAccessHelper.PhotoKeys.URI, uri);let fetchOption: photoAccessHelper.FetchOptions = {fetchColumns: [],predicates: predicates};// let size: image.Size = { width: 720, height: 720 };let phelper = photoAccessHelper.getPhotoAccessHelper(this.context)let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phelper.getAssets(fetchOption);console.log(`fetchResult=========${JSON.stringify(fetchResult)}`)let asset = await fetchResult.getFirstObject();console.info('asset displayName = ', asset.displayName);asset.getThumbnail().then((pixelMap) => {console.info('getThumbnail successful ' + pixelMap);}).catch((err: BusinessError) => {console.error(`getThumbnail fail with error: ${err.code}, ${err.message}`);});}
}// 定义一个返回的对象
interface UriModel {thumbPath: string;path: string;size: number;
}
工具类代码 :
/** Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
import common from '@ohos.app.ability.common';
import fs from '@ohos.file.fs';
import util from '@ohos.util';
import Log from '@ohos/flutter_ohos/src/main/ets/util/Log';const TAG = "FileUtils";export default class FileUtils {static getPathFromUri(context: common.Context | null, uri: string, defExtension?: string) {Log.i(TAG, "getPathFromUri : " + uri);let inputFile: fs.File;try {inputFile = fs.openSync(uri);} catch (err) {Log.e(TAG, "open uri file failed err:" + err)return null;}if (inputFile == null) {return null;}const uuid = util.generateRandomUUID();if (!context) {return}{const targetDirectoryPath = context.cacheDir + "/" + uuid;try {fs.mkdirSync(targetDirectoryPath);let targetDir = fs.openSync(targetDirectoryPath);Log.i(TAG, "mkdirSync success targetDirectoryPath:" + targetDirectoryPath + " fd: " + targetDir.fd);fs.closeSync(targetDir);} catch (err) {Log.e(TAG, "mkdirSync failed err:" + err);return null;}const inputFilePath = uri.substring(uri.lastIndexOf("/") + 1);const inputFilePathSplits = inputFilePath.split(".");Log.i(TAG, "getPathFromUri inputFilePath: " + inputFilePath);const outputFileName = inputFilePathSplits[0];let extension: string;if (inputFilePathSplits.length == 2) {extension = "." + inputFilePathSplits[1];} else {if (defExtension) {extension = defExtension;} else {extension = ".jpg";}}const outputFilePath = targetDirectoryPath + "/" + outputFileName + extension;const outputFile = fs.openSync(outputFilePath, fs.OpenMode.CREATE);try {Log.i(TAG, "copyFileSync inputFile fd:" + inputFile.fd + " outputFile fd:" + outputFile.fd);fs.copyFileSync(inputFile.fd, outputFilePath);} catch (err) {Log.e(TAG, "copyFileSync failed err:" + err);return null;} finally {fs.closeSync(inputFile);fs.closeSync(outputFile);}return outputFilePath;}}
}
编写完上述代码就可以运行example工程去测试相关功能了。 当测试完成之后 , 我们可以把整个源码工程拷贝到flutter工程中, 通过集成本地package的方式来集成这个package。或者你可以在发一个新的pacage到pub.dev上, 然后在按照原有方式集成即可。
参考资料
Flutter官方的package开发和使用
开发Plugin
相关文章:
Flutter鸿蒙化中的Plugin
Flutter鸿蒙化中的Plugin 前言鸿蒙项目内PluginFlutter端实现鸿蒙端实现创建Plugin的插件类注册Plugin 开发纯Dart的package为现有插件项目添加ohos平台支持创建插件配置插件编写插件内容 参考资料 前言 大家知道Flutter和鸿蒙通信方式和Flutter和其他平台通信方式都是一样的&…...
Ubuntu 22.04.5 修改IP
Ubuntu22.04.5使用的是netplan管理网络,因此需要在文件夹/etc/netplan下的01-network-manager-all.yaml中修改,需要权限,使用sudo vim或者其他编辑器,修改后的内容如下: # Let NetworkManager manage all devices on …...
后端:MyBatis
文章目录 1. MyBatis1-1. Mybatis 工具类的封装1-2. Mybatis 通过集合或实体类传递参数-实现插入数据(增)1-3. MyBatis 实现删除数据(删)1-4. MyBatis 实现修改数据(改)1-5. MyBatis 实现查询数据(查) 2. MyBatis 配置文件中的一些标签和属性2-1.environments标签2-2. dataSour…...
CBAM-2018学习笔记
名称: Convolutional Block Attention Module (CBAM) 来源: CBAM: Convolutional Block Attention Module 相关工作: #ResNet #GoogleNet #ResNeXt #Network-engineering #Attention-mechanism 创新点: 贡献: 提…...
HTML根元素<html>的语言属性lang:<html lang=“en“>
诸神缄默不语-个人CSDN博文目录 在编写HTML页面时,通常会看到<html lang"en">这行代码,特别是在网页的开头部分,就在<!DOCTYPE html>后面。许多开发者可能对这个属性的含义不太了解,它到底有什么作用&…...
解决github无法clone的问题
问题背景 (base) ~$ git clone https://github.com/isaac-sim/IsaacLab.git 正克隆到 IsaacLab... fatal: 无法访问 https://github.com/isaac-sim/IsaacLab.git/:gnutls_handshake() failed: Error in the pull function.解决办法 我使用了代理,需要配…...
第1章:Python TDD基础与乘法功能测试
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
【华为路由/交换机的ftp文件操作】
华为路由/交换机的ftp文件操作 PC:10.0.1.1 R1:10.0.1.254 / 10.0.2.254 FTP:10.0.2.1 S1:无配置 在桌面创建FTP-Huawei文件夹,里面创建config/test.txt。 点击上图中的“启动”按钮。 然后ftp到server,…...
【HBuilderX 中 Git 的使用】
目录: 一:安装必要的版本控制工具二:把Github上的项目克隆到本地三:将本地的项目上传到Github上 一:安装必要的版本控制工具 1️⃣ 安装 TortoiseGit 工具,下载地址:https://tortoisegit.org/do…...
语言模型的价值定位与技术突破:从信息处理到创新认知
标题:语言模型的价值定位与技术突破:从信息处理到创新认知 文章信息摘要: 当前语言模型的核心价值主要体现在信息综合与处理能力上,用户友好的交互界面是其成功关键。在模型计算机制方面,推理能力的实现包括chain-of-…...
使用Websocket进行前后端实时通信
1、引入jar,spring-websocket-starter <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 2、配置websocket config import org.springframe…...
【Leetcode 热题 100】70. 爬楼梯
问题背景 假设你正在爬楼梯。需要 n n n 阶你才能到达楼顶。 每次你可以爬 1 1 1 或 2 2 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 数据约束 1 ≤ n ≤ 45 1 \le n \le 45 1≤n≤45 解题过程 昨天刚刚当成扩展题做过,今天遇到了再写一次。…...
STM32更新程序OTA
STM32的OTA(Over-The-Air)更新程序是一种通过无线通信方式,为设备分发新软件、配置甚至更新加密密钥的技术。以下是关于STM32 OTA更新程序的详细介绍: 一、OTA升级流程 STM32的OTA升级流程通常包括以下几个关键步骤:…...
【海贼王航海日志:前端技术探索】一篇文章带你走进JavaScript(三)
目录 1 -> WebAPI背景知识 1.1 -> 什么是WebAPI 1.2 -> 什么是API 1.3 -> 什么是DOM 1.3.1 -> DOM树 2 -> 获取元素 2.1 -> querySelector 2.2 -> querySelectorAll 3 -> 事件初识 3.1 -> 基本概念 3.2 -> 事件三要素 4 -> 操…...
计算机创造的奇迹——C语言
一.简介 C语言是一种较早的程序设计语言,诞生于1972年的贝尔实验室。1972 年,Dennis Ritchie 设计了C语言,它继承了B语言的许多思想,并加入了数据类型的概念及其他特性。 尽管C 语言是与 UNIX 操作系统一起被开发出来的ÿ…...
TypeScript - 利用GPT辅助学习
TypeScript 一、基础1. 安装 TypeScript2. 创建你的第一个 TypeScript 文件3. 编译 TypeScript 代码4. 变量声明与类型注解5. 函数与类型注解6. 总结 二、进阶常用类型1. 类型别名2. 对象类型3. 类型断言4.typeof 操作符 高级类型1. 类2. 交叉类型3. 泛型与 keyof4. 索引签名类…...
Node.js 与 JavaScript 是什么关系
JavaScript 是一种编程语言,而 Node.js 是 JavaScript 的一个运行环境,它们在不同的环境中使用,具有一些共同的语言基础,但也有各自独特的 API 和模块,共同推动着 JavaScript 在前后端开发中的广泛应用。 一、基础语言…...
Spring MVC:设置响应
目录 引言 1. 返回静态页面 1.1 Spring 默认扫描路径 1.2 RestController 1.2.1 Controller > 返回页面 1.2.2 ResponseBody 2. 返回 HTML 2.1 RequestMapping 2.1.1 produces(修改响应的 Content-Type) 2.1.2 其他属性 3. 返回 JSON 4. 设置状态码 4.1 HttpSer…...
c#实现当捕获异常时自动重启程序
首先,需要说明这并不是一个推荐的做法,只有在你确实有这样的需求时才考虑这么做。 以下是AI的回答,为什么不推荐这么做,供参考。 在C#中,如果你在catch语句中尝试重启程序自身,可能会遇到以下几个问题&…...
游戏引擎学习第84天
仓库:https://gitee.com/mrxiao_com/2d_game_2 我们正在试图弄清楚如何完成我们的世界构建 上周做了一些偏离计划的工作,开发了一个小型的背景位图合成工具,这个工具做得还不错,虽然是临时拼凑的,但验证了背景构建的思路。这个过…...
Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )
一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化: 文件是存储数据的一种非常基本且重要的方式。通过文件,我们可 以将程序运行时产生的数据永久保存下来,以便将来使用。 跨平台兼容性: 文件是一种通用…...
“AI 大模型内容安全审核软件系统:守护网络世界的卫士
在如今这个信息爆炸的互联网时代,网络上的内容那是五花八门、层出不穷。这时候,咱就得靠 AI 大模型内容安全审核软件系统来给咱把把关了。 咱就说社交媒体平台吧,每天都有海量的用户在上面发布文字、图片、视频啥的。要是没有一个靠谱的审核系…...
快速入门Python的异步库:asyncio
目录 异步 Python asyncio 1. async 关键字 2. await 关键字 3. asyncio.run() 4. asyncio.sleep() 5. 协程 程序执行流程 可以被等待的异步 协程 任务 Futures 任务 asyncio.create_task() await 和任务结果 Reference 异步 我们首先先来谈谈异步,…...
大美祖国-使用Java盘点那些在地名中出现最多的汉字
目录 前言 一、地名数据准备 1、全国地名数据 二、使用Java进行汉字统计 1、汉字数据统计 2、汉字分割统计 三、浅谈地名汉字名次及其意义 1、山、城、江、河 2、安、平、宁 3、地名中的方位 四、总结 前言 在中国这片古老而又年轻的土地上,地名不仅仅是地…...
华为OD机试E卷 --羊、狼、农夫过河--24年OD统一考试(Java JS Python C C++)
文章目录 题目描述输入描述输出描述用例题目解析JS算法源码Java算法源码python算法源码c算法源码c++算法源码题目描述 羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。 要求求出不损失羊情况…...
Java - WebSocket
一、WebSocket 1.1、WebSocket概念 WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接,这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发,并于2…...
JavaWeb开发(十五)实战-生鲜后台管理系统(二)注册、登录、记住密码
1. 生鲜后台管理系统-注册功能 1.1. 注册功能 (1)创建注册RegisterServlet,接收form表单中的参数。 (2)service创建一个userService处理业务逻辑。 (3)RegisterServlet将参数传递给ser…...
【深度学习】利用Java DL4J 训练金融投资组合模型
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s…...
【MySQL篇】事务的认识以及四大特性
何为事务? 事务(Transaction)是指一组操作的集合,这些操作要么全部执行成功,要么全部不执行。事务通常用于保证数据库的一致性、完整性和可靠性,确保数据的完整性与正确性。 有效避免部分执行࿰…...
CSS 网络安全字体
适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体: Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…...
实战演示:利用ChatGPT高效撰写论文
在当今学术界,撰写论文是一项必不可少的技能。然而,许多研究人员和学生在写作过程中常常感到困惑和压力。幸运的是,人工智能的快速发展为我们提供了新的工具,其中ChatGPT便是一个优秀的选择。本文将通过易创AI创作平台,…...
显卡(Graphics Processing Unit,GPU)架构详细解读
显卡架构主要分为两大类:GPU 核心架构(也称为图形处理单元架构)和显卡的其他组件(如内存、控制器、输出接口等)。本篇文章将对显卡架构进行详细分析,重点介绍 GPU 核心架构、显卡计算单元、显存结构、显卡管…...
OpenCV相机标定与3D重建(63)校正图像的畸变函数undistort()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 转换图像以补偿镜头畸变。 该函数通过变换图像来补偿径向和切向镜头畸变。 此函数仅仅是 initUndistortRectifyMap(使用单位矩阵 R…...
人工智能-机器学习之多分类分析(项目实战二-鸢尾花的多分类分析)
Softmax回归听名字,依然好像是做回归任务的算法,但其实它是去做多分类任务的算法。 篮球比赛胜负是二分类,足球比赛胜平负就是多分类 识别手写数字0和1是二分类,识别手写数字0-9就是多分类 Softmax回归算法是一种用于多分类问题…...
【JDBC】数据库连接的艺术:深入解析数据库连接池、Apache-DBUtils与BasicDAO
文章目录 前言🌍 一.连接池❄️1. 传统获取Conntion问题分析❄️2. 数据库连接池❄️3.连接池之C3P0技术🍁3.1关键特性🍁3.2配置选项🍁3.3使用示例 ❄️4. 连接池之Druid技术🍁 4.1主要特性🍁 4.2 配置选项…...
【Envi遥感图像处理】006:影像融合(高光谱+多光谱)的方法
文章目录 一、图像融合概述二、加载数据三、图像融合操作四、结果比对五、高光谱与多光谱一、图像融合概述 图像融合是指将不同类型传感器的影像进行融合,既能使图向具有较高的空间分辨率,又具有多光谱的特性。 二、加载数据 三、图像融合操作 在ENvi中,图像融合使用的工具…...
C语言内存之旅:从静态到动态的跨越
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一 动态内存管理的必要性二 动态…...
Git本地搭建
Git本地搭建 (项目突然不给创建仓库了,为了方便管理项目只能自己本地搭建git服务) 为了在本地搭建Git环境并实现基本的Git操作,步骤如下: 安装Git软件 Windows:从Git官方网站下载并安装适用于Windows…...
电商|基于java的农业电商系统(源码+数据库+文档)
农业电商系统 目录 基于java的农业电商系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 前台: 后台: 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️…...
c语言分支和循环
文章目录 前言 一、分支结构 if语句 switch语句 三目运算符 二、循环结构 while循环 do-while循环 for循环 循环嵌套 循环控制语句 总结 前言 分支和循环是C语言中非常重要的控制结…...
大象机器人发布首款穿戴式数据采集器myController S570,助力具身智能数据收集!
myController S570 具有较高的数据采集速度和远程控制能力,大大简化了人形机器人的编程。 myController S570 是一款可移动的轻量级外骨骼,具有 14 个关节、2 个操纵杆和 2 个按钮,它提供高数据采集速度,出色的兼容性,…...
【HarmonyOS NEXT】华为分享-碰一碰开发分享
关键词:鸿蒙、碰一碰、systemShare、harmonyShare、Share Kit 华为分享新推出碰一碰分享,支持用户通过手机碰一碰发起跨端分享,可实现传输图片、共享wifi等。我们只需调用系统 api 传入所需参数拉起对应分享卡片模板即可,无需对 U…...
基于python+Django+mysql鲜花水果销售商城网站系统设计与实现
博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育、辅导。 所有项目都配有从入门到精通的基础知识视频课程ÿ…...
Linux C\C++方式下的文件I/O编程
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 Lin…...
2025寒假备战蓝桥杯01---朴素二分查找的学习
文章目录 1.暴力方法的引入2.暴力解法的思考 与改进3.朴素二分查找的引入4.朴素二分查找的流程5.朴素二分查找的细节6.朴素二分查找的题目 1.暴力方法的引入 对于下面的这个有序的数据元素的组合,我们的暴力解法就是挨个进行遍历操作,一直找到和我们的这…...
AI时代:弯道超车的新思维与实践路径
大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…...
HunyuanDiT代码笔记
HunyuanDiT 是由腾讯发布的文生图模型,适配中英双语。 在模型方面的改进,主要包括: transformer结构text encoderpositional encoding Improving Training Stability To stabilize training, we present three techniques: We add layer nor…...
C++: Dtrees:load(constg String filepath, const String nodeName)中nodeName参数含义
1. nodeName 的作用 当你保存模型时,整个决策树会被序列化到一个 XML 或 YAML 文件中。nodeName 是加载时指定的一个逻辑路径,用于从文件中找到某个节点或子结构,而不是存储在文件中的字段。如果你不指定 nodeName,OpenCV 默认会…...
项目练习:若依后台管理系统-后端服务开发步骤(springboot单节点版本)
文章目录 1、用Maven搭建项目脚手架,父子工程依赖。2、引入SpringBoot Web容器依赖3、引入Mybatisdruid依赖4、实现接口查询数据5、整合logback日志功能 1、用Maven搭建项目脚手架,父子工程依赖。 root模块的pom添加plugin配置 <build><plugins…...
Ubuntu安装docker
snap install docker # version 27.2.0, or apt install podman-docker # version 3.4.4ds1-1ubuntu1.22.04.2 apt install docker.io # version 24.0.7-0ubuntu2~22.04.1 我应该安装哪一个,部署企业级应用? 在部署企业级应用时,选择合适的容器化…...