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

低代码组件扩展方案在复杂业务场景下的设计与实践

组件是爱速搭的前端页面可视化模块的核心能力之一,它将前端研发人员从无休止的页面样式微调和分辨率兼容工作中解放了出来。

目前,爱速搭通过内置的上百种功能组件(120+),基本可以覆盖大部分中后台页面的可视化设计场景。组件的相关的设计理念和实现细节我们可以在前文面向复杂业务场景下的低代码平台组件设计与实践分享中看到。

实际开发的过程中,前端研发人员往往会面临大量定制 UI 或者有极为复杂交互的页面,使用单一的组件实现会比较困难。因此,爱速搭提供了自定义组件扩展机制,让开发人员可以定制化开发功能组件和业务组件,丰富可视化搭建物料,从而实现复杂业务场景的页面的设计与搭建。 

目前爱速搭已支持三种自定义组件扩展方式:Custom 自定义组件、线上版自定义组件和 NPM 组件扩展包对于交互和功能较为简单的自定义组件,可以使用 Custom 自定义组件和线上版自定义组件;而对于复杂的功能,我们建议使用 NPM 组件扩展包方式实现。

本文主要介绍 NPM 组件扩展包的设计原理和开发实践。

1        组件扩展包功能简介

NPM 组件扩展包是一种通过导入 NPM 包来扩展和补充爱速搭组件物料的机制,支持本地 IDE 纯 Coding 的开发模式,自由度较高,可用于开发任何复杂业务场景的自定义组件。

为了方便用户在本地开发自定义组件,百度智能云低代码平台爱速搭提供了一套自定义组件扩展包的开发工具(amis-widget-cli),支持各类自定义组件模板的下载、本地预览&调试、平台预览(linkDebug)和编译等一系列工具。

NPM组件扩展包主要包括如下四个功能点:

  • 支持同时扩展多个自定义组件

一个组件扩展包中可放置多个不同类型的自定义组件,比如 multiple-custom-widget-template 内包括三种技术栈的自定义组件。如果我们将该组件添加到爱速搭应用中,会同时导入 react-info-card、hello-jquery、vue-info-card 三种不同类型的自定义组件。

  • 支持多种技术栈

爱速搭的组件扩展支持 Vue 2.0、Vue 3.0、React、jQuery 和 UniApp 等多种技术栈,用户可以使用自己熟悉的一种技术栈来开发自定义组件。

  • 支持三种自定义组件本地预览&调试方式

  1. 组件预览模式(preview): 用于预览当前自定义组件内容。
  2. 本地开发模式(dev):在本地页面设计器中预览&调试自定义组件,用于确认页面设计器能否正常使用和展示当前自定义组件。

  3. 外链调试(linkDebug):在爱速搭中预览&调试本地的自定义组件,用于确认爱速搭平台中能否正常使用和展示当前自定义组件。

  • 支持多种类型的自定义组件扩展

  1. amis 自定义组件:用于扩展和补充 web 应用/普通页面的自定义组件物料。

  2. 小程序自定义组件:用于扩展和补充小程序应用页面的自定义组件物料。

  3. 快应用自定义组件:用于扩展和补充快应用和快应用卡片的自定义组件物料。

2        组件扩展包工作原理

NPM 组件扩展包的运行框架图如下所示

图片

2.1        NPM 自定义组件的两个核心模块

一个完整的自定义组件包含两个功能模块:amis 渲染器和 amis-editor 插件:

  • 「amis 渲染器」是页面渲染时需要调取的模块,如果没有它则意味着页面中不能正常显示自定义组件内容。

  • 「amis-editor 插件」是打通页面设计器的关键功能模块,可用于设置自定义组件在页面设计器中的组件物料面板中的显示位置(哪个分类下展示,展示顺序是什么,描述信息是什么等),也可用于设置首次插入页面时的初始数据是什么,所有和页面设计器关联的数据都在 amis-editor 插件中。

2.2        本地开发 NPM 组件扩展包

开发 NPM 组件扩展包时会用到两个工具: amis-widget、amis-widget-cli。

