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

[MAUI]集成富文本编辑器Editor.js至.NET MAUI Blazor项目

文章目录

    • 获取资源
      • 从源码构建
      • 从CDN获取
      • 获取扩展插件
    • 创建项目
      • 创建控件
      • 创建Blazor组件
      • 初始化
      • 保存
      • 销毁
      • 编写渲染逻辑
    • 实现只读/编辑功能
      • 切换模式
      • 获取只读模式状态
      • 响应切换事件
    • 实现明/暗主题切换
    • 项目地址

Editor.js 是一个基于 Web 的所见即所得富文本编辑器,它由CodeX团队开发。之前写过一篇博文专门介绍过这个编辑器,可以回看: 开源好用的所见即所得(WYSIWYG)编辑器:Editor.js。

.NET MAUI Blazor允许使用 Web UI 生成跨平台本机应用。 组件在 .NET 进程中以本机方式运行,并使用本地互操作通道将 Web UI 呈现到嵌入式 Web 视图控件(BlazorWebView)。

这次我们将Editor.js集成到.NET MAUI应用中。并实现只读切换,明/暗主题切换等功能。

在这里插入图片描述

使用.NET MAUI实现跨平台支持,本项目可运行于Android、iOS平台。

获取资源

我们先要获取web应用的资源文件(js,css等),以便MAUI的视图呈现标准的Web UI。有两种方式可以获取:

  1. 从源码构建
  2. 从CDN获取

从源码构建

此方法需要首先安装nodejs

克隆Editorjs项目到本地

git clone https://github.com/codex-team/editor.js.git

运行

npm i

以及

npm run build

等待nodejs构建完成,在项目根目录找到dist/editorjs.umd.js这个就是我们需要的js文件

在这里插入图片描述

从CDN获取

从官方CDN获取:

https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest

获取扩展插件

Editor.js中的每个块都由插件提供。有简单的外部脚本,有自己的逻辑。默认Editor.js项目中已包含唯一的 Paragraph 块。其它的工具插件可以单独获取。

同样我们可以找到这些插件的源码编译,或通过CDN获取:

  1. Header
  2. 链接
  3. HTML块
  4. 简单图片(无后端要求)
  5. 图片
  6. 清单
  7. 列表
  8. 嵌入
  9. 引用

创建项目

新建.NET MAUI Blazor项目,命名Editorjs

将editorjs.umd.js和各插件js文件拷贝至项目根目录下wwwroot文件夹,文件结构如下:

在这里插入图片描述

在wwwroot创建editorjs_index.html文件,并在body中引入editorjs.umd.js和各插件js文件

<body>...<script src="lib/editorjs/editorjs.umd.js"></script><script src="lib/editorjs/tools/checklist@latest.js"></script><script src="lib/editorjs/tools/code@latest.js"></script><script src="lib/editorjs/tools/delimiter@latest.js"></script><script src="lib/editorjs/tools/embed@latest.js"></script><script src="lib/editorjs/tools/header@latest.js"></script><script src="lib/editorjs/tools/image@latest.js"></script><script src="lib/editorjs/tools/inline-code@latest.js"></script><script src="lib/editorjs/tools/link@latest.js"></script><script src="lib/editorjs/tools/nested-list@latest.js"></script><script src="lib/editorjs/tools/marker@latest.js"></script><script src="lib/editorjs/tools/quote@latest.js"></script><script src="lib/editorjs/tools/table@latest.js"></script>
</body>

创建控件

