1. 功能介绍

    事件流,将复杂的逻辑拆分成多个逻辑步骤,通过配置文件配置的逻辑作为流程来流转执行,这样最大程度实现单个逻辑的重用性,方便不同的客户定制要求,不同业务能够通过配置文件组装的方式实现业务功能,同时也支持代码方式自定义修改或插入节点,以最大程度的实现产品组装化,同时,对于大批量数据的操作,事件流能够提供完整的后台调度方式,以及完善的监控,保证大批量数据操作的有效性。

  2. 主要特性

    1. 图形化界面画事件流程并生成事件流程的配置文件,注:配置文件也可以手工编写
    2. 通过配置文件组装事件流程,配置文件支持多种流程节点,如流程步骤,流程判断选项,这样能够最大程度的灵活配置等。
    3. 配置文件的选项支持表达式,支持常用的的语法解析,对于复杂语法调用配置的方法实现。
    4. 事件流参数传递,传递的参数在整个事件流生命周期有效,因为execute(IData param)参数,所有的逻辑步骤都用的是该参数对象,
    5. 提供事件流进度的监控,并能够通过查询表格和图表的方式查看流程进度。
    6. 提供流程执行方式,可以设置前台、后台执行方式,对于大数据量可设置后台执行,保证应用不会超时。
    7. 提供多种日志记录模式,对于不同的应用需要来配置日志模式。
    8. 提供自定义节点方式,可以在代码中修改已有节点或插入一个新节点,用于提供了公用流程时,如果需要根据公用流程自定义修改节点参数或插入新的节点。
  3. 开发步骤

    1. 生成配置文件。通过图形化配置工具配置页面流并生成配置文件,也可以手工编写页面流配置文件。
    2. 根据配置文件中配置的每个事件流步骤,编写对应的逻辑类和类方法。
    3. 编写代码,根据用户输入后触发事件流。
    4. 对于记录过日志或后台执行方式,配置事件流监控菜单,监控运行事件流的运行情况,如<a href="javascript:void(0)" onclick="redirectToNav('component.flow.logicflow.FlowList', 'queryFlows', null, 'contentframe')">流程进度监控</>
  4. 配置文件说明

    1. flow: 流程配置

      name 事件流名称
      desc 事件流描述
      logmode 日志记录模式,执行事件流的时候记录日志的方式
      可选值(1: 不记录任何日志 2: 只记录事件流主表日志 3: 记录事件流主表和步骤表日志), 默认不填为: 1
      execmode 执行模式,对于大批量数据可以考虑采用后台执行方式,可选值(1: 前台执行 2: 后台执行), 默认不填为: 1
      transmode 事务方式,可选值(jdbc: JDBC事务 xa: XA分布式事务),默认不填为: jdbc
    2. step: 步骤配置

      name 步骤名称,每个步骤必须唯一
      desc 步骤描述
      nextstep 接续步骤,即执行完当前步骤后的下一步骤
      class 步骤执行时调用的类路径,如:com.linkage.sale.bean.campaign.CampaignBean
      method 步骤执行时调用的类方法
    3. switch: 选项

      name 选项名称
      expression 选项执行的表达式,兼容ognl表达式写法,表达式中必须为特定变量(param,pageData),其中param表示pd.getData(),pageData表示PageData对象,支持表达式param.USER_ID、pageData.getParameter('USER_ID')、pageData.getData().get('CUST_TYPE')等,如果逻辑比较复杂,无法通过表达式实现,可以指定类名和方法来实现,如:com.TestBean@test, 表示调用TestBean的test的方法,其中方法必须是 public String test(PageData pd, IData param)这种类型,并且不限制为静态方法
      default 默认执行的case,如果表达式中取到的值为空或者没有匹配的case,则直接执行配置的默认case
      desc 选项描述
    4. case: 选项情形

      value case值
      desc case描述
      nextstep 接续的步骤名称
  5. 方法说明

    类路径 com.linkage.appframework.flow.logicflow.ILogicFlow
    类描述 事件流对象接口
    方法名称 public String getFlowId() throws Exception
    方法描述 获取事件流编号
    方法名称 public Object execute(IData param) throws Exception
    方法描述 传入IData参数,执行事件流,如:logicflow.execute(pd.getData())
    方法名称 public FlowStep getStep(String stepName) throws Exception
    方法描述 根据节点名获取节点对象,包括节点名,描述,类路径,类方法等
    方法名称 public void setStep(String step_name, FlowStep step) throws Exception
    方法描述 修改指定节点的参数,包括修改节点名,描述,类路径,类方法等
    方法名称 public void insertAfterStep(String step_name, FlowStep step) throws Exception
    方法描述 在指定节点后面插入新的节点,包括新节点的名称,描述,类路径,类方法等
    类路径 com.linkage.appframework.flow.logicflow.LogicFlow
    类描述 事件流对象实现类
    方法名称 public LogicFlow(PageData pd, String flowFile) throws Exception
    方法描述 传入PageData,flowFile流程配置文件,构造事件流对象,如:ILogicFlow flow = new LogicFlow(pd, "demo/Demo.xml");
    类路径 com.linkage.appframework.flow.logicflow.FlowStep
    类描述 事件流节点类
    方法名称 public String getName()
    方法描述 获取节点名
    方法名称 public void setName(String name)
    方法描述 设置节点名
    方法名称 public String getDesc()
    方法描述 获取节点描述
    方法名称 public void setDesc(String desc)
    方法描述 设置节点描述
    方法名称 public String getClassName()
    方法描述 获取节点类路径
    方法名称 public void setClassName(String className)
    方法描述 设置节点类路径
    方法名称 public String getMethod()
    方法描述 获取节点类方法
    方法名称 public void setMethod(String method)
    方法描述 设置节点类方法
  6. 注意事项

    1. 配置文件存放在etc/省代码../logicflow/目录下,如logicflow/demo/Demo.xml,作为配置文件构建事件流对象时,需要忽略logicflow/,如demo/Demo.xml。
    2. 当flow的logmode=1时,flow的execmode="ture"会报错,因为若不记录日志,不能用后台执行,因为没有记录参数.
    3. flow的execmode="1|2"表示前台执行|后台执行,默认为false前台执行,若为开发模式,配置为后台执行时照样会前台执行。
    4. 事件流步骤的类方法的参数必须为PageData, IData,如public void|返回对象 test(PageData pd, IData param) throws Exception,其中可以不返回或者返回对象,流程返回值为执行的最后一个节点调用逻辑后返回的值,中间节点的返回值将不做保存,若要获取,需要put到param中传递。
    5. 事件流在流程执行时execute(IData)传入的对象,将在事件流的整个生命周期中有效,即之前执行的事件流步骤与后续事件流步骤中的IData对象为同一个,这样如果要传递数据到后续的事件流步骤,只需param.put(...)到该对象中,后续就能获取到。
  7. 代码片段

    1. 配置文件代码(参考etc/../logicflow/demo/Demo.xml)

      <?xml version="1.0" encoding="GB2312"?>
      <flow name="CreateScheme" desc="创建营销案">
      	<step
      		name="begin"
      		desc="开始"
      		nextstep="inputScheme"
      		/>
      	<switch name="inputScheme" expression="param.CUST_TYPE" default="1" desc="客户类型">
      		<case value="1" nextstep="inputPersonCust" desc="普通客户"/>
      		<case value="2" nextstep="inputVipCust" desc="个人大客户"/>
      		<case value="3" nextstep="inputGroupCust" desc="集团大客户"/>
      	</switch>
      	<step
      		name="inputPersonCust"
      		desc="录入普通客户"
      		class="com.linkage.test.TestBean"
      		method="inputPersonCust"
      		nextstep="submitScheme"
      		/>
      	<step
      		name="inputVipCust"
      		desc="录入个人大客户"
      		class="com.linkage.test.TestBean"
      		method="inputVipCust"
      		nextstep="submitScheme"
      		/>
      	<step
      		name="inputGroupCust"
      		desc="录入集团大客户"
      		class="com.linkage.test.TestBean"
      		method="inputGroupCust"
      		nextstep="submitScheme"
      		/>
      	<step
      		name="submitScheme"
      		desc="创建营销案"
      		class="com.linkage.test.TestBean"
      		method="submitScheme"
      		nextstep="end"
      		/>
      	<step
      		name="end"
      		desc="结束"
      		/>
      </flow>
      
    2. JAVA代码(参考Bean文件)

      /** 录入普通客户 */
      public void inputPersonCust(PageData pd, IData param) throws Exception {
      	log.debug("call bean inputPersonCust, param : " + param);
      }
      /** 录入个人大客户 */
      public void inputVipCust(PageData pd, IData param) throws Exception {
      	log.debug("call bean inputVipCust, param : " + param);
      }
      /** 录入集团大客户 */
      public void inputGroupCust(PageData pd, IData param) throws Exception {
      	log.debug("call bean inputGroupCust, param : " + param);
      }
      /** 客户选择逻辑,若<switch expression="com.TestBean@switchCustType"..> */ 
      public String switchCustType(PageData pd, IData param) throws Exception {
      	log.debug("call bean switchCustType, param : " + param);
      	return "3"; //若为选项表达式,必须要返回对象,返回的值将和siwtch case的value匹配
      }
      /** 录入VIP客户信用资料 */
      public void inputCreditDatum(PageData pd, IData param) throws Exception {
      	log.debug("input credit datum, data:" + param);
      }
      /** 录入VIP客户积分资料 */
      public void inputScoreDatum(PageData pd, IData param) throws Exception {
      	log.debug("input score datum, data:" + param);
      }
      
      /** 创建营销案,提交事件流 */
      public void submitScheme(IRequestCycle cycle) throws Exception {
      	/* 直接调用事件流开始 */
      	ILogicFlow flow = new LogicFlow(pd, "demo/Demo.xml"); //根据PageData和流程配置文件构造事件流对象,
      	Object retuslt = flow.execute(param); //最后一个逻辑节点返回的结果
      	/* 直接调用事件流结束 */
      
      	/* 自定义扩展调用事件流开始 */
      	ILogicFlow flow = new LogicFlow(pd, "demo/Demo.xml"); //根据PageData和流程配置文件构造事件流对象,
      	
      	/*假设流程为公共配置,如果需要修改流程节点步骤的执行逻辑或者添加自定义流程节点步骤*/
      	//将录入大客户资料(inputVipCust)节点步骤改为录入信用资料(inputCreditDatum)节点步骤
      	FlowStep approveStep = flow.getStep("inputVipCust"); //获取大客户资料节点步骤
      	approveStep.setClassName("com.linkage.quickstart.bean.examples.ExamplesBean");//由于录入大客户资料和录入信用资料在同一类文件中,故这里不需要设置
      	approveStep.setMethod("inputCreditDatum");//设置执行逻辑为录入信用资料
      	flow.setStep("inputVipCust", approveStep);//替换大客户资料节点步骤为录入信用资料节点步骤
      	
      	//在录入大客户资料(inputVipCust)节点步骤后加入录入积分资料(inputCreditDatum)节点步骤
      	FlowStep scoreStep = new FlowStep(); //构造新的节点步骤
      	scoreStep.setName("inputScoreDatum"); //设置节点步骤名
      	scoreStep.setDesc("录入积分资料"); //设置节点步骤描述
      	scoreStep.setClassName("com.linkage.quickstart.bean.examples.ExamplesBean"); //设置节点步骤的类路径
      	scoreStep.setMethod("inputScoreDatum"); //设置节点步骤的方法
      	flow.insertAfterStep("inputVipCust", scoreStep); //在录入大客户资料节点步骤后插入录入积分资料节点步骤
      	
      	Object retuslt = flow.execute(param); //最后一个逻辑节点返回的结果
      	/* 自定义扩展调用事件流结束 */
      }
      
  8. 效果演示

    创建营销案流程