SpringBoot整合Flowable【08】- 前后端如何交互

news2025/7/24 0:00:29

引子

在第02篇中,我通过 Flowable-UI 绘制了一个简单的绩效流程,并在后续章节中基于这个流程演示了 Flowable 的各种API调用。然而,在实际业务场景中,如果要求前端将用户绘制的流程文件发送给后端再进行解析处理,这种方式显得繁琐且不够优雅。那么,有没有更简便的方法,让前端通过常规的参数传递方式就能实现流程创建呢?

答案是肯定的。Flowable 提供了强大的 BpmnModel API,它允许我们以编程方式动态构建流程定义,无需依赖XML文件。

什么是 BpmnModel ?

BpmnModelFlowable 提供的一个核心类,它允许开发者以编程方式构建完整的 BPMN 2.0 流程模型。与通过 Flowable-UI 设计流程并导出XML文件的方式不同,BpmnModel 让我们可以直接在代码中定义流程的各个元素。

所以,我们可以通过 BpmnModel 对象来动态创建流程定义,前端只需通过接口传递必要的流程参数即可,无需传递完整的 XML 文件。这里需要明确区分两个概念:一是后端如何接收参数并构建流程模型,二是前端如何提供流程设计的交互界面。对于后者,可以基于 bpmn.js 开发自定义设计器,也可以采用现有的开源方案,这些选项在第01篇中已有详细介绍。

代码编写

接下来,我将完全抛弃 Flowable UI 可视化建模方式,转而通过纯代码方式使用 BpmnModel 对象构建先前设计的绩效流程。让我们深入编码环节,一步步实现这一转换。

一、构建传参对象

1.流程定义实体

流程定义是创建流程的传参对象,包含流程的基本信息和节点结构。

import lombok.Data;
import java.io.Serializable;

/**
 * 流程定义.
 */
@Data
public class ProcessDef implements Serializable {

    /**
     * 流程定义id.
     */
    private String processDefKey;

    /**
     * 流程定义名称.
     */
    private String processName;

    /**
     * 流程定义描述.
     */
    private String description;

    /**
     * 创建人id.
     */
    private Long creatorId;

    /**
     * 流程定义节点.
     */
    private ProcessNode processNode;

}

2. 流程节点实体

流程节点定义了流程中的各个环节,包括节点类型、表单属性以及子节点关系等。

import lombok.Data;
import java.io.Serializable;
import java.util.List;

/**
 * 流程节点.
 */
@Data
public class ProcessNode implements Serializable {

    /**
     * 节点名称.
     */
    private String name;

    /**
     * 节点类型.
     */
    private NodeCategory category;

    /**
     * 是否启用 0否 1是.
     */
    private Integer enable;

    /**
     * 办理人属性.
     */
    private AssigneeProps assigneeProps;

    /**
     * 表单列表.
     */
    private List<FormProp> formProps;

    /**
     * 子节点.
     */
    private ProcessNode children;

}

3. 相关枚举和属性类

为了更好地定义流程节点的各种属性,我们最好还是定义相关枚举和辅助类。(Ps:在实际开发中,个人建议如果类型比较多的情况下,尽量使用枚举,避免魔法字段。)

节点类型枚举
/**
 * 节点类型.
 */
public enum NodeCategory {

    /**
     * 自评.
     */
    SELF_EVALUATION,

    /**
     * 上级评.
     */
    LEADER_EVALUATION,

    /**
     * 隔级评.
     */
    AUDIT,

    /**
     * 绩效确认.
     */
    CONFIRMATION;
}
办理人属性
import java.io.Serializable;
import lombok.Data;

/**
 * 办理人Props.
 */
@Data
public class AssigneeProps implements Serializable {
    /**
     * 办理人类型.
     */
    private AssigneeType assigneeType;

    /**
     * 候选办理人类型.
     */
    private AssigneeType candidateType;
}
办理人类型枚举
/**
 * 办理人类型.
 */
public enum AssigneeType {

    /**
     * 节点处理人类型, 用户本人,直接上级,上级部门管理员,隔级上级,隔级部门管理员.
     */
    USER_ASSESSED, LEADER, DEPT_MANAGER, SUPERIOR_LEADER, SUPERIOR_DEPT_MANAGER
}
表单属性
import java.io.Serializable;
import lombok.Data;

/**
 * FormProps 表单属性.
 */
@Data
public class FormProp implements Serializable {

    /**
     * id.
     */
    private String id;

