jeecg-boot框架activiti定时节点流转错误分析

news2024/9/25 17:19:20

文章目录

    • 一、项目介绍
    • 二、问题复现
    • 三、排查过程
      • 1、找到报错信息
      • 2、找到报错的堆栈信息
      • 3.找到错误代码
      • 4.分析错误原因
        • 4.1、首先要明白`SecurityManager`是什么?
        • 4.2、定时器前的流程跟之前的流程不是同一个流程
          • 👉定时任务的数据已经生成,那么该如何生成定时任务呢?
          • 👉介绍一下`JobExecutor`
          • 👉所以服务器上的`JobExecutor`的执行并不绑定到特定的服务器
      • 5、解决方案
      • 6、定时作业执行器不执行的问题

一、项目介绍

当前项目底层是开源的jeecg框架,公司根据此框架进行二次开发。但是框架本身集成的一些功能并没有去,比如:activiti、xxl-job等。

版本:
jeecg-boot v3.3.0
集成的activiti v5.22.0

请注意一下网址👉官网地址、JeecgBoot 开发文档、github地址、相关的jeecgFlow文档

二、问题复现

根据项目中的流程设计。画的部分流程图,如下显示:
在这里插入图片描述
节点流转:

  • 节点1:是部门审批节点。部门审批通过之前,设置延时(结束)时间,也可以叫下次派发时间
  • 节点2:定时器节点:延时到下次派发时间,后流转到3节点
  • 节点3:是部门派发节点。

因业务状态需要根据节点的流转进行同步的修改,所以在此基础上,我给每个节点都增加了一个create事件的TaskListener任务监听(监听Class:DefectFlowNodeStartTaskListener),在监听里面获取到节点信息,通过FeginClient接口修改业务数据的状态!

本质上来说,这是一个基本的业务,没啥难得,但是实际开发中遇到了一个问题,那就是节点2定时器到时间后,执行DefectFlowNodeStartTaskListener报错了!

问题来了,关于DefectFlowNodeStartTaskListener的日志不打印,断点也拦不住!根本判断,错误出到哪里!!!

三、排查过程

1、找到报错信息

最后详细了解activiti的知识,最后发现了,关于activiti-timer-job的信息,都存储到一个张表act_ru_job里。

-- auto-generated definition
create table act_ru_job
(
    ID_                  VARCHAR(64)             not null comment '主键'
        primary key,
    REV_                 INT(10)                 null comment '乐观锁',
    TYPE_                VARCHAR(255)            not null comment '类型',
    LOCK_EXP_TIME_       TIMESTAMP(23)           null comment '锁定过期时间',
    LOCK_OWNER_          VARCHAR(255)            null comment '锁定节点',
    EXCLUSIVE_           TINYINT(3)              null comment '是否唯一',
    EXECUTION_ID_        VARCHAR(64)             null comment '执行',
    PROCESS_INSTANCE_ID_ VARCHAR(64)             null comment '流程实例',
    PROC_DEF_ID_         VARCHAR(64)             null comment '流程定义',
    RETRIES_             INT(10)                 null comment '重试次数',
    EXCEPTION_STACK_ID_  VARCHAR(64)             null comment '异常堆栈',
    EXCEPTION_MSG_       VARCHAR(4000)           null comment '异常信息',
    DUEDATE_             TIMESTAMP(23)           null comment '截止时间',
    REPEAT_              VARCHAR(255)            null comment '重复',
    HANDLER_TYPE_        VARCHAR(255)            null comment '处理器类型',
    HANDLER_CFG_         VARCHAR(4000)           null comment '处理器配置',
    TENANT_ID_           VARCHAR(255) default '' null comment '租户id',
    constraint ACT_FK_JOB_EXCEPTION
        foreign key (EXCEPTION_STACK_ID_) references act_ge_bytearray (ID_)
);

最后在字段EXCEPTION_MSG_里找到了报错信息。但是只有报错信息,没有堆栈信息,无法排查是哪一行的错误。
报错信息如下:

Exception while invoking TaskListener: Exception while invoking TaskListener: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application config...

找到了一天半!都没解决!!
就想着找到报错的堆栈信息,包括不限于:打断点、通过错误日志找报错的那一行代码,通过代码分析报错的点、通过JVMjconsole查找堆栈信息。

2、找到报错的堆栈信息

