flowable 设置自定义属性教程

概述

        由于工作需要给flowable工作流设计器添加自定义属性,以满足功能实现。所以这篇文章介绍下用flowable 开源的的flowable-ui 前端添加自定义属性,后端解析属性值的例子。

技术栈

序号技术点名称版本
1Flowable6.8.0

使用的是flowable6.8.0 版的代码

GitHub - flowable/flowable-engine at flowable-release-6.8.0icon-default.png?t=N7T8https://github.com/flowable/flowable-engine/tree/flowable-release-6.8.0然后依照下面链接启动flowable-ui项目

手把手教大家编译 flowable 源码-腾讯云开发者社区-腾讯云松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。----要说这个编译源码其实没什么技术含量,但是由于国内的网络问题,Spring 等各种常...icon-default.png?t=N7T8https://cloud.tencent.com/developer/article/2108059

添加flowable-ui前端属性

添加boolean 属性

找到flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-logic\src\main\resources\stencilset_bpmn.json 路径文件 这个json 就是设计器的所有内容,

\flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\i18n\zh-CN.json 文件是汉化文件

下面是stencilset_bpmn.json 的文件格式:

{
    "title": "BPMN 2.0标准工具",
    "namespace": "http://b3mn.org/stencilset/bpmn2.0#",
    "description": "BPMN process editor",
    "propertyPackages": [{
        "name": "overrideidpackage",
        "properties": [{
            "id": "overrideid",
            "type": "String",
            "title": "Id",
            "value": "",
            "description": "元素的唯一标识.",
            "popular": true
        }]
    }, {
        "name": "namepackage",
        "properties": [{
            "id": "name",
            "type": "String",
            "title": "名称",
            "value": "",
            "description": "BPMN元素的描述名称.",
            "popular": true,
            "refToView": "text_name"
        }]
    }],
    "stencils": [{
        "type": "node",
        "id": "UserTask",
        "title": "用户活动",
        "description": "分配给特定人的任务 ",
        "view": "此处代码已省略,请查看本书配套资源内容",
        "groups": ["活动列表"],
        "propertyPackages": ["overrideidpackage", "namepackage", 
            "documentationpackage", "asynchronousdefinitionpackage", 
            "exclusivedefinitionpackage", "executionlistenerspackage", 
            "multiinstance_typepackage", "multiinstance_cardinalitypackage", 
            "multiinstance_collectionpackage", "multiinstance_variablepackage", 
            "multiinstance_conditionpackage", "isforcompensationpackage", 
            "usertaskassignmentpackage", "formkeydefinitionpackage", 
            "formreferencepackage", "duedatedefinitionpackage", 
            "prioritydefinitionpackage", "formpropertiespackage", "tasklistenerspackage"],
        "hiddenPropertyPackages": [],
        "roles": ["Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all"]
    }]
}

从以上配置文件内容中可以看出,最顶层有五个元素:title,namespace,description,

propertyPackages和stencils,分别代表标题,命名空间,描述,属性集合,节点属性,其中

propertyPackages表示的是设计器下栏的各个属性。通过propertyPackages 可以设置属性的名称,样式,字段类型。

 

type 对应的是当前属性的类型,和flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\editor-app\configuration\properties.js

里面的内容一一对应

stencils.propertyPackages 的值可以表示哪些活动使用哪些属性。

第一步:添加允许催办属性

第二步:将允许催办属性添加到用户属性下

第三步:重启服务

就可以看到用户任务下有允许催办属性了。

添加下拉框样式属性

上面我们完成了通过设置type 为boolean,添加允许催办属性,那么string,text属性大家也都可以在properties.js 文件中看到,按需添加即可。

如果是添加下拉框属性,我们可以仿照多实例的下拉框属性实现。

第一步:在stencilset_bpmn.json 文件的propertyPackages 下添加下拉属性的内容

,{
      "name" : "usertaskovertimehandlertypepackage",
      "properties" : [{
        "id" :"overtimehandlertype",
        "type" : "fd-overtimehandlertype",
        "title" : "逾期处理方式",
        "value" : "0",
        "description" : "逾期处理方式",
        "popular" : true
      }]
    }

注意id 和type ,我们去properties.js 文件下添加该类

第二步:在properties.js 文件下添加类型

注意1:properties.js 文件下的自定义名称为: oryx-上面的id-上面的type

注意2:不要用驼峰格式命名。

第三步:定义html

这些步骤我都是抄多实例怎么实现的。

下面是html 的下拉框格式,ng-controller 是用的angular.js 语言 下面红框里的内容我们自己定义

第四步:定义js 文件 

在 flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\index.html 文件下设置自定义的js路径

下面图片是js的内容,注意除默认值外其他两个字段需要和第二步html 里的值保持一致。

第五步:重启服务