    /**
     * 属性名称.
     */
    private String name;

    /**
     * 属性变量.
     */
    private String variable;

    /**
     * 变量类型.
     */
    private String type;

    /**
     * 值.
     */
    private String value;

    /**
     * 表单配置.
     */
    private FormConfig config;

    public FormConfig getConfig() {
        return config;
    }
}
表单配置
import java.io.Serializable;
import lombok.Data;

/**
 * FormConfig 表单配置.
 */
@Data
public class FormConfig implements Serializable {

    /**
     * 分组名称.
     */
    private String group;

    /**
     * 分组权重.
     */
    private Double weight;

    /**
     * 分类:评分SCORE、评语COMMENT.
     */
    private FormCategory category;

}
表单类别枚举
/**
 * 表单类别.
 */
public enum FormCategory {
    /**
     * 评分.
     */
    SCORE,

    /**
     * 评语.
     */
    COMMENT;
}

二、创建控制器

import com.pitayafruit.base.BaseResponse;
import com.pitayafruit.rest.vo.ProcessDef;
import com.pitayafruit.service.ProcessDefService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 流程Controller.
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/process-def/v1")
public class ProcessDefControllerV1 {

    private final ProcessDefService processDefService;

    /**
     * 创建流程模型并部署.
     *
     * @param processDef 流程定义
     * @return 流程key
     */
    @PostMapping
    public ResponseEntity<Object> createProcessDef(@RequestBody ProcessDef processDef) {
        //1,创建并部署流程模型
        String processDefKey = processDefService.createProcessDefApi(processDef);
        //2.返回流程模型key
        return new ResponseEntity<>(new BaseResponse<>(processDefKey), HttpStatus.OK);
    }


}

三、实现服务层主方法

这个负责将前端传递的数据结构转换为 Flowable 的 BpmnModel 模型,并进行部署。

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.pitayafruit.rest.vo.AssigneeProps;
import com.pitayafruit.rest.vo.ProcessDef;
import com.pitayafruit.rest.vo.ProcessNode;
import com.pitayafruit.service.ProcessDefService;
import com.pitayafruit.utils.UUIDUtil;
import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.validation.ValidationError;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 流程定义ServiceImpl.
 */
@Service
@RequiredArgsConstructor
public class ProcessDefServiceImpl implements ProcessDefService {

    private final RepositoryService repositoryService;

