基于文件数据处理的工作流管理系统的设计与实现
2021-11-20徐海啸董飒魏枫林于美铭张岩
徐海啸 董飒 魏枫林 于美铭 张岩
(1.吉林大学计算机科学与技术学院 吉林省长春市 130012 2.吉林大学公共计算机教学与研究中心 吉林省长春市 130012)
1 绪论
在计算机技术的应用中工作流技术可以称的上是一个重要的方面,同时在并行活动执行过程中也是一项非常重要的技术,在本文小结我们主要介绍了工作流管理技术的研究现状以及发展历史,并且全面的阐述了工作流理论的一些相关概念、技术成果和研究内容,
目前,在国内工作流技术的研究已经开展多年,有很多的技术人士已经从事了原型系统的开发,并且很多实验室已经研制出来先进的原型系统,研究人员从工作流系统的可行性、实用性、事务、安全、模型、架构等多方面考虑,不断地提高系统的使用价值,而且大量的学术论文被撰写出来共研发人员参考。21 世纪以后,随着信息产业的兴起,和工作流技术相关的标准化组织也逐渐的成立,多个组织也都相继的提出了各自的工作流技术的标准化规则,比较权威的规范有WSFL 和XLANG 等。
设计和实现基于数据文件处理的工作流管理系统。构建系统的总体结构,实现系统的三个组成部分:流程定义、流程控制、流程管理。建立流程定义方法、用户与系统进行交互的界面等;实现流程控制的数据结构、方法以及一些算法;实现流程管理中的界面、关键功能。解决工作流管理的问题,实现工作流间各个模块的信息交互,协同工作;实现对工作流任务状态进行跟踪与监控,达到工作流模块间的协调运行。
1993年工作流管理联盟(Workflow Management Coalition,WfMC)作为工作流管理的标准化组织而成立,标志着工作流技术逐步走向成熟。WfMC 对工作流给出定义为:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行[1][2][3]。
WfMS 定义的工作流管理系统为,工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境[4]。工作流管理系统(Workflow Management System,WFMS)是定义、创建、执行工作流的系统。
2 需求分析
任何的系统在设计和实施之前都要进行需求的分析,正因为有着相应的需求所以人们才会来开发相应的产品。在软件工程中,需求分析指的是在建立一个新的或改变一个现存的电脑系统时描写新系统的目的、范围、定义和功能时所要做的所有的工作。需求分析是软件工程中的一个关键过程。在这个过程中,系统分析员和软件工程师确定顾客的需要。只有在确定了这些需要后,他们才能够分析和寻求新系统的解决方法。需求分析阶段的任务是确定软件系统功能,接下来我将要详细的叙述本系统所要实现的功能。如下:
本系统主要的功能是基于工作流的操作是对文件的处理上,日常生活和工作中,都要处理大量的文件数据,并且对文件数据进行整理、收集、统计等等一系列工作,那么本系统就从日常出发,从用户的使用情况考虑,提供了以下几大文本处理功能:
删除功能:在正常的Window下,删除文件是一件很简单的事情,并不繁琐,但是Window 并没有提供多样的删除功能,比如:删除指定行,删除含有特定标示的字段或者行数等等。这些扩展的工作都需要用户自己手动的去操作,手动定位到指定行,手动搜索特俗字段等等。操作起来可想而知十分不方便。基于以上观点,本系统提供了多样式的删除功能(行数,字段)等,只需要把要操作的文件拖拽到软件指定位置,然后在系统中填写上相应的参数,就可以按照自己的意愿对文本进行多样式的删除操作,增强了用户的体验也方便了用户的操作。
合并功能:在平时的工作处理中,或多或少的我们会涉及到多个文本文件的合并操作,那么Window 自身是不提供多文本合并功能的,两个文本文件的合并可能相对来将不算复杂,复制两个文本到指定目录下面即可,但是如果一旦操作的文件数目多起来,对用户来讲一定会是一件乏味枯燥的事情,而且数目多的时候,也会降低操作的正确性,提高误差。因此本系统需要提供多文本文件的合并操作,用程序去实现合并功能,操作简单,而且可靠性也得到了提升,用户只需要把合并的多个文件拖拽到指定位置,然后设定一个文件作为合并后的目录,执行操作。简单操作、快速准确。
内容替换:任何一个编辑器都会提供这个功能,操作系统自带的文本编辑器也提供了内容替换功能,相对其它的文本编辑器来讲可能功能简单些不支持正则表达式。本系统中也只是提供了简单的操作,我们并不是把内容替换作为重要的讨论范围,因为简单的文本替换就可以满足用户的要求。之所以把这个功能考虑在系统中,是为了工作流操作。在这里不做太多的介绍和深入的研究。
文本比较:这是个非常常用的功能,尤其在项目开发、版本升级的过程中,至关重要。有的时候我们会对比一下代码的改动点,看看自己的代码和之前有什么不同,如果用肉眼去观察对比,那将是一件令你痛心的事情,甚至眼花缭乱也看不出什么名堂来。所以有了文本比较功能这个工作就变得简单了。目前市场上最好的文本比较产品是Compare 软件,这个软件的功能十分强大,比较的结果更是一目了然大快人心。在本系统中实现的功能无法和compare 相提并论,自愧不如。我的文本比较功能只能以行为单位进行比较,比较的结果也会输出到result 文件中。至于结果文件的显示格式我们在下面的章节中会详细的介绍。
内容统计:操作系统现有的文本编辑器并没有提供内容统计相关的功能,不像word office 这些商用的软件集成了这个功能。有的时候我们需要知道整个文本的行数、字符数、不同字段出现的频数等等。如果手工的操作起来,尤其字符数那将是一个很繁琐的工作。因此在本系统中我们开发了多功能的内容统计功能,包括文本的行数、文本的总字数、相应的字符出现的频数。在需求分析中,我们的设计思想都是采用拖拽的方式来获取操作的文件,然后在文本域中输入执行参数。执行操作。
重命名:重命名操作系统中已经提供,但是由于鼠标键盘操作比较繁琐,所以我们把这个功能设计到里面来,能够方便用户进行批处理的更名操作,同时也是为了增加工作流的定义形式,打造多种文件操作方式。
行排序:行排序操作是Window 系统无法提供的,甚至一般的文本编辑器也都不提供此项功能,而且行排序在特定的情况是会被频繁使用的,因此有必要将此功能设计在内,作为需求分析的一部分。但是我们开发的比较简单,系统只能提供按行排序,用户可以选择是按照升序还是降序操作,至于更加多样的排序操作还有待开发。在此不做过多的说明。
工作流操作:这个是本系统的重点,也是实现的难点所在。在工作流模式下面我们可以指定上述操作的执行顺序,也就是顺序执行,前一个操作的输出可以作为后一个操作的输入,以用户的意向为主导,自己定义工作流,对系统提供的功能任意组合,来达到用户所要完成的工作。而且我们还会给用户提供一个意见窗口,来不断地完善系统的基本功能。工作流模式是系统的灵魂,上面所讲述的基本操作都是为工作流模式做铺垫,所以本系统主要任务就是实现工作流模式的管理和定义。
3 系统的设计和实现
3.1 界面的设计和实现
利用WindowBuilder 插件来完成本次毕设的界面设计,开发者可以把主要的精力投入到系统内部的实现上面,而不用过多的去关心怎么设计和实现界面,同时也免去了重复式的硬编码过程,给开发者带来便捷。下面我会把界面设计的过程详细的呈现给大家。
功能区:首先在WindowBuilder 工程中新建了一个JFrame 类,取名为OperatorUI.java,本系统的主要界面就是在这个类中实现的,包含了所有的操作。界面的风格很简洁有层次性,页面的左侧是一系列的操作按钮,包含了上面介绍的几大基本操作,主要是一系列的Jbutton 组件,并且每一个JButton 组件都添加了事件监听器。WindowBuilder 插件真是一个功能强大的界面设计软件,如果采用硬编码的形式下,我们对组件添加事件监听器要一步一步的手工编写匿名内部类,但是,现在只需要一步就可以完成,我们只需要双击JButton 按钮,系统就会自动的生成相应代码,并且,鼠标也会跳转到代码区,我们只需要在鼠标跳转处写上事件的处理逻辑即可,非常的便捷。由于WindowBuilder 的设计中组件都是拖拽的方式,因此本系统中的所有JPane 都是采用绝对布局管理器,组件拖放的位置就是程序执行时的位置。这只是页面左侧的几个功能按钮介绍,并且按钮已经添加了事件处理。我们把这个区域的设计取名为功能区。
操作区:在介绍操作区之前有必要先了解一下CardLayout布局,卡片布局能够让多个组件共享同一个显示空间,共享空间的组件之间的关系就像一叠牌,组件叠在一起,初始时显示该空间中第一个添加的组件,通过CardLayout 类提供的方法可以切换该空间中显示的组件。
操作区,是用户在功能区选定一个功能按钮之后进行操作的页面,由于每个功能的操作不一样,输入的参数、输出的格式也大相径庭,无法用一个页面来实现,所以一个主要的问题就是不同的功能之间涉及到页面的切换。故而,操作区的设计采用CardLayout布局管理器。其主要的思想是,新建一个JPane 坐为最底层的面板,这个面板采用卡片布局管理器,承接多个操作的页面,在本系统中基于底层面板我们新建了6 个JPane,其中有一个负责页面的初始化,显示基本的提示信息,剩余的5 个JPane 则是真正的操作区,每一个面板都对应着左侧的一个功能按钮,面板中有相应的输入参数,和相应的输出结果。唯一的共同点就是,每个面板都有一个执行按钮,没有把执行操作抽离出来,是为了提高程序的耦合度。在上一小节中介绍了功能区按钮的事件处理,其主要的工作就是在点击按钮的时候,实现相应页面之间的切换,切换的操作也很简单,得益于WindowBuilder,当添加不同的面板到卡片布局管理器中的时候,系统会自动的给这个面板分配一个ID 号,并且这个号码是编写在代码中的,在程序执行的时候如果想跳转到相应的页面,只需要利用卡片布局管理器提供的show(ID)方法就可以完成,可想而知,功能区按钮的事件处理逻辑就是提供一个显示方法,在此不做过多的阐述。
卡片布局管理器的优势在于页面之间的便捷切换,最初的设计是采用简单的JFrame 来实现,但是程序开发到一半发现很难实现,而且程序的性能很低,每一个页面都用一个窗口组件来隐藏、显示,给用户带来的体验也是相当的差,而且对于开发者来讲代码工作量也是相当的大,而卡片布局管理器完美的解决了这个问题。
工作流模式区:这个区域的功能是程序的灵魂所在,也是本次毕设的主旨,但是从其界面设计上来讲,界面非常简洁,整个工作流模式区只有三个按钮,一个工作流模式按钮,一个退出工作流模式按钮,一个执行工作流模式。并且每一个按钮都添加了事件监听器,至于内部的实现逻辑和相应的操作,我们将会在下面的章节功能的设计和实现中进行介绍。这里只做简单叙述,工作流模式按钮主要的任务是区别于功能区的基本操作,以工作流的形式执行程序。退出工作流模式,回复到基本操作模式,本系统涉及到的两个模式的操作类型就是通过这两个按钮来进行切换的。执行工作流模式,程序执行定义好的工作流。其实从三个按钮的名字上面就可以看出来每个按钮的功能。在区域的右侧中心位置,有一个文本显示组件(JTextField)用来显示工作流的具体操作内容,只是简单的显示出功能顺序,并不能显示出相应的输入和输出。所以这个区域的界面也就不用花费太多的文章来介绍。
工作流区域最初的设计是采取拖拽组件的方式来定义工作流,但是由于每个功能的输入参数不好控制,如果在同一个区域内给每个功能都提供一个入参的接口,那么最终构思出来的界面十分混乱,极其的不美观,所以只好放弃这个设计方案。采用了操作简单、可控制的顺序点击方案,这个方案虽然不像刚刚提到的拖拽方式时尚,但是无论从开发者还是用户的角度来讲,都是一件大快人心的事情。便捷开发,方便用户操作,提高用户体验。
3.2 功能的设计和实现
在上面的小结中我们介绍了界面的设计和实现,那么界面的下一层设计就是功能了,美观的界面是呈现给用户的,换句话说,界面只不过是程序和人的一个交互界面,没有实质性的作用,而对于开发者来讲,程序才是软件的灵魂,我们看待界面只不过是一个面具罢了,我们提供给用户一个接口来和内部进行交流沟通,这才是开发者眼中的界面。程序的开发目的就是实现其应该具备的功能,美观的界面加上高质量的代码才可称的上是一个成功的软件设计,所以本小结中我们将会重点介绍功能的设计和实现,和上一小节中的界面设计相吻合,到达界面功能一体化。
在需求分析的章节中我们对系统的基本功能需求进行了整理和采集,最终为程序设定了以下七大功能,既文件删除、文件合并、内容替换、文本比较、内容统计、重命名、行排序。在本小结中我们将一一讲解每个功能的实现方式。
文件删除:首先我们利用JTextFilder 组件的事件监听器,来获得输入的文件参数,这样我们就知道了要删除的文件路径,然后利用Window 的命令行形式来删除文件,考虑到性能的方面,我们采用了Close的方式,既程序执行完之后,操作系统自动关闭cmd后台。并且把这个方法解耦到单独的类中,方便日后的维护和版本的升级。
文件合并:同理,我们采用同样的技术获得输入的文本参数。操作的文本是一个字符串,保存在一个字符数组中,这个数组目前的限定是3 个空间,也就是我们同时最多可以合并3 个文件,这个空间的大小是可以随时改变的,而且不用修改其他任何地方,在调用和赋值的地方我使用一个size 的变量来控制,方便以后的空间扩展。考虑到性能方面,在合并的操作中我没有采用简单的java 输入输出流,而是用到了FileChannel(文件通道),Java NIO 中的FileChannel 是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel 无法设置为非阻塞模式,它总是运行在阻塞模式下。所以利用FileChannel 来合并文件不但快速而且还可以多线程工作,合并文件的本质就是,把多个文件一一复制到指定文件中。代码的实现逻辑也是同样的道理,逐个字符的读取然后写入到合并结果文件中,直到所有的文件都读取完毕,代码在此就不明示了。
内容替换:同样方式,同一个字符串数组变量来保存获得的文件参数,而且还需要额外的两个字符串变量,一个是要替换的文本,另一个保存替换后的文本,这两个参数都是通过JTextFild 组件提供的getText()方法获得的,所需的输入参数都已经获取到。接下来分析实现机制,本功能中我们采用的是FileReader 类,通过这个对象的read()方法,可以将文件中的所有内容都读取出来,然后保存在一个字符串中。在java 提供的API 中有很多对字符串的操作,利用其replace()函数,就可以实现字符串的替换,最后在将替换后的字符串重新写入文件中去,完成字符串替换操作。本功能的主要思想就是把文本内容转为字符串,通过对字符串的操作来实现替换功能。
文本比较:比较功能是提供的基本操作里面最有价值的。实现的过程中采用了BufferedWriter 对象,因为本系统的文本比较功能比较简易,只是提供了以行为单位的文本比较,BufferedWriter 对象恰恰提供了按行读取的方法。所以按行读取两个比较文本,然后进行字符串对比,循环遍历整个文本内容,相等的行我们会在结果输出文件中打印Equal:+行数的字样,不相等的行,我们会输出different 字样。比较结果一目了然,可以清楚的看出改动的行数。
内容统计:实际上这个操作包含着三个小的功能:第一,文本行数统计采用LineNumberReader 对象,这个对象的优势在于可以获取到当前IO 流所在文本行数,遍历IO 流直到文本末尾,然后利用所提供的getLineNumber()函数获得行数,最后把这个值返回到调用出。第二,字符数统计仍然采用缓存流来读取文件,将整个的文本内容转换为一个字符串,返回length()函数的值。第三,指定字符出现的频数也是将文本内容先转换为字符串,然后利用API 提供的indexof()函数,这里有必要讲解一下函数的作用,indexOf 方法返回一个整数值,指出 String 对象内子字符串的开始位置。即indexOf()括号内所包含的字符在该字符串内的循序位置,在第几位就返回几,如果有重复的字符出现,以第一个字符为准。如果没有找到子字符串,则返回 -1。 因此从首位开始循环调用直到返回-1 为止,然后用一个计数器记录出现的次数,这样我们就能计算出字符的频数了,最终返回给调用处。在这里介绍一下结果的显示方式,这三个结果都是直接显示在界面中的,并没有进行缓存处理,利用JTextFild 组件的setText()方法直接呈现给用户。
重命名:这个功能的内部实现相对比较简单,首先我们获取到操作的文件参数表,然后给用户提供一个JTestFild 组件用于输入文件名参数,在调用处我们直接getText()来获取并没有对其进行缓存。我们是利用File 对象提供的renameTo()方法来实现重命名操作的,函数的具体使用规则,详见java API。由于这个操作实现十分的简单,因此我们并没有把其抽离到单独的对象中,直接放在了主类里面即可。
行排序:这个功能里面我们用到了LineNumberReader 对象,因为我们要实现的是按照行来排序那么就要获取整行的内容,所以这个对象是最好的选择,我们循环的调用readLine 函数,目的就是把每一行的内容都存储到List 数组中,然后对list 数组进行排序,这里简单的讲解一下List 数组按照指定升降排序的方法。Comparator 是个接口,可重写compare()及equals()这两个方法,用于比价功能;如果是null 的话,就是使用元素的默认顺序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f,g 这样,当然数字也是这样的。我们就是用这个接口实现的排序功能,默认的sort()函数是按照字典序升序排列的,我们可以重载Collections.sort(list, new PriceComparator())函数来实现降序排列,第二个参数返回一个int型的值,就相当于一个标志,告诉sort 方法按什么顺序来对list 进行排序。对list 排序之后我们在重新的把内容输入到文件中,这样,行排序工作就完成了。
接下来是流程的定义,这里才是程序的重中之重,真正涉及到了工作流的概念,可以说前面的章节都是在为本小结做铺垫,这部分的前期设计是想采用拖拽的方式来给用户提供操作的,但是考虑到和内部的连通,比较繁琐,而且用户的参数不好输入等等,最后放弃了这种的设计概念。工作流的功能设计和实现我们打算按照按钮的层次来介绍,在界面的设计和实现中简单的介绍了三个按钮的主要功能,那么接下来我们详细的说明这些功能是怎么实现的。三大按钮既:工作流模式、退出工作流模式、执行工作流。
工作流模式按钮:我们申明了一个全局布尔变量(isWorkFlow),这是普通模式和工作流模式的一个标志位,当点击次按钮的时候,事件触发器会把这个变量设置为true,再true 的情况下,我们获取的处理文件参数和普通模式下的参数的保存方式是不一样的,两种模式下采用了不同的存储方式,普通模式用统一的变量来存储,因为他不需要对获取的参数进行缓存,但是工作流模式下面我们是需要不留不同操作的参数的,然后定义好工作流之后再执行,因此我们设置了一个标志位来区别不同模式下的存储方式。此外,我们还申明了一个工作流尺寸的数组变量,这个int 数组变量的功能主要是记录工作流的顺序,数组的大小等于提供的基本操作数量,并且初始化都是0。当点击按钮之后,我们会按照参照步骤去任意点击上述基本操作,每个操作的内部都设定了一个int 值来标示,所以在点击之后我们就会把数组按照点击顺序赋值成内部的操作ID,这样我们就把定义的工作流记录下来。
退出工作流模式按钮:这个按钮的操作十分简单,和工作流模式按钮的操作相反,把isWorkFlow 标志位设置为false,回退到普通模式,这样以后的所有操作都是普通模式下的处理方式,并且恢复所有工作流模式下的变量值,保证下次进入工作流模式的时候,所有的变量都是初始值,减少错误的发生。
执行工作流按钮:这个按钮的事件处理,主要是通过switch 语句来实现的,在工作流模式按钮中介绍了一个数组,这个数组就是定义的工作流执行操作,在这里我们通过case 语句,遍历数组,把操作id 指定为case 的取值,然后就可以依据数组中的值进行不同的操作了,并且数组的值是按照执行顺序赋值的,所以遍历之后,我们就把定义的工作流执行了一遍。这里有必要说一句关于代码的耦合度,在需求分析里面我们提及到,所有的操作都是封装在单独的类里面的,在调用出只需要直接调用对象的方法就可以,几乎都是static 的对象。同理,case 语句我们的处理只是调用了不同的对象方法。这样代码的逻辑很高,并且易于管理和维护。此外,在事件监听器方法的开始我们用一个字数串变量来记录工作流,在case中对字符串进行叠加,然后将字符串输出在界面中,来提示用户此工作流的工作。
4 结论
本文主要是按照开发的顺序来讲解软件的开发流程,开始我们介绍了软件的开发环境和所用到的技术,包括开发语言、使用的插件等等。
用WindowBuilder 插件实现简洁的UI 界面以便和用户进行交互,省去了枯燥繁琐的硬编码过程。然后我们对系统的基本需求分析也做了简单的描述,概况了要实现的基本功能。最后,对系统的设计和实现进行了细致的阐述,从上层的界面设计到底层的内部实现,每一个组件,每一个实现细节都做了精心的描述。本文层次清晰,由里到外,对系统进行了全面的剖析。不但给用户提供了明确的操作方法,也让相关的技术人士能够清晰的知道内部的实现逻辑,对系统的运行有清楚的理解。