> 文章列表 > java基于BS结构下的OA流程可视化的研究与实现

java基于BS结构下的OA流程可视化的研究与实现

java基于BS结构下的OA流程可视化的研究与实现

       工作流是指整个或部分业务流程在计算机支持下的全自动或半自动化。在计算机网络环境下,工作任务在多个人或单位之间的流转实际上将表现为信息或数据在多个人之间的传送。使用可视化的OA工作流设计工具,用户不需要编程就可以定义设计出满足要求的收发文流程,实际使用效果良好。论文以可视化的OA工作流设计工具的开发为基础,主要阐述五个方面的内容。第一部分介绍了工作流和工作流设计工具的相关概念与开发背景;第二部分对工作相关基础理论技术、系统环境与平台基础、以及开发技术进行了描述;第三部分对系统功能进行了分析;第四部分详细介绍了系统流程、流程可视化设计的实际开发过程中使用到的关键技术;最后一部分在总结了系统开发心得的同时,提出了目前系统存在的不足和有待改进的地方。

1 引言

1.1 课题背景

办公自动化(OA-Office Automation)是将现代化办公和计算机网络功能结合起来的一种新型的办公方式,通过网络,组织机构内部的人员可跨越时间、地点协同工作。OA中涉及到诸多业务流程,流程的定义对与OA系统中业务的自动流转具有十分重要的意义,但是在一般B/S模式下的OA系统,对于流程的定义都是文字型或者表单形式的,而不是图形化的,因为基于HTML解析的B/S在绘图方面存在缺陷,因此大多B/S的OA系统在流程定义时,为了达到可视化的效果,都采用了流程定义用C/S来辅助。但是java中的applet技术可以实现在B/S下的绘图,因此,结合applet技术,可以在B/S系统中直接尝试流程的可视化定义研究。

1.2 技术可行性研究

在对可视化流程设计工具的研究和实现过程中一共用到了三种技术:Java Applet、XML、Microsoft Office Access2003。在技术难度方面,由于有指导老师的指导和相关的参考文献,使得在开发过程中所遇到的困难都能够一一得到解决。

1.2.1 Java Applet技术的可行性研究

本系统利用Java Applet作为开发工具,是因为成熟的Java技术采用面向对象的编程方法——把程序和数据封装起来作为一个对象,并为每个对象赋予相应的属性。而Java Applet具有能嵌入到浏览器中运行,能通过可视化技术手段实现绘图功能,能连接数据库服务器和应用服务器等这些特点,完全满足了此次B/S结构下OA流程可视化研究和实现的各种要求。

1.2.2 XML技术的可行性研究

“可扩展标记语言”(XML) 提供一种描述结构化数据的方法。与主要用于控制数据的显示和外观的 HTML 标记不同,XML 标记用于定义数据本身的结构和数据类型。利用XML技术可实现将绘制图形中的节点关系和图形信息保存在XML文件中并通过XML文件提供上层接口服务的功能。

1.2.3 Microsoft Office Access 2003数据库的可行性研究

系统采用Microsoft Office Access 2003作为开发数据库,使用于中度规模的数据录入要求。它通过工具界面所提供的组件输入数据到数据库,可以使用查询设计和SQL实现查询并生成报表。

2 相关基础理论技术以及开发技术

2.1工作流的定义与存在问题描述

2.1.1 OA中工作流的定义

当今社会分工越来越细,在一个单位内部也越来越强调专业化,大部分工作都需要多个部门和员工合作完成。一个制度良好的单位往往对各种工作的工作流程以文件的形式固定下来,即使是管理不太正规的单位也有约定俗成的工作步骤。这种工作流程保证了一件任务能按预定的顺序从起点流向终点,并且在需要的时候可以跟踪、查询和统计。

工作流(workflow)的概念是为提高工作效率的研究而产生的,目前尚无统一、明确的定义。工作流管理联盟(WorkFlow Management Coalition ,WFMC)将工作流定义为:业务流程的全部或部分自动化,在此过程中,文档、信息或者任务按照一定的过程规则流转,实现组织成员间的协调工作以期达到业务的整体目标。

工作流包括以下几个要素:

实体(Entity):是工作流的主体,是需要随着工作流一起流动的物件(Object)。例如,在一个采购申请批准流程中,实体就是采购申请单;在公文审批流程中,实体就是公文。

参与者(Participant):是各个处理步骤中的责任人,可能是人,也可能是某个职能部门,还可能是某个自动化的设备;