重启服务就可以看到flowable-ui 界面上出现下拉框的属性了。如果是其他样式的属性,可以借鉴flowable-ui  中相同的样式是如何实现的。

后端添加自定义属性解析处理类

第一步:定义UserTaskJsonConverter实现类

package org.flowable.ui.application.converter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.*;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.BpmnJsonConverterContext;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;

import java.util.List;
import java.util.Map;

/**
 * @author admin
 */
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {


    /**
     *  用户任务类型
     */
    public static final String ACTIVE_TYPE = "activetype";
    /**
     *  允许撤回
     */
    public static final String ALLOW_RECALL = "allowrecall";
    /**
     *  允许终止
     */
    public static final String ALLOW_STOP = "allowstop";
    /**
     *  允许跳过
     */
    public static final String ALLOW_SKIP = "allowskip";
    /**
     *  允许修改下一个节点参与者
     */
    public static final String ALLOW_UPDATE_NEXT_ONE = "allowupdatenextone";

    /**
     *  允许修改后续节点参与者
     */
    public static final String ALLOW_UPDATE_NEXT_ALL = "allowupdatenextall";
    /**
     *  允许上传附件
     */
    public static final String ALLOW_UPLOAD = "allowupload";
    /**
     *  工作期限(单位:天)
     */
    public static final String LIMIT_TIME = "limittime";
    /**
     *  逾期处理方式
     */
    public static final String OVER_TIME_HANDLER_TYPE = "overtimehandlertype";
    /**
     *  预警提醒(逾期前天数)
     */
    public static final String OVER_TIME_WARN_TIME = "overtimewarntime";
    /**
     *  预警提醒(逾期前天数)
     */
    public static final String CIRCULATION_WARN_TIME = "circulationwarntime";

    @Override
    protected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement, BpmnJsonConverterContext converterContext) {
        super.convertElementToJson(propertiesNode, baseElement, converterContext);
        UserTask userTask = (UserTask) baseElement;
        //解析
        Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();
        if(extensionElements != null && extensionElements.containsKey(ACTIVE_TYPE)){
            ExtensionElement e = extensionElements.get(ACTIVE_TYPE).get(0);
            setPropertyValue(ACTIVE_TYPE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_RECALL)){
            ExtensionElement e = extensionElements.get(ALLOW_RECALL).get(0);
            setPropertyValue(ALLOW_RECALL, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_STOP)){
            ExtensionElement e = extensionElements.get(ALLOW_STOP).get(0);
            setPropertyValue(ALLOW_STOP, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_SKIP)){
            ExtensionElement e = extensionElements.get(ALLOW_SKIP).get(0);
            setPropertyValue(ALLOW_SKIP, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ONE)){
            ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ONE).get(0);
            setPropertyValue(ALLOW_UPDATE_NEXT_ONE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ALL)){
            ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ALL).get(0);
            setPropertyValue(ALLOW_UPDATE_NEXT_ALL, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPLOAD)){
            ExtensionElement e = extensionElements.get(ALLOW_UPLOAD).get(0);
            setPropertyValue(ALLOW_UPLOAD, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(LIMIT_TIME)){
            ExtensionElement e = extensionElements.get(LIMIT_TIME).get(0);
            setPropertyValue(LIMIT_TIME, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(OVER_TIME_HANDLER_TYPE)){
            ExtensionElement e = extensionElements.get(OVER_TIME_HANDLER_TYPE).get(0);
            setPropertyValue(OVER_TIME_HANDLER_TYPE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(OVER_TIME_WARN_TIME)){
            ExtensionElement e = extensionElements.get(OVER_TIME_WARN_TIME).get(0);
            setPropertyValue(OVER_TIME_WARN_TIME, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(CIRCULATION_WARN_TIME)){
            ExtensionElement e = extensionElements.get(CIRCULATION_WARN_TIME).get(0);
            setPropertyValue(CIRCULATION_WARN_TIME, e.getElementText(), propertiesNode);
        }
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap, BpmnJsonConverterContext converterContext) {
        FlowElement flowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap, converterContext);
        UserTask userTask = (UserTask) flowElement;
        //解析自定义扩展属性
        this.addExtansionPropertiesElement(userTask,elementNode,ACTIVE_TYPE);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_RECALL);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_STOP);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_SKIP);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ONE);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ALL);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPLOAD);
        this.addExtansionPropertiesElement(userTask,elementNode,LIMIT_TIME);
        this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_HANDLER_TYPE);
        this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_WARN_TIME);
        this.addExtansionPropertiesElement(userTask,elementNode,CIRCULATION_WARN_TIME);

        return userTask;
    }

    private void addExtansionPropertiesElement(UserTask userTask,  JsonNode elementNode, String name) {
        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName(name);
        //BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX
        extensionElement.setNamespacePrefix("model");
        extensionElement.setNamespace(BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE);
        String customProperties = getPropertyValueAsString(name, elementNode);
        extensionElement.setElementText(customProperties);
        userTask.addExtensionElement(extensionElement);
    }

    public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>
                                         convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends
            BaseBpmnJsonConverter>> convertersToJsonMap) {

        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>
                                             convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

    public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extends
            BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);
    }

}