其中 amis-widget 提供用于注册 amis 渲染器 和 amis-editor 插件的方法,而 amis-widget-cli 是用于开发 amis 自定义组件的脚手架,其核心是基于 AKFun (https://github.com/wibetter/akfun)现有的前端工程能力,为用户提供自定义组件模板下载、预览&调试、编译和多技术栈支持等功能。

图片

用户在本地完成自定义组件的编码后,可通过构建工具(使用 amis-widget-cli 或者 webpack、rollup 等构建工具)进行编译,将自定义 amis 渲染器和自定义 amis-editor 插件分别打包成静态 js 脚本,并发布成一个 NPM 包。

关于开发 NPM 组件扩展包的一些建议:

  • NPM 扩展包编译时默认会剔除第三方 npm 依赖,使用多个组件扩展包时,第三方依赖只会打包一次,避免平台运行时重复加载第三方依赖功能的代码。

  • 尽可能将同一类型的自定义组件放在一个组件扩展包中,多个自定义组件或者多个组件扩展包用到的公共模块建议封装成单独的NPM模块,最后通过 NPM 依赖的形式进行引用。

2.3        在应用中添加 NPM 组件扩展包

爱速搭支持组织级和应用级的 NPM 组件扩展包,组织级添加的组件扩展包,在组织下所有应用中可见可用,但不可编辑(不能设置显隐、排序和分类等操作)。

图片

在组织或者应用中添加 NPM 组件扩展包后会自动触发构建工作,将当前组织或应用中的所有组件扩展包分别打包成来两个 js 静态脚本(渲染器和插件),存放到平台默认存储对象中,并将静态脚本路径分别记录在应用中的 npmCustomComponentSrc 和 npmCustomPluginSrc 上。之所以打包成两个 js 静态脚本,是为了在应用运行时环境仅加载渲染器脚本,避免加载多余的设计态脚本代码。

3        多技术栈支持

爱速搭和 amis 属于 React 技术栈体系,对于其他技术栈的自定义组件是不能直接在平台运行的。因此我们在注册自定义组件时,支持将非 React 技术栈的自定义组件先包裹成 React 组件对象后再进行注册。

下面我们以 Vue 2.0 和 Vue 3.0 为例,展示转换为 React 组件的关键方法。

图片

将 Vue 2.0 组件对象转换成 React 组件关键方法

import React from 'react';
import ReactDOM from 'react-dom';
import Vue from 'vue';
import { ScopedContext, IScopedContext, RendererProps } from 'amis-core';
import { extendObject } from '../utils';export function createVue2Component(vueObj: any) {
if (!vueObj || (typeof vueObj !== 'function' && typeof vueObj !== 'object')) {
return;}
class VueFactory extends React.Component<RendererProps> {domRef: any;vm: any;isUnmount: boolean;static contextType = ScopedContext;constructor(props: RendererProps, context: IScopedContext) {
super(props);
this.domRef = React.createRef();const scoped = context;scoped.registerComponent(this);this.resolveAmisProps = this.resolveAmisProps.bind(this);
this.renderChild = this.renderChild.bind(this);}componentDidMount() {
const { amisData, amisFunc } = this.resolveAmisProps();
const { data, ...rest } = (vueObj =typeof vueObj === 'function' ? new vueObj() : vueObj);
const vueData = typeof data === 'function' ? data() : data;
const curVueData = extendObject(vueData, amisData);
this.vm = new Vue({...rest,
data: () => curVueData,props: extendObject(amisFunc, rest.props || {}),});Object.keys(amisFunc).forEach((key) => {
this.vm.$props[key] = amisFunc[key];
if (key === 'render') {
this.vm.$props['renderChild'] = (schemaPosition: string,childSchema: any,insertElemId: string,) => {
this.renderChild(schemaPosition, childSchema, insertElemId);};}});
this.domRef.current.appendChild(this.vm.$mount().$el);}renderChild(schemaPosition: string,childSchema: any,insertElemId: string,) {let childElemCont = null;
if (this.props['render'] && childSchema && insertElemId) {
const childElem = this.props['render'](schemaPosition, childSchema);childElemCont = ReactDOM.render(childElem,document.getElementById(insertElemId),);}
return childElemCont;}componentDidUpdate() {
if (!this.isUnmount) {
const { amisData } = this.resolveAmisProps();
if (this.vm) {Object.keys(amisData).forEach((key) => {
this.vm[key] = amisData[key];});
this.vm.$forceUpdate();}}}componentWillUnmount() {
this.isUnmount = true;
const scoped = this.context as IScopedContext;scoped.unRegisterComponent(this);
this.vm.$destroy();}resolveAmisProps() {let amisFunc: any = {};let amisData: any = {};Object.keys(this.props).forEach((key) => {
const value = this.props[key];
if (typeof value === 'function') {amisFunc[key] = value;} else {amisData[key] = value;}});
return { amisData, amisFunc };}render() {
return <div ref={this.domRef}></div>;}}return VueFactory;
}
  • 将 Vue 3.0 组件对象转换成 React 组件关键方
import React from 'react';
import { ScopedContext, IScopedContext, RendererProps } from 'amis-core';
import { createApp, getCurrentInstance, ref, isProxy, shallowRef } from 'vue';
import { isObject, extendObject } from '../utils';export function createVue3Component(vueObj: any) {if (!vueObj || (typeof vueObj !== 'function' && typeof vueObj !== 'object')) {return;}class VueFactory extends React.Component<RendererProps> {domRef: any;app: any;vm: any;isUnmount: boolean;static contextType = ScopedContext;constructor(props: RendererProps, context: IScopedContext) {super(props);this.domRef = React.createRef();const scoped = context;scoped.registerComponent(this);this.resolveAmisProps = this.resolveAmisProps.bind(this);}componentDidMount() {const { amisData, amisFunc } = this.resolveAmisProps();const { data, ...rest } = (vueObj =typeof vueObj === 'function' ? new vueObj() : vueObj);const vueData = typeof data === 'function' ? data() : data;const curVueData = extendObject(vueData, amisData);this.app = createApp({data: () => curVueData,...rest,props: extendObject(amisFunc, rest.props || {}),});this.vm = this.app.mount(this.domRef.current);}componentDidUpdate() {if (!this.isUnmount) {const { amisData } = this.resolveAmisProps();if (this.vm) {Object.keys(amisData).forEach((key) => {this.vm[key] = amisData[key];});this.vm.$forceUpdate();}}}componentWillUnmount() {this.isUnmount = true;const scoped = this.context as IScopedContext;scoped.unRegisterComponent(this);this.app.unmount();}resolveAmisProps() {let amisFunc: any = {};let amisData: any = {};Object.keys(this.props).forEach((key) => {const value = this.props[key];if (typeof value === 'function') {amisFunc[key] = value;} else {if (isProxy(value)) {amisData[key] = shallowRef(value);} else if (isObject(value)) {amisData[key] = ref(value);} else {amisData[key] = value;}}});return { amisData, amisFunc };}render() {return <div ref={this.domRef}></div>;}}return VueFactory;
}

4        小程序和快应用自定义组件扩展机制

在实际的开发过程中,往往会存在 H5、小程序、APP、大屏、快应用等多种展示终端。在传统的开发模式下,开发人员往往需要为多端重新编写对应的代码。

爱速搭通过「同一个 DSL 可视化编辑器」+「多套运行时」实现一次搭建构建多端应用,让用户可以通过爱速搭快速搭建 H5、APP、快应用和各类小程序应用。

当前,爱速搭移动应用和快应用通过 aipage-editor 实现可视化页面设计,可在线设计 H5、小程序、快应用和 APP 等页面。其中 APP 和各类小程序运行时使用 UniApp 运行时承载页面渲染和展示,快应用页面使用快应用运行时承载页面渲染和展示。

扩展小程序自定义组件时,开发 UniApp 版自定义组件的同时还需要额外「开发」一份对应的 H5 自定义组件。其中 H5 自定义组件是小程序自定义组件的「替身组件」,也叫预览组件(仅在平台端预览展示使用)。这个预览组件支持通过 UniApp 版的自定义组件编译生成,无需额外开发。当发布或导出小程序应用时,应用中用到的预览组件会替换成对应的 UniApp 版自定义组件。(一个小程序抽奖自定义组件示例:https://github.com/wibetter/lottery-custom-widget)

快应用自定义组件和小程序自定义组件的扩展机制是一样的,但对应的预览组件需要额外开发,用于充当快应用自定义组件的“替身组件”。

图片
小程序自定义组件扩展机制原理图

5        NPM 组件扩展包开发实战

下面我们将通过一个简单的示例(使用 Vue 2.0)来开发并发布一个 amis 组件扩展包。

图片

需要准备的环境:

  • node(推荐 v17.4.0,或更新版本)

  • npm(推荐 8.3.1,或更新版本)

需要使用到的 NPM 工具:

  • amis-widget-cli(自定义组件开发脚手架)

  • amis-widget(自定义组件注册器,支持 React 和 Vue2.0 技术栈,用于注册自定义渲染器和插件)

开发 amis 组件扩展包关键步骤:

步骤 1:全局安装 amis-widget-cli

yarn global add amis-widget-cli 或者 npm i -g amis-widget-cli

步骤 2:初始化 NPM 组件扩展包

amis init -e=amis -m=copy 或 amis init --editor=amis --mode=copy

目前已提供多种自定义组件类型:

图片

比如使用 Vue 2.0 开发一个 amis 组件扩展包(amis 自定义组件),可选择 Vue 自定义组件,输入组件扩展包名称后,即可得到如下目录结构的自定义组件项目:

图片

备注:自定义组件目录说明请见 vue-custom-widget-template# 目录说明

步骤 3:开发一个自定义组件

使用 Vue 2.0开发 amis 自定义组件(Vue 2.0 使用文档请见 Vue 官方文档)。

图片

步骤 4:注册为一个爱速搭可用的 amis 自定义组件

开发完成的自定义组件,使用 amis-widget 中的 registerRendererByType 方法注册为爱速搭可识别的自定义组件(amis 渲染器):

import InfoCard from './widget/info-card';
import { registerRendererByType } from 'amis-widget';registerRendererByType(InfoCard, {type: 'vue-info-card',usage: 'renderer',weight: 99,framework: 'vue',
});

步骤 5:为 amis 自定义组件设置基本属性和可配置项

使用 amis-widget 中的 registerAmisEditorPlugin 方法为自定义组件制定基本属性和配置项,后续在编辑器端使用时,左侧组件物料面板会按照基本属性中的分类和排序展示当前自定义组件。

其中 scaffold 中的数据会作为自定义组件初次添加到页面中的默认数据,panelControls 中的数据则会用于生成自定义组件的配置项(编辑器端的右侧属性配置面板)。

import { registerAmisEditorPlugin } from 'amis-widget';export class InfoCardPlugin {rendererName = 'vue-info-card';$schema = '/schemas/UnkownSchema.json';name = 'vue组件';description = '信息展示卡片';tags = ['自定义'];icon = 'fa fa-file-code-o';scaffolds = [{type: 'vue-info-card',label: 'vue组件1',name: 'info-card1',scaffold: {type: 'vue-info-card',label: 'vue组件1',title:'amis 是一个低代码前端框架,它使用 JSON 配置来生成页面,可以减少页面开发工作量,极大提升效率。',backgroundImage:'https://suda.cdn.bcebos.com/widget-tpl/%E6%99%BA%E8%83%BD%E7%94%9F%E6%80%81.png',img_count: 5,comment_count: 2021,},}];previewSchema = {type: 'vue-info-card',label: 'vue-info-card',};panelTitle = '配置';panelControls = [{type: 'textarea',name: 'title',label: '卡片title',value:'amis 是一个低代码前端框架,它使用 JSON 配置来生成页面,可以减少页面开发工作量,极大提升效率。',},{type: 'text',name: 'backgroundImage',label: '展示图片',value:'https://search-operate.cdn.bcebos.com/64c279f23794a831f9a8e7a4e0b722dd.jpg',},{type: 'input-number',name: 'img_count',label: '图片数量',value: 3,},{type: 'input-number',name: 'comment_count',label: '评论数',value: 2021,},];
}registerAmisEditorPlugin(InfoCardPlugin);export default InfoCardPlugin;

步骤 6:本地预览&调试自定义组件内容

预览方式 1:在控制台输入 npm run preview ,打开浏览器预览自定义组件内容。

预览方式 2:在控制台输入 npm run dev 后,在本地打开一个页面编辑器(amis-editor),预览和调试自定义组件内容。

图片

步骤 7:在爱速搭中调试自定义组件

当自定义组件开发完成,并可在编辑器端正常使用和展示时,我们还可以使用 linkDebug 调试工具验证当前自定义组件在爱速搭平台中能否正常使用。

在控制台输入:npm run linkDebug 后,复制控制台输出的脚本地址,添加到爱速搭/临时外链中并保存。

图片

打开应用中一个普通页面,进入页面编辑器查看能否正常使用当前自定义组件:

图片

步骤 8:发布 NPM 组件扩展包

当自定义组件开发完成,并能正常在爱搭平台中正常使用和展示,就可以将其发布成一个 NPM 组件扩展包。

  • 构建自定义组件静态脚本

发布前需要先构建自定义组件,执行:npm run build2lib。构建完成的自定义组件静态脚本默认存放在dist目录下。

  • 在 package.json 中声明自定义组件信息

package.json / amis-widgets 中添加自定义组件信息,导入爱速搭时会读取这里的信息:

图片

  • 发布到 npm 仓库

执行:npm publish,需确保当前NPM组件扩展包名称和版本号是唯一的。

图片

至此我们已经成功发布了一个 NPM 组件扩展包。

6        常见使用疑问

Q:为什么使用 NPM 方式托管自定义组件?

A:爱速搭的主要客户是私有化部署使用,使用 NPM 托管方式可以更好的与平台解耦,用户在开发自定义组件无需过多关注平台功能,比如编译后的 js 静态资源不放对象存储也能正常使用。

Q:现有业务组件能否快速发布成 NPM 组件扩展包?

A:现有业务组件无需进行结构性改造,只需将其注册成 amis 渲染器,同时按需补充 amis-editor 插件,即可快速发布成 NPM 组件扩展包。

Q:爱速搭支持单独使用 amis-widget 开发自定义组件吗?

A:对于有一定前端工程能力的用户或者团队,可单独使用 amis-widget 开发自定义组件,无需额外引入 amis-widget-cli,可以完整保留业务现有的前端工程代码。

Q:爱速搭支持使用私有 NPM 仓库发布组件扩展包吗?

A:对于涉密业务组件,爱速搭私有化部署时支持配置私有 NPM 托管仓库(比如百度的私有 NPM 仓库、或者淘宝的私有仓库)。

爱速搭平台默认使用的官方 NPM 仓库的搜索接口(NPM_SEARCH)实现组件扩展包搜索导入功能,但如果私有化部署时配置成私有仓库(私有仓库自身没有NPM的搜索接口),会导致搜索导入功能失效。添加组件扩展包时,请使用「手动添加NPM组件扩展包」方式添加 NPM 组件扩展包。

图片

7        小结

百度智能云低代码平台爱速搭的目标是让开发者少写或者不写代码也可以可快速搭建企业信息化管理系统。

爱通过通过内置的 120+ 功能组件和可视化页面设计器,可实现大部分中后台页面的可视化设计;通过 API 管理和 API 编排,实现了业务接口的可视化设计;通过数据模型,实现了内外部数据表的可视化设计;通过 JSONQL,实现了 SQL 可视化设计并支持多种数据库类型,最终实现整个应用的一站式的全栈可视化搭建能力。


企业借助爱速搭平台完成信息化系统的建设的同时,往往还会面对老旧系统的维护工作,此时企业也可借助本文介绍的组件扩展包能力,将老旧业务系统的业务模块封装成NPM自定义组件封装为业务组件物料,完成老旧系统到低代码的快速迁移,实现企业内部新老系统的有机融合。

相关文章:

低代码组件扩展方案在复杂业务场景下的设计与实践

组件是爱速搭的前端页面可视化模块的核心能力之一&#xff0c;它将前端研发人员从无休止的页面样式微调和分辨率兼容工作中解放了出来。 目前&#xff0c;爱速搭通过内置的上百种功能组件&#xff08;120&#xff09;&#xff0c;基本可以覆盖大部分中后台页面的可视化设计场景…...

震撼科技界的GPT-4o发布首日即遭“越狱破防”

前言 本文主要解读分析OpenAI最新推出的大型模型GPT-4o可能存在的越狱风险。 5 月14 日凌晨的科技圈再一次被OpenAI轰动&#xff0c;其发布的最新大模型GPT-4o&#xff0c;能力横跨语音、文本和视觉&#xff0c;这一成果无疑再次巩固了OpenAI在人工智能领域的领先地位。 然而…...

保护密码安全,探讨密码加盐及其在Go语言中的实现

介绍 在当今数字化时代&#xff0c;个人隐私和数据安全成为了人们关注的焦点之一。随着网络犯罪的不断增加&#xff0c;用户的密码安全性变得尤为重要。密码加盐作为一种常见的安全措施&#xff0c;被广泛应用于密码存储和认证系统中。本文将深入探讨密码加盐的概念、重要性以…...

Sqoop学习详细介绍!!

一、Sqoop介绍 Sqoop是一款开源的工具&#xff0c;主要用于在Hadoop(HDFS/Hive/HBase)与传统的数据库(mysql、postgresql...)间进行数据的传递&#xff0c;可以将一个关系型数据库&#xff08;例如 &#xff1a; MySQL ,Oracle ,Postgres等&#xff09;中的数据导进到Hadoop的H…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 生成哈夫曼树(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 生成哈夫曼树(100分) 🌍 评测功能需要订阅专栏后私信联系清…...

ctfshow web 单身杯

web签到 <?phperror_reporting(0); highlight_file(__FILE__);$file $_POST[file];if(isset($file)){if(strrev($file)$file){ //翻转函数include $file;}}要进行反转并且包含文件用data协议 自己写不好写可以用函数帮你翻转 <?php $adata:text/plain,<?eval(…...

天锐绿盾加密软件,它的适用范围是什么?

天锐绿盾数据防泄密软件的适用范围广泛&#xff0c;主要可以归纳为以下几点&#xff1a; 行业适用性&#xff1a; 适用于各个行业&#xff0c;包括但不限于制造业、设计行业、软件开发、金融服务等&#xff0c;特别是对数据安全性要求较高的行业。企业规模与类型&#xff1a; 适…...

mysql面试题 Day2

1 长文本如何存储&#xff1f; 可以使用Text存储 TINYTEXT(255长度) TEXT(65535) MEDIUMTEXT&#xff08;int最大值16M&#xff09; LONGTEXT(long最大值4G) 2 大段文本存储如何设计表结构&#xff1f; 分表存储 分表后多段存储 3 大段文本查找时如何建立索引&#xff1…...

Excel加密怎么设置?这5个方法不容错过!(2024总结)

Excel加密怎么设置&#xff1f;如何不让别人未经允许查看我的excel文件&#xff1f;如果您也有这些疑问&#xff0c;那么千万不要错过本篇文章了。今天小编将向大家分享excel加密的5个简单方法&#xff0c;保证任何人都可以轻松掌握&#xff01;毫无疑问的是&#xff0c;为Exce…...

2024年下一个风口是什么?萤领优选 轻资产创业项目全国诚招合伙人

2024年&#xff0c;全球经济与科技发展的步伐不断加快&#xff0c;各行各业都在探寻新的增长点与风口。在这样的时代背景下&#xff0c;萤领优选作为一个轻资产创业项目&#xff0c;正以其独特的商业模式和前瞻的市场洞察力&#xff0c;吸引着众多创业者的目光。(领取&#xff…...

Redis 网络模型

一、用户空间和内核空间 1.1 linux 简介 服务器大多采用 Linux 系统&#xff0c;这里我们以 Linux 为例来讲解&#xff0c;下面有两个不同的 linux 发行版&#xff0c;分别位 ubuntu 和 centos&#xff0c;其实发行版就是在 Linux 系统上包了一层壳。 任何 Linux 发行版&#…...

【设计模式之组合模式 -- C++】

组合模式 – 树状结构&#xff0c;递归遍历 组合模式(Composite Pattern)是一种结构型设计模式&#xff0c;它可以让你将对象组合成树形结构&#xff0c;并且能像使用独立对象一样使用它们。这种模式定义了包含人和组的类&#xff0c;每个类都有可以在树形结构中显示的方法。这…...

C# 通过Win32API设置客户端系统时间

在日常工作中&#xff0c;有时可能会需要获取或修改客户端电脑的系统时间&#xff0c;比如软件设置了Licence有效期&#xff0c;预计2024-06-01 00:00:00到期&#xff0c;如果客户手动修改了客户端电脑时间&#xff0c;往前调整了一年&#xff0c;则软件就可以继续使用一年&…...

VirtualHere 允许通过网络远程使用 USB 设备,就像本地连接一样!

传统上&#xff0c;USB 设备需要直接插入计算机才能使用。有了 VirtualHere&#xff0c;就不再需要这样做&#xff0c;网络本身就变成了传输 USB 信号的电缆&#xff08;也称为 USB over IP、USB/IP、USB over WiFi、USB over Ethernet、USB 设备服务器&#xff09;。 此 USB …...

【Kubernetes】k8s 自动伸缩机制—— HPA 部署

一、在K8s中扩缩容分为两种&#xff1a; ●Node层面&#xff1a;对K8s物理节点扩容和缩容&#xff0c;根据业务规模实现物理节点自动扩缩容 ●Pod层面&#xff1a;我们一般会使用Deployment中的Replicas参数&#xff0c;设置多个副本集来保证服务的高可用&#xff0c;但是这是…...

MT1415 大小相同

题目 给定一个由N(<10)个正整数组成的数组A&#xff0c;生成一些最小元素和最大元素相同的子数组数&#xff08;可以仅包含1个元素&#xff09;&#xff0c;统计这些子数组的数量并输出。 注&#xff1a;最大元素和最小元素相同就是数组中的元素全部为同一个值。如数组&am…...

使用python库moviepy完成视频剪辑

1.关于moviepy和原理 moviepy事github上面的一个开源项目&#xff0c;地址是&#xff1a;GitHub - Zulko/moviepy: Video editing with Python 官方文档地址&#xff1a; User Guide — MoviePy 1.0.2 documentation 中文版文档可参考&#xff1a; MoviePy中文手册 — mov…...

Java高手的30k之路|面试宝典|精通泛型

泛型 知识点 在Java高级开发中&#xff0c;掌握泛型&#xff08;Generics&#xff09;是非常重要的&#xff0c;它是Java语言中的一项重要特性&#xff0c;提供了编译时类型安全检查机制&#xff0c;使得代码更加灵活和可重用。以下是Java高级开发需要掌握的泛型知识点&#…...

清理Linux操作系统buff/cache缓存

清理Linux操作系统buff/cache缓存 清理页缓存 echo 1 > /proc/sys/vm/drop_caches 或者 sysctl -w vm.drop_caches1 清理目录项和inode缓存 echo 2 > /proc/sys/vm/drop_caches 或者 sysctl -w vm.drop_caches2 同时清理页缓存、目录项和inode缓存 echo 3 > /pr…...

接口测试的几种方法

其实无论用那种测试方法&#xff0c;接口测试的原理是通过测试程序模拟客户端向服务器发送请求报文&#xff0c;服务器接收请求报文后对相应的报文做出处理然后再把应答报文发送给客户端&#xff0c;客户端接收应答报文这一个过程。 方法一、用LoadRunner实现接口测试 大家都…...

OpenGL3.3_C++_Windows(3)

GLSL Shader基础 Shader&#xff08;把输入转化为输出,运行在GPU上&#xff09;&#xff1a;首先要声明版本&#xff0c;有各自的入口点main&#xff08;&#xff09;顶点数据上限:16个包含4分量&#xff1a;16 * 4 64个分量向量&#xff1a;容器vec。使用.x、.y、.z和.w&am…...

24执业药师报名时间汇总及报名流程!

24执业药师报名时间汇总&#xff01;报名流程&#xff01; &#x1f55b;️各省市报名时间汇总&#xff08;共9地&#xff09; 西藏&#xff1a;6月29日-7月8日 新疆&#xff1a;6月25日10:30-7月9日19:00 内蒙古&#xff1a;6月20日9:00-7月3日24:00 新疆兵团&#xff1a;6月2…...

成都跃享未来教育咨询解锁新篇章

在快节奏的现代社会中&#xff0c;每个人都在追求着属于自己的非凡人生。而成都跃享未来教育咨询&#xff0c;正是那个能够智慧引领你走向成功、成就非凡人生的灯塔。 跃享未来教育咨询&#xff0c;位于历史悠久的文化名城成都&#xff0c;这里不仅有丰富的文化底蕴&#xff0c…...

怎么把网页上的接口信息导入postman

第一步 打开f12&#xff0c;右键选中需要的接口。选择copy-copy as cURL 第二步 打开postman&#xff0c;选择"Raw Text"&#xff0c; 把刚才复制的curl粘贴到空白位置&#xff0c;点击Continue - 最后的效果。导入的接口自带cookie&#xff0c;不用再输入cookie&a…...

10KM无人机高清图传通信模组,低延迟、抗干扰,飞睿智能无线MESH组网模块

随着科技的飞速发展&#xff0c;无人机技术在各个领域的应用越来越广泛。尤其在海上监测、搜索救援、货物运输等场景中&#xff0c;无人机的应用显得尤为重要。然而&#xff0c;要实现无人机在复杂海域环境中的高效通信&#xff0c;高清图传通信模组的作用不可忽视。本文将深入…...

分布式文件存储 - - - MinIO从入门到飞翔

MinIO从入门到飞翔 文章目录 MinIO从入门到飞翔0、前言1、分布式文件系统2、MinIO 介绍3、 MinIO安装&#xff08;docker&#xff09;4、基本概念5、通过代码上传文件到MinIO6、封装MinIO为starter7、在其他项目中集成封装好的模块 0、前言 对象存储是一种数据存储架构&#x…...

Python界面编辑器Tkinter布局助手 使用体验

一、发现 我今天在网上搜关于Python Tkinter方面的信息时&#xff0c;发现了Python界面编辑器 Tkinter布局助手 的使用说明。 https://blog.csdn.net/weixin_52777652/article/details/135291731?spm1001.2014.3001.5506 这个编辑器是个开源的项目&#xff0c;个人用户可以…...

嵌入式操作系统_2.嵌入式操作系统的一般架构

1.嵌入式操作系统的概念 嵌入式操作系统通常由硬件驱动程序、调式代理、操作系统内核、文件系统和可配置组件等功能组成&#xff0c;并为应用软件提供标准的API&#xff08;Application Programming Interface&#xff09;接口服务。 2.一般嵌入式操作系统的体系结构 从嵌入…...

docker 容器 network host 模式启动

docker 默认启动容器 network 是 bridge 模式&#xff0c;需使用 -p 映射端口实现容器与宿主机网络通信&#xff0c;较安全&#xff1b; 当使用 network host 模式&#xff0c;直接走宿主机网络通信&#xff0c;较不安全。 下面来一个 docker 容器 network host 模式启动 的 实…...

群晖NAS安装配置Joplin Server用来存储同步Joplin笔记内容

一、Joplin Server简介 1.1、Joplin Server介绍 Joplin支持多种方式进行同步用户的笔记数据&#xff08;如&#xff1a;Joplin自己提供的收费的云服务Joplin Cloud&#xff0c;还有第三方的云盘如Dropbox、OneDrive&#xff0c;还有自建的云盘Nextcloud、或者通过WebDAV协议来…...

单页网站cms/网站可以自己建立吗

Jewelry Exhibition 时间限制: 1 Sec 内存限制: 64 MB提交: 3 解决: 3[提交][状态][讨论版] 题目描述 To guard the art jewelry exhibition at night, the security agency has decided to use a new laser beam system, consisting of sender-receiver pairs. Each pair ge…...

反向代理服务器做wordpress外网/办公软件培训

"C:/Program Files/Java/jre6/bin/java.exe" -jar PLSQLspeci.jar >>log.txtfor %%c in (*.html) do %%c pause...

别人帮做的网站怎么修改/品牌咨询

策略模式&#xff1a;定义了算法族&#xff0c;分别分装起来&#xff0c;让它们之间可以相互替换&#xff0c;此模式让算法的变化可以独立于使用算法的用户。 /** * Created by wqc on 2017/10/3. * 算法抽象类&#xff08;武器抽象类&#xff09; */public interface WeaponBe…...

银川做网站公司/网络销售挣钱吗

ECHO服务: ECHO服务器仅返回它从客户处收集到的所有数据。是网络管理员测试可达性、调试协议软件及识别选路问题的重要工具&#xff0c;周知端口位于7 与此类似&#xff0c;Time服务的知名端口是37&#xff0c;记录了从1900年1月1日午夜起所经历的秒数&#xff1b;DATETIME服务…...

建筑网站首页大图/网站seo运营

触摸事件: 三种在规范中列出并获得跨移动设备广泛实现的基本触摸事件&#xff1a; 1.touchstart&#xff1a;手指放在一个DOM元素上。 2.touchmove&#xff1a;手指拖曳一个DOM元素。 3.touchend&#xff1a;手指从一个DOM元素上移开。 每个触摸事件都包括了三个触摸列表&#…...

网站建设公司石家庄/地推平台

1.创建命名空间 新建一个yaml文件命名为monitor-namespace.yaml&#xff0c;写入如下内容&#xff1a; apiVersion: v1 kind: Namespace metadata:name: monitoring 执行如下命令创建monitoring命名空间&#xff1a; kubectl create -f monitor-namespace.yaml 2.创建ClusterRo…...