创建 EditNotePage.xaml ,EditNotePage类作为视图控件,继承于ContentView,EditNotePage.xaml的完整代码如下:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:mato="clr-namespace:Editorjs;assembly=Editorjs"xmlns:service="clr-namespace:Editorjs.ViewModels;assembly=Editorjs"xmlns:xct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"x:Name="MainPage"x:Class="Editorjs.Controls.EditNotePage"><Grid BackgroundColor="{AppThemeBinding Light={StaticResource LightPageBackgroundColor}, Dark={StaticResource DarkPageBackgroundColor}}"RowDefinitions="Auto, *, Auto"Padding="20, 10, 20, 0"><Grid Grid.Row="0"Margin="0, 0, 0, 10"><Grid.ColumnDefinitions><ColumnDefinition Width="auto"></ColumnDefinition><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Entry Grid.Column="1"Placeholder="请输入标题"Margin="10, 0, 0, 0"VerticalOptions="Center"Text="{Binding Title}"
></Entry><HorizontalStackLayout Grid.Column="2"HeightRequest="60"VerticalOptions="Center"HorizontalOptions="End"Margin="0, 0, 10, 0"><StackLayout RadioButtonGroup.GroupName="State"RadioButtonGroup.SelectedValue="{Binding NoteSegmentState,Mode=TwoWay}"Orientation="Horizontal"><RadioButton Value="{x:Static service:NoteSegmentState.Edit}"Content="编辑"></RadioButton><RadioButton Value="{x:Static service:NoteSegmentState.PreView}"Content="预览"></RadioButton></StackLayout></HorizontalStackLayout></Grid><BlazorWebView Grid.Row="1"Margin="-10, 0"x:Name="mainMapBlazorWebView"HostPage="wwwroot/editorjs_index.html"><BlazorWebView.RootComponents><RootComponent Selector="#app"x:Name="rootComponent"ComponentType="{x:Type mato:EditorjsPage}" /></BlazorWebView.RootComponents></BlazorWebView><ActivityIndicator Grid.RowSpan="4"IsRunning="{Binding Loading}"></ActivityIndicator></Grid>
</ContentView>

创建一个EditNotePageViewModel的ViewModel类,用于处理页面逻辑。代码如下:

