BPMN.JS中文教程学习

news2025/6/22 8:54:52

基础篇

vue+ bpmn.js

建模BpmnModeler+将数据转图形bpmnModeler.importXML

// basic.vue
  <script>
    // 引入相关的依赖
    import BpmnModeler from 'bpmn-js/lib/Modeler'
    import {
      xmlStr
    } from '../mock/xmlStr' // 这里是直接引用了xml字符串
    export default {
      name: '',
      components: {},
      // 生命周期 - 创建完成(可以访问当前this实例)
      created() { },
      // 生命周期 - 载入后, Vue 实例挂载到实际的 DOM 操作完成,一般在该过程进行 Ajax 交互
      mounted() {
        this.init()
      },
      data() {
        return {
          // bpmn建模器
          bpmnModeler: null,
          container: null,
          canvas: null
        }
      },
      methods: {
        init() {
          // 获取到属性ref为“canvas”的dom节点
          const canvas = this.$refs.canvas
          // 建模
          this.bpmnModeler = new BpmnModeler({
            container: canvas
          })
          this.createNewDiagram()
        },
        createNewDiagram() {
          // 将字符串转换成图显示出来
          this.bpmnModeler.importXML(xmlStr, (err) => {
            if (err) {
              // console.error(err)
            } else {
              // 这里是成功之后的回调, 可以在这里做一系列事情
              this.success()
            }
          })
        },
        success() {
          // console.log('创建成功!')
        }
      }
    }
  </script>

创建BpmnModeler实例时配置additionalModules属性

左侧工具栏 prpertiesProviderModule

右侧属性栏 bpmn-js-properties-panel

// panel.vue
<script>
...
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
...
methods: {
  init() {
    // 获取到属性ref为“canvas”的dom节点
    const canvas = this.$refs.canvas
    // 建模
    this.bpmnModeler = new BpmnModeler({
      container: canvas,
      //添加控制板
      propertiesPanel: {
        parent: '#js-properties-panel'
      },
      additionalModules: [
        // 左边工具栏以及节点
        propertiesProviderModule,
        // 右边的工具栏
        propertiesPanelModule
      ]
    })
    this.createNewDiagram()
  },
   createNewDiagram() {
          // 将字符串转换成图显示出来
       this.bpmnModeler.importXML(xmlStr, (err) => {
          if (err) {
              // console.error(err)
           } else {
              // 这里是成功之后的回调, 可以在这里做一系列事情
             this.success()
          }
       })
    },
        success() {
          // console.log('创建成功!')
        }
  
}

http篇

字符串数据通过请求获取

// axios.vue
<script>
...
import axios from 'axios'
import { xmlStr } from '../mock/xmlStr' // 引入一个本地的xml字符串, 若是没有获取到后台的数据则用它
​
export default {
    ...
    data () {
       return {
        ...
        loading: true,
        xmlUrl: '',
        defaultXmlStr: xmlStr
        }
    },
    methods: {
    async init () {
      this.loading = true
      this.xmlUrl = await this.getXmlUrl()
      console.log(this.xmlUrl)
      this.loading = false
      this.$nextTick(() => { // 等待 DOM 更新之后再对工作流进行初始化
        this.initBpmn()
        })
    },
    getXmlUrl () { // 该方法模拟请求后台获取bpmn文件地址
        return new Promise(resolve => {
            setTimeout(() => {
                const url = 'https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmnMock.bpmn' // 模拟网络请求的一个地址
                resolve(url)
            }, 1000)
        })
    },
    initBpmn () {
      ... // 这里是初始化工作流的代码
      this.createNewDiagram()
    },
    async createNewDiagram () {
        const that = this
        let bpmnXmlStr = ''
        if (this.xmlUrl === '') { // 若是后台没有数据则使用默认的一个xml
            bpmnXmlStr = this.defaultXmlStr
            this.transformCanvas(bpmnXmlStr)
        } else {
            let res = await axios({
                method: 'get',
                timeout: 120000,
                url: that.xmlUrl,
                headers: { 'Content-Type': 'multipart/form-data' }
            })
            console.log(res)
            bpmnXmlStr = res['data']
            this.transformCanvas(bpmnXmlStr)
        }
    },
    transformCanvas(bpmnXmlStr) {
      // 将字符串转换成图显示出来
      this.bpmnModeler.importXML(bpmnXmlStr, (err) => {
        if (err) {
          console.error(err)
        } else {
          this.success()
        }
        // 让图能自适应屏幕
        var canvas = this.bpmnModeler.get('canvas')
        canvas.zoom('fit-viewport')
      })
    },
    success () {
        console.log('创建成功!')
    }
    }
}
</script>