最后在头昏脑胀的时候,突然发现,上面那一张表,有一个字段叫EXCEPTION_STACK_ID_,这个 异常堆栈是一个ID,而且还是一个外键。
这就有意思了,通过的IDEA DataGridShow Diagram...找到了对应表act_ge_bytearray
在这里插入图片描述
在这里插入图片描述

act_ge_bytearray这张表比较有意思。

-- auto-generated definition
create table act_ge_bytearray
(
    ID_            VARCHAR(64)  not null comment '主键'
        primary key,
    REV_           INT(10)      null comment '乐观锁',
    NAME_          VARCHAR(255) null comment '部署的文件名称',
    DEPLOYMENT_ID_ VARCHAR(64)  null comment '部署表ID',
    BYTES_         LONGBLOB(max) null comment '部署文件',
    GENERATED_     TINYINT(3)   null comment '是否是引擎生成(0为用户生成,1为activiti生成)',
    constraint ACT_FK_BYTEARR_DEPL
        foreign key (DEPLOYMENT_ID_) references act_re_deployment (ID_)
);

刚开始出现报错的时候,我曾猜测,可能是我流程图画错了,通过跟踪接口,最后发现了这张表。关于生成的activitibpm.xml流程图生成的图片信息流程页面画的图的信息等信息都存在入了这样表!
用官方的话说就是:ACT_GE_BYTEARRAY表用于存储与流程定义相关的二进制数据,比如流程图的图片文件、模型的XML定义以及其他与流程实例或任务相关的文件。

本表字段NAME_
字段值是stacktrace都是执行出错的堆栈信息
字段值是bpmn20.xml结尾的,是流程生成的 bpm.xml信息
字段值是source的,是流程生成的 bpm.xml的json信息,比如:节点、连线关系。
字段值是source-extra的,是流程定义的额外源代码信息。具体来说,这是指在BPMN模型中可能存在的额外元数据或者是在编辑流程模型时添加的附加信息。例如,如果你使用Activiti Modeler或其他支持的BPMN编辑器,那么source-extra可能包含编辑器特定的数据,如用户界面布局信息、注释、自定义属性等,这些数据不直接参与流程执行,但在编辑或展示流程模型时有用。

当时因为数据太多,根本没发现里面存在堆栈信息。
最后根据上面的EXCEPTION_STACK_ID_关联到本表的ID_上,才查询出来报错的堆栈信息。

org.activiti.engine.ActivitiException: Exception while invoking TaskListener: Exception while invoking TaskListener: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.
	at org.activiti.engine.impl.persistence.entity.TaskEntity.fireEvent(TaskEntity.java:742)
	at org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior.execute(UserTaskActivityBehavior.java:212)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationActivityExecute.execute(AtomicOperationActivityExecute.java:60)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionNotifyListenerStart.eventNotificationsCompleted(AtomicOperationTransitionNotifyListenerStart.java:52)
	at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:56)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:49)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionCreateScope.execute(AtomicOperationTransitionCreateScope.java:49)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionNotifyListenerTake.execute(AtomicOperationTransitionNotifyListenerTake.java:80)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionDestroyScope.execute(AtomicOperationTransitionDestroyScope.java:116)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionNotifyListenerEnd.eventNotificationsCompleted(AtomicOperationTransitionNotifyListenerEnd.java:35)
	at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:56)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:49)
	at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:97)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:650)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:643)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:460)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:438)
	at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performOutgoingBehavior(BpmnActivityBehavior.java:140)
	at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performDefaultOutgoingBehavior(BpmnActivityBehavior.java:66)
	at org.activiti.engine.impl.bpmn.behavior.FlowNodeActivityBehavior.leave(FlowNodeActivityBehavior.java:44)
	at org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior.leave(AbstractBpmnActivityBehavior.java:47)
	at org.activiti.engine.impl.bpmn.behavior.IntermediateCatchEventActivityBehavior.signal(IntermediateCatchEventActivityBehavior.java:27)
	at org.activiti.engine.impl.persistence.entity.ExecutionEntity.signal(ExecutionEntity.java:417)
	at org.activiti.engine.impl.jobexecutor.TimerCatchIntermediateEventJobHandler.execute(TimerCatchIntermediateEventJobHandler.java:58)
	at org.activiti.engine.impl.persistence.entity.JobEntity.execute(JobEntity.java:85)
	at org.activiti.engine.impl.persistence.entity.TimerEntity.execute(TimerEntity.java:96)
	at org.activiti.engine.impl.cmd.ExecuteJobsCmd.execute(ExecuteJobsCmd.java:88)
	at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:24)
	at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:57)
	at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
	at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45)
	at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:31)
	at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:40)
	at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:35)
	at org.activiti.engine.impl.jobexecutor.ExecuteJobsRunnable.handleMultipleJobs(ExecuteJobsRunnable.java:94)
	at org.activiti.engine.impl.jobexecutor.ExecuteJobsRunnable.run(ExecuteJobsRunnable.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.activiti.engine.ActivitiException: Exception while invoking TaskListener: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.
	at org.activiti.engine.impl.bpmn.helper.ClassDelegate.notify(ClassDelegate.java:123)
	at org.activiti.engine.impl.delegate.TaskListenerInvocation.invoke(TaskListenerInvocation.java:34)
	at org.activiti.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:37)
	at org.activiti.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:25)
	at org.activiti.engine.impl.persistence.entity.TaskEntity.fireEvent(TaskEntity.java:740)
	... 60 more
