资源描述
Java通用页面流程框架及实例介绍
在企业的应用系统中,存在着大量的页面流程,即一个交易需要多个页面以及操作才能够完成,这些交易的多个页面之间存在复杂的逻辑和复用关系。本文介绍 IBM Branch Transformation Toolkit(本文简称 BTT)中的一个重要框架 -- 通用页面流框架。作为企业 J2EE 应用的一个重要组件,通用页面流同时支持 Web 页面流、Java 客户端页面流和手机客户端页面流。同时 IBM BTT 通用页面流框架具有很强的扩展性,用户可以扩展用以特殊的页面流程处理,比如电视渠道页面流程。
企业前端渠道应用的特点
企业的前端渠道应用,指企业应用业务服务系统的前端渠道接口。这里的前端渠道是相对于后台来说。以银行应用系统为例,前端渠道应用指网上银行、柜面应用、低柜理财应用、电话中心、ATM 应用、Kiosk 应用、手机银行等等。而银行后台系统,则指后台的核心业务系统。企业的前端渠道应用和后台业务系统都有其各自的特点,本文的通用页面流框架主要应用于企业的前端渠道应用中。
对于企业后台业务来说,SOA 架构思想使得企业中间业务组件化、服务化,具有更好的适应性和扩展性,以至于企业面对市场,能够以更快的速度开发出新的业务流程,符合客户和市场的需求。随着企业业务流程的 SOA 整合,企业的后台业务流程日趋规范。
而对于企业的前端渠道应用来说,随着企业“以客户为中心”转化的趋势,企业的前端渠道应用建设日趋重要,很多企业都建立起网上系统、手机应用、电话服务等前端渠道应用。而且,企业的前端渠道越来越多。
图 1. 企业前端渠道应用的特点 – 多渠道、以客户为中心
在前端渠道应用系统开发过程中,页面流程是一个非常重要的模块。由于企业前端渠道越来越多,各种渠道具有异构的特点,可能是 Web 平台,也可能是富客户端前台,也可能是手机应用,所以一个适合企业前端渠道应用的页面流程框架需要是通用的,适合常用的前端平台。比如 Web、Java 富客户端,也需要是可扩展的,能够适用于未来的前端特殊渠道应用,比如电视渠道。
什么是页面流程,什么是通用页面流程
页面流程,是指一系列页面和业务的组合,他们之间可以按照一定流程规则进行导航,所有的页面和业务操作都是以流程为中心组织。以往的应用程序,一个交易往往包含着多个的页面,每个页面上可以提交多个的业务操作,然后根据这些业务操作返回的结果导航到不同的其它页面。页面流程的提出以统一定义的流程方式梳理和导航这些页面和业务操作集合。
页面流程包括界面、页面导航引擎、业务流程和业务操作,包含了一个企业前端渠道应用交易的所有部分,以流程的方式有效清晰的组织企业的交易。
现在企业前端应用越来越复杂,服务越来越多,理解和管理页面流程也越来越困难了。下面是一个普通的银行信用卡申请页面流程。
图 2. 信用卡申请页面流程图
信用卡申请页面流程用例:
· 用户在一个页面上选择申请信用卡。有两种选项,一种是用户以前没有该银行的储蓄卡,另一种是用户已有银行储蓄卡。
· 用户如果选择已有银行的储蓄卡,就输入卡号,系统就会尝试获取该用户的信息。
· 如果不能找到足够的信息,就到“用户财务信息”输入页面。
· 用户财务信息输入成功后,就会转到下一个页面,这个页面显示这个用户适合的所有信用卡类型。这个页面中,用户可以选择其中的一款信用卡并进入下一个页面,还有一个“取消”按钮,用户点击后,就可以结束交易。
· 系统显示确认页面,包含用户的信用卡申请的概要信息,以及用户选择的信用卡基本信息。确认页面中同样包含了“取消”按钮,用户点击后,就可以结束交易。同时,还包含着“返回”按钮,用于用户发现选择错误后,返回上一页面进行修改。最好还包含“确定”按钮,用户点击后,提交信用卡申请流程。
· 系统展示用户提交成功页面,页面上有“确认”按钮,点击后回到主页面。
· 上面的页面流程中,“用户财务信息”页面流程是一个子页面流程,可以被众多的其他页面流程复用。
· 在上面的页面流程的所有步骤中,如果出现错误,系统还会转到“错误提示页面”,并告知用户所有的填写错误。
这个信用卡申请页面流程可以是 Web 的页面流程,也可以富客户端页面流程,也可以是手机页面流程,甚至可以是用户扩展的其他页面流程,诸如电视渠道页面流程。而这个通用的页面流程,就称之为企业前段渠道应用通用页面流程框架。我们在接下来的介绍中,还会用到这个页面流程用例。
当今现有的页面导航和页面流程技术
当今绝大多数的 MVC 框架都具有页面导航的功能,但并不是所有的 MVC 框架都具有页面流程,而通用的页面流程,则目前只有 IBM BTT 产品才具有。下面是常用最流行的 MVC 框架页面导航以及页面流程技术介绍和分析:
Struts 页面导航
Apache Struts MVC 框架使用非常广泛,但 Struts 中没有页面流程的概念和组件。 Struts 的 Web 应用中,为了在 Struts 里面实现页面流程,框架提供了 MVC 的 Action(动作)和 View(视图)来实现页面导航。在 Struts 中,一个 Action 和一个指定的请求 URL 进行绑定,只有当请求从那个 URL 过来的时候,Action 才会被执行,这里的 Action 是业务操作。在 Action 业务操作执行过程中,会进行一系列的处理,并且会返回处理结果,Struts 导航框架会根据这个 Action 处理的返回结果,导航到下一个合适的视图显示结果。这种方式简单、有效,指定两个 View,通过 Action 串成两个 View 之间的导航。所以要在 Struts 中实现多步控制的页面流程,需要多个 Action,并把多个 View 形成链,形成一条多步的页面流程。
这是当前常用的页面导航方法,特点是简单、有效。但是它具有一个很大的缺陷:就是只能看到 Action 操作和 View 视图,从 struts-config.xml 配置文件定义中不能清晰的看到页面流程。就像在地图中您不能清晰地看见北京到广州的路线,而只能看见北京到广州途中的所有各个城市,任何两个城市之间的路线。这种定义灵活性强,但组织性不清晰。而且复用性不好,只能在 Action 和 View 之间复用,而不能像页面流程一样复用子页面流程。
JSF 页面导航
JSF 是 Web 组件的框架,是 JSP 在页面的基础上而不是请求的基础上使用事件驱动的方法进行页面导航,使得每个页面和它的后退控制器逻辑保持一致。但总的来说,JSF 的页面导航与 Struts 一样,是两个页面之间的导航,没有一个流程的概念。但 JSF 作为标准,具有很强的扩展性,Spring Web Flow 在 JSF 基础上扩展支持以 Web Flow 页面流程的方式进行页面导航。 Spring Web Flow 为 JSF 提供了一个定义良好的、能跨越多个页面和不同路径、统一流程生存周期管理的页面流程。
Spring Web Flow 页面流程
Spring Web Flow 是一个基于 Spring 的开源 Web 页面流程框架,是 2006 年产生并逐渐流行的一个开源 Web 页面流程框架。 Spring Web Flow 是 Web 页面导航的流程化定义和引擎,这个页面流程的生存周期要比 Struts 和 JSF 的基于请求的、或基于事件的单一两个页面之间的导航长,但是却比一个 HTTP 会话要短。它允许您使用一个简单清晰的流程化方法体现您的页面流程,并且随时重用。 Spring Web Flow 页面流程提供一下优点:
· Web 应用中的页面流程可以通过 Web 流程的定义(XML 文件或者 Java 类)清晰的展现出来。
· Web 流程被设计成自包含的。这就允许您把您的应用中的一部分看作是一个模块,这样就可以在多种场合重用它。
· Web 流程捕获任何合理的页面流程总是使用同种技术。您不必被迫在特定的场合使用特定的控制器。
· 最后,Web 页面流程是可以通过一个良好定义的契约使用。它具有一个清晰的,可观察的生存周期为您自动管理。通过简单配置,系统便会为您管理复杂的逻辑,非常容易使用。
Spring Web Flow 的工作原理就是状态机机制,Web 页面流程是由一组状态(states)的集合组成,一个状态是页面流程中发生某事的一个点,每个状态都有一个或更多的转变(transitions)用来移动到下一个状态。一个转变是由一个事件(event)触发的。
BTT 通用页面流程 – Generic Screen Flow
BTT 通用页面流程,早在 10 年前就是 BTT 前端渠道建设及整合产品的一个重要组件,而前面介绍的 Spring Web Flow 则是 2006 年才发布的 1.0 版本。通过下面的进一步介绍技术细节,读者会发现 Spring Web Flow 的思路和 BTT Generic Screen Flow 框架很类似,页面流程通过通用页面流程定义 XML 文件清晰的展现出来。只不过后者更加强大,具有下面更多的优点:
· BTT 通用页面流程是通用的页面流程框架,支持 Web 页面流程、Java 富客户端页面流程、以及手机客户端页面流程,而且用户可以进行扩展支持其他前端渠道的页面流程。
· BTT 通用页面流程采用树形的数据结构,具有很好的性能,被全世界一百多家对性能要求非常严格的企业所采用。关于 BTT 的数据结构是另外一个话题,本文不进行深入讨论。
BTT 通用页面流框架
BTT 是企业前端多渠道建设及整合框架,它的通用页面流程框架则是适合所有前端渠道的页面流程。BTT 通用页面流程由页面、页面导航引擎、业务流程、业务操作四个部分组成:
1. 页面:一个单独的页面,可以是一个产品信息,可以是一个登录页面。它可以是 Web HTML 页面,也可以是 Java SWT 页面。
2. 页面导航引擎:在多个页面之间进行页面导航。企业前端应用存在大量的用户页面,这些页面之间存在着逻辑关系,可以在不同页面直接根据操作结果的不同进行导航。每个页面提交之后,会根据执行“动作”的返回结果,到达相应另外的页面,这里的“动作”指的是下面的“业务流程”和“业务操作”。
3. 业务流程:指一系列业务操作组成的带逻辑结构和判断的流程。简单的业务流程可以是一个状态机组成,状态机的每一步是一个业务操作,然后根据业务操作的执行结果会执行相应的其他业务操作。
4. 业务操作:这里的业务指的是单一的操作,可以是技术范畴的操作,也可以是业务范畴的业务操作。业务操作可以是记录电子日志,可以是发短信,可以是访问用户数据。
图 3. 页面流程的组成
从上图中可以看出,前端页面流程逻辑中的节点(State),可以是页面(Page),可以是业务逻辑(Business Logic),也可以是业务操作(Operation)。而业务逻辑(Business Logic)又是由业务操作(Operation)组成的业务流程。
BTT 通用页面流程设计和各种流程
在 BTT 中,流程(Flow Processor)是最基本的,然后可以基于流程,扩展出业务流程(Operation Flow Processor)、Web 页面流程(HTML Flow Processor)和 Java 富客户端页面流程(Java Flow Processor)。对于 Java 富客户端页面流,BTT 有两种,一种是导航 Swing 和 SWT 页面的页面流程,另外一种是导航由 XML 生成的页面的页面流程。
流程(Flow Processor)
流程是一个状态机框架,它是各种流程的基础,所有的 BTT 的业务流程和页面流程都是基于流程(Flow Processor)扩展而来。开发人员,也可以根据自己的需要扩展自己需要的页面流程。
流程本质上是一个状态机,它由一系列的状态组成。一个流程包含一个初始状态,一个或多个的结束状态,和一系列中间状态。流程的所有状态和步骤都可以定义在 XML 文件中。在 BTT 中,可以定义在流程定义文件中 (processor.xml) 或者独立流程定义文件(Self-Defined)中。
图 4. 流程的状态机结构
BTT 提供了一系列关于实现流程的接口:Action(动作), GuardCondition(条件), Processor(流程), State(状态)和 Transition(跳转)。同时还有 entry actions(入口动作),exit actions(出口动作)和 event(事件)。
流程中还有一个重要的概念:状态。流程管理器根据状态来管理流程的生命周期。状态是流程的执行情况,BTT 中的流程有以下几种状态:
· 未初始化– 引擎已经建立了流程实例,但还没有初始化。
· 初始化– 流程引擎已经初始化了流程实例,但是还没有执行。
· 执行– 流程引擎开始执行流程实例
· 停止– 流程引擎在流程未结束前停止,并且不能被重新启动。
· 挂起- 流程引擎在流程未结束前停止,但可以被重新启动。
· 完成– 流程执行结束,流程执行到结束状态。
业务流程(Operation Flow Processor)
业务流程是由业务操作组成的流程。它是对流程的扩展,业务流程中的每一个状态都可以用于执行一个或多个的业务操作。架构上它实现了业务操作接口,流程中的状态可以执行业务操作。业务流程和流程之间的关系如下图所示:
图 5. 业务流程和流程之间的关系
BTTOperationProcessor 类是业务流程的实现类,它实现了流程类 BTTProcessor 。下面是业务流程的一个实例:
清单 1. 业务流程(Operation Flow Processor)实例
<!-- 业务流程 -->
<opProcessor id="genFlow">
<!—开始状态 -->
<state id="initial" type="initial">
<!— 状态入口动作 -->
<entryActions>
<!— Step是业务操作,执行用户编写的业务逻辑 -->
<Step id="dummyJournalAct"
implClass="com.ibm.btt.samples.appl.JournalHostRequestDataStep"/>
</entryActions>
<!— 根据业务操作的执行结果,流程相应进行到下一个状态,
如果业务操作成功就进入state2,如果业务操作执行失败,则到状态finalNotOk。 -->
<transitions>
<transition id="dummyJournalAct.ok" targetState="state2"/>
<transition id="dummyJournalAct.error" targetState="finalNotOk"/>
</transitions>
</state>
<state id="state2">
<entryActions>
<Step implClass="com.ibm.btt.samples.appl.SendHostStep"
id="dummyHostAct"/>
</entryActions>
<transitions>
<transition id="dummyHostAct.ok" targetState="state3"/>
<transition id="dummyHostAct.error" targetState="finalNotOk"/>
</transitions>
</state>
<state id="state3">
<entryActions>
<Step implClass="com.ibm.btt.samples.appl.JournalHostReplyDataStep"
id="dummyJournalAct"/>
</entryActions>
<transitions>
<transition id="dummyJournalAct.ok" targetState="finalOk"/>
<transition id="dummyJournalAct.error" targetState="finalNotOk"/>
</transitions>
</state>
<state id="finalOk" type="final" typeIdInfo="ok"/>
<state id="finalNotOk" type="final" typeIdInfo="error"/>
</opProcessor>
Web 页面流程(HTML Flow Processor)
BTT 为 B/S 的应用系统提供了 Web 页面流程,用于把一个交易中的所有 HTML 页面、JSP 页面、业务流程和业务操作组织成一个流程,并根据状态机进行业务的执行和页面的导航。通用页面流程中的 BTTHtmlProcessor 就是用于驱动 Web 页面流程的。
图 6. Web 页面流程和流程之间的关系
Web 页面流程为了支持导航 Web 页面,在流程状态机中增强了下面特性:
· Web 页面流程是异步执行的,流程的状态可以和状态机的外部产生交互,也就是和前端的用户界面产生关联。 Web 页面流程执行到页面状态时,流程就缓存在服务器端,直到客户端用户触发了页面操作,才根据页面上触发的操作重新继续未完成的 Web 页面流程。而上面介绍的业务流程只有同步执行的功能。
· Web 页面流程有两个扩展的状态:页面和子流程。当 Web 页面流程执行到这两个状态时,流程就释放流程控制权,直到页面状态和子流程执行完毕,控制权重新回到 Web 页面流程。
· 当执行到页面状态时,只有当从浏览器接收到相应的事件,流程才继续往下执行。用户页面数据含有隐藏字段 <dse_nextEventName>,后台的 Web 页面流程根据前端页面发送 <dse_nextEventName> 的事件值,转到下一个状态。
· 当执行到子流程状态时,页面流程的控制权就转移到子流程,只有从子流程结束后,父流程才能继续。父流程根据子流程结束状态中的 <typeIdInfo> 的值,转移到下一个状态。
· Web 页面流程是异步的,所以存在超时的情况。可以定义 processorTimeout 属性来指定 Web 页面流程实例的超时等待时间。当 Web 页面流程超时时,引擎会发送超时事件,清空流程实例以及内存等资源。下面是相应的定义:<field id="defaultProcessesTimeout" value="1000"/> 。值以毫秒为单位,默认值是 0,表示永远不超时。
下面是 Web 页面流程的实例,XML 配置的方式清晰易懂,就算是业务人员也可以看懂。注释中有相应的流程解释:
清单 2. Web 页面流程(HTML Flow Processor)实例
<!-- HTML Processor表示Web页面流程, id唯一标示这个web页面流程-->
<htmlProcessor context="creditCardsCtx" id="creditCardsProc">
<!-- 开始状态-->
<htmlState id="initial" type="initial">
<transitions>
<htmlTransition id="initial.start" targetState="creditCardsWellcome"/>
</transitions>
</htmlState>
<!-- 欢迎页面状态, 导航到欢迎页面。type="page"表示是页面状态,
typeIdInfo="creditCardsWellcome.jsp"表示页面内容。-->
<htmlState id="creditCardsWellcome" type="page"
typeIdInfo="creditCardsWellcome.jsp">
<transitions>
<!-- 根据页面上出发的事件,转到下一个状态creditHistoryOpState。
页面上的事件如: nextEventName="history" -->
<htmlTransition
context="creditCardsWellcome_history_Ctx"
id="creditCardsWellcome.history" targetState="creditHistoryOpState"/>
</transitions>
</htmlState>
<!-- 从页面到此业务状态,执行相应的业务操作,
type="operation"表示这个状态是一个业务操作,
typeIdInfo="creditHistoryOp"表示这个业务操作的ID-->
<!-- Operation state. The operation is executed by the specialized state.
The operation is firing the exit events -->
<operationState id="creditHistoryOpState" type="operation"
typeIdInfo="creditHistoryOp">
<!-- 根据业务操作的返回结果,转移到下一个Web流程的下一个状态-->
<transitions>
<transition id="creditHistoryOpState.accountExists"
targetState="selectCardsOpState"/>
<transition id="creditHistoryOpState.newAccount"
targetState="financialInfoState"/>
<transition id="creditHistoryOpState.error"
targetState="finalNotOK"/>
</transitions>
</operationState>
<!-- 子流程状态,这是一个特殊的页面状态,
type="subFlow"表示是一个子页面流程,
typeIdInfo="financialInfoProc"表示子页面流程的ID,
Web流程会根据ID并且执行子页面流程-->
<htmlState id="financialInfoState" type="subFlow"
typeIdInfo="financialInfoProc">
<!-- 根据子页面流程的结果,Web流程执行下一个流程状态 -->
<transitions>
<!-- 如果子页面流程执行成功,则到selectCardsOpState状态 -->
<htmlTransition id="financialInfoState.OK"
outputMapFmt="financialInfoToCreditApplFormat"
targetState="selectCardsOpState"/>
<!-- 如果子页面流程执行失败,则到finalNotOK状态 -->
<htmlTransition id="financialInfoState.notOK"
outputMapFmt="errorMessagesMapper"
targetState="finalNotOK"/>
<!-- 如果子页面流程取消,则重新回到欢迎界面,用户可以重新开始流程 -->
<transition id="financialInfoState.canceled"
targetState="creditCardsWellcome"/>
</transitions>
</htmlState>
<!-- 这个状态得到信用卡的种类信息 -->
<htmlState id="selectCardsOpState">
<entryActions>
<executeOperationAct id="selectCardsAct"
operationName="selectCardsOp"/>
</entryActions>
<transitions>
<transition id="selectCardsAct.ok" targetState="creditCardsPage"/>
<transition id="selectCardsAct.error" targetState="finalNotOK"/>
</transitions>
</htmlState>
<!-- 选择信用卡类型页面状态,type="page"表示这个状态是页面,
typeIdInfo="creditCardsPage.jsp"表示页面内容。-->
<htmlState id="creditCardsPage" type="page"
typeIdInfo="creditCardsPage.jsp">
<!-- 根据选择信用卡的结果,转到流程的下一个状态 -->
<transitions>
<!-- 如果用户信用卡选择成功,转到流程的下一个状态creditCardConfirmationPage -->
<transition id="creditCardsPage.OK"
targetState="creditCardConfirmationPage"/>
<!-- 如果用户取消了信用卡申请,则转到流程的下一个状态finalOK -->
<transition id="creditCardsPage.Cancel" targetState="finalOK"/>
</transitions>
</htmlState>
<!-- 信用卡确认信息页面,type="page"表示这个状态是页面,
typeIdInfo="creditCardConfirmationPage.jsp"表示页面内容 -->
<htmlState id="creditCardConfirmationPage" type="page"
typeIdInfo="creditCardConfirmationPage.jsp">
<transitions>
<!-- 如果用户确认了信用卡信息,
则转移到下一个流程状态creditCardProcessingOpState。 -->
<transition id="creditCardConfirmationPage.OK"
targetState="creditCardProcessingOpState"/>
<!-- 如果用户取消了信用卡申请,则转到流程的下一个状态finalOK -->
<transition id="creditCardConfirmationPage.Cancel"
targetState="finalOK"/>
</transitions>
</htmlState>
<!-- 信用卡处理逻辑状态 -->
<htmlState id="creditCardProcessingOpState">
<entryActions>
<!-- 执行业务操作,operationName="creditCardProcessingOp"表示业务操作的ID -->
<executeOperationAct id="creditCardProcAct"
linkContextTo="processor" operationName="creditCardProcessingOp"/>
</entryActions>
<transitions>
<!-- 如果信用卡处理申请提交成功,则转移到下一个状态creditCardProcessedState。 -->
<transition id="creditCardProcAct.ok" targetState="creditCardProcessedState"/>
<!-- 如果信用卡处理申请提交失败,则转移到下一个状态finalNotOK。 -->
<transition id="creditCardProcAct.error" targetState="finalNotOK"/>
</transitions>
</htmlState>
<!-- 信用卡处理完成页面。type="page"表示这个状态是页面,
typeIdInfo="creditCardProcessedPage.jsp"表示页面内容 -->
<htmlState id="creditCardProcessedState" type="page"
typeIdInfo="creditCardProcessedPage.jsp">
<transitions>
<transition id="creditCardProcessedState.OK" targetState="finalOK"/>
</transitions>
</htmlState>
<!-- 申请错误页面。type="final"表示这个状态是流程的结束状态,
finalPage="apologies.jsp"表示页面内容 -->
<htmlState finalPage="apologies.jsp" id="finalNotOK"
type="final" typeIdInfo="notOK"/>
<!-- 申请成功页面。type="final"表示这个状态是流程的结束状态,
finalPage="accountinquiry.jsp"表示页面内容 -->
<htmlState finalPage="accountinquiry.jsp" id="finalOK"
type="final" typeIdInfo="OK"/>
</htmlProcessor>
XUI 页面流程(XUI Flow Processor)
XUI 页面流程是 Java 富客户端的页面流程,是 BTT 两种 Java 富客户端页面流程中的一种。 XUI 页面流程把一个交易中的所有 XML UI 页面、业务流程和业务操作组成一个流程,并且根据状态机进行业务的执行和页面的导航。通用页面流程中的 XUIProcessor 就是用于驱动 XUI 富客户端页面流程的。
图 7. XUI 富客户端页面流程和流程之间的关系
XUI 富客户端页面流程和 Web 页面流程一样,是异步的,具有 XUI 页面状态(state),超时机制等。下面是同样的信用卡申请流程的 XUI 页面流程定义。我们可以看出,其原理和 Web 页面流程非常类似。
清单 3. XUI 富客户端页面流程(XUI Flow Processor)实例
<!-- xuiProcessor表示XUI富客户端页面流流程, id唯一标示这个xui富客户端页面流程-->
<xuiProcessor context="creditCardsCtx" id="creditCardsProc">
<!-- 开始状态,执行initialStep业务操作,并根据结果导航到下一个状态-->
<state id="initial" type="initial">
<entryActions>
<Step id="initialStep"
implClass="com.ibm.btt.rcp.sample.operation.step.InitialStep" />
</entryActions>
<transitions>
<transition id="initialStep.ok"
targetState="creditCardsWellcome" />
<transition id="initialStep.error"
targetState="finalNotOk" />
</transitions>
</state>
<!-- 欢迎页面状态。type="page"表示是页面状态,
typeIdInfo="jar:///xui/firstStep.xui"表示页面内容对应的XML。-->
<xuiState id="creditCardsWellcome" type="page"
typeIdInfo="jar:///xui/firstStep.xui">
<!-- 根据页面上出发的事件,转到下一个状态creditHistoryOpState。
页面上会使用StateChangeAction,发送"history"事件 -->
<transitions>
<transition context="creditCardsWellcome_history_Ctx"
id="creditCardsWellcome.history"
targetState="creditHistoryOpState" />
</transitions>
</xuiState>
<!-- 业务状态,执行相应的业务操作,
type="operation"表示这个状态是一个业务操作-->
<state id="creditHistoryOpState" type="operation">
<en
展开阅读全文