将编辑之后的最新bpmn发送给后台

该功能就涉及到了bpmn.js中的事件绑定, 也就是前端需要给图形绑定一个事件来检测到图形的改变, 并获取到最新的xml 信息.

获取最新xml信息

bpmnModeler.on('commandStack.changed',function(){})

// save.vue
<script>
   success () {
        console.log('创建成功!')
        this.addBpmnListener()
    },
        // 添加绑定事件
    addBpmnListener () {
      const that = this
      // 给图绑定事件,当图有发生改变就会触发这个事件
      this.bpmnModeler.on('commandStack.changed', function () {
        that.saveDiagram(function(err, xml) {
          console.log(xml) // 这里获取到的就是最新的xml信息
        })
      })
    },
    // 下载为bpmn格式,done是个函数,调用的时候传入的
    saveDiagram(done) {
      // 把传入的done再传给bpmn原型的saveXML函数调用
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
        done(err, xml)
      })
    }
</script>
​

这段代码是一个Vue组件中的一部分,用于处理保存操作。首先定义了一个名为success的方法,当保存成功时调用。在success方法中调用了addBpmnListener方法,用于添加BPMN图的事件监听器

addBpmnListener方法中,通过**this.bpmnModeler.on**方法给BPMN图绑定了一个事件监听器,当图有发生改变时触发**commandStack.changed**事件。事件回调函数中调用了saveDiagram方法,并传入一个回调函数作为参数。

saveDiagram方法用于保存BPMN图为XML格式,并通过传入的回调函数将保存结果传递出去。在方法内部调用了this.bpmnModeler.saveXML方法来保存XML,并将结果通过传入的回调函数返回。

总的来说,这段代码的逻辑是:当BPMN图有变化时,触发保存操作,并将保存的XML结果传递出去。在保存操作完成后,可以通过传入的回调函数获取保存的XML信息。

编辑完保存为bpmn文件或svg文件

API

bpmnModeler.saveSVG(function(){})

this.bpmnModeler.saveXML( function(err, xml) {callback(err, xml)} )

encodeURIComponent li标签

// save.vue
<script>
    ...
  addBpmnListener () {
      const that = this
      // 获取a标签dom节点
      const downloadLink = this.$refs.saveDiagram
      const downloadSvgLink = this.$refs.saveSvg
        // 给图绑定事件,当图有发生改变就会触发这个事件
      this.bpmnModeler.on('commandStack.changed', function () {
        that.saveSVG(function(err, svg) {
            that.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg)
        })
        that.saveDiagram(function(err, xml) {
            that.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml)
        })
      })
  },
  // 下载为SVG格式,done是个函数,调用的时候传入的
  saveSVG(done) {
      // 把传入的done再传给bpmn原型的saveSVG函数调用
      this.bpmnModeler.saveSVG(done)
  },
  // 下载为bpmn格式,done是个函数,调用的时候传入的
  saveDiagram(done) {
      // 把传入的done再传给bpmn原型的saveXML函数调用
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
          done(err, xml)
      })
  },
  // 当图发生改变的时候会调用这个函数,这个data就是图的xml
  setEncoded(link, name, data) {
      // 把xml转换为URI,下载要用到的
      const encodedData = encodeURIComponent(data)
      // 下载图的具体操作,改变a的属性,className令a标签可点击,href令能下载,download是下载的文件的名字
      console.log(link, name, data)
      let xmlFile = new File([data], 'test.bpmn')
      console.log(xmlFile)
      if (data) {
        link.className = 'active'
        link.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        link.download = name
      }
  }
