在企业中,大部分重要的业务需要进行审批,由于具有决定权的领导者事务繁忙或者受环境或低于限制,没法通过互联网进行工作处理。
移动审批,通过手机方便快捷地登陆企业内部网及互联网,即使处于无线的状态下,也能进行远程办公,以此来提高对于突发事件的反应能力,提升企业竞争力。
这篇文章我将使用iPhone作为移动终端进行设计与实现,iPhone引入了基于大型多触点显示屏和领先性新软件的全新用户界面,让用户用手指即可控制iPhone。iPhone还开创了移动设备软件尖端功能的新纪元,重新定义了移动电话的功能。iPhone开发中,除了比较复杂的游戏开发,还有一种就是跟数据库打交道的应用程序,这可以在本文中得到体现。
WF4.0是微软提供的一套工作流开发框架,里面包含:流程设计器,各种类型封装好的工作流活动,持久化服务,WCF服务等功能。这篇文章我将结合iPhone+WF4.0实现移动审批工作流。通过一个简单的例子你可以清楚的看到与数据库相关的iPhone应用程序的开发,以及使用iPhone+WCF+WF实现移动审批的各种关键技术的使用。
设计架构图:由于是使用了WCF的restful服务,所以其它手机平台也会很方便使用此工作流服务。
iPhone客户端的表单可以通过从服务端设计的表单结构的XML动态产生。
下面通过一个简单的请假流程说明如何实现:
用例流程图:
上面的流程大致为:申请人在iPhone上打开请假流程,填写姓名和请假天数,点击提交,这个流程将走到他的上级,上级进行审批,并将审批结果通过短信知道申请者。
参考上图,通过WF4.0设计器设计一个流程,如下图:
下面我使用WCF将此流程封装到restful服务中。
wcf restful服务设计如下:
[ServiceContract]
publicinterface IRestServiceImpl
{
///<summary>
/// 获取未审核列表
///</summary>
///<returns></returns>
[OperationContract]
[WebInvoke(Method ="GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate ="getleavelist")]
List<Leave> GetLeaveList();
///<summary>
/// 启动流程
///</summary>
///<param name="name"></param>
///<param name="day"></param>
///<returns></returns>
[OperationContract]
[WebInvoke(Method ="POST",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate ="createleave/{name}/{day}")]
string CreateLSeave(string name, string day);
///<summary>
/// 审批流程
///</summary>
///<param name="id"></param>
///<param name="comment"></param>
///<returns></returns>
[OperationContract]
[WebInvoke(Method ="POST",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate ="auditingleave/{id}/{comment}")]
string AuditingLeave(string id, string comment);
}
数据库设计:
1、WF持久化数据表:使用WF自带的数据表。
2、业务数据表:请假单,设计如下:
WF流程启动和运行代码:
publicclass WorkFlowProcess
{
staticstring constring ="Data Source=PC-ZHUQL\\ZHUQL;Initial Catalog=TestDB;Integrated Security=True;Pooling=False";
static AutoResetEvent instanceUnloaded =new AutoResetEvent(false);
static Hashtable InstanceHashtable =new Hashtable();
publicstaticstring RunInstance(Guid ID,string Comment)
{
SqlWorkflowInstanceStore instanceStore =new SqlWorkflowInstanceStore(constring);
WorkflowApplication application1 =new WorkflowApplication(new LeaveProcess());
application1.InstanceStore = instanceStore;
application1.Completed = (workflowApplicationCompletedEventArgs) =>
{
Console.WriteLine("\nWorkflowApplication has Completed in the {0} state.", workflowApplicationCompletedEventArgs.CompletionState);
};
application1.Unloaded = (workflowApplicationEventArgs) =>
{
Console.WriteLine("WorkflowApplication has Unloaded\n");
instanceUnloaded.Set();
};
application1.Load(ID);
application1.ResumeBookmark("Check", Comment);
instanceUnloaded.WaitOne();
return"success";
}
// creates a workflow application, binds parameters, links extensions and run it
publicstaticstring CreateAndRun(string LeaveName, int LeaveDay)
{
SqlWorkflowInstanceStore instanceStore =new SqlWorkflowInstanceStore(constring);
InstanceView view = instanceStore.Execute(instanceStore.CreateInstanceHandle(), new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
IDictionary<string, object> input =new Dictionary<string, object>
{
{ "LeaveName" , LeaveName },
{ "LeaveDay" , LeaveDay }
};
WorkflowApplication application =new WorkflowApplication(new LeaveProcess(), input);
application.InstanceStore = instanceStore;
application.PersistableIdle = (e) =>
{
instanceUnloaded.Set();
return PersistableIdleAction.Unload;
};
application.Unloaded = (e) =>
{
instanceUnloaded.Set();
};
application.OnUnhandledException = (ex) =>
{
Console.Write("Exception");
return UnhandledExceptionAction.Terminate;
};
Guid id = application.Id;
application.Run();
instanceUnloaded.WaitOne();
return"success";
}
// executed when instance is persisted
publicstaticvoid OnWorkflowCompleted(WorkflowApplicationCompletedEventArgs e)
{
}
// executed when instance goes idle
publicstaticvoid OnIdle(WorkflowApplicationIdleEventArgs e)
{
}
publicstatic PersistableIdleAction OnIdleAndPersistable(WorkflowApplicationIdleEventArgs e)
{
return PersistableIdleAction.Persist;
}
}
iPhone客户端调用:
在前一篇文章:iPhone中调用WCF RESTFUL Service,讲解了iPhone中如何调用WCF restful服务,下面用启动流程为例说明:
-(IBAction) btnSender:(id)sender
{
NSString * urlString =@"http://10.5.23.117:8008/RestServiceImpl.svc/createleave/%@/%@";
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:urlString,txtName.text,txtDay.text]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:@"POST"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"杩斿洖缁撴灉"
message:@"鎻愪氦鎴愬姛"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
}
iPhone界面设计:
1、启动流程界面:
2、填写表单信息:
3、启动流程
4、待审核列表:
5、审核界面:
6、审核结果:
这里是个简单的demo,界面非常的简陋。
总结:本文通过一个简单的用例来说明了移动审批流程的各个层面的各种技术的实现。使用这些技术实现一个工作流服务以及工作流客户端界面将非常简单。