流程定义(Flow Definition):是实现某工作目标而要完成的一系列步骤的描述。它包含了所有使业务过程能被工作流执行服务的必要信息。这些信息包含起始和终止条件、各个组成活动、活动调度规则、各业务的参与和需要做的工作、相关应用次序和数据的调用信息等。过程由活动和相关数据组成。

流程定义工具被用来创建计算机可处理的业务过程描述。它可是形式过程定义语言或对象关系模型,也可以是简单地规定用户间信息传输的一组路由命令。

在本论文中所研究的可视化流程设计工具就是一种通过Java 语言实现的利用图形来定义业务流程模型的一种工具。

WFMC对工作流有一个简化的定义由一个四元组{Pt,Pa,Dt,Ti}对其进行描述:

1)工作流参与者(Workflow Participant):定义活动的执行者,执行者可以是人和其他实体。

2)工作流过程活动(Workflow Process Activity):定义工作流活动的执行步骤,它可分为原子活动和子工作流过程。前者不可再分,后者可由原子活动和其他子工作流组成。

3)工作流相关数据(Workflow Relevant Data):定义工作流活动和应用所涉及的数据信息,它们可能包含系统和环境数据。

4)跃迁信息(Transition Information):定义工作流活动执行的依赖信息,决定活动之间的跃迁、一个活动的完成可能对其他活动的执行产生影响。

下面给出一个例子,并用上面的定义的规范进行分解:

Pt = {拟稿人(处员)A,处室领导B,处室会签负责人C,领导D,核稿人E,打字员F,档案室G}

Pa = {拟稿a,送审b,送核稿c,审核d,写审核意见e,送会签f,会签意见g,返回拟稿人h,写核稿意见i,送领导批示j,编号k,送打字室l,写批示意见m,返回核稿人n,排版印刷o,封发p,送档案室q,归档r}

Dt = {文件}

Ti = {Pt(i):->t Pt(j)}表示从一个状态到达另一个状态,t 是触发条件,

这些定义和例子将是我们通过流程设计工具设计流程时的参考。

2.1.2工作流中的流程定义问题

在一般B/S模式下的OA系统,对于流程的定义都是文字型或者表单形式的,而不是图形化的,因为基于HTML解析的B/S在绘图方面存在缺陷,因此大多B/S的OA系统在流程定义时,为了达到可视化的效果,都采用了流程定义用C/S来辅助。而java中的applet技术恰恰可以实现在B/S下的绘图,因此结合applet技术可以在B/S系统中直接尝试流程的可视化定义研究。

如何将上一小节的工作流定义转变成B/S结构下的OA系统可以具体运行的程序?首先在数据库中设计一组表单作为状态的模板,用一XML文档来保存流程图形的状态,所有XML 文档保存在一个数据库XML表中。上层接口通过读取并解释数据库中的XML文件来实现工作流程。来如何设计出有效的可视化流程设计工具是本文的重点。

2.2 java appletapplet绘图技术的介绍

2.2.1 applet的介绍

Applet是使用Java语言编写,可以在浏览器环境中运行的小应用程序。它与Application的区别主要在于其执行方式的不同。application 是从其中的main() 方法开始运行的,而Applet 是在浏览器中运行的。首先必须创建一个HTML 文件,通过编写HTML语言代码告诉浏览器载入何种Applet 以及如何运行。就因为applet能在浏览器里运行的这一特点,满足了B/S结构下的浏览器界面的需求,所以我们为选择了applet作为可视化OA工作流程设计工具的开发工具。

小应用程序的生命周期相对于Application而言较为复杂。在其生命周期中涉及到Applet类的四个方法(也被JApplet类继承):init()、start()、stop()和destroy()。

Applet的生命周期中有四个状态:初始态、运行态、停止态和消亡态。当程序执行完init()方法以后,Applet程序就进入了初始态;然后马上执行start()方法,Applet程序进入运行态;当Applet程序所在的浏览器图标化或者是转入其它页面时,该Applet程序马上执行stop()方法,Applet程序进入停止态;在停止态中,如果浏览器又重新装载该Applet程序所在的页面,或者是浏览器从图标中复原,则Applet程序马上调用start()方法,进入运行态;当然,在停止态时,如果浏览器关闭,则Applet程序调用destroy()方法,进入消亡态。

2.2.2 Applet的AWT绘制

Applet程序中所采用的AWT的绘图机制主要涉及三个方法:paint()方法、update()方法和repaint()方法,update()方法和paint()方法都有一个Graphics类参数。Graphics是画图的关键,它可以支持两种绘图:一种是基本的绘图,如:画线、矩形、圆等;另一种是画图象,主要用于动画制作。