Caused by: org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.
	at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
	at org.apache.shiro.subject.Subject$Builder.<init>(Subject.java:626)
	at org.apache.shiro.SecurityUtils.getSubject(SecurityUtils.java:56)
	at org.jeecg.modules.activiti.tasklistener.defetct.DefectFlowNodeStartTaskListener.notify(DefectFlowNodeStartTaskListener.java:42)
	at org.activiti.engine.impl.delegate.TaskListenerInvocation.invoke(TaskListenerInvocation.java:34)
	at org.activiti.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:37)
	at org.activiti.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:25)
	at org.activiti.engine.impl.bpmn.helper.ClassDelegate.notify(ClassDelegate.java:121)
	... 64 more

3.找到错误代码

最后根据报错的堆栈信息
在这里插入图片描述

找到了一行代码:

 LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

4.分析错误原因

为什么获取LoginUser 的时候会报错SecurityManager的错误呢?

4.1、首先要明白SecurityManager是什么?

SecurityManager 是 Java 安全模型的核心组件之一,它提供了一种机制来控制程序中的敏感操作,如文件和网络访问、系统属性读取、类加载以及反射操作等。SecurityManager 允许应用程序开发者定义安全策略,从而决定在运行时哪些操作是被允许的,哪些是被禁止的。

主要功能

  • 安全策略管理:
    • 定义安全策略,规定哪些操作可以在程序中执行。
  • 权限控制:
    • 控制对敏感资源的访问权限,比如文件系统、网络连接、系统属性等。
  • 执行检查:
    • 包含一系列以 check 开头的方法,用于在执行潜在敏感操作前进行权限检查。
      例如,checkRead(String file) 方法会在读取文件前检查权限。
  • 异常抛出:
    • 如果 SecurityManager 认定某个操作不被允许,它会通过抛出 SecurityException 或其子类来阻止该操作的执行。
  • 默认实例:
    • 在 JVM 启动时,默认的 SecurityManager 实例可能不会启用,除非显式地设置了 -Djava.security.manager 参数或在安全策略文件中指定了它。
  • Policy 文件:
    • 通常,SecurityManager 使用一个名为 policy 的配置文件来确定哪些代码具有什么权限。
    • 这个文件可以指定代码来源(代码基)与相应的权限集之间的映射。

这个类,咱们最常用的就是获取用户信息,就上面那个一段代码:

LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

跟踪SecurityUtils.getSubject()方法,就会发现ThreadContext

public static Subject getSubject() {
    Subject subject = ThreadContext.getSubject();
    if (subject == null) {
        subject = (new Subject.Builder()).buildSubject();
        ThreadContext.bind(subject);
    }
    return subject;
}

跟踪ThreadContext.getSubject()方法,进入ThreadContext类就会发现一个属性

private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();

咱们的Subject 就是从这个属性resources 里获取的。看到ThreadLocal大家应该就明白了。报错估计就是从这里来的。
定时器到时候后,执行taskListener,结果监听里面有一个获取用户的方法!结果去ThreadLocal里获取用户,获取不到用户信息就报错了!
为什么获取不到用户?之前的流程跟定时器开启的流程,不是同一个sessionId的实例。

注意:Jeecg-boot框架集成了shiro,上面的代码是 Apache Shiro 的代码

4.2、定时器前的流程跟之前的流程不是同一个流程