</script>

将最新的XML保存至后端(待补充)

事件篇

监听modeler并绑定事件

shape.added 新增一个shape之后触发;

shape.move.end 移动完一个shape之后触发;

shape.removed 删除一个shape之后触发;

API

var elementRegistry = bpmnjs.get('elementRegistry') var shape = e.element ? elementRegistry.get(e.element.id) : e.shape

// event.vue
<script>
...
success () {
  this.addModelerListener()
},
// 监听 modeler
addModelerListener() {
  const bpmnjs = this.bpmnModeler
  const that = this
  // 这里我是用了一个forEach给modeler上添加要绑定的事件
  const events = ['shape.added', 'shape.move.end', 'shape.removed', 'connect.end',  'connect.move']
  events.forEach(function(event) {
    that.bpmnModeler.on(event, e => {
      console.log(event, e)
      var elementRegistry = bpmnjs.get('elementRegistry')
      var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
      console.log(shape)
    })
  })
},

监听element并绑定事件

上面介绍的是监听modeler并绑定事件, 可能你也需要监听用户点击图形上的element或者监听某个element改变:

element.click 点击元素;

element.changed 当元素发生改变的时候(包括新增、移动、删除元素)

// event.vue
<script>
...
success () {
    ...
    this.addEventBusListener()
},
addEventBusListener () {
    let that = this
  const eventBus = this.bpmnModeler.get('eventBus') // 需要使用eventBus
  const eventTypes = ['element.click', 'element.changed'] // 需要监听的事件集合
  eventTypes.forEach(function(eventType) {
    eventBus.on(eventType, function(e) {
      console.log(e)
    })
  })
}
</script>
//获取Elememnt
eventBus.on(eventType, function(e) {
  if (!e || e.element.type == 'bpmn:Process') return // 这里我的根元素是bpmn:Process
  console.log(e)
  var elementRegistry = this.bpmnModeler.get('elementRegistry')
  var shape = elementRegistry.get(e.element.id) // 传递id进去
  console.log(shape) // {Shape}
  console.log(e.element) // {Shape}
  console.log(JSON.stringify(shape)===JSON.stringify(e.element)) // true
})

通过监听事件判断操作方式

上面我们已经介绍了modelerelement的监听绑定方式, 在事件应用中, 你更多的需要知道用户要进行什么操作, 好写对应的业务逻辑.

这里我就以我工作中要用到的场景为案例进行讲解.

新增了shape

新增了线(connection)

删除了shape和connection

移动了shape和线