    /**
     * 创建流程模型并部署.
     *
     * @param processDef 流程定义
     * @return 流程key
     */
    @Override
    public String createProcessDefApi(ProcessDef processDef) {
        //1.设置流程定义Key
        processDef.setProcessDefKey("processDef" + UUIDUtil.getUUID());
        //2.设置流程定义创建人id
        processDef.setCreatorId(1L);
        //3.设置流程定义名称
        processDef.setProcessName("绩效流程");
        //4.创建流程模型
        BpmnModel bpmnModel = toBpmn(processDef);
        //5.部署流程模型
        repositoryService.createDeployment()
                //5-1.流程定义key
                .key(processDef.getProcessDefKey())
                //5-2.流程定义名称
                .name(processDef.getProcessName())
                //5-3.添加流程模型
                .addBpmnModel(processDef.getProcessDefKey() + ".bpmn", bpmnModel)
                //5-4.部署
                .deploy();
        //6.返回流程定义key
        return processDef.getProcessDefKey();
    }

四、流程模型转换方法

类型转换涉及到的逻辑比较多,所以把这个方法单独抽取出来。首先创建一个流程对象,设置流程的基本属性,添加开始事件,然后通过调用 buildTask 方法递归构建流程中的各个节点,最后生成并验证 BpmnModel。

/**
 * 将流程定义转换为BpmnModel.
 *
 * @param processDef 流程定义
 * @return Bpmn模型
 */
private BpmnModel toBpmn(ProcessDef processDef) {
    //1.创建流程
    //1-1.声明流程对象
    Process process = new Process();
    //1-2.设置流程id
    process.setId(processDef.getProcessDefKey());
    //1-3.设置流程名称
    process.setName(processDef.getProcessName());
    //2.创建开始事件
    //2-1.声明开始事件对象
    StartEvent startEvent = new StartEvent();
    //2-2.设置开始事件id
    startEvent.setId("startEvent" + UUIDUtil.getUUID());
    //2-3.设置开始事件名称
    startEvent.setName("开始");
    //2-4.将开始事件添加到流程中
    process.addFlowElement(startEvent);
    //创建用户节点
    ProcessNode processNode = processDef.getProcessNode();
    buildTask(startEvent, processNode, process);
    //创建流程模型
    BpmnModel bpmnModel = new BpmnModel();
    bpmnModel.addProcess(process);
    // 验证BPMN模型
    List<ValidationError> validationErrors = repositoryService.validateProcess(bpmnModel);
    if (ObjectUtil.isNotEmpty(validationErrors)) {
        //打印失败日志
        validationErrors.forEach(validationError -> System.out.println(validationError.toString()));
        throw new IllegalArgumentException("验证失败");
    }
    return bpmnModel;
}

五、任务节点构建方法

这个方法负责创建用户任务节点。根据传入的流程节点数据,创建一个用户任务对象,设置其属性,添加自定义属性和任务监听器,然后将任务添加到流程中,并构建与前一个节点的连线。如果当前节点未启用,则直接处理下一个节点。

/**
 * 创建用户任务节点.
 *
 * @param parentTask  父节点
 * @param processNode 流程节点
 * @param process     流程定义
 */
private void buildTask(FlowNode parentTask, ProcessNode processNode, Process process) {
    //如果节点启用,处理当前节点
    if (ObjectUtil.isNotNull(processNode.getEnable()) && processNode.getEnable() == 1) {
        UserTask userTask = new UserTask();
        userTask.setId("userTask" + UUIDUtil.getUUID());
        userTask.setName(processNode.getName());
        //设置节点类型
        userTask.setCategory(processNode.getCategory().toString());
        List<CustomProperty> customProperties = new ArrayList<>();
        //办理人属性
        AssigneeProps assigneeProps = processNode.getAssigneeProps();
        //设置办理人类型
        customProperties.add(
                buildCustomProperty("assigneeType", assigneeProps.getAssigneeType().toString()));
        //设置候选办理人类型
        if (ObjectUtil.isNotNull(assigneeProps.getCandidateType())) {
            customProperties.add(buildCustomProperty("candidateType", assigneeProps.getCandidateType().toString()));
        }
        //绑定表单
        userTask.setFormProperties(buildFormProperty(processNode));
        //表单列表添加到节点扩展属性
        customProperties.add(buildCustomProperty("formProps", JSON.toJSONString(processNode.getFormProps())));
        //设置自定义属性,包括办理人类型和表单分组和权重配置
        userTask.setCustomProperties(customProperties);
        //监听器列表
        List<FlowableListener> taskListeners = new ArrayList<>();
        //任务创建时添加监听器,用于动态指定任务的办理人和设置变量
        taskListeners.add(buildTaskListener(TaskListener.EVENTNAME_CREATE, "taskCreateListener"));
        //任务完成后添加监听器,用于计算分数和保存表单
        //如果是手动填写流程,添加手动填写的监听器
        taskListeners.add(buildTaskListener(TaskListener.EVENTNAME_COMPLETE, "taskCompleteListener"));
        //设置任务监听器
        userTask.setTaskListeners(taskListeners);
        // 将用户任务节点添加到流程定义
        process.addFlowElement(userTask);
        //添加流程连线
        process.addFlowElement(new SequenceFlow(parentTask.getId(), userTask.getId()));
        //解析下一个节点,参数为当前任务,当前流程节点,流程定义,流程类型
        buildChildren(userTask, processNode, process);
    } else {
        //当前节点关闭的情况下,直接解析下一个节点,参数为父任务,当前流程节点,流程定义,流程类型
        buildChildren(parentTask, processNode, process);
    }
}

六、子节点处理方法

这个方法用于处理流程节点的子节点。它检查当前节点是否有子节点,如果有则递归调用 buildTask 方法构建子节点,如果没有则创建结束事件,表示流程的结束。

/**
 * 解析子节点.
 *
 * @param parentTask  下一个节点的父任务
 * @param processNode 流程节点
 * @param process     流程定义
 */
private void buildChildren(FlowNode parentTask, ProcessNode processNode, Process process) {
    ProcessNode childrenNode = processNode.getChildren();
    if (ObjectUtil.isNotNull(childrenNode)) {
        //创建子节点
        buildTask(parentTask, childrenNode, process);
    } else {
        //创建结束事件
        EndEvent endEvent = new EndEvent();
        endEvent.setId("endEvent" + UUIDUtil.getUUID());
        endEvent.setName("结束");
        process.addFlowElement(endEvent);
        //添加流程连线
        process.addFlowElement(new SequenceFlow(parentTask.getId(), endEvent.getId()));
    }
}

七、任务监听器创建方法

这个方法用于创建任务监听器。在Flowable中,任务监听器可以在任务的不同生命周期阶段触发特定逻辑,例如在任务创建时动态分配任务办理人,或在任务完成时处理表单数据。这里使用了委托表达式方式,将监听器的实现委托给Spring容器中的Bean。

/**
 * 创建任务监听器,用于动态分配任务的办理人.
 *
 * @param event    事件
 * @param beanName 类名
 * @return 任务监听器
 */
private FlowableListener buildTaskListener(String event, String beanName) {
    FlowableListener flowableListener = new FlowableListener();
    flowableListener.setEvent(event);
    flowableListener.setImplementationType("delegateExpression");
    flowableListener.setImplementation("${" + beanName + "}");
    return flowableListener;
}

八、表单属性创建方法

这个方法用于创建表单属性。它遍历流程节点中的表单属性列表,为每个表单属性创建一个Flowable的FormProperty对象,设置其ID、名称、变量名等属性,并将原始表单属性的ID和变量名更新为实际使用的值,以便在后续处理中使用。

/**
 * 创建表单属性.
 *
 * @param processNode 流程节点
 */
private List<FormProperty> buildFormProperty(ProcessNode processNode) {
    List<FormProperty> formProperties = new ArrayList<>();
    if (ObjectUtil.isNull(processNode.getFormProps())) {
        return formProperties;
    }
    processNode.getFormProps().forEach(prop -> {
        //新建表单属性对象
        FormProperty formProperty = new FormProperty();
        //设置表单属性id
        String id = "formProperty" + UUIDUtil.getUUID();
        formProperty.setId(id);
        //设置表单名称
        formProperty.setName(prop.getName());
        //设置表单变量名为表单id
        formProperty.setVariable(id);
        //设置表单变量类型
        formProperty.setType(prop.getType());
        //设置表单是否必填
        formProperty.setRequired(true);
        formProperties.add(formProperty);
        //设置表单属性id
        prop.setId(id);
        prop.setVariable(id);
    });
    return formProperties;
}

九、自定义属性创建方法

这个方法用于创建自定义属性。在 Flowable 中,自定义属性可以用于存储不属于标准BPMN规范但业务上需要的信息,通常用来传递我们的业务数据。

/**
 * 创建自定义属性.
 *
 * @param key  键
 * @param value 值
 * @return 自定义属性
 */
private CustomProperty buildCustomProperty(String key, String value) {
    CustomProperty customProperty = new CustomProperty();
    //自定义属性名称
    customProperty.setName(key);
    //自定义属性值
    customProperty.setSimpleValue(value);
    return customProperty;
}

接口测试

我把请求转换成了curl命令,方便直接在命令行中测试。创建的这个流程与前面篇章中介绍的结构一致,包含三个核心节点:员工自评、上级评价和隔级评价,每个节点都包含分数、评语等表单项,并且每个节点都设置了不同的权重。

为什么要加权重?这是因为在实际业务场景中,不同评价环节的重要性往往不同。

curl -X POST 'http://localhost:8080/api/process-def/v1' \
-H 'Content-Type: application/json' \
-d '{
  "processName": "通过bpmn model创建的绩效流程",
  "description": "用于员工季度绩效评估",
  "processNode": {
    "name": "员工自评",
    "category": "SELF_EVALUATION",
    "enable": 1,
    "assigneeProps": {
      "assigneeType": "USER_ASSESSED"
    },
    "formProps": [
      {
        "name": "自评分数",
        "type": "string",
        "value": "0",
        "config": {
          "group": "绩效评分",
          "weight": 0.3,
          "category": "SCORE"
        }
      },
      {
        "name": "自我评价",
        "type": "string",
        "config": {
          "group": "评语",
          "weight": 0.3,
          "category": "COMMENT"
        }
      }
    ],
    "children": {
      "name": "上级评价",
      "category": "LEADER_EVALUATION",
      "enable": 1,
      "assigneeProps": {
        "assigneeType": "LEADER"
      },
      "formProps": [
        {
          "name": "上级评分",
          "type": "string",
          "value": "0",
          "config": {
            "group": "绩效评分",
            "weight": 0.5,
            "category": "SCORE"
          }
        },
        {
          "name": "上级评语",
          "type": "string",
          "config": {
            "group": "评语",
            "weight": 0.5,
            "category": "COMMENT"
          }
        }
      ],
      "children": {
        "name": "隔级评价",
        "category": "AUDIT",
        "enable": 1,
        "assigneeProps": {
          "assigneeType": "SUPERIOR_LEADER"
        },
        "formProps": [
          {
            "name": "隔级评分",
            "type": "string",
            "value": "0",
            "config": {
              "group": "绩效评分",
              "weight": 0.2,
              "category": "SCORE"
            }
          },
          {
            "name": "隔级评语",
            "type": "string",
            "config": {
              "group": "评语",
              "weight": 0.2,
              "category": "COMMENT"
            }
          }
        ],
        "children": null
      }
    }
  }
}'