要进行绘图,首先要找到一个Graphics类的对象。update()方法和paint()方法所传递的参数都是Graphics类的对象,因此主要是通过重载它们来进行绘图,这是在动画程序中经常使用的方法。我们还可以通过getGraphics()方法得到一个Graphics类的对象,这个对象和update()方法和paint()方法中所传递的对象一样,都是该成员所对应的Graphics类的对象。得到了Graphics类的对象,就可使用各种绘图方法。

Graphics中提供的图形绘制方法有:

paint( ) //进行绘图的具体操作,必须有程序员重写

update( ) //用于更新图形,先清除背景、前景,再调用paint()

repaint( ) /*用于重绘图形,在组件外形发生变化,即大小改变或位置移动时,repaint( )方法立即被系统自动调用,而实际上repaint()方法是自动调用update()方法*/

下面的方法支持基本的绘图和画图像:

void drawLine( ) //画直线,void drawArc( )  //画弧线,

void drawPolygon( ) //画多边形,void drawRect( ) //画矩形,

void drawRoundRect( ) //画带有圆角的矩形,

void fill3DRect( ) //画三维矩形,

void fillOval( ) //画椭圆,

这些方法都是来自于java.awt.Graphics类   

2.3系统环境与平台基础

OA可视化工作流设计工具在Java环境基础上,后台以Microsoft Office Access 2003为数据库平台,前台采用具有较强跨平台性的Java Applet开发。具体环境描述如下:Microsoft Windows Server 2003;Microsoft Office Access 2003;jdk1.5.0_09;Eclipse 3.1。

3 系统需求分析与总体设计

3.1系统需求分析

在最近几年的各级单位的信息化改造建设中,随着信息化基础设施建设的逐渐完备,各类应用系统开始受到各级单位的重视,开发重点主要侧重于人事信息数字化、文书信息化、公文流转、交互式审批等信息化可行性高的工作领域。 因此,改革传统办公模式,开展电子办公,使业务办公、公文流转和管理过程电子化、信息化,并通过统一办公规范,提高工作效率降低办公成本,实现办公自动化已势在必行。

而上述所介绍的公文流转的一个重要特征就是流程复杂,难以用标准的程序化语言解释,因而公文流转系统必须有与之相适应的工作流程定义系统,使操作人员能够自主地设定公文流转流程。为此我们设计了一个可视化流程设计工具,该工具可以作为工作流管理系统里的一个模块。它具有图形用户界面,用户定义与任务执行完全分离,其体系结构基本上符合WFMC 标准结构。用户不需要程序员的支持就可以定义和设计出工作流程模型,根据该模型生成的文件可以非常方便地被解释为上层接口所需的工作流。

3.2 系统功能介绍

可视化OA工作流程设计工具针对用户的要求对工作流程进行定制和维护,主要包括:对接点、接点连接线可自由拖放。具备删除节点、节点之间连接线功能。接点之间采用箭头连接。接点采用矩形表示。图形内容利用XML形式保存于的Access数据库中,可查询,编辑,保存,更多自定义属性。

通过对用户需求的分析,要求本流程设计工具具有以下功能:

(1)可视化的操作界面;

(2)可以对流程节点和弧线进行填加、修改、删除操作; 

(3)工作流程支持串签、会签和分支流程;

(4)可以将图形内容保存于access数据库或(xml)中,可查询,编辑,保存;

(5)可以通过流程模型解释接口和引擎主程序提供给上层程序使用

3.3 系统模块功能和设计思想

1994年11月,工作流管理联盟发布了工作流管理系统的参考模型,该模型定义了一个基本的工作流管理系统所需要的6个基本模块:过程定义工具,工作流执行服务,其他工作流执行服务,客户应用程序,被调应用程序,管理及监控工具;并制定了个模块之间的接口标准。

流程设计工具与其系统交互的简单模块关系图:

可视化流程设计工具各模块的功能描述和设计思想介绍:

(1)绘图模块:可将需要设计的流程用此模块画出,利用java.awt来绘制节点和弧线;

(2)图象关系序列化模块:可将已画出流程中的节点和弧线序列化,利用接口java.io.Serializable就能实现;

(3)图象关系保存模块:可将序列化后的节点和弧线关系保存起来供上层流程定义解释器使用。

3.4数据库设计

3.4.1 E-R图设计

实体关系图(E-R图)将系统中的数据模型以一种更加清楚、具体的方式展现出来。图中方框代表实体,椭圆代表实体的属性,实体和实体之间的关系用菱形来表示。

