简单的Activiti Modoler 流程在线编辑器

简单的Activiti Modoler 流程在线编辑器

1.需求

我们公司使用的流程是activiti5.22.0,版本有些老了,然后使用的编辑器都是eclipse的流程编辑器插件,每次编辑流程需要打开eclipse进行编辑,然后再导入到项目里面,不是特别方便,所以我们决定使用官方提供的 Activiti Modoler,实现项目集成在线编辑器,方便流程的发布编辑以及部署。

2.具体实现步骤

整体的实现步骤就是从官网下载对应的activiti5.22.0 或者版本相近的包,然后找到对应的前端需要集成的文件以及controller等文件,添加到自己的项目中,我使用的springboot项目,然后需要配置静态资源的对应的地址信息,便可以进行简单的使用了。

2.1 添加pom需要jar包

我们此处就只列举了流程所需包,其他包简略

	<!-- activiti 5.22.0启动器,排除mybatis依赖 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>5.22.0</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-diagram-rest</artifactId><version>5.22.0</version></dependency><!-- Activiti在线设计 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-modeler</artifactId><version>5.22.0</version></dependency>

2.2 下载包

我们下载的地址为 activiti5.x.x 官方包
在这里插入图片描述

2.3 解压复制文件到项目中

替换文件主要是两部分,一部分为java文件,一部分为静态资源文件,首先替换java文件
activiti-webexplore\Activiti-5.x\modules\activiti-modeler\src\main\java\org\activiti\rest\editor 向下的所有java文件到自己项目中
在这里插入图片描述

注意,ModelSaveRestResource 对应的请求方式修改为 POST。