按照接口的定义,部署成功后会返回流程模型key。
在这里插入图片描述

同时查看部署表和流程运行表,可以看到这个流程已经启动了。

在这里插入图片描述
在这里插入图片描述

小结

通过本章的实践,我们可以明显看到利用 BpmnModel API 构建流程虽然灵活强大,但即使是构建一个相对简单的线性流程,也需要编写大量代码来处理各种细节。这种方法的复杂性在面对更复杂的流程结构(如并行网关、排他网关或子流程等)时会进一步增加。

因此,在实际项目中,我建议大家可以花点时间封装,比如可以将创建开始事件、任务节点、结束事件、网关等常见元素的代码封装成独立方法。通过这些封装,在写业务的时候就能像搭积木一样轻松组合各种流程元素,提高开发效率和代码可维护性。

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

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

相关文章

【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN

【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN 目录 【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-LSTM、Transformer、CNN-LSTM、LSTM、…

深入了解MCP基础与架构

一、引言 在人工智能技术以指数级速度渗透各行业领域的今天&#xff0c;我们正站在一个关键的技术拐点。当ChatGPT月活突破亿级、Gemini Pro实现多模态实时交互、Claude 3.5 Sonnet突破百万上下文长度&#xff0c;这些里程碑事件背后&#xff0c;一个崭新的大门逐步打开&#…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.13 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.13 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用图。 dataframe<-data.frame( yc(36,18,30,39,20…