public class EditNotePageViewModel : ObservableObject, IEditorViewModel
{public Func<Task<string>> OnSubmitting { get; set; }public Action<string> OnInited { get; set; }public Action OnFocus { get; set; }public EditNotePageViewModel(){Submit = new Command(SubmitAction);NoteSegmentState=NoteSegmentState.Edit;var content = "";using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Editorjs.Assets.sample1.json")){if (stream != null){using (StreamReader reader = new StreamReader(stream)){content = reader.ReadToEnd();                     }}}Init(new Note(){Title = "sample",Content=content});}private void Init(Note note){if (note != null){Title = note.Title;Content = note.Content;}OnInited?.Invoke(this.Content);}private string _title;public string Title{get { return _title; }set{_title = value;OnPropertyChanged();}}private string _content;public string Content{get { return _content; }set{_content = value;OnPropertyChanged();}}private async void SubmitAction(object obj){var savedContent = await OnSubmitting?.Invoke();if (string.IsNullOrEmpty(savedContent)){return;}this.Content=savedContent;var note = new Note();note.Title = this.Title;note.Content = this.Content;}public Command Submit { get; set; }}

注意这里的Init方法,用于初始化内容。这里我们读取Editorjs.Assets.sample1.json资源文件作为初始内容。

在这里插入图片描述

创建Blazor组件

创建Blazor页面EditorjsPage.razor

EditorjsPage.razor页面中,我们放置一个div,用于放置编辑器,

razor页面的 @Code 代码段中,放置EditNotePageViewModel属性,以及一个DotNetObjectReference对象,用于在JS中调用C#方法。

@code {[Parameter]public IEditorViewModel EditNotePageViewModel { get; set; }private DotNetObjectReference<EditorjsPage> objRef;protected override void OnInitialized(){objRef = DotNetObjectReference.Create(this);}

初始化

在script代码段中,创建LoadContent函数,用于加载EditorJs的初始内容。

<div class="ce-main"><div id="editorjs"></div>
</div>

LoadContent中,调用函数window.editor = new window.EditorJS(config)创建一个EditorJS对象,其中config对象包括holder,tools,data等属性,关于EditorJs配置的更多说明请参考官方文档

<script type="text/javascript">window.editor = null;window.viewService = {LoadContent: function (content) {var obj = JSON.parse(content);var createEdtor = () => {window.editor = new window.EditorJS({                 holder: 'editorjs',/*** Tools list*/tools: {paragraph: {config: {placeholder: "Enter something"}},header: {class: Header,inlineToolbar: ['link'],config: {placeholder: 'Header'},shortcut: 'CMD+SHIFT+H'},/*** Or pass class directly without any configuration*/image: {class: ImageTool},list: {class: NestedList,inlineToolbar: true,shortcut: 'CMD+SHIFT+L'},checklist: {class: Checklist,inlineToolbar: true,},quote: {class: Quote,inlineToolbar: true,config: {quotePlaceholder: '输入引用内容',captionPlaceholder: '引用标题',},shortcut: 'CMD+SHIFT+O'},marker: {class: Marker,shortcut: 'CMD+SHIFT+M'},code: {class: CodeTool,shortcut: 'CMD+SHIFT+C'},delimiter: Delimiter,inlineCode: {class: InlineCode,shortcut: 'CMD+SHIFT+C'},linkTool: LinkTool,embed: Embed,table: {class: Table,inlineToolbar: true,shortcut: 'CMD+ALT+T'},},i18n: {messages: {"ui": {"blockTunes": {"toggler": {"Click to tune": "点击转换","or drag to move": "拖动调整"},},"inlineToolbar": {"converter": {"Convert to": "转换成"}},"toolbar": {"toolbox": {"Add": "添加","Filter": "过滤","Nothing found": "无内容"},"popover": {"Filter": "过滤","Nothing found": "无内容"}}},"toolNames": {"Text": "段落","Heading": "标题","List": "列表","Warning": "警告","Checklist": "清单","Quote": "引用","Code": "代码","Delimiter": "分割线","Raw HTML": "HTML片段","Table": "表格","Link": "链接","Marker": "突出显示","Bold": "加粗","Italic": "倾斜","InlineCode": "代码片段","Image": "图片"},"tools": {"link": {"Add a link": "添加链接"},"stub": {'The block can not be displayed correctly.': '该模块不能放置在这里'},"image": {"Caption": "图片说明","Select an Image": "选择图片","With border": "添加边框","Stretch image": "拉伸图像","With background": "添加背景",},"code": {"Enter a code": "输入代码",},"linkTool": {"Link": "请输入链接地址","Couldn't fetch the link data": "获取链接数据失败","Couldn't get this link data, try the other one": "该链接不能访问,请修改","Wrong response format from the server": "错误响应",},"header": {"Header": "标题","Heading 1": "一级标题","Heading 2": "二级标题","Heading 3": "三级标题","Heading 4": "四级标题","Heading 5": "五级标题","Heading 6": "六级标题",},"paragraph": {"Enter something": "请输入笔记内容",},"list": {"Ordered": "有序列表","Unordered": "无序列表",},"table": {"Heading": "标题","Add column to left": "在左侧插入列","Add column to right": "在右侧插入列","Delete column": "删除列","Add row above": "在上方插入行","Add row below": "在下方插入行","Delete row": "删除行","With headings": "有标题","Without headings": "无标题",},"quote": {"Align Left": "左对齐","Align Center": "居中对齐",}},"blockTunes": {"delete": {"Delete": "删除",'Click to delete': "点击删除"},"moveUp": {"Move up": "向上移"},"moveDown": {"Move down": "向下移"},"filter": {"Filter": "过滤"}},}},/*** Initial Editor data*/data: obj});}if (window.editor) {editor.isReady.then(() => {editor.destroy();createEdtor();});}else {createEdtor();}},DumpContent: async function () {outputData = null;if (window.editor) {if (window.editor.readOnly.isEnabled) {await window.editor.readOnly.toggle();}var outputObj = await window.editor.save();outputData = JSON.stringify(outputObj);}return outputData;},SwitchTheme: function () {document.body.classList.toggle("dark-mode");},SwitchState: async function () {state = null;if (window.editor && window.editor.readOnly) {var readOnlyState = await window.editor.readOnly.toggle();state = readOnlyState;}return state;},Focus: async function (atEnd) {if (window.editor) {await window.editor.focus(atEnd);}},GetState() {if (window.editor && window.editor.readOnly) {return window.editor.readOnly.isEnabled;}},Destroy: function () {if (window.editor) {window.editor.destroy();}},}window.initObjRef = function (objRef) {window.objRef = objRef;}</script>

在这里插入图片描述

保存

创建转存函数DumpContent

DumpContent: async function () {outputData = null;if (window.editor) {if (window.editor.readOnly.isEnabled) {await window.editor.readOnly.toggle();}var outputObj = await window.editor.save();outputData = JSON.stringify(outputObj);}return outputData;
},

销毁

创建销毁函数Destroy


Destroy: function () {if (window.editor) {window.editor.destroy();}
},

编写渲染逻辑

在OnAfterRenderAsync中调用初始化函数,并订阅OnSubmitting和OnInited事件,以便在提交事件触发时保存,以及文本状态变更时重新渲染。

 protected override async Task OnAfterRenderAsync(bool firstRender){if (!firstRender)return;if (EditNotePageViewModel != null){EditNotePageViewModel.PropertyChanged += EditNotePageViewModel_PropertyChanged;this.EditNotePageViewModel.OnSubmitting += OnSubmitting;this.EditNotePageViewModel.OnInited += OnInited;var currentContent = EditNotePageViewModel.Content;await JSRuntime.InvokeVoidAsync("viewService.LoadContent", currentContent);}await JSRuntime.InvokeVoidAsync("window.initObjRef", this.objRef);}
private async Task<string> OnSubmitting()
{var savedContent = await JSRuntime.InvokeAsync<string>("viewService.DumpContent");return savedContent;
}private async void OnInited(string content)
{await JSRuntime.InvokeVoidAsync("viewService.LoadContent", content);
}

在这里插入图片描述

实现只读/编辑功能

在.NET本机中,我们使用枚举来表示编辑状态。 并在控件上设置一个按钮来切换编辑状态。

public enum NoteSegmentState
{Edit,PreView
}

EditNotePageViewModel.cs:

...
private NoteSegmentState _noteSegmentState;public NoteSegmentState NoteSegmentState{get { return _noteSegmentState; }set{_noteSegmentState = value;OnPropertyChanged();}}

EditNotePage.xaml:

...
<StackLayout RadioButtonGroup.GroupName="State"RadioButtonGroup.SelectedValue="{Binding NoteSegmentState,Mode=TwoWay}"Orientation="Horizontal"><RadioButton Value="{x:Static service:NoteSegmentState.Edit}"Content="编辑"></RadioButton><RadioButton Value="{x:Static service:NoteSegmentState.PreView}"Content="预览"></RadioButton></StackLayout>

Editorjs官方提供了readOnly对象,通过toggle()方法,可以切换编辑模式和只读模式。

在创建Editorjs实例时,也可以通过设置readOnly属性为true即可实现只读模式。

切换模式

在razor页面中创建SwitchState函数,用来切换编辑模式和只读模式。

SwitchState: async function () {state = null;if (window.editor && window.editor.readOnly) {var readOnlyState = await window.editor.readOnly.toggle();state = readOnlyState;}return state;
},

获取只读模式状态

在razor页面中创建GetState函数,用来获取编辑模式和只读模式的状态。


GetState() {if (window.editor && window.editor.readOnly) {return window.editor.readOnly.isEnabled;}
},

响应切换事件

我们监听EditNotePageViewModel 的NoteSegmentState属性变更事件,当状态改变时,调用对应的js方法

private async void EditNotePageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{if (e.PropertyName == nameof(EditNotePageViewModel.NoteSegmentState)){if (EditNotePageViewModel.NoteSegmentState==NoteSegmentState.PreView){var state = await JSRuntime.InvokeAsync<bool>("viewService.GetState");if (!state){await JSRuntime.InvokeAsync<bool>("viewService.SwitchState");}}else if (EditNotePageViewModel.NoteSegmentState==NoteSegmentState.Edit){var state = await JSRuntime.InvokeAsync<bool>("viewService.GetState");if (state){await JSRuntime.InvokeAsync<bool>("viewService.SwitchState");}}}
}

在这里插入图片描述

实现明/暗主题切换

lib/editorjs/css/main.css中,定义了.dark-mode类的样式表

.dark-mode {
--color-border-light: rgba(255, 255, 255,.08);
--color-bg-main: #212121;
--color-text-main: #F5F5F5;
}.dark-mode .ce-popover {--color-background: #424242;--color-text-primary: #F5F5F5;--color-text-secondary: #707684;--color-border: #424242;
}.dark-mode .ce-toolbar__settings-btn {background: #2A2A2A;border: 1px solid #424242;
}.dark-mode .ce-toolbar__plus {background: #2A2A2A;border: 1px solid #424242;
}.dark-mode .ce-popover-item__icon {background: #2A2A2A;
}.dark-mode .ce-code__textarea {color: #212121;background: #2A2A2A;
}.dark-mode .tc-popover {--color-border: #424242;--color-background: #424242;
}
.dark-mode .tc-wrap {--color-background: #424242;
}

在razor页面中添加SwitchTheme函数,用于用于切换dark-mode"的`类名,从而实现暗黑模式和正常模式之间的切换。

SwitchTheme: function () {document.body.classList.toggle("dark-mode");
},

OnInitializedAsync中,订阅Application.Current.RequestedThemeChanged事件,用于监听主题切换事件,并调用SwitchTheme函数。

protected override async Task OnInitializedAsync()
{objRef = DotNetObjectReference.Create(this);Application.Current.RequestedThemeChanged += OnRequestedThemeChanged;}
private async void OnRequestedThemeChanged(object sender, AppThemeChangedEventArgs args)
{await JSRuntime.InvokeVoidAsync("viewService.SwitchTheme");
}

在渲染页面时,也判断是否需要切换主题

protected override async Task OnAfterRenderAsync(bool firstRender)
{if (!firstRender)return;···if (Application.Current.UserAppTheme==AppTheme.Dark){await JSRuntime.InvokeVoidAsync("viewService.SwitchTheme");}}

在这里插入图片描述

项目地址

Github:maui-samples

相关文章:

[MAUI]集成富文本编辑器Editor.js至.NET MAUI Blazor项目

文章目录 获取资源从源码构建从CDN获取获取扩展插件 创建项目创建控件创建Blazor组件初始化保存销毁编写渲染逻辑 实现只读/编辑功能切换模式获取只读模式状态响应切换事件 实现明/暗主题切换项目地址 Editor.js 是一个基于 Web 的所见即所得富文本编辑器&#xff0c;它由CodeX…...

Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )

目录: Spring Boot 整合 "Servlet三大组件" &#xff1a;1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…...

错误分析 (Machine Learning研习十九)

错误分析 您将探索数据准备选项&#xff0c;尝试多个模型&#xff0c;筛选出最佳模型&#xff0c;使用 Grid SearchCV微调其超参数&#xff0c;并尽可能实现自动化。在此&#xff0c;我们假设您已经找到了一个有前途的模型&#xff0c;并希望找到改进它的方法。其中一种方法就…...

SQL系统函数知识点梳理(Oracle)

这里写目录标题 函数系统函数转换函数to_date()to_char()将数值转换成字符格式 添加货币符号将日期转换成字符 其他不常用的转换函数 字符型函数连接函数大小写转换函数大写转换小写转换首字母大写&#xff0c;其余的小写 替换函数去除空格函数截取函数填充函数获取字符长度函数…...

面试突击---MySQL索引

面试突击---MYSQL索引 面试表达技巧&#xff1a;1、谈一下你对于mysql索引的理解&#xff1f;&#xff08;为什么mysql要选择B树来存储索引&#xff09;2、索引有哪些分类&#xff1f;3、聚簇索引与非聚簇索引4、回表、索引覆盖、最左匹配原则、索引下推&#xff08;1&#xff…...

关注 | 我国已对百种产品实施强制性产品认证

市场监管总局在7日举行的新闻发布会上介绍&#xff0c;该局日前发布《市场监管总局关于对商用燃气燃烧器具等产品实施强制性产品认证管理的公告》&#xff0c;对具有较高安全风险的商用燃气燃烧器具、阻燃电线电缆、电子坐便器、电动自行车乘员头盔、可燃气体探测报警产品、水性…...

虚幻引擎架构自动化及蓝图编辑器高级开发进修班

课程名称&#xff1a;虚幻引擎架构自动化及蓝图编辑器高级开发进修班 课程介绍 大家好 我们即将推出一套课程 自动化系统开发。 自动化技术在项目开发的前中后期都大量运用。如何您是一家游戏公司&#xff0c;做的是网络游戏&#xff0c;是不是经常会遇到程序员打包加部署需…...

Weakly Supervised Audio-Visual Violence Detection 论文阅读

Weakly Supervised Audio-Visual Violence Detection 论文阅读 摘要III. METHODOLOGYA. Multimodal FusionB. Relation Modeling ModuleC. Training and Inference IV. EXPERIMENTSV. CONCLUSION阅读总结 文章信息&#xff1a; 发表于&#xff1a;IEEE TRANSACTIONS ON MULTIME…...

华为海思数字芯片设计笔试第六套

声明 下面的题目作答都是自己认为正确的答案&#xff0c;并非官方答案&#xff0c;如果有不同的意见&#xff0c;可以评论区交流。 这些题目也是笔者从各个地方收集的&#xff0c;感觉有些题目答案并不正确&#xff0c;所以在个别题目会给出自己的见解&#xff0c;欢迎大家讨论…...

重绘和重排:概念、区别和应用示例

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…...

创建k8s deploy yaml文件的imagePullSecrets语句

镜像仓库是harbor kubectl create secret docker-registry key --docker-server192.168.0.190 --docker-usernameadmin --docker-passwordHarbor12345...

大模型预测结果导入到Doccano,人工修正预测不准的数据

背景 使用大语言模型做实体识别的实验时&#xff0c;发现大模型关于实体的边界预测一直不准。 主要原因在于当时找了很多同学标注数据&#xff0c;由于不同组同学关于实体的边界没有统一&#xff0c;故导致数据集中实体边界也没统一。 &#xff08;找太多人标&#xff0c;会有…...

python三方库_ciscoconfparse学习笔记

文章目录 介绍使用基本原理父子关系 属性ioscfg 获取配置信息,返回列表is_config_line 判断是否是配置行is_intf 判断IOSCfgLine是不是interfaceis_subintf 判断IOSCfgLine是不是子接口lineage 不知道用法is_ethernet_intf 判断IOSCfgLine是否是以太网接口is_loopback_intf 判断…...

HDFS详解(Hadoop)

Hadoop 分布式文件系统&#xff08;Hadoop Distributed File System&#xff0c;HDFS&#xff09;是 Apache Hadoop 生态系统的核心组件之一&#xff0c;它是设计用于存储大规模数据集并运行在廉价硬件上的分布式文件系统。 1. 分布式存储&#xff1a; HDFS 将文件分割成若干块…...

python创建word文档并向word中写数据

一、docx库的安装方法 python创建word文档需要用到docx库&#xff0c;安装命令如下&#xff1a; pip install python-docx 注意&#xff0c;安装的是python-docx。 二、使用方法 使用方法有很多&#xff0c;这里只介绍创建文档并向文档中写入数据。 import docxmydocdocx.Do…...

MongoDB的安装配置及使用

文章目录 前言一、MongoDB的下载、安装、配置二、检验MongoDB是否安装成功三、Navicat 操作MongoDB四、创建一个集合&#xff0c;存放三个文档总结 前言 本文内容&#xff1a; &#x1f4ab; MongoDB的下载、安装、配置 &#x1f4ab; 检验MongoDB是否安装成功 ❤️ Navicat 操…...

Go学习路线

Go学习路线 文章目录 Go学习路线入门阶段一、Go基础和Goland的安装二、学习日志文件及配置文件三、学习mysql四、html&#xff0c;css&#xff0c;js快速入门五、写一个简单的前后端分离的记事本项目六、Linux快速入门七、Docker快速入门八、Git命令快速入门九、使用Docker打包…...

安全大脑与盲人摸象

21世纪是数字科技和数字经济爆发的时代&#xff0c;互联网正从网状结构向类脑模型进行进化&#xff0c;出现了结构和覆盖范围庞大&#xff0c;能够适应不同技术环境、经济场景&#xff0c;跨地域、跨行业的类脑复杂巨型系统。如腾讯、Facebook等社交网络具备的神经网络特征&…...

如何使用Git-Secrets防止将敏感信息意外上传至Git库

关于Git-Secrets Git-secrets是一款功能强大的开发安全工具&#xff0c;该工具可以防止开发人员意外将密码和其他敏感信息上传到Git库中。 Git-secrets首先会扫描提交的代码和说明&#xff0c;当与用户预先配置的正则表达式模式匹配时&#xff0c;便会阻止此次提交。该工具的优…...

Day 14 网络协议

常见网络设备&#xff1a;交换机 路由器 中继器 多协议网关&#xff08;路由器的前身&#xff09; 交换机&#xff1a;用于连接统一网络的设备&#xff0c;实现内网设备通信。 从广义上分为&#xff1a;局域网交换机&#xff0c;广域网交换机 从网络构成分为&#xff1a;接…...

msyql中SQL 错误 [1118] [42000]: Row size too large (> 8126)

场景&#xff1a; CREATE TABLE test-qd.eqtree (INSERT INTO test.eqtree (idocid VARCHAR(50) NULL,sfcode VARCHAR(50) NULL,sfname VARCHAR(50) NULL,sfengname VARCHAR(50) NULL,…… ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_general_ci;或 alter table eqtre…...

实验六 智能手机互联网程序设计(微信程序方向)实验报告

实验目的和要求 请完成创建图片库应用&#xff0c;显示一系列预设的图片。 提供按钮来切换显示不同类别的图片。 二、实验步骤与结果&#xff08;给出对应的代码或运行结果截图&#xff09; 1.WXML <view> <button bindtap"showAll">所有图片</but…...

Linux环境下,让Jar项目多线程部署成为可能

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Linux环境下&#xff0c;让Jar项目多线程部署成为可能 前言背景介绍使用sh脚本实现使用systemd来实现使用docker-compose实现 前言 在当今互联网时代&#xff0c;应用程序的高可用性和性能是至关重要…...

k8s调度场景

15个KUBERNETES调度情景实用指南 Kubernetes调度是确保集群中的Pod在适当节点上运行的关键组件。通过灵活配置调度策略&#xff0c;可以提高资源利用率、负载平衡和高可用性。 在本文中&#xff0c;我们将深入探讨一些实际的Kubernetes调度场景&#xff0c;并提供相应的配置示…...

基于小程序实现的餐饮外卖系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…...

家居网购项目(手写分页)

文章目录 1.后台管理—分页显示1.程序框架图2.编写数据模型Page.java 3.编写dao层1.修改FurnDao增加方法 2.修改FurnDaoImpl增加方法 3.单元测试FurnDaoTest 4.编写service层1.修改FurnService增加方法 2.修改FurnServiceImpl增加方法3.单元测试FurnServiceTest 5.编写DataUtil…...

goland2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Goland 是一款由 JetBrains 公司开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门用于 Go 语言的开发。它提供了丰富的功能和工具&#xff0c;帮助开发者更高效地编写、调试和管理 Go 语言项目。 功能特点&#x…...

35、链表-LRU缓存

思路&#xff1a; 首先要了解LRU缓存的原理&#xff0c;首先定下容量&#xff0c;每次get请求和put请求都会把当前元素放最前/后面&#xff0c;如果超过容量那么头部/尾部元素就被移除&#xff0c;所以最近最少使用的元素会被优先移除&#xff0c;保证热点数据持续存在。 不管放…...

数据结构速成--栈

由于是速成专题&#xff0c;因此内容不会十分全面&#xff0c;只会涵盖考试重点&#xff0c;各学校课程要求不同 &#xff0c;大家可以按照考纲复习&#xff0c;不全面的内容&#xff0c;可以看一下小编主页数据结构初阶的内容&#xff0c;找到对应专题详细学习一下。 目录 一…...

算法练习第15天|226.翻转二叉树

226.翻转二叉树 力扣链接https://leetcode.cn/problems/invert-binary-tree/description/ 题目描述&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&am…...

广东珠海网站建设/微信小程序开发平台

为什么80%的码农都做不了架构师&#xff1f;>>> 应用名称&#xff1a;乐窝&#xff0d;分享快乐段子、幽默笑话 应用URL地址&#xff1a;http://lewole.cloudfoundry.com 应用说明及使用场景&#xff1a; 乐窝就是一个简单的网站&#xff0c;主要用于分享搞笑、…...

关于网站开发的参考文献有哪些/google服务框架

一、React 介绍 1. 什么是 React React 是一个用于构建用户界面的 JavaScript 库用户界面:HTML页面(前端),React 主要用来写HTML页面,或构建Web应用如果从 MVC 的角度来看,React 仅仅是视图层(V),也就是只负责视图的渲染,而并非提供了完整的 M 和 C 的功能。React 起…...

五金日杂店做网站/百度一下首页

​ 应用场景: 用户在注册或者密码丢失等过程中,账号绑定邮箱,用户在进行身份认证的过程中,电子邮箱确实是一种很常用的方式,Python中提供了smtplib可以实现发送电子邮件功能,Flask框架也有对应的flask-email库,扩展对电子发送的支持 安装 pip3 install flask-mail 导入及初始化…...

徐州市 两学一做网站/百度一下搜索网页

2019独角兽企业重金招聘Python工程师标准>>> 按行读取文件 with open(1.txt, r) as f:for line in f:print line按行读取gzip文件 import gzipdef x_read_gzip(filename):with gzip.open(filename, rb) as f:for line in f:yield line按行读取zip文件 import zipfil…...

北京app外包/seo建站是什么

在python中用到pow函数&#xff0c;一般都是求数值的三次方&#xff0c; pow(x,y)----->其意思是数字x的y次方 例如&#xff1a;pow(5,3)------>表示5的三次方&#xff0c;其结果为&#xff1a;555...

青岛专业网站制作/seo快速建站

利用Application对象实现访问人数的统计很常见&#xff0c;但是一些书籍讲解这一技术的时候&#xff0c;往往没有做完整。一旦服务器重启&#xff0c;由于Application会被销毁&#xff0c;重新建立&#xff0c;人数统计则会再一次从零开始。解决方法&#xff0c;个人认为&#…...