在工作流管理系统中,上层程序需要通过读取保存在数据库里流程的XML文件来实现流程的解释和实例化。在对工作流进行定义的工作中用到的E-R如下图所示:

 

3.4.2 表的构建

表1  流程节点表(flow_Node)

对象名称

数据类型

功能描述

Node_ID

数字

节点编号

Node_Nane

文本

节点名称

Node_prev

文本

节点前驱名称

Node_prevID

数字

前驱节点号

Node_next

文本

节点后继

Node_nextID

数字

后继节点号

Flow_ID

数字

节点所属的流程号

表2  流程表(flowdata)

对象名称

数据类型

功能描述

fileName

文本

保存流程的文件名

id

数字

流程号

type

文本

Node 类型还是 line 类型

3.4.3 数据库连接实现

public  Connection getConnection(){

                // now we can get the connection from the DriverManager

  Connection con = null;

  try {

    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 

    //驱动 set this to a MS Access DB you have on your machine

    String filename = "/fileData.mdb";

    String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=";

    database+= filename.trim() + ";DriverID=22;READONLY=true}";

    // add on to the end

    con = DriverManager.getConnection( "jdbc:odbc:ccos" ,"","");

    //数据源

     } catch (ClassNotFoundException e) {

      // TODO Auto-generated catch block

                e.printStackTrace();

     } catch (SQLException e) {

      // TODO Auto-generated catch block

                e.printStackTrace();

              }

       return con;

 }

4 系统功能模块实现

4.1系统流程及图示

一个流程的设计是先通过绘图来对实际业务过程进行分析、建模,然后通过一定的技术生成所建立流程模型的可被上层接口处理的形式化描述。其流程如下图:

 

4.2流程可视化设计实现

4.2.1界面可视化

这是工具开始运行出现的第一个界面,由Internet Explorer浏览器打开,可以适应B/S结构的OA系统。

 

界面的布局由BorderLayout来实现,分北部、西部、中部三部分。

包括:

北部 控制板(ArcControls);

西部 绘图工具板(ToolBlank);

中部 绘图画板 (ArcCanvas)。

具体代码实现如下:

  this.setLayout(borderLayout1);

  this.add(ArcControls,BorderLayout.NORTH);

  this.add(ArcCanvas,BorderLayout.CENTER);

  this.add(ToolBlank, BorderLayout.WEST);

4.2.2 绘图功能设计                                                                                                 

当设计一个流程时,用户点击绘图工作板中的绘制节点和绘制弧线两个按钮结合着选择环节名,将指定的可视化部件拖拉绘制在工作平台上,每一个可视化部件代表一个角色,用流向箭头将各个部件关联起来。还可以对节点和弧线进行修改和删除。

一个矩形节点的绘制,需要对它的各项属性进行定义,包括对它的起点坐标、矩形的宽和高、矩形的边框坐标。以下是节点定义的简单描述:

public class Node extends BaseObject{

  int LeftUpNodeX;//定义顶点坐标

  int LeftUpNodeY;

  private int starx;  //定义起始点,高,宽

  private int stary;

  private int Heigh;

  private int Width;

  private int MinX;  //定义边框

  private int MinY;

  private int MaxX;

  private int MaxY;

  Color color;  //定义外框颜色

  String NodeName="";//节点名称

}

绘制节点:

g.drawRect(this.starx,this.stary,this.Width,this.Height);//画矩形

g.drawString(this.NodeName,this.starx+this.Width/3,this.stary+Height/2);//画节点名

拖动节点:

public void SetNodeMoved(int x,int y){

  this.starx = x;

  this.stary = y;

  this.MinX = starx;

  this.MinY = stary;

  this.MaxX = starx + Width;

  this.MaxY = stary + Height;

  }

拖动节点时鼠标动态:

public void mouseDragged(MouseEvent e) { //鼠标拖动

  int x = e.getX();

  int y = e.getY();

  switch(status){

    case 1:

      if (this.NodeIFinit == true) {

        node = new Node(e.getX(), e.getY(),CurrentNodeName);

          this.NodeObject.add(node);

          this.IfDrag = true;

          this.NodeIFinit = false;

          repaint();

        }

       else {

         if (IfDrag == true) {

           if (node != null) {

            node.SetHeightAndWidth(x, y);

            repaint();

            }

          }

          else {

            if (SelectNodeDrag == true) {

              node.SetNodeMoved(x, y);

              node.DrawMyself(this.getGraphics());

              repaint();

            }

          }

        }

        break;

  }

}