【java面试】MySQL篇

MySQL篇 一、总体结构二、优化&#xff08;一&#xff09;定位慢查询1.1 开源工具1.2Mysql自带的慢日志查询1.3 总结 &#xff08;二&#xff09;定位后优化2.1 优化2.2 总结 &#xff08;三&#xff09;索引3.1 索引3.2 索引底层数据结构——B树3.3 总结 &#xff08;四&#…

贪心算法应用:欧拉路径(Fleury算法)详解

Java中的贪心算法应用&#xff1a;欧拉路径&#xff08;Fleury算法&#xff09;详解 一、欧拉路径与欧拉回路基础 1.1 基本概念 欧拉路径&#xff08;Eulerian Path&#xff09;是指在一个图中&#xff0c;经过图中每一条边且每一条边只经过一次的路径。如果这条路径的起点和…

【算法设计与分析】实验——二维0-1背包问题(算法分析题:算法思路),独立任务最优调度问题(算法实现题:实验过程,描述,小结)

说明&#xff1a;博主是大学生&#xff0c;有一门课是算法设计与分析&#xff0c;这是博主记录课程实验报告的内容&#xff0c;题目是老师给的&#xff0c;其他内容和代码均为原创&#xff0c;可以参考学习&#xff0c;转载和搬运需评论吱声并注明出处哦。 要求&#xff1a;3-…

【Git】View Submitted Updates——diff、show、log

在 Git 中查看更新的内容&#xff08;即工作区、暂存区或提交之间的差异&#xff09;是日常开发中的常见操作。以下是常用的命令和场景说明&#xff1a; 文章目录 1、查看工作区与暂存区的差异2、查看提交历史中的差异3、查看工作区与最新提交的差异4、查看两个提交之间的差异5…

deepseek原理和项目实战笔记2 -- deepseek核心架构

混合专家&#xff08;MoE&#xff09; ​​混合专家&#xff08;Mixture of Experts, MoE&#xff09;​​ 是一种机器学习模型架构&#xff0c;其核心思想是通过组合多个“专家”子模型&#xff08;通常为小型神经网络&#xff09;来处理不同输入&#xff0c;从而提高模型的容…

在 MATLAB 2015a 中如何调用 Python

在 MATLAB 2015a 中调用 Python 可通过系统命令调用、.NET 交互层包装、MEX 接口间接桥接、环境变量配置四种方式&#xff0c;但因该版本对 Python 支持有限&#xff0c;主要依赖的是系统命令调用与间接脚本交互。其中&#xff0c;通过 system() 函数调用 Python 脚本是最简单且…

