JeecgBoot 3.0集成Activiti 5.22工作流引擎:流程审批实战指南

发布时间:2026/11/11 22:28:30

JeecgBoot 3.0集成Activiti 5.22工作流引擎:流程审批实战指南 简介一套将 jeecg-boot 3.0、Activiti 5.22 与官方流程画布整合在一起的开发方案面向需要快速搭建企业级应用、并实现业务流程自动化的 Spring Boot 开发者既可帮助初学者理解三大组件的集成思路也能为已有项目从 2.4.6 升级到 3.0 提供参考。压缩包共 2000 个文件、约 22.5MB其中 625 个 Java 文件承载后端核心逻辑349 个 Vue 与 193 个 JS 文件构成前端交互界面168 个 bcmap 为字体映射资源另有 XML 流程定义、SQL 增量脚本、Dockerfile、yml 配置及 README 等文件覆盖开发、部署与文档说明等多个环节。目前已有 278 人学习。借助资源包可系统了解 jeecg-boot 代码生成、Activiti 流程设计、官方画布可视化建模如何衔接并借助完整代码、升级脚本与配置快速搭建可运行原型同时清晰的目录结构和多样文件类型便于按需查阅升级脚本也能帮助旧版本用户平滑迁移减少重复搭建成本。 几年前接一个内部管理系统时甲方列了一堆流程审批需求多级会签、撤回、改签、环节超时提醒。我扫了一遍 JeecgBoot 3.0 自带的流程能力发现应付简单审批可以碰到这种复杂度就吃力了。于是当时的方案很直接——把 Activiti 5.22 塞进 JeecgBoot并且直接用 Activiti 官方的流程画布Modeler做在线流程设计。这套组合从搭环境到正式跑通前后花了两周左右中间踩的坑不少但最后效果是真稳。这篇就是把整个集成过程、版本冲突处理、画布适配、数据库兼容这些细节完整记录下来给正在折腾 JeecgBoot Activiti 的开发者一个参考。如果你是刚开始了解 JeecgBoot或者准备在项目里接工作流引擎但不知道选哪个版本又或者已经导入了 activiti 依赖但启动报错、画布打不开这篇文章都能给你省掉不少排查时间。下面我按实际集成顺序讲从选型原因到最终上线一条线捋到底。1. 为什么是“jeecg-boot 3.0 activiti 5.22”这套组合1.1 本来是冲着JeecgBoot的快速开发去的JeecgBoot 3.0 吸引我的地方在于低代码能力代码生成器一键生成前后端页面表单、列表、菜单这些基础开发量直接砍掉大半。对于企业内部管理系统来说这是很实用的一套底座。但管理系统的核心业务里审批流几乎是躲不开的模块。采购单要走审批请假要审批合同要审批而且每家公司的流程都不太一样甲方今天说三步审批明天就可能改成五步还要求流程中途能改签、能撤回。这种需求已经超出了 JeecgBoot 内置流程插件的范畴必须引入专业的工作流引擎。在 Java 生态里工作流引擎无非就是 Activiti、Flowable、Camunda 这几个主流选择。考虑到团队对 Activiti API 最熟网上资料最多最终定了 Activiti。1.2 Activiti 5.22并没有网上说的那么“不能用”很多人在选型时会纠结Activiti 都出到 7 了为什么还要用 5.22这里有个现实问题——项目的基础环境是 JDK 8 Spring Boot 2.x MyBatis-Plus这套组合里 Activiti 5.22 反而是最稳定的选择。先说 5.22 的定位。5.22.0 是 Activiti 5 系列的最终版本5 系列这么多年的 bug 修复都沉淀在这个版本里社区的踩坑贴子也最多遇到问题基本能搜到解决方案。而且 5.22 的 API 设计非常直观RepositoryService、RuntimeService、TaskService 几个核心 Service 一学就会项目成员的接手成本很低。Activiti 7 虽然新但它把身份管理、安全框架都重写了和 Spring Boot 2.x 集成时需要引入额外的 Spring Security 配置对于一个只想在后台管理系统里加审批流的场景来说改动面太大。Flowable 是从 Activiti 5 分叉出去的功能确实强但 API 有细微变动团队还得重新熟悉一遍。权衡下来5.22 是最务实的选项。至于官方画布这个选择就更明确了。自己从头写一个流程设计器不现实基于 bpmn-js 二次开发工作量也不小。Activiti 官方自带的 Modeler 是一个基于 AngularJS 的在线拖拽画布能画开始事件、用户任务、排他网关、结束事件这些基础元素保存成官方模型 JSON发布时再解析成 BPMN 文件。直接把官方这套搬进来用省时省力。2. 依赖整合与数据源配置先把引擎跑起来2.1 处理Maven依赖冲突mybatis/jackson/spring三座大山第一关就是 Maven 依赖。Activiti 5.22 是 2017 年前后的版本它内部依赖的 Spring、MyBatis、Jackson 版本都偏老直接往 JeecgBoot 3.0 的 pom.xml 里一放启动大概率会报 jar 包冲突。最常见的冲突有三类MyBatisActiviti 引擎内部自己也用了 MyBatis 做持久层这一点很多人不知道。它自带的 mybatis 版本如果和 JeecgBoot 里的 MyBatis-Plus 依赖的 mybatis 核心包版本不一致轻则启动告警重则NoClassDefFoundError。SpringActiviti 5.22 的 activiti-spring 模块依赖的是 Spring 4 时代的包而 Spring Boot 2.x 用的是 Spring 5。两边如果没处理干净会出现BeanCreationException。Jackson官方画布的前后端交互走的是 JSONActiviti 内部也绑定了 Jackson 版本和 Boot 自带的 Jackson 版本不一致时模型解析会出怪问题。我的做法是引入 activiti-spring 时把它的传递依赖全部排除掉再让项目统一使用 JeecgBoot 锁定的版本dependency groupIdorg.activiti/groupId artifactIdactiviti-spring/artifactId version5.22.0/version exclusions exclusion groupIdorg.mybatis/groupId artifactIdmybatis/artifactId /exclusion exclusion groupIdorg.springframework/groupId artifactIdspring-context/artifactId /exclusion exclusion groupIdorg.springframework/groupId artifactIdspring-tx/artifactId /exclusion exclusion groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId /exclusion /exclusions /dependency这里要注意排除掉 Activiti 自带的 mybatis 后需要保证项目里存在一个它能识别的 MyBatis 版本。我项目里没有额外加依赖直接用了 MyBatis-Plus 传递进来的 MyBatis 核心包实测没问题。2.2 引擎配置与自动建表依赖搞定后就是创建 ProcessEngine。Activiti 5.22 在 Spring 环境下的标准做法是用ProcessEngineFactoryBean配合SpringProcessEngineConfiguration。在 JeecgBoot 里写一个配置类Configuration public class ActivitiConfig { Bean public ProcessEngineFactoryBean processEngineFactoryBean(DataSource dataSource) { ProcessEngineFactoryBean factoryBean new ProcessEngineFactoryBean(); SpringProcessEngineConfiguration config new SpringProcessEngineConfiguration(); config.setDataSource(dataSource); config.setDatabaseSchemaUpdate(true); config.setJobExecutorActivate(true); factoryBean.setProcessEngineConfiguration(config); return factoryBean; } Bean public RepositoryService repositoryService(ProcessEngine processEngine) { return processEngine.getRepositoryService(); } // RuntimeService、TaskService、HistoryService 同理 }几个关键参数要解释一下。databaseSchemaUpdatetrue表示启动时自动建表或更新表结构第一次集成时建议开启跑起来后到数据库里确认 ACT_ 开头的表都生成了再把参数改成false避免生产环境误操作。jobExecutorActivatetrue是激活定时任务执行器如果流程里没有定时事件可以先关掉减少不必要的后台线程。这里有个非常容易踩的坑传入的 DataSource 必须是业务库同一个数据源。如果 JeecgBoot 配置了多数据源或者 Activiti 配置类里自己 new 了一个数据源那流程表就会建到别的库去后面查数据的时候一脸懵。我用的是 JeecgBoot 默认数据源直接把 DataSource 注入进来就好。2.3 事务处理细节Activiti 5.22 的事务机制是独立的它内部用 CommandContext 管理事务。如果业务代码里加了Transactional然后又调用了 Activiti 的 Service 方法两者并不是天然在同一个事务里。简单场景下比如启动流程、完成任务不需要强行把它们做到一个事务里流程操作独立提交反而更安全。如果业务表单数据和流程实例必须保持强一致我建议在业务事务提交后通过TransactionSynchronizationManager.registerSynchronization再触发流程操作。虽然多了一步但能避免“业务数据提交了流程没启动成功”或者反过来“流程启动了业务数据回滚了”这种尴尬情况。3. 官方画布搬进JeecgBoot前后端的适配过程3.1 从Explorer包中拆出Modeler前端资源Activiti 官方画布并没有作为独立插件发布它藏在 Activiti Explorer 的 Web 应用里。你需要下载activiti-webapp-explorer-5.22.0.war解压后把里面的editor-app和diagram-viewer两个目录拷贝出来放到 JeecgBoot 的src/main/resources/static/activiti/目录下。editor-app是画布的核心前端资源里面是 AngularJS 写的单页应用。diagram-viewer是流程图预览组件。注意把这些静态资源放到 static 目录后访问路径就是/activiti/editor-app/editor.html后续挂 iframe 要用这个路径。拷贝完后要改一个关键文件editor-app/app-cfg.js。这个文件里有 AngularJS 的 context 路径配置默认指向的是 Activiti Explorer 的服务端地址。不改的话前端会去请求一个不存在的接口画布打开是空白。改成你的项目根路径即可。3.2 补一套模型读写接口官方 Modeler 保存画布时调用的核心接口是“读取模型 JSON”和“保存模型 JSON”。Activiti 官方把这套接口写在ModelEditorJsonRestResource里。最简单的办法是把这些 REST 接口的代码抄到自己的 Controller 里只保留和模型相关的部分不依赖完整的 activiti-rest 模块。核心逻辑并不复杂主要围绕RepositoryServiceRestController RequestMapping(/activitiModel) public class ActivitiModelController { Autowired private RepositoryService repositoryService; GetMapping(/{modelId}/json) public AjaxResult getModelJson(PathVariable String modelId) { Model model repositoryService.createModelQuery().modelId(modelId).singleResult(); byte[] editorSource repositoryService.getModelEditorSource(modelId); // 返回给前端画布使用的 JSON return AjaxResult.success(ok, JSON.parseObject(new String(editorSource, StandardCharsets.UTF_8))); } PostMapping(/{modelId}/save) public AjaxResult saveModel(PathVariable String modelId, RequestBody JsonNode body) { repositoryService.addModelEditorSource(modelId, body.toString().getBytes(StandardCharsets.UTF_8)); return AjaxResult.success(); } }新建模型的接口也一样用repositoryService.newModel()创建 Model 对象设置 key、name、metaInfo然后调用saveModel保存。这样官方画布的前后端链路就通了。3.3 Vue3页面用iframe挂载画布并放行登录拦截JeecgBoot 3.0 的前端是 Vue3官方画布是 AngularJS两者技术栈完全不同硬往一个页面里揉很容易互相干扰。我用的是最省事的方案在 JeecgBoot 里新开一个路由页面内容就是一个 iframe指向/activiti/editor-app/editor.html?idxxx。template div styleheight: calc(100vh - 50px) iframe :srcmodelerUrl stylewidth: 100%; height: 100%; border: none / /div /templateiframe 隔离性最好AngularJS 的全局变量和 Vue3 的响应式系统互不干扰这是我最推荐的做法。但这里有个绕不开的问题JeecgBoot 默认有登录拦截无论是 Shiro 还是其他权限框架请求/activiti/**和/activitiModel/**时都会被拦下来。我的处理方式是在权限配置里放行这两类资源画布加载时通过 URL 参数携带 token后端写一个简单的过滤器校验 token 合法性。这样既不影响整体登录安全画布又能正常访问。还有一个小坑是stencilset.json的路径。这个文件定义了画布里有哪些组件开始事件、用户任务、网关等官方 Modeler 初始化时会去请求/service/editor/stencilset。如果这个请求 404 了画布打开后左侧组件区是空的。需要把官方StencilsetRestResource的逻辑也复制到自己的 Controller 里或者直接把 stencilset 静态资源放到可访问的路径下。4. 流程定义、部署与业务表单打通4.1 从画布保存到流程部署画布保存的是模型 JSON不是真正的 BPMN 文件要让 Activiti 引擎跑起来还要把模型 JSON 转成 BPMN 并创建部署。Activiti 5.22 提供了两个转换器BpmnJsonConverter和BpmnXMLConverter。转换代码如下ObjectMapper objectMapper new ObjectMapper(); JsonNode jsonNode objectMapper.readTree(modelEditorSource); BpmnModel bpmnModel new BpmnJsonConverter().convertToBpmnModel(jsonNode); byte[] bpmnBytes new BpmnXMLConverter().convertToXML(bpmnModel); Deployment deployment repositoryService.createDeployment() .name(model.getName()) .addString(model.getKey() .bpmn20.xml, new String(bpmnBytes, StandardCharsets.UTF_8)) .deploy();部署成功后会在ACT_RE_PROCDEF表里生成一条流程定义记录key 对应模型 key版本号默认从 1 开始。重复部署同 key 的模型版本号会递增这在流程版本管理上是合理的但要注意旧版本流程实例仍在运行不要贸然清理。我的做法是在模型列表页面增加一个“部署”按钮点击后执行转换和部署逻辑部署成功后再把 deploymentId 回写到模型表的 metaInfo 里方便后面追溯。4.2 启动流程实例与业务数据关联部署完成不代表流程能直接用你还需要从业务页面发起流程。启动流程实例最常用的方法是按流程 key 启动MapString, Object variables new HashMap(); variables.put(applyUserId, currentUserId); variables.put(days, 3); variables.put(reason, 出差申请); ProcessInstance processInstance runtimeService.startProcessInstanceByKey( processDefinitionKey, businessKey, variables );第三个参数businessKey非常关键。我习惯把业务表单的主键传进去比如采购单 id、请假单 id这样通过runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey)就能反查流程实例审批记录和业务数据也能一一对应。画布上每个用户任务的Assignee、Candidate Users这些属性如果在画布上写死字符串那就所有流程都一个办理人显然不现实。我的做法是启动流程时把当前登录用户 id 放进 variables然后在画布的用户任务分配表达式里写${applyUserId}之类的变量引用。这样每次发起流程时第一个环节的办理人就是申请人自己后续节点再根据业务逻辑动态指定。4.3 待办查询与审批完成待办查询对接到 JeecgBoot 的后台管理页面后实现起来很直接ListTask todoTasks taskService.createTaskQuery() .taskAssignee(currentUserId) .orderByTaskCreateTime().desc() .list();审批通过就是完成任务并传入流程变量MapString, Object taskVariables new HashMap(); taskVariables.put(approved, true); taskService.complete(taskId, taskVariables);审批历史则从historyService.createHistoricProcessInstanceQuery()和createHistoricActivityInstanceQuery()里查。到这里一条完整的审批链路就走通了。5. 数据库版本兼容与Idea插件离线安装这些周边问题5.1 Activiti 5.22在不同数据库版本下的适配Activiti 5.22 支持的数据库不少但我实际用下来遇到最多问题的是 MySQL 版本差异。项目里两个环境一个 MySQL 5.7一个 MySQL 8.0这里有个大坑必须说MySQL 8.x 默认的密码认证插件是caching_sha2_password如果项目还在用老版本的 mysql-connector-java启动时直接报Unable to load authentication plugin caching_sha2_password。解决办法是把 mysql-connector-java 升级到 8.0.x并在 JDBC URL 里补上几个参数jdbc:mysql://localhost:3306/jeecg_boot?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrueActiviti 5.22 自动生成的表结构在 MySQL 5.7 和 8.0 下都能正常使用主要就是驱动和连接参数的问题。表引擎一定得是 InnoDBMyISAM 不支持事务如果发现历史表是 MyISAM 建的用下面这句批量改回来ALTER TABLE act_hi_procinst ENGINE InnoDB;另外ACT_GE_PROPERTY表里存着 schema 版本号启动时引擎会检查它和自身版本是否匹配。如果从老版本 Activiti 升级上来版本号对不上会直接抛异常这个后面排查章节再细讲。5.2 Idea的Activiti插件离线安装经历与建议一开始我也想着在 Idea 里装个 Activiti 插件本地画 .bpmn 文件但折腾了一圈后放弃了。主要原因有两个一是 actiBPM 这个插件基本停更了在最近几个 Idea 版本上要么搜不到要么装完界面渲染异常二是就算装上离线安装包也不好找官方插件仓库目前把旧版隐藏了不少。如果确实处于内网环境只能离线安装标准操作是在 JetBrains 插件商店页面手动下载对应版本的 zip 包然后打开 Idea 的 Settings - Plugins - 齿轮图标 - Install Plugin from Disk选择下载好的 zip重启后生效。但据我实测Idea 2021 之后的版本对 actiBPM 的兼容性很不乐观经常出现插件列表里能看到但画布工具栏空白的情况。所以我后来彻底放弃了本地插件画流程统一使用官方画布在线设计。官方画布能直接保存和部署少一次文件传输环节对于团队协作也更友好。如果你实在需要在本地画 BPMN我更推荐 VS Code 的 bpmn-io 扩展轻量且渲染可靠画完导出.bpmn20.xml再导入 JeecgBoot 即可。6. 集成后最容易踩的坑问题排查看图说话6.1 高发报错对照表集成过程中我遇到过不少报错整理成一张表方便你对照排查现象根本原因解决办法启动失败NoClassDefFoundError: org/mybatis/...Activiti 内置 MyBatis 与项目版本冲突排除 Activiti 传递的 mybatis统一用项目版本BeanCreationException: ProcessEngine初始化失败数据源连接参数不对或驱动过旧检查 url、driver、MySQL 驱动版本画布打开后左侧组件区空白stencilset.json请求 404补上官方 StencilsetRestResource 或放行静态资源画布保存接口 401登录拦截器把 REST 请求拦了放行/activitiModel/**并校验 token启动流程后待办查不到任务 Assignee 与当前查询用户不一致确认流程变量和用户任务表达式Schema validation failed数据库 schema 版本与引擎版本不匹配检查 ACT_GE_PROPERTY 里的版本号模型 JSON 转 BPMN 时报节点解析异常画布里有官方 JSON 转换器不识别的扩展节点回画布删掉多余元素重新发布6.2 一次完整的排错案例ACT_表“消失”了这里分享一个我印象最深的案例。配置全部写好后启动项目日志里没有报错ProcessEngine 也创建成功了但打开数据库一查一张 ACT_ 的表都没有。我愣了很久还以为是databaseSchemaUpdatetrue没生效。后来把日志级别调到 DEBUG 才发现引擎执行建表语句用的连接指向的是另一个库——因为我项目里配了动态数据源Activiti 注入到的 DataSource 是动态数据源的默认路由但实际运行时上下文里选中的默认库和业务库不是同一个。MyBatis-Plus 的多数据源插件在启动阶段拿到的是主数据源而 Act 引擎用的连接被路由到了别的库。解决方式也很简单给 Activiti 单独定义一个数据源 Bean明确指向业务库然后在配置类里用Qualifier指定这个数据源。这类问题不看日志很难发现强烈建议在集成阶段把org.activiti的日志级别调到 DEBUG启动时能看到完整的建表 SQL 和引擎初始化的每一步。6.3 把日志级别打开能省一大半时间最后这点算是我反复踩坑后的心得。Activiti 5.22 的日志系统用的是 slf4j可以直接通过 application.yml 配置日志级别logging: level: org.activiti: debug org.apache.ibatis: debug开启后每次启动都能看到引擎执行了哪些 SQL、是否执行了 schema 检查、部署了哪些流程定义。遇到问题时不要一上来就怀疑代码逻辑先看日志里引擎是否正常初始化再看 SQL 是否执行到预期位置大多数问题都能快速定位到是哪一层出的问题。7. 关于这套方案我最后想说的几点经验这套“jeecg-boot 3.0 activiti 5.22 官方画布”的组合我这边项目已经跑了半年多线上流程定义有四十多个引擎一直很稳定没出现过流程数据错乱或任务丢失的情况。我个人体会是技术选型不一定要追新稳定和团队熟悉度更重要。如果你也在集成过程中卡住按这篇文章的顺序捋一遍基本能解决大部分问题——依赖冲突、数据源指向、画布静态资源、登录拦截这四个环节是 90% 故障的根源。再补一句特别实用的建议pom.xml 里的 activiti 版本千万不要用 latest 这种动态版本号直接锁死 5.22.0不然哪天依赖解析到不同小版本线上跑着跑着就可能出现诡异行为到时候排查成本远比今天多写一个版本号高得多。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/11/12 7:19:24

macOS 屏幕录制免费方案 QuickRecorder:10MB 装下 7 种录制模式

macOS 屏幕录制免费方案 QuickRecorder:10MB 装下 7 种录制模式 【免费下载链接】QuickRecorder A lightweight screen recorder based on ScreenCapture Kit for macOS / 基于 ScreenCapture Kit 的轻量化多功能 macOS 录屏工具 项目地址: https://gitcode.com/G…

2026/11/12 7:14:27

低压电工证企业会复审怎么网上查询

低压电工证企业会复审怎么网上查询 证书过期了不知道怎么复审延期,网上查询流程还不清楚?很多电工从业者都遇到过这个问题,特别是在企业岗位中,低压电工证作为从业必备资质,复审不及时就可能面临停工、罚款甚至被辞退。本文结合漯河房建工程从业者的实际…

2026/11/12 7:14:27

南京电工证报考费用值不值得考?外省证能转过来吗

南京电工证报考费用值不值得考?外省证能转过来吗 之前考的证在外省能不能转过来?这几乎是每个想在南京从事电工相关工作的人都会问的问题,尤其是那些已经在外地考了证的从业者。如果你也正面临这个困惑,那这篇文章会给你一个清晰的答案,还告诉你南京电工…

2026/11/12 7:14:27

建筑电工证未复核怎么处理?真实经历告诉你

建筑电工证未复核怎么处理?真实经历告诉你 学历不高怕报不上名,这个问题我懂,我身边就有好几个朋友,都是初中毕业,干了几年工地,想考个建筑电工证,结果一查报名条件,门槛挺高,心里直打鼓。别急,我来给你说说,我有个朋友小张,就是通过 真实经历…

2026/11/12 7:14:27

泗县考低压电工证怕考不过白交培训费?全国通用证书怎么拿?

泗县考低压电工证怕考不过白交培训费?全国通用证书怎么拿? 怕考不过白交培训费?泗县考低压电工证的你是不是也这么想?其实只要掌握正确的方法和资源,全国通用的低压电工证并不难考。本文从新乡劳务班组负责人的角度出发,详细解析低压电工证的考试内容、…

2026/11/12 7:14:27

施工单位有多少特种工考前押题怎么准备才靠谱

施工单位有多少特种工考前押题怎么准备才靠谱 不知道去哪报名怕被中介坑?特种作业证是施工单位的“硬通货”,尤其是像高压电工、焊工、高处作业这些岗位,没证连进场都难。而很多工人在准备考试时,最大的问题就是找不到靠谱的培训机构,怕被坑钱、怕考不过…

2026/11/11 12:42:59

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/12 0:04:01

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘 工地太忙根本没时间复习考试?你不是一个人。作为一名在南阳卧龙区干了七八年市政公用工程的电工,我深知这个问题的现实性。电工证不仅是工作的“入场券”,更是职业发展的“通行证”,但备考过程…

2026/11/12 0:04:01

双流电工证考别怕挂科!郑州报考避坑指南全攻略

双流电工证考别怕挂科!郑州报考避坑指南全攻略 实操考试心里没底怕挂科?双流电工证考在郑州报名,很多人因为不了解流程、准备不充分,白白浪费时间和金钱。作为三门峡应届工程类毕业生,我也曾经历过这样的焦虑。今天就从零开始,手把手教你如何避开郑州报…

2026/11/12 0:04:01

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少 之前考的证在外省能不能转过来?这个问题确实让不少准备换城市工作的朋友犯了难,尤其像电工证这种实操性很强的证书,很多人担心跨省后证书能不能继续用。其实,只要符合相关流程,是可以顺利转…

2026/11/11 20:27:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