// event.vue
    ...
    success () {
      this.addModelerListener()
      this.addEventBusListener()
    },
    // 添加绑定事件
    addBpmnListener () {
      const that = this
      // 获取a标签dom节点
      const downloadLink = this.$refs.saveDiagram
      const downloadSvgLink = this.$refs.saveSvg
        // 给图绑定事件,当图有发生改变就会触发这个事件
      this.bpmnModeler.on('commandStack.changed', function () {
        that.saveSVG(function(err, svg) {
            that.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg)
        })
        that.saveDiagram(function(err, xml) {
            that.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml)
        })
      })
    },
    addModelerListener() {
      // 监听 modeler
      const bpmnjs = this.bpmnModeler
      const that = this
      // 'shape.removed', 'connect.end', 'connect.move'
      const events = ['shape.added', 'shape.move.end', 'shape.removed']
      events.forEach(function(event) {
        that.bpmnModeler.on(event, e => {
          var elementRegistry = bpmnjs.get('elementRegistry')
          var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
          // console.log(shape)
          if (event === 'shape.added') {
            console.log('新增了shape')
          } else if (event === 'shape.move.end') {
            console.log('移动了shape')
          } else if (event === 'shape.removed') {
            console.log('删除了shape')
          }
        })
      })
    },
    addEventBusListener() {
      // 监听 element
      let that = this
      const eventBus = this.bpmnModeler.get('eventBus')
      const eventTypes = ['element.click', 'element.changed']
      eventTypes.forEach(function(eventType) {
        eventBus.on(eventType, function(e) {
          if (!e || e.element.type == 'bpmn:Process') return
          if (eventType === 'element.changed') {
            that.elementChanged(eventType, e)
          } else if (eventType === 'element.click') {
            console.log('点击了element')
          }
        })
      })
    },
    elementChanged(eventType, e) {
      var shape = this.getShape(e.element.id)
      if (!shape) {
        // 若是shape为null则表示删除, 无论是shape还是connect删除都调用此处
        console.log('无效的shape')
        // 由于上面已经用 shape.removed 检测了shape的删除, 因此这里只判断是否是线
        if (this.isSequenceFlow(shape.type)) {
          console.log('删除了线')
        }
      }
      if (!this.isInvalid(shape.type)) {
        if (this.isSequenceFlow(shape.type)) {
          console.log('改变了线')
        }
      }
    },
    getShape(id) {
      var elementRegistry = this.bpmnModeler.get('elementRegistry')
      return elementRegistry.get(id)
    },
    isInvalid (param) { // 判断是否是无效的值
      return param === null || param === undefined || param === ''
    },
    isSequenceFlow (type) { // 判断是否是线
      return type === 'bpmn:SequenceFlow'
    }

自定义Palette篇(左侧绘画板)

原型

$inject

自定义Renderer篇(画布上元素)

自定义ContextPad篇

编辑、删除节点篇

封装组件

Properties篇

我们在用bpmn.js画的每一个节点其实都被称之为diagram element(图表元素, 是不是很好理解😁)

而在bpmn文件中的每个xml标签称之为BPMN element.

diagram elementBPMN element的一些属性关联起来靠的是一个叫做businessObject的属性. 从名称上理解你也可以知道它是一个对象(Object), 你可以在这个对象中添加上一些特殊的属性, 并且这些属性是可以直接插到BPMN element上的.

读取
var elementRegistry = bpmnJs.get('elementRegistry').get('ID').businessObject
//一致element情况
element.bussinessObject
const {bussinessObject}=element
修改
var moddle = bpmnJS.get('moddle');
​
// 创建一个BPMN element , 并且载入到导出的xml里
var newCondition = moddle.create('bpmn:FormalExpression', {
  body: '${ value > 100 }'
});
​
// 写入属性, 但是不支持撤销 
sequenceFlow.conditionExpression = newCondition;
//支撑撤销/重新 
var modeling = bpmnJS.get('modeling');
modeling.updateProperties(sequenceFlowElement, {
  conditionExpression: newCondition
});
​
//updateProperties()
//属性查看下面meta-model descriptor
modeling.updateProperties(startEventElement, {
    name: '我是修改后的虚线节点',
    isInterrupting: false
})
​

《meta-model descriptor》

XML Schema(XML Schema Definition,XSD)是一种用于描述 XML 文档结构和约束的语言。它本身是一种 XML 文档,用于定义 XML 文档中元素和属性的结构、数据类型以及约束规则。

XML Schema 的目的是为 XML 文档提供验证机制,以确保其符合特定的规范和要求。通过 XML Schema,您可以明确指定 XML 文档中包含的元素、属性以及它们之间的关系,指定数据类型,提供约束规则,以及定义文档的命名空间等。

XML Schema 是 XML 的一个重要标准,由 W3C(World Wide Web Consortium)制定和维护。它通常以 .xsd 文件扩展名保存,并可以使用各种 XML 解析器和编辑器进行创建、编辑和验证。

XML Schema 的基本结构包括:

  1. 元素声明(Element Declaration):定义 XML 文档中的元素,包括元素名称、类型、出现次数等信息。

  2. 属性声明(Attribute Declaration):定义 XML 元素的属性,包括属性名称、数据类型、默认值等信息。

  3. 简单类型(Simple Type):定义 XML 元素或属性的数据类型,如字符串、数字、日期等。

  4. 复杂类型(Complex Type):定义包含其他元素和属性的复杂结构,可以指定序列、选择和重复等约束规则。