节点与节点之间需要用弧线进行连接。一段弧线需要对它的起点坐标、终点坐标等属性进行定义。以下是弧线定义的简单描述:

弧线定义:

public class Arc {

  private int endx; //结束坐标

  private int endy;

  private int startx;//起点坐标

  private int starty;

  private int[] SelectedNode = new int[2];//选择节点

  private Vector Point;//点元素

  private Color color;

  private boolean ArcEnd;//判断弧段是否结束增加节点

  public Arc(int x,int y) {

    Point = new Vector();

    int[] star = new int[2];//点由2元素(x,y)组成

    star[0] = x;

    star[1] = y;

    this.startx = x;

    this.starty = y;

    this.Point.addElement(star);

    this.color = Color.BLACK;

    this.ArcEnd = false;

  }

绘制弧线:

public void DrawMyself(Graphics g){

    int length = Point.size();

    g.setColor(color);

    if (length > 0) {

      System.out.println("Arc node size:" + length);

      if (length == 1) { }

      else {

        for (int i = 0; i < length - 1; i++) {

          int[] Spoint = (int[]) Point.elementAt(i);

          int[] Epoint = (int[]) Point.elementAt(i + 1);

          g.drawLine(Spoint[0], Spoint[1], Epoint[0], Epoint[1]);

                }

弧线拖动:

public void mouseDragged(MouseEvent e) {  //鼠标拖动

    int x = e.getX();

    int y = e.getY();

    switch(status){

            case 3:

        if (SelectArcDrag == true) {

          if ( (arc != null) && (arcNodeindex != -1)) {

            arc.SetSelectedNode(arcNodeindex, x, y);

            repaint();

        }else if((arc != null)&&(arcNodeindex == -1)){//选中的是最后一个不再Vetor里面的点

            arc.SetSelectedNode(x, y);

            repaint();

          }

        }

        break;

    }

  }

画箭头:

int[] lastpoint = (int[]) Point.elementAt(length - 1);

 g.drawLine(lastpoint[0], lastpoint[1], this.endx, this.endy); //画箭头

 if((lastpoint[0] == endx)&&(lastpoint[1]<endy))//开口向下

   {

     g.drawLine(endx,endy,endx+3,endy-3);

     g.drawLine(endx,endy,endx-3,endy-3);

     }else if((lastpoint[0] == endx)&&(lastpoint[1]>endy)){ //开口向上

        g.drawLine(endx,endy,endx+3,endy+3);

        g.drawLine(endx,endy,endx-3,endy+3);

     }else if((lastpoint[1] == endy)&&(lastpoint[0]>endx)){//开口向左

        g.drawLine(endx,endy,endx+3,endy-3);

        g.drawLine(endx,endy,endx+3,endy+3);

     }else if((lastpoint[1] == endy)&&(lastpoint[0]<endx)){//开口向右

        g.drawLine(endx,endy,endx-3,endy-3);

        g.drawLine(endx,endy,endx-3,endy+3);

     }else{//任意方向用点代替

        g.fillOval(endx-2,endy-2,5,5);

     }

     if ( (SelectedNode[0] != 0) && (SelectedNode[1] != 0)) {

        g.setColor(Color.BLUE);

        g.fillOval(SelectedNode[0]-2,SelectedNode[1]-2,5,5);

      }

删除节点:

public void DeleteSelectedNode() {

  if (haveSelectedNode == true) {

    this.NodeObject.removeElementAt(nodeindex);

    this.haveSelectedNode = false;

    repaint();

    }

  }

删除弧线 :

public void DeleteSelectedArc() {

  if (haveSelectedArc == true) {

    this.ArcObject.removeElementAt(arcindex);

    this.haveSelectedArc = false;

    repaint();

    }

  }

下图为一设计好了的流程图:

 

4.2.3 流程图保存和读取方法设计

将序列化后的节点与弧线的对象保存为xml文件,易于保存和重绘。

序列化是将对象写到流中,序列化需要对象实现Serializable接口,序列化后能将对象转换成一系列字节,并可在以后完全复原。序列化可以实现“有限持久化”。

在保存前先要对已经绘出的节点以及弧线进行属性采集,我们用一个NodeBean以及ArcBean方法来实现其功能,NodeBean的代码描述如下:

public class NodeBean implements java.io.Serializable{}

public NodeBean(){

  }

  String LeftUpNodeX; //定义顶点坐标

  String LeftUpNodeY;

  private String MinX;//定义边框

  private String MinY;

  private String MaxX;

  private String MaxY;

Color color; //定义外框颜色

String NodeName="";//节点名称

public String getNodeName() {

  return NodeName;

}

public void setNodeName(String nodeName) {

  NodeName = nodeName;

}

public Color getColor() {

  return color;

}

public void setColor(Color color) {

  this.color = color;

}

public String getLeftUpNodeX() {

  return LeftUpNodeX;

}

public void setLeftUpNodeX(String leftUpNodeX) {

  LeftUpNodeX = leftUpNodeX;

}

public String getLeftUpNodeY() {

  return LeftUpNodeY;

}

public void setLeftUpNodeY(String leftUpNodeY) {

  LeftUpNodeY = leftUpNodeY;

}

public String getMaxX() {

  return MaxX;

}

public void setMaxX(String maxX) {

  MaxX = maxX;

}

public String getMaxY() {

  return MaxY;

}

public void setMaxY(String maxY) {

  MaxY = maxY;

}

public String getMinX() {

  return MinX;

}

public void setMinX(String minX) {

  MinX = minX;

}

public String getMinY() {

  return MinY;

}

public void setMinY(String minY) {

  MinY = minY;

}

将流程图中节点的属性对象进行采集以后,通过调用

ObjectToXMLUtil.objectXmlEncoder方法可以对节点和弧段进行保存,以下代码是对节点的保存,描述如下:

Vector v = new Vector();

Vector temp = this.canvas.getNodeObject();

for(int i=0;i<temp.size();i++){//通过NODEBEAN存储

       Node o = (Node)temp.elementAt(i);

       NodeBean bean = new NodeBean();

       bean.setNodeName(o.NodeName);

       bean.setLeftUpNodeX(o.getLeftUpNodeX()+"");

       bean.setLeftUpNodeY(o.getLeftUpNodeY()+"");

       bean.setMaxX(o.GetMaxX()+"");

       bean.setMaxY(o.GetMaxY()+"");

       bean.setMinX(o.GetMinX()+"");

       bean.setMinY(o.GetMinY()+"");

       v.add(bean); 

       }

String nodeFile = "nodeData"+System.currentTimeMillis()+".xml";

ObjectToXMLUtil.objectXmlEncoder( v ,nodeFile );

对弧线的属性采集类ArcBean相关的代码描述如下:

public class ArcBean implements java.io.Serializable{}

  private String endx;

         private String endy;

         private String startx;

         private String starty;

         public ArcBean(){//返回值

         }

       public String getEndx() {

              return endx;

       }

       public void setEndx(String endx) {

              this.endx = endx;

       }

       public String getEndy() {

              return endy;

       }

       public void setEndy(String endy) {

              this.endy = endy;

       }

       public String getStartx() {

              return startx;

       }

       public void setStartx(String startx) {

              this.startx = startx;

       }

       public String getStarty() {

              return starty;

       }

       public void setStarty(String starty) {

              this.starty = starty;

    }

将流程图中弧线的属性对象进行采集以后,通过调用

ObjectToXMLUtil.objectXmlEncoder方法可以对节点和弧段进行保存,以下代码是对节点的保存,描述如下:

Vector line = new Vector();

Vector lineTemp = this.canvas.getArcObject();

     for(int i=0;i<lineTemp.size();i++){

     Arc o = (Arc)lineTemp.elementAt(i);

     ArcBean bean = new ArcBean();

     bean.setStartx(o.getStartx()+"");

     bean.setStarty(o.getStarty()+"");

     bean.setEndx(o.getEndx()+"");

     bean.setEndy(o.getEndy()+"");

     line.add(bean); 

     }

String lineFile = "lineData"+System.currentTimeMillis()+".xml";

ObjectToXMLUtil.objectXmlEncoder(line , lineFile);

流程图的读取,也就是将保存的xml文件中的节点以及弧线的属性读取出来,然后调用各个的显示方法,重新绘制在屏幕上。

对节点的读取:

String fileName = oper.getFile("node");

ArrayList list = null;

if(null != fileName && !fileName.equals("")){

  ist = (ArrayList)ObjectToXMLUtil.objectXmlDecoder(fileName);

  }else{

  list=(ArrayList)ObjectToXMLUtil.objectXmlDecoder("nodeData.xml");                      }

  if(list != null && list.size()>0){

    Vector v = new Vector();

        for(int i= 0;i<list.size();i++){

          v = (Vector)list.get(i);

          }

  Vector nodeVector = new Vector();

  for(int j = 0;j<v.size();j++){

    NodeBean bean = (NodeBean)v.elementAt(j);

    Node node = new Node(Integer.parseInt(bean.getLeftUpNodeX()),

    Integer.parseInt(bean.getLeftUpNodeY()),bean.getNodeName());

       node.setMaxX(Integer.parseInt(bean.getMaxX()));

    node.setMaxY(Integer.parseInt(bean.getMaxY()));

    node.setMinX(Integer.parseInt(bean.getMinX()));

    node.setMinY(Integer.parseInt(bean.getMinY()));

    node.SetHeightAndWidth(node.GetMaxX(), node.GetMaxY());

    node.getLeftUpNodeY());

    nodeVector.add(node);

       }

        this.canvas.setNodeObject(nodeVector);

  }

对弧线的读取:

String fileLineName = oper.getFile("line");

ArrayList listLine = null;

if(null != fileLineName && !fileLineName.equals("")){

  System.out.println("line:" + fileLineName);

  listLine = (ArrayList)ObjectToXMLUtil.objectXmlDecoder(fileLineName);

}else{

  listLine = (ArrayList)ObjectToXMLUtil.objectXmlDecoder("lineData.xml");

  }

  System.out.println("lisrlineL" + listLine);

  if(listLine != null && listLine.size()>0){

    Vector lineVector = new Vector();

    for(int i= 0;i<listLine.size();i++)

      lineVector = (Vector)listLine.get(i);

      Vector line = new Vector();

      for(int j = 0;j<lineVector.size();j++){

      ArcBean bean = (ArcBean)lineVector.elementAt(j);

Arcnode=new

 Arc(Integer.parseInt(bean.getStartx()),Integer.parseInt(bean.getStarty()));

                 node.setEndx(Integer.parseInt(bean.getEndx()));

                 node.setEndy(Integer.parseInt(bean.getEndy()));

                 node.AddPoint(new int[]{node.getEndx(),node.getEndy()});

                 node.SetArcEnd();

                 line.add(node);

              }

              this.canvas.setArcObject(line);

  }

4.2.4 节点间关系保存的实现

要设计一个流程,必须用一个算法将流程各个节点与节点之间的关系表示出来。我们采用矩形来表示节点实例,用带箭头的弧线表示节点实例间的前驱后继关系,如果节点实例A是节点实例B的前驱,则有一条由A出发到B结束的箭头。这样就必须保证任意两条连接线都不重叠。

节点和弧线的关系通过运算之后生成一份xml文档,同时把这份xml文档序列化后保存在数据库中。通过解析这样的xml文档,上层应用程序能了解节点之间的先后关系,并应用到上层程序逻辑。下面是图6中流程所保存的节点xml文件,其中包括对节点位置的信息,也包括对节点间关系的信息。

public class Node extends BaseObject

{

     public node()

     {

       public string Node_Name;// 节点名

       public int Node_ID;//节点号

       public string Node_next;// 节点后继节点

       public int Node_nextID;// 后继节点号

       public string Node_prev;// 节点前驱节点名

       public int Node_prevID;// 前驱节点号

      }

}

在XML中保存的节点信息:

<java version="1.5.0_09" class="java.beans.XMLDecoder">

-<object class="java.util.Vector">

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>225</string></void>

- <void property="leftUpNodeY"><string>20</string></void>

- <void property="maxX"><string>320</string></void>

- <void property="maxY"><string>59</string></void>

- <void property="minX"><string>225</string></void>

- <void property="minY"><string>20</string></void>

- <void property="nodeName"><string>开始</string></void>

- <void property=" Node_ID "><string>1</string></void>

-<void property="Node_next"><string>拟稿</string></void>

-<void property=" Node_nextID "><string>2</string></void>

-<void property="Node_prev"><string>0</string></void>

-<void property=" Node_prevID "><string>0</string></void>

</object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>224</string></void>

- <void property="leftUpNodeY"><string>93</string></void>

- <void property="maxX"><string>321</string></void>

- <void property="maxY"><string>135</string></void>

- <void property="minX"><string>224</string></void>

- <void property="minY"><string>93</string></void>

- <void property="nodeName"><string>拟稿</string></void>

-<void property=" Node_prevID "><string>2</string></void>

-<void property="Node_next"><string>处室审核</string></void>

-<void property=" Node_nextID "><string>3</string></void>

-<void property="Node_next"><string>处室审核</string></void>

-<void property=" Node_nextID "><string>4</string></void>

-<void property="Node_prev"><string>开始</string></void>

-<void property=" Node_prevID "><string>1</string></void>

</object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>127</string></void>

- <void property="leftUpNodeY"><string>178</string></void>

- <void property="maxX"><string>242</string></void>

- <void property="maxY"><string>224</string></void>

- <void property="minX"><string>137</string></void>

- <void property="minY"><string>174</string></void>

- <void property="nodeName"><string>处室审核</string>

- <void property=" Node_ID "><string>3</string></void>

-<void property="Node_next"><string>主任审核</string></void>

-<void property=" Node_nextID "><string>5</string></void>

-<void property="Node_prev"><string>拟稿</string></void>

-<void property=" Node_prevID "><string>2</string></void>

  </object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>296</string></void>

- <void property="leftUpNodeY"><string>180</string></void>

-<void property="maxX"><string>412</string></void>

-<void property="maxY"><string>229</string></void>

- <void property="minX"><string>285</string></void>

- <void property="minY"><string>173</string></void>

- <void property="nodeName"><string>处室审核</string>

- <void property=" Node_ID "><string>4</string></void>

-<void property="Node_next"><string>主任审核</string></void>

-<void property=" Node_nextID "><string>5</string></void>

-<void property="Node_prev"><string>拟稿</string></void>

-<void property=" Node_prevID "><string>2</string></void>

  </object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>218</string></void>

- <void property="leftUpNodeY"><string>262</string></void>

-<void property="maxX"><string>316</string></void>

- <void property="maxY"><string>317</string></void>

- <void property="minX"><string>218</string></void>

- <void property="minY"><string>262</string></void>

- <void property="nodeName"><string>主任审核</string>

- <void property=" Node_ID "><string>5</string></void>

-<void property="Node_next"><string>局长审核</string></void>

-<void property=" Node_nextID "><string>6</string></void>

-<void property="Node_prev"><string>处室审核</string></void>

-<void property=" Node_prevID "><string>3</string></void>

-<void property="Node_prev"><string>处室审核</string></void>

-<void property=" Node_prevID "><string>4</string></void>

  </object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>214</string></void>

- <void property="leftUpNodeY"><string>362</string></void>

- <void property="maxX"><string>321</string></void>

-<void property="maxY"><string>414</string></void>

- <void property="minX"><string>214</string></void>

- <void property="minY"><string>362</string></void>

- <void property="nodeName"><string>局长审核</string>

- <void property=" Node_ID "><string>6</string></void>

-<void property="Node_next"><string>签发</string></void>

-<void property=" Node_nextID "><string>7</string></void>

-<void property="Node_prev"><string>主任审核</string></void>

-<void property=" Node_prevID "><string>5</string></void>

  </object></void>

- <void method="add">

- <object class="applettest.NodeBean">

- <void property="leftUpNodeX"><string>212</string></void>

-<void property="leftUpNodeY"><string>450</string></void>

- <void property="maxX"><string>325</string></void>

- <void property="maxY"><string>496</string></void>

- <void property="minX"><string>212</string></void>

- <void property="minY"><string>450</string></void>

- <void property="nodeName"><string>签发</string>

- <void property=" Node_ID "><string>7</string></void>

-<void property="Node_next"><string>null</string></void>

-<void property=" Node_nextID "><string>255</string></void>

-<void property="Node_prev"><string>局长审核</string></void>

-<void property=" Node_prevID "><string>6</string></void>

  </object></java>

5 系统测试结果及存在的问题和改进的方案

测试结果:

由于本工具的开发使用了Eclipse 3.1作为开发工具,具有可视化的编程环境,在编程的过程中就可以对所做的结果进行运行,以立即进行改正。经过反复的修改调试后最终测试,该工具工作运行正常,能够准确地实现需求分析里的功能。但有点遗憾是因为没有上层的oa办公流程解释器、办公流程引擎等等程序,未能真正的实现一次办公自动化的整个流程。

存在问题和改进方案:

该可视化流程设计工具是一个实验性的程序,在有些功能的编写上不是非常合理。例如:

1 在选择节点的功能实现上做的不够好,它需要先点一下绘图板上的选择节点键再绘图板上的节点才能将它选中,而不是直接在绘图板上点击节点选种对象,这样直接造成工作效率降低。选择弧线也是同样情况;

2 弧线不能拖动;

3 在保存节点关系的时候不能按自己意愿输入保存xml文件名而是由机器按时间生成xml文件名;

4 在读取节点关系的时候只能够读取最近一次保存的节点关系。

5 因为是实验性的程序,在本论文中所描述的流程设计工具在开发中直接使用了实例模型,而不能对节点自定义属性;

这些不足也是以后将此工具逐步完善的动力和信心的来源。