第二步:定义BpmnJsonConverter实现类

package org.flowable.ui.application.converter;

import org.flowable.editor.language.json.converter.BpmnJsonConverter;

/**
 * @author admin
 */

public class CustomBpmnJsonConverter extends BpmnJsonConverter {

    static {
        //这里可以加入所有自定义的属性内容

        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

}

第三步:解析json 转成Bpmn

package org.flowable.ui.application;


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.ui.application.converter.CustomBpmnJsonConverter;
import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class RunCustomJsonConverterDemo {

    @Test
    public void runCustomJsonConverterDemo() throws Exception {
        //读取Flowable Modeler保存的Json
        InputStream processModelJsonInputStream =
                getClass().getClassLoader().getResourceAsStream("model-json/model.json");
        ObjectMapper mapper = new ObjectMapper();
        JsonNode processJsonNode = mapper.readTree(processModelJsonInputStream);
        //获取流程模型的Json
        //使用自定义转换类由Json转换为BpmnModel对象
        BpmnJsonConverter bpmnJsonConverter = new CustomBpmnJsonConverter();
        BpmnModel bpmnModel = bpmnJsonConverter.convertToBpmnModel(processJsonNode);
        Process mainProcess = bpmnModel.getMainProcess();
        UserTask userTask = (UserTask) mainProcess.getFlowElement("sid-DA2AB9F9-3CB2-40C5-945B-95B6DADFA1E1");
        //查询用户任务对象并打印属性
        Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();
        List<ExtensionElement> allowurgingExtension = extensionElements.get("allowrecall");
        if (CollectionUtils.isNotEmpty(allowurgingExtension)) {
            log.info("扩展属性activetype值为:{}", allowurgingExtension.get(0).getElementText());
        }
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);// 转xml
        log.info("bpmnBytes:"+new String(bpmnBytes));

    }
}

其中model.json 是flowable-ui点击保存传过来的

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flink 1.18.1的基本使用

系统示例应用 /usr/local/flink-1.18.1/bin/flink run /usr/local/flies/streaming/SocketWindowWordCount.jar --port 9010nc -l 9010 asd asd sdfsf sdf sdfsdagd sdf单次统计示例工程 cd C:\Dev\IdeaProjectsmvn archetype:generate -DarchetypeGroupIdorg.apache.flink -…

单元测试实践

一、写在开始写单元测试前 1.1 背景 我们开发都知道单元测试的重要性&#xff0c;而且每个开发都有要写单元测试的意识单元测试和代码编写结构息息相关&#xff0c;业界常用专业名词TDD&#xff08;测试驱动开发&#xff09;&#xff0c;言外之意我们开始编写代码的时候就已经…

开发板——X210开发板的SD卡启动方式

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考博客&#xff1a; S5PV210 SD卡启动 - 简书 关于存储器的相关基础知识&#xff0c;见博文&#xff1a; 外存——SD卡/iNand芯片与S5PV210的SD/MMC/iNand控制器-CSDN博客 RAM、ROM和FLASH三…

Qt6入门教程 15:QRadioButton

目录 一.简介 二.常用接口 三.实战演练 1.径向渐变 2.QSS贴图 3.开关效果 4.非互斥 一.简介 QRadioButton控件提供了一个带有文本标签的单选按钮。 QRadioButton是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项…

Flink 流式读取 Debezium CDC 数据写入 Hudi 表无法处理 -D / Delete 消息

问题场景是&#xff1a;使用 Kafka Connect 的 Debezium MySQL Source Connector 将 MySQL 的 CDC 数据 &#xff08;Avro 格式&#xff09;接入到 Kafka 之后&#xff0c;通过 Flink 读取并解析这些 CDC 数据&#xff0c;然后以流式方式写入到 Hudi 表中&#xff0c;测试中发现…

Java Springboot解决很多页面Whitelabel Error Page(404)问题

前言 最近接手了一个前后端一体的项目&#xff0c;发现其默认路径不是主机端口&#xff08;如&#xff1a;http://localhost:3453/&#xff09;的形式。很多页面的访问是加了一个层级。只要访问就会出现如下提示&#xff1a; Whitelabel Error Page This application has no …

双目相机立体匹配基础

双目匹配就是用左相机和右相机去拍摄同一个点&#xff0c;目的是找到三维世界的同一个点&#xff0c;也就是在左相机和右相机中的成像点之间的像素差&#xff08;视差&#xff09;&#xff0c;根据视差去求解深度&#xff0c;那么找到左相机点到右相机的同一个对应点这个过程就…

