北在北方

太白枝头看,花开不计年,杯中浮日月,楼外是青天。

导航

判断流程开始节点是否能连通到结束节点

Posted on 2012-09-19 17:59  CN.programmer.Luxh  阅读(1229)  评论(2编辑  收藏  举报

  在流程管理中,有用户自定义流程的需求。就是用户自己建立流程节点,并指定流程节点的走向。

  因为是用户自己操作,所以需要对用户建立的流程的连通性进行判断:从开始节点经过若干审核节点的流转后是否最终能到达结束节点。

  一个流程必须有一个开始节点、一个结束节点和若干审核节点。

  例如用户建立的节点如下:

                                 

  然后用户指定节点的流向:

    1)正确的节点流向

                                  

 

                  以上这些都是正确的节点流向,所谓正确,就是开始节点经过若干审核节点的流转可以最终连通到结束节点。

     2)不正确的节点流向 

                                  

      以上这些都是不正确定的节点流向。

      所以必须检查用户指定的流向是否能从开始节点经过若干审核节点连通到结束节点。


  1)建立两个表,一个节点表和一个流向表。

              

  2)对应的实体

  节点Node:

/**
 * 节点
 * @author Luxh
 * 2012-9-19
 */
@Entity
@Table(name="t_node")
public class Node {
    @Id
    @GeneratedValue
    private Integer id;
    
    //节点名称
    private String name;
    //节点标记:START--开始节点;AUDIT--审核节点;END--结束节点
    private String flag;
    //一个检查标记位,在递归是设置,避免死循环。   Y-已检查  
    private String checkStatus;
}

 

  流向Flow:

/**
 * 流向
 * @author Luxh
 * 2012-9-19
 */
@Entity
@Table(name="t_flow")
public class Flow {
    @Id
    @GeneratedValue
    private Integer id;
    
    //开始编号
    private Integer beginNo;
    //指向编号
    private Integer endNo;

    

  

  3)递归判断方法

/**
 * 节点检查测试
 * @author Luxh
 * 2012-9-19
 */
public class NodeTest {
    EntityManagerFactory emf = null;
    
    @Before
    public void before() {
        //根据在persistence.xml中配置的persistence-unit name 创建EntityManagerFactory
        emf = Persistence.createEntityManagerFactory("myJPA");
    }
    
    @After
    public void after() {
        if(null != emf) {
            emf.close();
        }
    }
    
    /**
     * 添加节点数据
     */
    @Test
    public void testAddNode(){
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        
        Node n1 = new Node();
        n1.setName("开始节点");
        n1.setFlag("START");
        
        Node n2 = new Node();
        n2.setName("节点2");
        n2.setFlag("AUDIT");
        
        Node n3 = new Node();
        n3.setName("节点3");
        n3.setFlag("AUDIT");
        
        Node n4 = new Node();
        n4.setName("节点4");
        n4.setFlag("AUDIT");
        
        Node n5 = new Node();
        n5.setName("结束节点");
        n5.setFlag("END");
        
        
        
        em.persist(n1);
        em.persist(n2);
        em.persist(n3);
        em.persist(n4);
        em.persist(n5);
        
        em.getTransaction().commit();
        em.close();
        
    }
    
    
    /**
     * 添加节点流向数据
     */
    @Test
    public void testAddFlow(){
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        
        Flow f1 = new Flow();
        f1.setBeginNo(1);
        f1.setEndNo(2);
        
        Flow f2 = new Flow();
        f2.setBeginNo(2);
        f2.setEndNo(3);
        
        Flow f3 = new Flow();
        f3.setBeginNo(3);
        f3.setEndNo(4);
        
        Flow f4 = new Flow();
        f4.setBeginNo(4);
        f4.setEndNo(2);
        
        Flow f5 = new Flow();
        f5.setBeginNo(4);
        f5.setEndNo(5);
        
        em.persist(f1);
        em.persist(f2);
        em.persist(f3);
        em.persist(f4);
        em.persist(f4);
        em.persist(f5);
        
        em.getTransaction().commit();
        em.close();
        
    }
    
    /**
     * 测试
     */
    @Test
    public void testIsStartCan2End() {
        //获取JPA实体管理器
        EntityManager em = emf.createEntityManager();
        
        //流程开始节点的编号
        Integer beginNo = 1;
        List<String> flagList = new ArrayList<String>();
        //因为可能会多次检查开始节点是否可以连通结束节点,
        //所以在调用递归检查方法前,一定要清空当前流程所有节点的标记位
        //实际中节点表肯定会有一个字段表示所属流程,根据该字段清空当前流程的所有节点的标记位
        
        //调用清空标记位方法
        //...
        
        //首次调用时,一定是传入开始节点的编号
        isStartCan2End(beginNo,flagList,em);
        if(flagList.contains("END")) {
            System.out.println("开始节点可以连通结束节点");
        }else {
            System.out.println("开始节点无法连通结束节点");
        }
        em.close();
    }
    
    /**
     * 递归判断 开始节点是否可以连通到结束节点
     * @param beginNo 开始编号
     * @param flagList 存放结束节点标记,递归结束后,如果flagList中有结束标记,说明开始节点可以连通到结束节点
     * @param em         JPA的实体管理器,类似以hibernate的session
     */
    public void isStartCan2End(Integer beginNo,List<String> flagList,EntityManager em) {
            //根据开始编号查询出该开始编号的所有指向的节点的编号
            String jpql = "select f from Flow f where f.beginNo = ?";
            List<Flow> flows = em.createQuery(jpql).setParameter(1, beginNo).getResultList();
            
            if(flows != null && flows.size()>0) {
                //遍历开始编号所指向的所有流向
                for(Flow f : flows) {
                    //根据编号找出节点
                    Node n = em.find(Node.class, f.getEndNo());
                    //如果是结束节点,就中断循环
                    if("END".equals(n.getFlag())) {
                        flagList.add(n.getFlag());//将结束节点的标记存放到flagList中
                        break;
                    }else if("START".equals(n.getFlag())||"Y".equals(n.getCheckStatus())) {
                        //如果是开始节点,或者节点的标记位Y,说明该节点已被查找过,跳过,避免递归时死循环
                        continue;
                    }else {
                        em.getTransaction().begin();
                        n.setCheckStatus("Y");//设置节点的标记位
                        em.merge(n);
                        em.getTransaction().commit();
                        //如果是审核节点,则递归查找结束节点
                        isStartCan2End(n.getId(),flagList,em);
                    }
                    
                }
            }
        
        
    }
    
}