在之后我们需要添加一个发起流程图编辑或新增的入口 ModelerController,发起以及修改全部从此方法进入,最后导入后台文件效果如下
在这里插入图片描述
最后添加的几个controller代码如下:

  • ModelEditorJsonRestResource

    package cn.git.workflow.modeler;import cn.git.common.exception.ServiceException;
    import cn.git.common.util.LogUtil;
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.alibaba.fastjson.JSONObject;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.activiti.editor.constants.ModelDataJsonConstants;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.repository.Model;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;import java.nio.charset.StandardCharsets;/*** @description: 通过modelId获取流程model json数据* @program: bank-credit-sy* @author: lixuchun* @create: 2024-11-21*/
    @Api(value = "model流程设计器获取json数据", tags = "model流程设计器获取json数据")
    @Slf4j
    @RestController
    public class ModelEditorJsonRestResource implements ModelDataJsonConstants {@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ObjectMapper objectMapper;/*** 获取流程图json数据** @param modelId* @return*/@ApiOperation(value = "获取流程图json数据", notes = "获取流程图json数据")@RequestMapping(value = "/model/{modelId}/json", method = RequestMethod.GET, produces = "application/json")public Object getEditorJson(@PathVariable String modelId) {// 最终响应数据ObjectNode modelNode = null;Model model = repositoryService.getModel(modelId);// 获取流程定义if (ObjectUtil.isNotNull(model)) {try {// 获取流程定义的JSON数据if (StrUtil.isNotBlank(model.getMetaInfo())) {modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());} else {modelNode = objectMapper.createObjectNode();modelNode.put(MODEL_NAME, model.getName());}// 设置流程定义的IDmodelNode.put(MODEL_ID, model.getId());// 获取流程定义的JSON数据ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));modelNode.put("model", editorJsonNode);} catch (Exception e) {log.error(StrUtil.format("通过modelId获取model对应json数据失败,失败信息为[{}]", LogUtil.getStackTraceInfo(e)));throw new ServiceException("通过modelId获取model对应json数据失败!");}}return JSONObject.parseObject(modelNode.toString());}
    }
  • ModelerController

    package cn.git.workflow.modeler;import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.activiti.editor.constants.ModelDataJsonConstants;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.repository.Model;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;import javax.annotation.Resource;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.rmi.ServerException;/** * @description: model流程设计器保存* @program: bank-credit-sy* @author: lixuchun* @create: 2024-11-21*/
    @Api(value = "model流程设计器保存", tags = "model流程图画图模块保存")
    @Controller
    @RequestMapping("/modeler")
    public class ModelerController {@Resourceprivate RepositoryService repositoryService;@Resourceprivate ObjectMapper objectMapper;/*** 初始化流程设计器方法,跳转至流程设计器** @param modelName      模型名称* @param modelKey       模型key* @param modelDescription 模型描述* @param modelId        模型id* @return*/@ApiOperation(value = "初始化流程设计器方法,跳转至流程设计器", notes = "初始化流程设计器方法,跳转至流程设计器")@GetMapping("/save")public void save(HttpServletResponse response,@RequestParam(value = "modelName", required = false) String modelName,@RequestParam(value = "modelKey", required = false) String modelKey,@RequestParam(value = "modelDescription", required = false) String modelDescription,@RequestParam(value = "modelId", required = false) String modelId) throws IOException {// 如果有modelId,则直接跳转if (StrUtil.isNotBlank(modelId)) {Model model = repositoryService.getModel(modelId);if (ObjectUtil.isNotNull(model)) {response.sendRedirect("/static/activiti/modeler.html?modelId=" + model.getId());} else {throw new ServerException(StrUtil.format("模型不存在,请检查modelId[{}]", modelId));}} else {// modelId为空,则表示请求为新建一个模型,则进行必填参数校验if (StrUtil.isBlank(modelName) ||StrUtil.isBlank(modelKey) || StrUtil.isBlank(modelDescription)) {throw new ServerException("参数[modelName, modelKey, modelDescription]不能为空,请确认!");}// 创建模型Model modelData = repositoryService.newModel();ObjectNode modelObjectNode = objectMapper.createObjectNode();// 模型名称modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, modelName);// 模型版本modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);// 模型详情modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelDescription);// 以字符串信息存储进信息属性中modelData.setMetaInfo(modelObjectNode.toString());// 模型名称modelData.setName(modelName);// 模型keymodelData.setKey(modelKey);// 初始化json数据ObjectNode editorNode = objectMapper.createObjectNode();editorNode.put("id", "canvas");editorNode.put("resourceId", "canvas");// 创建一个stencilset节点ObjectNode stencilSetNode = objectMapper.createObjectNode();stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");editorNode.set("stencilset", stencilSetNode);// 添加模型repositoryService.saveModel(modelData);repositoryService.addModelEditorSource(modelData.getId(),editorNode.toString().getBytes(StandardCharsets.UTF_8));response.sendRedirect("/static/activiti/modeler.html?modelId=" + modelData.getId());}}}
    
  • ModelSaveRestResource

    注意:此方法,请求方式修改为POST

    package cn.git.workflow.modeler;import cn.git.common.exception.ServiceException;
    import cn.git.common.result.Result;
    import cn.git.common.util.LogUtil;
    import cn.hutool.core.util.StrUtil;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.activiti.editor.constants.ModelDataJsonConstants;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.repository.Model;
    import org.apache.batik.transcoder.TranscoderInput;
    import org.apache.batik.transcoder.TranscoderOutput;
    import org.apache.batik.transcoder.image.PNGTranscoder;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.*;import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;/** * @description: 控制器类用于保存activiti模型* @program: bank-credit-sy* @author: lixuchun* @create: 2024-11-21*/
    @Api(value = "model流程设计器编辑保存", tags = "model流程设计器编辑保存")
    @RestController
    public class ModelSaveRestResource implements ModelDataJsonConstants {protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);@Autowiredprivate RepositoryService repositoryService;/*** Jackson ObjectMapper*/@Autowiredprivate ObjectMapper objectMapper;/*** 模型修改,通过jsno格式保存信息** @param modelId 模型 ID* @param name 模型名称* @param description 模型描述* @param json_xml JSON 格式的模型数据* @param svg_xml SVG 格式的模型数据*/@ApiOperation(value = "模型修改,通过jsno格式保存信息", notes = "模型修改,通过jsno格式保存信息")@RequestMapping(value = "/model/{modelId}/save", method = RequestMethod.POST)@ResponseStatus(value = HttpStatus.OK)public Result<String> saveModel(@PathVariable String modelId, String name, String description, String json_xml, String svg_xml) {// 创建一个 ByteArrayOutputStream 对象,用于存储转换后的 PNG 图像try (ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {// 获取指定 ID 的模型Model model = repositoryService.getModel(modelId);// 将模型的元数据转换为 JSON 对象ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());// 更新模型的名称和描述modelJson.put(MODEL_NAME, name);modelJson.put(MODEL_DESCRIPTION, description);model.setMetaInfo(modelJson.toString());model.setName(name);// 保存更新后的模型repositoryService.saveModel(model);// 将 JSON 格式的模型数据保存到模型编辑源repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes(StandardCharsets.UTF_8));// 将 SVG 格式的模型数据转换为 PNG 图像InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(StandardCharsets.UTF_8));TranscoderInput input = new TranscoderInput(svgStream);PNGTranscoder transcoder = new PNGTranscoder();// 设置输出流TranscoderOutput output = new TranscoderOutput(outStream);// 执行转换transcoder.transcode(input, output);final byte[] result = outStream.toByteArray();// 将转换后的 PNG 图像保存到模型编辑源额外数据repositoryService.addModelEditorSourceExtra(model.getId(), result);return Result.ok("保存成功!");} catch (Exception e) {throw new ServiceException(StrUtil.format("模型保存失败,具体失败原因为[{}]", LogUtil.getStackTraceInfo(e)));}}
    }
  • StencilsetRestResource

    package cn.git.workflow.modeler;import java.io.InputStream;import com.alibaba.fastjson.JSONObject;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.activiti.engine.ActivitiException;
    import org.apache.commons.io.IOUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;/*** @description: 在线模板中文转义文件获取* @program: bank-credit-sy* @author: lixuchun* @create: 2024-11-20*/
    @Api(value = "model流程设计器加载中文模板文件", tags = "model流程设计器加载中文模板文件")
    @RestController
    public class StencilsetRestResource {/*** 在线编辑器中文模板文件*/public static final String EDITOR_CH_FILE = "stencilset.json";/*** 获取在线编辑器中文模板文件** @return*/@ApiOperation(value = "加载stencilset.json中文文件", notes = "加载stencilset.json中文文件")@RequestMapping(value = "/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")public @ResponseBody Object getStencilset() {InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(EDITOR_CH_FILE);try {assert inputStream != null;return JSONObject.parseObject(IOUtils.toString(inputStream, "utf-8"));} catch (Exception e) {throw new ActivitiException("获取流程在线编辑器中文模板失败!", e);}}
    }

我们的项目是springboot前后端分离项目,我们整合的流程在线编辑器与前端项目需要进行 iframe 嵌套,所以有跨域问题。需要开放允许跨域。具体代码如下:

  • GlobalCrossConfig
    package cn.git.workflow.config;import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;/*** 通用跨域设置,允许跨域访问本项目* @program: bank-credit-sy* @author: lixuchun* @create: 2021-06-01*/
    @Configuration
    public class GlobalCrossConfig {/*** 设置跨域配置信息*/@Beanpublic CorsFilter corsFilter() {CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*");corsConfiguration.setAllowCredentials(true);corsConfiguration.addAllowedMethod("*");corsConfiguration.addAllowedHeader("*");corsConfiguration.addExposedHeader("*");UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", corsConfiguration);return new CorsFilter(configSource);}}

除此之外,还需要开启允许进行iframe嵌套,需要禁用X-Frame-Options头。X-Frame-Options是一个HTTP响应头,用于控制浏览器是否允许在一个 <frame>, <iframe>, 或 <object> 中加载页面。默认情况下,这个头会设置为 DENY 或 SAMEORIGIN,以防止点击劫持(Clickjacking)攻击。

调用 disable() 方法会禁用 X-Frame-Options 头,即不在响应中发送这个头。这样,页面可以在任何域的 <frame><iframe> 中加载,具体操作代码如下

  • SecurityConfig
    package cn.git.workflow.config;import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;/*** @description: 禁用activiti-rest引入后的security主动校验功能* @program: bank-credit-sy* @author: lixuchun* @create: 2024-06-11*/
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 禁用activiti-rest引入后的security主动校验功能* @param http* @throws Exception*/@Overridepublic void configure(HttpSecurity http) throws Exception {// 关闭securityhttp.httpBasic().disable().csrf().disable()// 允许iframe嵌套.headers().frameOptions().disable();http.authorizeRequests().anyRequest().permitAll();}
    }
    

我们还需要设置静态资源信息,提供我们在线编辑器的再跳转功能,具体设置如下:

  • WebMvcConfig

    package cn.git.workflow.config;import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @description: 添加fastjson转换器* @program: bank-credit-sy* @author: lixuchun* @create: 2024-11-21*/
    @Configuration
    class WebMvcConfig implements WebMvcConfigurer {/*** 添加静态资源文件,外部可以直接访问地址** @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// 添加外部静态资源registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");// 添加模板信息registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");}
    }
    

2.4 前端文件设置

具体替换文件 activiti-webexplore\Activiti-5.x\modules\activiti-webapp-explorer2\src\main\webapp下的是哪个文件
在这里插入图片描述
以及 activiti-webexplore\Activiti-5.x\modules\activiti-webapp-explorer2\src\main\resource目录下的文件标签文件
在这里插入图片描述
最终复制文件到项目中,目录格式如下
在这里插入图片描述

注意:我们也可以替换 stencilset.json,将流程页面展示信息变更为中文提示信息,此为中文文件地址

修改 app-cfg.js文件,将contextRoot 修改为空

var ACTIVITI = ACTIVITI || {};
ACTIVITI.CONFIG = {'contextRoot' : '',
};

修改 /editor-app/configuration/toolbar-default-actions.js,update方法修改请求方式为POST,对应前面ModelSaveRestResource请求方式修改为POST
在这里插入图片描述

3. 进行测试

测试分为两个部分,一个是流程服务自己测试,一个是使用iframe嵌套到前端项目中,进行测试

3.1 流程项目自己测试

启动服务,我们便可以进行简单测试了,访问 http://3.1.19.13:11203/modeler/save?modelName=测试啦999&modelKey=jackAoteMan&modelDescription=杰克奥特曼 进行新增
在这里插入图片描述
在这里插入图片描述
访问 http://3.1.19.13:11203/modeler/save?modelId=9fb167fa2434422697090a8ea56467e8 可以进行修改编辑
在这里插入图片描述

3.2 前端嵌入iframe测试

我们公司则是将其嵌入到了公司的前端项目中,我们通过公司前端进行访问,访问我们新增的流程model信息
在这里插入图片描述
点击修改按钮,进行简单修改
在这里插入图片描述
点击部署按钮,进行部署,之后此流程便可以正常使用了
在这里插入图片描述
在这里插入图片描述

除了部署修改,还有移除,下载xml文件等操作,此处便不多赘述,部署之后,可以在已部署目录中查看已部署信息,包含历史全部部署文件信息,可以分版本下载查看
在这里插入图片描述

本文参考此篇博文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887652.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

玩转 uni-app 静态资源 static 目录的条件编译

一. 前言 老生常谈&#xff0c;了解 uni-app 的开发都知道&#xff0c;uni-app 可以同时支持编译到多个平台&#xff0c;如小程序、H5、移动端 App 等。它的多端编译能力是 uni-app 的一大特点&#xff0c;让开发者可以使用同一套代码基于 Vue.js 的语法编写程序&#xff0c;然…

云技术-docker

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…

【C++】从C语言到C++学习指南

如果你也是从C语言一路过来的&#xff0c;那么请一起看下去吧&#xff01; 文章目录 面型对象程序设计C基础C和C一些语法区别C在非对象方面对C语言的扩充C的一些标准&#xff08;兼容旧标准&#xff09; 首先&#xff0c;在C的学习中&#xff0c;我们要时刻清醒一点&#xff1…

【FPGA开发】Vivado自定义封装IP核,绑定总线

支持单个文件的封装、整个工程的封装&#xff0c;这里用单个文件举例。 在文件工程目录下&#xff0c;自建一个文件夹&#xff0c;里面放上需要封装的verilog文件。 选择第三个&#xff0c;指定路径封装&#xff0c;找到文件所在目录 取个名&#xff0c;选择封装IP的路径 会…

CA系统(file.h---申请认证的处理)

#pragma once #ifndef FILEMANAGER_H #define FILEMANAGER_H #include <string> namespace F_ile {// 读取文件&#xff0c;返回文件内容bool readFilename(const std::string& filePath);bool readFilePubilcpath(const std::string& filePath);bool getNameFro…

前端-Git

一.基本概念 Git版本控制系统时一个分布式系统&#xff0c;是用来保存工程源代码历史状态的命令行工具 简单来说Git的作用就是版本管理工具。 Git的应用场景&#xff1a;多人开发管理代码&#xff1b;异地开发&#xff0c;版本管理&#xff0c;版本回滚。 Git 的三个区域&a…

深入浅出摸透AIGC文生图产品SD(Stable Diffusion)

hihi,朋友们,时隔半年(24年11月),终于能腾出时间唠一唠SD了🤣,真怕再不唠一唠,就轮不到SD了,技术更新换代是在是太快! 朋友们,最近(24年2月)是真的没时间整理笔记,每天都在疯狂的学习Stable Diffusion和WebUI & ComfyUI,工作实在有点忙,实践期间在飞书上…

HCIP——堆叠技术实验配置

目录 一、堆叠的理论知识 二、堆叠技术实验配置 三、总结 一、堆叠的理论知识 1.1堆叠概述&#xff1a; 是指将两台交换机通过堆叠线缆连接在一起&#xff0c;从逻辑上变成一台交换设备&#xff0c;作为一个整体参与数据的转发。 1.2堆叠的基本概念 堆叠系统中所有的单台…

快速上手:如何开发一个实用的 Edge 插件

在日常浏览网页时&#xff0c;背景图片能够显著提升网页的视觉体验。如果你也想为自己的浏览器页面添加个性化背景图片&#xff0c;并希望背景图片设置能够持久保存&#xff0c;本文将介绍如何通过开发一个自定义Edge插件来实现这一功能。我们将涵盖保存背景设置到插件选项页&a…

介绍一下atol(arr);(c基础)

hi , I am 36 适合对象c语言初学者 atol(arr)&#xff1b;是返回整数(long型)&#xff0c;整数是arr数组中字符中数字 格式 #include<stdio.h> atol(arr); 返回值arr数组中的数字 未改变arr数组 #include<stdio.h> //atol(arr); 返 <stdlib> int main…

Python的排序算法

一、算法 1.1 算法概念 算法就是计算机解决问题的方法或者步骤 程序 数据结构 算法 1.2 算法的特性 1】确定性&#xff1a; 算法的每条语句具有明确的意思&#xff0c;不能模棱两可 2】有穷性&#xff1a;在执行一定的时间后&#xff0c;能自动结束算法 3】输入&#…

npm install -g@vue/cli报错解决:npm error code ENOENT npm error syscall open

这里写目录标题 报错信息1解决方案 报错信息2解决方案 报错信息1 使用npm install -gvue/cli时&#xff0c;发生报错&#xff0c;报错图片如下&#xff1a; 根据报错信息可以知道&#xff0c;缺少package.json文件。 解决方案 缺什么补什么&#xff0c;这里我们使用命令npm…

在windows操作系统上,用git与github账户连接

一、环境准备 1.1 git软件 1.2 github账号 1.3 创建一个项目目录&#xff0c;比如 D:\project\gitproject 二、开始操作 1. 进入项目目录下&#xff0c;右键&#xff0c;如图&#xff0c;打开git bash命令行 2. 在命令行输入以下三个命令 $ git config --global user.name &quo…

视频监控实现画面缩放功能

文章目录 概要一、功能说明二、核心实现代码三、技术细节 概要 在视频监控系统中&#xff0c;经常需要查看视频画面中的细节。通过实现区域放大、滚轮缩放和拖拽平移等功能&#xff0c;可以让用户更方便地观察视频细节。本文介绍如何在 Windows 系统下实现这些交互功能。 一、…

鸿蒙本地模拟器 模拟TCP服务端的过程

鸿蒙模拟器模拟TCP服务端的过程涉及几个关键步骤&#xff0c;主要包括创建TCPSocketServer实例、绑定IP地址和端口、监听连接请求、接收和发送数据以及处理连接事件。以下是详细的模拟过程&#xff1a; **1.创建TCPSocketServer实例&#xff1a;**首先&#xff0c;需要导入鸿蒙…

Three.js 和其他 WebGL 库 对比

在WebGL开发中&#xff0c;Three.js是一个非常流行的库&#xff0c;它简化了3D图形的创建和渲染过程。然而&#xff0c;市场上还有许多其他的WebGL库&#xff0c;如 Babylon.js、PlayCanvas、PIXI.js 和 Cesium&#xff0c;它们也有各自的特点和优势。本文将对Three.js 与这些常…

【04】MySQL数据库和数据表的基本操作详解与实例

文章目录 一、连接MySQL服务器二、数据库的基本操作2.1数据库的基本操作1. 创建数据库2. 选择数据库3. 删除数据库4.查询所有数据库5.修改数据库的字符集 2.2 数据表的基本操作1. 创建数据表2. 查看数据表结构3. 删除数据表4. 修改数据表5. 插入数据6. 查询数据7. 更新数据8. 删…

CTF-Hub SQL 报错注入(纯手动注入)

​ 当输入1时&#xff0c;发现只有查询正确&#xff0c;基本上可以判断出没有回显 开始注入(工具hackerBar) 题目是报错注入&#xff0c;方向就比较明显&#xff0c;大致说一下用到的函数和原理。 常见报错注入函数&#xff1a; 通过 floor() 报错注入通过 extractValue() …

2024 阿里云的Debian12.8,安装mariadb【图文讲解】

目录 一、安装 MariaDB Server 二、登录到MariaDB&#xff0c;记得输入密码&#xff08;注意&#xff1a;密码非明文&#xff0c;只管输入&#xff0c;完成以后回车&#xff09; 三、创建用户 root&#xff0c;并允许从任何主机连接 四、授予用户访问权限 五、刷新权限 六、…

新用户引导库-driverjs

一个比好用的新用户引导的库 driverjs 在做这个功能时&#xff0c;首先要确定目标是什么样子的&#xff0c; 如果只是随意点击下一步下一步&#xff0c;那我感觉可能用图片轮播图的方式会快一点&#xff0c;更容易解决且方便&#xff0c;想要什么步骤 只需要更改图片就好&…