草图导入3d后模型贴材质的步骤?---模大狮模型网

3D模型在导入草图大师后出现混乱可能有多种原因&#xff0c;以下是一些可能的原因和解决方法&#xff1a; 模型尺寸问题&#xff1a;如果3D模型的尺寸在导入草图大师时与画布尺寸不匹配&#xff0c;可能导致模型混乱。解决方法是在3D建模软件中调整模型的尺寸&#xff0c;使其适…

【NodeJS】005- MongoDB数据库

1.简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的 应用程序 1.3 数据库的作用 数据库的主要作用就是…

目标检测:1预备知识

开始涉及目标检测内容&#xff0c;总结一下学习记录 1、目标检测的基本概念 &#xff08;一&#xff09;什么是目标检测 目标检测&#xff08;Object Detection&#xff09; 的任务是找出图像中所有感兴趣的目标&#xff08;物体&#xff09;&#xff0c;不同于分类和回归问题…

react-virtualized实现行元素不等高的虚拟列表滚动

前言&#xff1a; 当一个页面中需要接受接口返回的全部数据进行页面渲染时间&#xff0c;如果数据量比较庞大&#xff0c;前端在渲染dom的过程中需要花费时间&#xff0c;造成页面经常出现卡顿现象。 需求&#xff1a;通过虚拟加载&#xff0c;优化页面渲染速度 优点&#xff1…

如何批量删除文件名里的多余文字?

如何批量删除文件名里的多余文字&#xff1f;删除文件名中多余的文字可以提高文件管理的效率和可读性。简洁性&#xff1a;删除多余的文字可以使文件名更简洁&#xff0c;减少冗余信息。这样可以更轻松地浏览和识别文件&#xff0c;尤其是当文件数量较多时。可读性&#xff1a;…

tcp/ip模型中,帧是第几层的数据单元?

在网络通信的世界中&#xff0c;TCP/IP模型以其高效和可靠性而著称。这个模型是现代互联网通信的基石&#xff0c;它定义了数据在网络中如何被传输和接收。其中&#xff0c;一个核心的概念是数据单元的层级&#xff0c;特别是“帧”在这个模型中的位置。今天&#xff0c;我们就…

代码随想录day17--二叉树的应用5

LeetCode654.最大二叉树 题目描述&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后…

后端性能优化的一些总结

目录 1、背景 2、优化实现 2.1查询数据表速度慢 2.2调别人接口速度慢 2.3导入速度慢、 2.4导出速度慢的做出介绍 2.5统计功能速度慢 3、总结 1、背景 系统上线后&#xff0c;被用户反应系统很多功能响应时长很慢。用户页面影响速度有要求&#xff0c;下面针对查询数据表…

C#,入门教程(36)——尝试(try)捕捉(catch)不同异常(Exception)的点滴知识与源代码

上一篇&#xff1a; C#&#xff0c;入门教程(35)——哈希表&#xff08;Hashtable&#xff09;的基础知识与用法https://blog.csdn.net/beijinghorn/article/details/124236243 1、try catch 错误机制 Try-catch 语句包含一个后接一个或多个 catch 子句的 try 块&#xff0c;这…

深度学习(7)--Keras项目详解(卷积神经网络)

目录 一.项目介绍 二.卷积神经网络构造 2.1.判断是否是channels first的back end 2.2.卷积层构造 2.3.添加激活函数 2.4.池化层构造 2.5.全连接FC层构造 三.完整代码 3.1.学习率衰减设置 四.首次运行结果 五.数据增强对结果的影响 六.BatchNormalization对结果的影…

LeetCode: 160.相交链表(令人赞叹的优雅)

160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 目录 官方双指针解法&#xff1a; 博主的辣眼代码&#xff1a; 每日一表情包&#xff1a; 博主还未学习哈希表&#xff0c;所以介绍的是双指针法&#xff0c;此题的哈希表解法时O&#xff08;nm&#xff09;空O&…

R语言入门笔记2.0

1.创建数据框 在R语言中&#xff0c;可以使用data.frame函数来创建数据框。以下是一个简单的示例&#xff0c;这段R语言代码创建了一个名为student的数据框&#xff0c;其中包含了学生的ID、性别、姓名和出生日期&#xff0c;首先创建一个包含学生出生日期的向量&#xff0c;再…

网络时间协议NTP

网络时间协议NTP(Network Time Protocol)是TCP/IP协议族里面的一个应用层协议。NTP用于在一系列分布式时间服务器与客户端之间同步时钟。NTP的实现基于IP和UDP。NTP报文通过UDP传输,端口号是123。 随着网络拓扑的日益复杂,整个网络内设备的时钟同步将变得十分重要。如果依靠…