通过定义这些结构,XML Schema 可以帮助确保 XML 文档的结构、内容和数据格式符合预期,从而提高文档的可靠性和互操作性。

Properties-panel篇(上)

// 这里引入的是右侧属性栏这个框
import propertiesPanelModule from 'bpmn-js-properties-panel'
// 而这个引入的是右侧属性栏里的内容
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
​
additionalModules: [
  propertiesPanelModule,
  propertiesProviderModule
]

//第一个propertiesPanelModule 表示的是属性栏这个框, 就是告诉别人这里要有个属性栏; //第二个propertiesProviderModule表示的是属性栏里的内容, 也就是点击不同的element该显示什么内容.

自定义

既然这样的话, 我们只需要重写propertiesProviderModule就可以了, 不要引入官方提供的(也就是从bpmn-js-properties-panel/lib/provider/camunda引入的), 而是自定义一个**propertiesProviderModule**来显示自己想要的内容.

扩展使用Properties-panel properties-panel-extension

Properties-panel篇(下)

样式主题切换

自定义properties-panel

input框双向绑定 @change

/**
* 改变控件触发的事件
* @param { Object } input的Event
* @param { String } 要修改的属性的名称
*/
changeField (event, type) {
  const value = event.target.value
  let properties = {}
  properties[type] = value
  this.element[type] = value
  this.updateProperties(properties) // 调用属性更新方法
}

修改节点名称label属性

updateName(name) {
  const { modeler, element } = this
  const modeling = modeler.get('modeling')
  modeling.updateLabel(element, name)
  // 等同于 modeling.updateProperties(element, { name })
},
API:modeling.updateLabel()

修改节点颜色color属性

/**
 * 改变控件触发的事件
 * @param { Object } input的Event
 * @param { String } 要修改的属性的名称
 */
changeField(event, type) {
  const value = event.target.value
  let properties = {}
  properties[type] = value
  if (type === 'color') { // 若是color属性
    this.onChangeColor(value)
  }
  this.element[type] = value
  this.updateProperties(properties)
},
onChangeColor(color) {
  const { modeler, element } = this
  const modeling = this.modeler.get('modeling')
  modeling.setColor(element, {
    fill: color,
    stroke: null
  })
},
​
//API:modeling.setColor()

修改event节点类型

实现这个功能我们需要用到bpmnReplace.replaceElement这个方法.

首先让我们看看event里这个属性是放在哪里的.

changeEventType(event) { // 改变下拉框
  const { modeler, element } = this
  const value = event.target.value
  const bpmnReplace = modeler.get('bpmnReplace')
  this.eventType = value
  bpmnReplace.replaceElement(element, {
    type: element.businessObject.$type,
    eventDefinitionType: value
  })
},

现在改变下拉框的值, 就可以改变eventDefinitionType的值了, 不过还有一个问题, 就是你点击了其它的节点, 然后再次点回开始节点的时候, 下拉框的默认值(应该是本身所选元素的eventDefinition属性值)就不对了, 也就是说我们还需要获取到这个开始节点本身的eventDefinitionType值.

init () {
    modeler.on('selection.changed', e => {
        this.selectedElements = e.newSelection
        this.element = e.newSelection[0]
        console.log(this.element)
        this.setDefaultProperties() // 设置一些默认的值
      })
}
setDefaultProperties() {
  const { element } = this
  if (element) {
    const { type, businessObject } = element
    if (this.verifyIsEvent(type)) { // 若是event类型
      // 获取默认的 eventDefinitionType
      this.eventType = businessObject.eventDefinitions ? businessObject.eventDefinitions[0]['$type'] : ''
    }
  }
}

修改Task节点的类型