房屋租赁系统 Java+Vue.js+SpringBoot,包括房屋类型、房屋信息、预约看房、合同信息、房屋报修、房屋评价、房主管理模块

房屋租赁系统 JavaVue.jsSpringBoot&#xff0c;包括房屋类型、房屋信息、预约看房、合同信息、房屋报修、房屋评价、房主管理模块 百度云盘链接&#xff1a;https://pan.baidu.com/s/1KmwOFzN9qogyaLQei3b6qw 密码&#xff1a;l2yn 摘 要 社会的发展和科学技术的进步&#xf…

华为OD机试真题——生成哈夫曼树(2025B卷:100分)Java/python/JavaScript/C/C++/GO六种最佳实现

2025 B卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《生成…

Redis最佳实践——性能优化技巧之监控与告警详解

Redis 在电商应用的性能优化技巧之监控与告警全面详解 一、监控体系构建 1. 核心监控指标矩阵 指标类别关键指标计算方式/说明健康阈值&#xff08;参考值&#xff09;内存相关used_memoryINFO Memory 获取不超过 maxmemory 的 80%mem_fragmentation_ratio内存碎片率 used_m…

R3GAN训练自己的数据集

简介 简介&#xff1a;这篇论文挑战了"GANs难以训练"的广泛观点&#xff0c;通过提出一个更稳定的损失函数和现代化的网络架构&#xff0c;构建了一个简洁而高效的GAN基线模型R3GAN。作者证明了通过合适的理论基础和架构设计&#xff0c;GANs可以稳定训练并达到优异…

【容器docker】启动容器kibana报错:“message“:“Error: Cannot find module ‘./logs‘

说明&#xff1a; 1、服务器数据盘挂了&#xff0c;然后将以前的数据用rsync拷贝过去&#xff0c;启动容器kibana服务&#xff0c;报错信息如下图所示&#xff1a; 2、可能是拷贝docker文件夹&#xff0c;有些文件没有拷贝过去&#xff0c;导致无论是给文件夹授权用户kibana或者…

C#里与嵌入式系统W5500网络通讯(4)

怎么样修改W5500里的socket收发缓冲区呢? 需要进行下面的工作,首先要了解socket缓冲区的作用,接着了解缓冲区的硬件资源, 最后就是要了解自己的需求,比如自己需要哪个socket的收发送缓冲区多大。 硬件的寄存器为: 这是 W5500 数据手册中关于 Sn_RXBUF_SIZE(Socket n …

Spring boot集成milvus(spring ai)

服务器部署Milvus Run Milvus with Docker Compose (Linux) milvus版本可在docker-compose.yml中进行image修改 启动后&#xff0c;docker查看启动成功 spring boot集成milvus 参考了这篇文章 Spring AI开发RAG示例&#xff0c;理解RAG执行原理 但集成过程中遇到了一系列…

Visual Studio+SQL Server数据挖掘

这里写自定义目录标题 工具准备安装Visual studio 2017安装SQL Server安装SQL Server Management Studio安装analysis service SSMS连接sql serverVisual studio新建项目数据源数据源视图挖掘结构部署模型设置挖掘预测 部署易错点 工具准备 Visual studio 2017 analysis servi…

通过阿里云服务发送邮件

通过阿里云服务发送邮件 1. 整体描述2. 方案选择2.1 控制台发送2.2 API接口接入2.3 SMTP接口接入2.4 结论 3. 前期工作3.1 准备工作3.2 配置工作3.3 总结 4. 收费模式4.1 免费额度4.2 资源包4.3 按量付费 5. Demo开发5.1 选择SMTP服务器5.2 pom引用5.3 demo代码5.4 运行结果 6 …

Vad-R1:通过从感知到认知的思维链进行视频异常推理

文章目录 速览摘要1 引言2 相关工作视频异常检测与数据集视频多模态大语言模型具备推理能力的多模态大语言模型 3 方法&#xff1a;Vad-R13.1 从感知到认知的思维链&#xff08;Perception-to-Cognition Chain-of-Thought&#xff09;3.2 数据集&#xff1a;Vad-Reasoning3.3 A…

黑马Java面试笔记之MySQL篇(事务)

一. 事务的特性 事务的特性是什么&#xff1f;可以详细说一下吗&#xff1f; 事务是一组操作的集合&#xff0c;他是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失…