Apache Commons-SCXML系列之Demo:"请假流程"
来源:互联网 发布:js获取url页面内容 编辑:程序博客网 时间:2024/05/16 17:54
首先分析自己的业务逻辑,画好状态图
1、请假流程状态图
画图工具EA
2、根据状态图编写xml文件
<?xml version="1.0"?><!--请假流程定义,状态图如上图所示--><scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" datamodel="jexl" initial="filling"> <!-- 请假单需要的数据--> <datamodel> <data id="applicant" expr=""></data> <data id="reason" expr=""></data> <data id="from" expr=""></data> <data id="to" expr=""></data> <data id="departmentApprove" expr="false"></data> <data id="personnelApprove" expr="false"></data> </datamodel> <state id="filling"> <onentry> </onentry> <!--当填写完了表单,将外界的数据通过,系统变量_event.data传进来,data其实是一个map--> <transition event="fill.end" target="approving"> <assign location="applicant" expr="_event.data.name"></assign> <assign location="reason" expr="_event.data.reason"></assign> <assign location="from" expr="_event.data.from"></assign> <assign location="to" expr="_event.data.to"></assign> <!--调用leaveEntity的填表函数,在这个函数里面,我们可以操作做数据持久化--> <!--个人觉得这种方式和领域驱动设计很像,欢迎和我交流--> <script> leaveEntity.fillForm(applicant,reason,from,to) </script> </transition> </state> <!--这是一个复合状态:一个大状太--> <state id="approving"> <initial> <transition target="departmentApproving"> </transition> </initial> <!--部门经理审批状态--> <state id="departmentApproving"> <onentry></onentry> <!--如果部门经理同意,就将departmentApprove的值赋值为true,然后我们可以执行持久化的数据操作(我这里只是简单的输出)--> <transition event="approve" target="personnelApproving"> <assign location="departmentApprove" expr="true"></assign> <script> leaveEntity.departmentApprove(departmentApprove) </script> </transition> </state> <!--人事经理审批状态--> <state id="personnelApproving"> <!--如果人事经理同意,就将personnelApprove的值赋值为true,然后我们可以执行持久化的数据操作(我这里只是简单的输出)--> <transition event="approve" target="approveEnd"> <assign location="personnelApprove" expr="true"></assign> <script> leaveEntity.personnelApprove(personnelApprove) </script> </transition> </state> <final id="approveEnd"></final> <!--这个转移的事件“event.state.approving”是当当前复合状态到达 <final> 节点的时候框架自动生成的。--> <transition event="done.state.approving" target="approved" /> <!--这个转移事件,是只要任何一个经理拒绝了请求,就转向被拒绝状态--> <transition event="reject" target="rejected"> </transition> </state> <!--已同意状态,进入状态的时候,可以发送邮件给相应的用户--> <state id="approved"> <onentry> <script> leaveEntity.sendEmail() </script> </onentry> <!--一个eventless(自动转移),执行完了<onentry>里面的事件就转移了--> <transition target="archiving" ></transition> </state> <!--被拒绝状态,进入状态的时候,可以发送邮件给相应的用户--> <state id="rejected"> <onentry> <script> leaveEntity.sendEmail() </script> </onentry> <!--申请者选择继续修改申请信息的时候的转移,--> <transition event="goFilling" target="filling"></transition> <!--申请者可以取消本次请假--> <transition event="goEnd" target="archiving"></transition> </state> <!--归档状态,进入的时候直接归档--> <state id="archiving"> <onentry> <script> leaveEntity.archive() </script> </onentry> <transition target="end"/> </state> <!--结束状态--> <final id="end"> </final></scxml>
3、编写程序、控制状态变化
LeaveEntity.java
package leave;/** * Created by zhengshouzi on 2015/11/24. * * 这个类是一个实体类,就想领域驱动设计里面的思想一样,每一个实体类不仅要有数据,而且要有实体类对应的方法。 * 不知道什么是领域驱动设计的,请另行百度。 */public class LeaveEntity { //请假表单信息,这些字段都可以不需要,凡事需要使用这些字段的地方,都可以选择从状态机里面传递出来,我也刚研究,最好还是加上。 private String appliant; private String reason; private String from ; private String to; private boolean departmentApprove; private boolean personnelApprove; /** * 做表单数据保存操作 * @param name * @param reason * @param from * @param to */ public void fillForm(String name,String reason,String from,String to){ this.appliant = name; this.reason = reason; this.from=from; this.to= to; System.out.println("请假人:"+appliant); System.out.println("请假原因:"+reason); System.out.println("开始时间:"+from); System.out.println("结束时间:"+to); } /** * 更新部门经理同意信息 * @param b */ public void departmentApprove(boolean b){ this.departmentApprove = b; System.out.println("部门经理同意"); } /** * 更新人事经理同意信息 * @param b */ public void personnelApprove(boolean b){ this.personnelApprove =b; System.out.println("人事经理同意"); } /** * 发送邮件信息 */ public void sendEmail(){ if (departmentApprove && personnelApprove){ System.out.println(appliant+":你好,你的请假已经通过了"); }else{ System.out.println(appliant+":你好,你的请假没有通过,请重新填写"); } } /** * 自动执行归档功能 */ public void archive(){ System.out.println("开始归档"); }}
LeaveFrame.java
/** * Created by zhengshouzi on 2015/11/24. */package leave;import org.apache.commons.scxml2.Context;import org.apache.commons.scxml2.Evaluator;import org.apache.commons.scxml2.SCXMLExecutor;import org.apache.commons.scxml2.TriggerEvent;import org.apache.commons.scxml2.env.SimpleErrorReporter;import org.apache.commons.scxml2.env.jexl.JexlEvaluator;import org.apache.commons.scxml2.io.SCXMLReader;import org.apache.commons.scxml2.model.ModelException;import org.apache.commons.scxml2.model.SCXML;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.net.URL;import java.util.HashMap;import java.util.Map;public class LeaveFrame extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; //一系列的按钮,标签 private JLabel applicant; private JLabel reason; private JLabel from; private JLabel to; private JTextField nameTest; private JTextField reasonTest; private JTextField fromTest; private JTextField toTest; private JButton submit; private JButton departmentApprove; private JButton personeelApprove; private JButton reject; private JButton continueFill; private JButton archive; private JButton start; private SCXMLExecutor executor=null; public LeaveFrame() { super("SCXML Leave"); initUI(); } public static void main(String[] args) { new LeaveFrame(); } /** * 初始化请假流程 */ private void initWorkflow() { //得到资源文件路径 final URL leaveApprovel = this.getClass().getResource("leaveApprove1.xml"); //实例化数据模型解析器 Evaluator evaluator = new JexlEvaluator(); //实例化引擎 executor = new SCXMLExecutor(evaluator, null, new SimpleErrorReporter()); try { //加载资源文件,实例化到一个SCXML对象,两者之间一一对应 SCXML scxml = SCXMLReader.read(leaveApprovel); //将这样的一个SCXML实例,作为状态机对象,传入到引擎里面。 executor.setStateMachine(scxml); //设置引擎执行的根上下文 Context rootContext = evaluator.newContext(null); LeaveEntity leaveEntity = new LeaveEntity(); rootContext.set("leaveEntity", leaveEntity); executor.setRootContext(rootContext); //开始启动流程 executor.go(); }catch (Exception e){ e.printStackTrace(); } System.out.println(executor.getGlobalContext().getSystemContext().get("_sessionid")); } /** * 监听器里面的方法,根据界面上的事件来触发对应的转移 * @param event */ public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); try { if ("submit".equals(command)) { setEnabledAndDisabled(new JComponent[]{reject,departmentApprove}, new JComponent[]{submit}); //添加请假的内容进去 Map<String, String> payloadData = new HashMap<String, String>(); payloadData.put("name",nameTest.getText()); payloadData.put("reason",reasonTest.getText()); payloadData.put("from", fromTest.getText()); payloadData.put("to", toTest.getText()); //生成表单填完的事件,携带外部数据进去,然后触发 executor.triggerEvent(new TriggerEvent("fill.end", TriggerEvent.SIGNAL_EVENT,payloadData)); }else if ("departmentApprove".equals(command)){ setEnabledAndDisabled(new JComponent[]{personeelApprove}, new JComponent[]{departmentApprove}); executor.triggerEvent(new TriggerEvent("approve", TriggerEvent.SIGNAL_EVENT)); }else if ("personeelApprove".equals(command)){ setEnabledAndDisabled(new JComponent[]{}, new JComponent[]{personeelApprove,reject,departmentApprove}); executor.triggerEvent(new TriggerEvent("approve", TriggerEvent.SIGNAL_EVENT)); }else if ("reject".equals(command)){ setEnabledAndDisabled(new JComponent[]{continueFill,archive}, new JComponent[]{submit,personeelApprove,reject,departmentApprove}); executor.triggerEvent(new TriggerEvent("reject", TriggerEvent.SIGNAL_EVENT)); }else if ("continueFill".equals(command)){ setEnabledAndDisabled(new JComponent[]{submit}, new JComponent[]{departmentApprove, personeelApprove, reject, continueFill, archive}); executor.triggerEvent(new TriggerEvent("goFilling", TriggerEvent.SIGNAL_EVENT)); }else if ("archive".equals(command)){ setEnabledAndDisabled(new JComponent[]{}, new JComponent[]{departmentApprove, personeelApprove, reject, continueFill, archive, submit}); executor.triggerEvent(new TriggerEvent("goEnd", TriggerEvent.SIGNAL_EVENT)); }else if ("start".equals(command)){ setEnabledAndDisabled(new JComponent[]{submit}, new JComponent[]{departmentApprove, personeelApprove, reject, continueFill, archive, start}); setEnabledAndDisabled(new JComponent[]{nameTest,reasonTest,fromTest,toTest}, new JComponent[]{}); initWorkflow(); } } catch (ModelException e) { e.printStackTrace(); } } /** * 初始化界面 */ private void initUI() { JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); JPanel contentPanel = new JPanel(); contentPanel.setLayout(new GridLayout(8,2)); applicant = new JLabel("申请人:"); nameTest = new JTextField(10); reason = new JLabel("原因:"); reasonTest = new JTextField(50); from = new JLabel("开始时间:"); fromTest = new JTextField(10); to = new JLabel("结束时间:"); toTest = new JTextField(10); start = createButton("start","请假"); submit = createButton("submit","Submit"); departmentApprove= createButton("departmentApprove","部门同意"); personeelApprove= createButton("personeelApprove","人事同意"); reject = createButton("reject","拒绝"); continueFill = createButton("continueFill","继续填写"); archive= createButton("archive","结束"); setEnabledAndDisabled(new JComponent[]{start}, new JComponent[]{departmentApprove, personeelApprove, reject, continueFill, archive, submit}); setEnabledAndDisabled(new JComponent[]{}, new JComponent[]{nameTest, reasonTest, fromTest, toTest}); gridLayoutAdd(contentPanel,new JComponent[]{applicant,nameTest,reason,reasonTest,from,fromTest,to,toTest,start,submit,departmentApprove,personeelApprove,reject,continueFill,archive}); mainPanel.add(contentPanel, BorderLayout.CENTER); setContentPane(mainPanel); setLocation(200, 200); setSize(400, 400); setResizable(true); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } private void gridLayoutAdd(JPanel content, JComponent[] components){ for (int i = 0; i < components.length; i++) { content.add(components[i]); } } private JButton createButton(final String command, final String text) { JButton button = new JButton(text); button.setActionCommand(command); button.addActionListener(this); return button; } private void setEnabledAndDisabled(JComponent[] enabled,JComponent[] disabled){ for (int i=0;i<enabled.length;i++){ enabled[i].setEnabled(true); } for (int i=0;i<disabled.length;i++){ disabled[i].setEnabled(false); } }}
4、程序分析
1、首先打开程序
2、然后点击请假,发起一个请假流程,图中的一串字符是当前会话的id。
3、一旦提交表单,就轮到部门经理审批,部门经理可以选择同意或者拒绝。
4、这里先演示部门同意,接下来就该到人事经理了。
5、这里演示人事经理拒绝,那么按照我们之前话的状态图,这时候应该到“被拒绝“状态,发起人可以更改信息,重新提交或者放弃请假。
6、这里假设我们继续填写,点击提交,又回到了部门经理审批,然后人事经理审批环节,假设两者都同意,然后整个流程就结束了。
5、总结
用状态图只要控制好event 和condition 表达复杂的行为很方便。SCXML框架只有控制状态变化的能力,如果我们能够添加上任务分派功能,那就是一个很强大的状态机工作流了。
更多文章请移步:ThinerZQ’s Blog
0 0
- Apache Commons-SCXML系列之Demo:"请假流程"
- Apache Commons-SCXML系列之Demo:"秒表"
- Apache Commons-SCXML系列之项目介绍
- Apache Commons-SCXML系列之"HelloWorld"
- apache common scxml框架学习DEMO
- apache commons学习系列之Email组件
- Apache Commons 系列简介 之 Lang
- Apache Commons 系列简介 之 Pool
- Apache Commons 系列简介 之 CLI
- Apache SCXML 状态机
- 请假流程
- 请假流程
- apache commons 之 commons.lang
- apache commons 之 commons-configuration
- apache-comnons系列之commons-io-2.5 org.apache.commons.io.IOUtils学习笔记
- apache-comnons系列之commons-io-2.5 org.apache.commons.io.FileUtils学习笔记
- apache-comnons系列之commons-collections4 org.apache.commons.collections4.CollectionUtils学习笔记
- jpbm4入门实践之web请假流程。
- 原型 和 原型链
- 样式设置--美丽邵阳(二)
- Android之ScrollView滚动布局控件使用以及显示新闻网页
- JAVA文件上传
- java 静态代码块,实例代码块,构造方法的执行顺序
- Apache Commons-SCXML系列之Demo:"请假流程"
- MySQL数据库水平切分的实现原理解析
- LineChart
- Android Studio常用快捷键
- 精通javascript study
- maven项目,代码正确的情况下,整个项目中的类报cannot be resolved to a type
- Android Studio 乱码问题
- QT Rectanle 类型解析
- 【Leetcode】Best Time to Buy and Sell Stock II