changeTaskType(event) {
  const { modeler, element } = this
  const value = event.target.value // 当前下拉框选择的值
  const bpmnReplace = modeler.get('bpmnReplace')
  bpmnReplace.replaceElement(element, {
    type: value // 直接修改type就可以了
  })
}

初始化properties-panel并设置一些默认值

init () {
    modeler.on('selection.changed', e => {
        this.selectedElements = e.newSelection
        this.element = e.newSelection[0]
        console.log(this.element)
        this.setDefaultProperties() // 设置一些默认的值
      })
}
setDefaultProperties() {
  const { element } = this
  if (element) {
    // 这里可以拿到当前点击的节点的所有属性
    const { type, businessObject } = element
    // doSomeThing
  }
}

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

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

相关文章

使用 Docker 部署 Open-Resume 在线简历平台

1&#xff09;Open-Resume 介绍 GitHub&#xff1a; https://github.com/xitanggg/open-resume Open-Resume 是一款功能强大的开源 简历生成器 和 简历解析器 。可以帮助我们快速的生成个人简历&#xff0c;并定制化不同的主题和布局风格。该项目的目标是为每个人提供免费的现…

Qt5 编译 Qt Creator 源码中的 linguist 模块

文章目录 下载 Qt Creator 源码手动翻译多语言自动翻译多语言 下载 Qt Creator 源码 Github: https://github.com/qt/qttools 笔记打算用 Qt 5.12.12 来编译 qt creator-linguist 所以笔者下载的是 tag - 5.12.12 &#xff0c;解压后如下&#xff0c;先删除多余的文件&#xf…

视觉SLAM学习打卡【10】-后端·滑动窗口法位姿图

本节是对上一节BA的进一步简化&#xff0c;旨在提高优化实时性.难点在于位姿图部分的雅可比矩阵求解&#xff08;涉及李代数扰动模型求导&#xff09;&#xff0c;书中的相关推导存在跳步&#xff08;可能数学功底强的人认为过渡的理所当然&#xff09;&#xff0c;笔者参考了知…

B站广告推广操作教程及费用?

哔哩哔哩&#xff08;B站&#xff09;作为国内极具影响力的年轻人文化社区&#xff0c;已成为众多品牌与企业触达目标受众、提升品牌影响力的重要阵地。然而&#xff0c;面对B站复杂的广告系统与精细化运营需求&#xff0c;许多广告主可能对如何高效开展B站广告推广感到困惑。云…

2024年同城网总流量全新生态,个人工作室落地式游戏玩法,单账户月入3万

我要为大家解读的是本地生活新项目&#xff0c;这个业务模式中&#xff0c;即使是低收入的玩法&#xff0c;一个月赚取万儿八千也是完全可行的。而高收入的玩法&#xff0c;一单的收入甚至能超过一万。目前&#xff0c;你的圈子里已经有一些同行业的人开始以个人工作室的形式去…

stm32开发之threadx+netxduo(结合 modbus 编写tcp接口程序)

前言 本篇结合freemodbus源码程序进行移植,驱动实现的接口为modbus tcp需要知道threadx的 事件标志组、信号量、线程相关的知识需要知道netxduo tcp方面的api和创建流程方面的知识 freemodbus程序源码 本次使用的源码来自于rt-thread软件包里面的&#xff0c;可以参考之前的…

linux查看网络连接数

目录 netstat top netstat 1.netstat查看当前主机上网络连接信息&#xff0c;端口号&#xff0c;pid,程序名等等 #直接查看 netstat -anp #一般使用的时候&#xff0c;可能要筛选 #比如8080端口是否被占用 netstat -anp | grep 8080 #minio服务占用了那些端口 netstat -anp …

掌握判断IPv4地址是否正确的方法

在数字通信和互联网领域中&#xff0c;IPv4地址作为标识网络设备的核心元素&#xff0c;其正确性至关重要。一个有效的IPv4地址能够确保设备在网络中的正常通信和交互&#xff0c;而错误的IPv4地址则可能导致连接失败、通信中断甚至网络安全问题。因此&#xff0c;掌握判断IPv4…