这就要说到activiti定时器了,他是怎么执行的,他是如何发起新的流程的!
先说,关于activiti的定时器的数据。当上一节点【部门审批】审批通过后,就会生成关于定时器的任务定时数据,存入到表act_ru_job中。这个上面已说,详细的不在赘述!
数据已经存储成功,那么接下来,就是定时任务的执行了!

👉定时任务的数据已经生成,那么该如何生成定时任务呢?

这时的定时器作业是由配置的JobExecutor(作业执行器)来负责。
JobExecutor的工作机制是定期查询数据库中的定时器作业,并执行那些达到触发时间的作业。

👉介绍一下JobExecutor

JobExecutor是一个核心组件,用于异步执行各种类型的后台作业,包括但不限于定时器事件、信号事件、消息事件等。

1、JobExecutor的主要职责

  • 作业调度:JobExecutor负责定期查询数据库,找出那些需要立即执行的作业。它会检查作业的触发时间,并执行那些已经到达或超过触发时间的作业。
  • 作业执行:一旦找到需要执行的作业,JobExecutor会将其从数据库中取出,并交给相应的JobHandler进行处理。JobHandler负责具体的作业处理逻辑,例如触发定时器事件、发送信号或消息等。
  • 错误处理与重试:如果作业执行失败,JobExecutor会根据配置的策略进行重试。它可以配置重试次数和重试间隔,以确保即使在暂时的失败情况下,作业也能最终得到执行。
  • 集群支持:在集群环境中,JobExecutor可以配置为分布式模式,允许多个服务器节点共享作业的执行。这提高了系统的可伸缩性和容错能力,确保即使部分节点出现故障,作业也能在其他节点上得到执行。

2、JobExecutor的配置
JobExecutor的配置通常在ActivitiProcessEngineConfiguration中进行。以下是一些关键的配置选项:

  • asyncExecutorActivate:启用或禁用JobExecutor的异步执行功能。
  • asyncExecutor:指定JobExecutor使用的异步执行器,例如线程池。
  • lockTimeInMillis:作业的锁定时间,以毫秒为单位。这决定了作业在被处理期间的锁定持续时间,防止其他JobExecutor实例尝试同时处理同一个作业。
  • asyncJobAcquireWaitTimeInMillis:JobExecutor在每次尝试获取作业之间的等待时间,以毫秒为单位。
  • asyncJobLockTimeInMillis:作业被锁定的时间长度,以毫秒为单位,这有助于防止作业被重复处理。

3、JobExecutor的实现
Activiti提供了几种不同的JobExecutor实现,包括:

  • ThreadPoolJobExecutor:使用线程池来执行作业,适合单个服务器或小型集群环境。
  • StandaloneAsyncJobExecutor:用于独立运行的环境,不建议在集群中使用。
  • MuleJobExecutor:专为Mule ESB环境设计的JobExecutor实现。
👉所以服务器上的JobExecutor的执行并不绑定到特定的服务器

在单个服务器的环境中,JobExecutor将直接在该服务器上执行定时器作业。但在集群环境中,多个服务器上的JobExecutor实例会竞争执行数据库中的定时器作业,通常第一个获取到作业的JobExecutor将锁定该作业并执行它。

因此,如果在集群中的服务器A上启动的流程执行到了含有定时器的节点,定时器作业将被存储在数据库中。
当定时器触发时间到达时,任何一个集群中的JobExecutor(包括服务器A上的JobExecutor)都有可能执行这个定时器作业,具体取决于哪个JobExecutor首先获取并锁定了这个作业。

😭😭😭😭😭😭
其实,当我找到代码的错误后,我就已经修改成功了,但是后来,无论我怎么测试,数据库的act_ge_bytearray表里存储的堆栈信息,永远都是这个。
而且有时候,还报其他的错误!日志不打印,断点拦不到。。。
😭😭😭因为定时器根本就没在我这执行!!!!😭😭😭
😭😭😭为了这个解决这个问题,我前前后后刷了两天半的时间,来排查这个问题!😭😭😭
😭😭😭本来不宽裕的开发时间吗,就更雪上加霜了!😭😭😭
这也就说明了,定时器前后,根本不是一个流程!在流程数据上说,可能是同一个processDefinitionId的流程。
但是在JAVA看来,这根本就不是同一个实例!
毕竟生成定时器数据是一个服务器,执行定时任务的有可能是另一个服务器!

5、解决方案

第一个方案:其实不是为了解决最终的问题,而是避开这个错误,那就是不在【部门派发】节点增加create事件的taskListener。由【部门审批】节点delete事件的taskListener来做更新业务状态的操作。
但是这样的话,就需要自己写一个timer,手动的定时更新业务数据的状态。