【docker】之linux写shell脚本备份线上数据库(备份为dump文件)

目录 1. SH文件1.1 SH文件示例1.2 文件解释1.3 .sh文件执行 2. 备份线上数据库的.sh文件2.1 文件命令解析 3. 命令执行4. 线下dump文件的恢复与备份 环境&#xff1a;linux容器&#xff1a;docker 1. SH文件 SH文件通常指的是 Shell 脚本文件&#xff0c;文件后缀名为.sh&…

Spring Boot统一功能处理(一)

本篇主要介绍Spring Boot的统一功能处理中的拦截器。 目录 一、拦截器的基本使用 二、拦截器实操 三、浅尝源码 初始化DispatcherServerlet 处理请求&#xff08;doDispatch) 四、适配器模式 一、拦截器的基本使用 在一般的学校或者社区门口&#xff0c;通常会安排几个…

【C++学习】C++11新特性(第一节)

文章目录 ♫一.文章前言♫二.C11新特性♫一.统一的列表初始化♫二.std::initializer_list♫三.声明♫四.decltype关键字♫五.nullptr♫六.新增加容器---静态数组array、forward_list以及unordered系列♫6.1unordered_map与unoredered_set♫6.2array♫6.3 forward_list&#xff…

Leetcode算法训练日记 | day18

一、找树左下角的值 1.题目 Leetcode&#xff1a;第 513 题 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出:…

nandgame中的Memory(内存操作):栈、堆、静态区

Push Memory Push Memory 将内存中的值push到栈内堆栈顶部的值是一个内存地址。从堆栈中弹出地址。获取内存地址的当前内容&#xff0c;并将其推送到堆栈上。POP_A //堆栈顶部的值是一个内存地址。从堆栈中弹出地址。 D *A //获取内存地址的当前内容 PUSH_D //将其推送到…

JVM性能调优——运行时参数

文章目录 1、JVM参数选项类型1.1、标准参数选项1.2、非标准参数选项1.3、非稳定参数选项 2、添加JVM参数的方式3、常用JVM参数选项4、通过Java代码获取JVM参数5、小结 熟悉JVM参数对于系统调优是非常重要的。比如一个高流量的延迟的电子交易平台&#xff0c;它要求的响应时间都…

ROS机器人未知环境自主探索功能包explore_lite最全源码详细解析(五)

本系列文章主要针对ROS机器人常使用的未知环境自主探索功能包explore_lite展开全源码的详细解析&#xff0c;并进行概括总结。 本系列文章共包含六篇文章&#xff0c;前五篇文章主要介绍explore_lite功能包中 explore.cpp、costmap_tools.h、frontier_search.cpp、costmap_clie…

MySQL:关于数据库的一些练习题

文章目录 前面的内容已经把数据库的一些必要知识已经储备好了&#xff0c;因此下面就对于这些语句进行一些练习&#xff1a; 批量插入数据 insert into actor values (1, PENELOPE, GUINESS, 2006-02-15 12:34:33), (2, NICK, WAHLBERG, 2006-02-15 12:34:33);SQL202 找出所有…

C/S医学检验LIS实验室信息管理系统源码 医院LIS源码

LIS系统即实验室信息管理系统。LIS系统能实现临床检验信息化&#xff0c;检验科信息管理自动化。其主要功能是将检验科的实验仪器传出的检验数据经数据分析后&#xff0c;自动生成打印报告&#xff0c;通过网络存储在数据库中&#xff0c;使医生能够通过医生工作站方便、及时地…

一起学习python——基础篇(14)

今天讲一下python的json解析方式。 上一篇文章讲述了将传参数据转换为json格式的数据传给后台&#xff0c;如果后端返回的json格式数据&#xff0c;我们该如何解析呢&#xff1f; 例子一&#xff1a;简单的json数据格式 如果后端返回的json数据如下&#xff0c; { "na…

【leetcode面试经典150题】34.有效的数独(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

Docker Compose 一键安装

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…