第二种方案:就是去掉那一行代码。。。但是么,这也有问题啊。你要让小伙伴们,合并你的代码。。。😂😂😂求人还是挺难的!!!好难开口啊!!!万一,你还没改对,还要让所有的小伙伴们,再合并一遍?😂😂😂

6、定时作业执行器不执行的问题

还有如果你是定时任务不执行的问题。那可能是你定时任务执行器就没开!!!添加如下配置:

spring:
    activiti:
        async-executor-activate: true
        async-executor-enabled: true

最后提个醒:
子流程不能嵌入开始事件。
当嵌入定时开始事件的流程部署新版本,上一个版本的定时器作业会被移除。
一旦部署了流程,计时器启动事件就会被调度。没有必要调用startProcessInstanceBy…,尽管调用start进程方法是不受限制的,>并且会导致在startProcessInstanceBy的时候再次启动进程…调用。

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

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

相关文章

Moretl 日志采集 使用说明

永久免费: Gitee下载最新版本 使用咨询: 扫码添加QQ 1: 服务器 部署Moretl文件采集服务.(管理员身份运行) 2. 在<设备电脑>打开 [部署页面],下载 [Client.zip].解压打开[Start.exe] 步骤3: [部署页面]输入远程Token.看到刚刚部署的设备电脑. 3.1 点击[明细],修改[…

Java Excel复杂表头,表头合并单元格

Java Excel复杂表头&#xff0c;表头合并单元格 效果预览 一、maven依赖 <!--操作excel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version><scope>test</…

Sqlserver查询链接服务器数据问题,如何解决??

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

群晖NAS使用Docker命令方式安装cpolar内网穿透工具详细流程

文章目录 前言1. 检查安装Container Manager2. 检查开启群晖SSH连接3. Windows SSH 连接群晖4. 下载Cpolar 镜像5. 群晖Docker安装Cpolar 前言 在某些群晖NAS型号版本&#xff0c;无法使用套件安装的时候&#xff0c;我们可以采用Docker的方式进行安装cpolar内网穿透工具&…

连接未来:幂简集成引领API新时代

写在前面 在这个信息爆炸的数字时代&#xff0c;我们迎来了所谓的"数据的黄金时代"。数据不仅仅是数字和信息的集合&#xff0c;它已经成为推动现代企业决策、创新和增长的关键资产。 而API作为数据流通的桥梁&#xff0c;在现代互联网架构中发挥着至关重要的作用。…

Stability AI推出Stable Fast 3D:从单个图像快速生成 3D 模型资产

Stable Fast 3D是Stability AI公司推出的一款革命性的3D资产生成技术&#xff0c;它能够在0.5秒内将单张输入图像转化为详尽的3D模型&#xff0c;为3D重建领域带来了速度和质量上的显著提升。这项技术不仅生成UV展开网格、材料参数和反照率颜色&#xff0c;还支持用户选择四边形…

thinkphp8开发的广告联盟网站系统源码

这款程序是采用国内主流的PHP框架&#xff0c;最新版本thinkphp8.0.4&#xff0c;也是目前市面上功能相对比较强大&#xff0c;界面比较好看的一款全开源的广告联盟系统&#xff0c;程序支持任意二开商业&#xff0c;并且代码无任何加密处理。 程序开发&#xff1a;PHPMySQL …

【ROS 最简单教程 001/300】ROS 概念介绍:机器人元操作系统

ROS&#xff1a;Robot Operating System 【适用于机器人的开源元操作系统】 ROS Plumbing Tools Capabilities Ecosystem 通讯 Plumbing ⭐ 实现ROS不同节点之间的交互工具 Tools ⭐ 工具软件包 (ROS中的开发和调试工具)&#xff0c;提供 仿真 功能&#xff1b;功能 Capabi…

苹果10使用操作

1、关闭应用&#xff1a;要关闭iPhone X的后台任务&#xff0c;必须在多任务界面长按应用卡片&#xff0c;这时缩略图左上角会出现关闭符号&#xff0c;点击关闭符号或者上滑卡片都可以关闭。 注意&#xff1a;在没有长按触发关闭符号的情况下&#xff0c;上滑任务卡片是无法关…

大数据技术原理-Hadoop的安装

摘要 随着大数据时代的到来&#xff0c;Hadoop作为一项重要的分布式计算框架&#xff0c;其安装与配置是大数据技术学习者必须掌握的技能。本文通过实验报告的形式&#xff0c;详细记录了在虚拟机环境下安装Hadoop并配置其为伪分布式模式的全过程。实验过程中&#xff0c;遇到…

【从零开始一步步学习VSOA开发】 概述

概述 概念 VSOA&#xff08;Vehicle SOA&#xff09;是翼辉为了解决任务关键型系统不能适用当前微服务通信架构问题而设计的⼀个轻量级适用于任务关键领域的微服务通信架构&#xff0c;以方便开发者构建大型分布式松耦合软件系统&#xff0c;且支持并行开发。 特点 其主要特…

PAI-DSW中对齐NoteBook和命令行的Python环境

我在命令行使用 pip 安装了neo4j&#xff0c;但是在NoteBook中却无法import成功&#xff0c;问了Chat-GPT才知道可能是NoteBook和命令行的Python不一致造成的。下面将介绍如何验证NoteBook和命令行的Python环境是否一致&#xff0c;以及如何将NoteBook的Python环境修改成命令行…

0702随机存取存储器RAM

随机存取存储器RAM 7.2随机存取存储器&#xff08;RAM&#xff09;7.2.1静态随机存取存储器&#xff08;SRAM&#xff09;7.2.2同步静态随机存取存储器&#xff08;SSRAM&#xff09;SSRAM的使用特点&#xff1a; 7.2.3 动态随机存取存储器2.DRAM的基本结构 7.2.4 存储器容量的…

抖音上传视频模糊怎么办?模糊视频怎么变高清?

抖音上传视频有时候会遇到视频不清晰的情况&#xff0c;那么自己在遇到不清楚的情况之下怎么办呢&#xff0c;抖音上传视频模糊怎么办&#xff0c;我们要怎么调整? 一、抖音上传视频模糊的原因是什么? 1.前期拍摄不清晰 2.视频压缩方法欠佳、视频传送被系统压缩 3.上传视频…

C++篇:C++入门基础(1)

C前言&#xff1a; C 的发展历史可以追溯到1979年&#xff0c;当时C语言以其效率和灵活性成为广泛使用的系统编程语言&#xff0c;但它也有一些限制&#xff0c;例如缺乏直接支持面向对象编程&#xff08;OOP&#xff09;的特性。 之后Bjarne Stroustrup(也就是C之父)是C的创始…

Linux服务器CPU使用率或CPU负载较高问题的排查及解决方案

本文主要介绍当Linux系统ECS实例CPU使用率或CPU负载较高时&#xff0c;如何排查分析及常见案例说明。 操作场景 在您使用ECS实例过程中&#xff0c;可能会遇到实例CPU使用率或CPU负载持续较高的情况&#xff0c;您可以按照以下步骤排查定位具体问题。 找到影响CPU使用率或CPU…

网页UI大部分风格出手就是另一种形式的高大上

艾斯视觉作为行业ui设计和前端开发领域的从业者&#xff0c;其观点始终认为&#xff1a;网页UI设计是现代互联网技术中不可或缺的一部分&#xff0c;它不仅关系到用户体验&#xff0c;也是品牌形象的重要组成。"网页UI大部分风格出手就是另一种形式的高大上"这个主题…

TCP/IP_IP协议简介

目录 一、IP协议 二、地址管理 2.1 网络划分 2.2 特殊的IP地址 总结 一、IP协议 IP 协议是处于网络层的协议。 【IP协议段格式】 【字段介绍】 4位版本&#xff1a;指定 IP 协议版本&#xff0c;对于 IPv4&#xff0c;就是 4。 4位首部长度&#xff1a;IP 报头&#…

MySQL数据库忘记密码,怎么重新修改密码?

1、停止MySQL数据服务 systemctl stop mariadb 2、跳过权限表检查并启动MySQL mysqld_safe --skip-grant-tables& 使用mysqld_safe --skip-grant-tables&命令后&#xff0c;不需要密码也可以进去MySQL&#xff0c;随便输入密码也是可以进入MySQL的&#xff0c;因为这个…

测试用例设计指南之生命周期及编写要素

软件测试设计是测试过程中重要的测试活动&#xff0c;怎么样设计测试用例能提高我们测试的效率和质量&#xff0c;从以下几个方面做了简单的讲解。 测试用例设计原则 测试用例设计的基本原则包括&#xff1a;有效性、清晰性、可复用性、可维护性、完整性、兼容性、易操作性、…