H3流程开发笔记(二)启动一个新流程(上)
一:定义表单页面
1.新建StartInstance.aspx页面,修改页面类继承至BasePage
该页面显示所有的流程模板,选择模板提交后进入启动页(第一个活动项),该页面表单如下:

Start按钮事件定义如下:
protected void btnStart_Click(object sender, EventArgs e)
{
if (ddlVersion.SelectedIndex > -1)
{
//根据流程类型,名称和板本,得到流程模板
OThinker.H3.WorkflowTemplate.WorkflowTemplate workflow = OThinker.H3.Server.Engine.WorkflowManager.GetWorkflow(ddlFlowType.Text, ddlFlowName.Text, Convert.ToInt32(ddlVersion.Text));
// 开始节点(活动项)
OThinker.H3.WorkflowTemplate.ActivityTemplate startActivity = workflow.GetActivity(workflow.StartActivity);
// 开始的表单
OThinker.H3.WorkflowTemplate.Sheet startSheet = workflow.GetSheet(startActivity.SheetName);
// URL参数,传入流程类型,名称和版本,以及操作
System.Text.StringBuilder instanceParamBuilder = new System.Text.StringBuilder();
foreach (string key in this.Request.QueryString.Keys)
{
string lowerKey = key.ToLower();
if (lowerKey != "mode" &&
lowerKey != "workflowpackage" &&
lowerKey != "workflowname" &&
lowerKey != "workflowversion")
{
if (instanceParamBuilder.Length > 0)
{
instanceParamBuilder.Append("&");
}
instanceParamBuilder.Append(key + "=" + this.Request.QueryString[key]);
}
}
string url = GetFlowSheetUrl(startSheet);
this.Response.Redirect(
url + "?" + Param_Mode + "=" + SheetMode.Originate + "&" +
"workflowpackage=" + System.Web.HttpUtility.UrlEncode(workflow.WorkflowPackageName) + "&" +
"workflowname=" + System.Web.HttpUtility.UrlEncode(workflow.WorkflowName) + "&" +
"workflowversion=" + workflow.WorkflowVersion +
(instanceParamBuilder.Length == 0 ? null : ("&" + instanceParamBuilder.ToString())));
}
}
其中GetFlowSheetUrl在BasePage中定义:
public string GetFlowSheetUrl(OThinker.H3.WorkflowTemplate.Sheet sheet)
{
if (string.IsNullOrEmpty(sheet.SheetAddress)) throw new ArgumentNullException(sheet.SheetName + "没有定义表单", "SheetAddress");
string m_rootUrl = "http://" + HttpContext.Current.Request.Url.Authority;
if (!string.IsNullOrEmpty(HttpContext.Current.Request.ApplicationPath))
{
m_rootUrl += HttpContext.Current.Request.ApplicationPath;
}
if (sheet.SheetAddress[0] == '/')
{
m_rootUrl += sheet.SheetAddress;
}
else
{
m_rootUrl += "/" + sheet.SheetAddress;
}
return m_rootUrl;
}
2.创建表单页面放到Examples/WorkSheets下面,取名为ApplyLeave.aspx(路径和名称自便,这里只是以本人的习惯取的)
修改页面类继承至BasePage,设计页面如下,全部用Asp.net自带的控件,不用H3的WorkSheet里的控件,怕不好扩展
提交事件定义如下:
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(WorkflowName) || WorkflowVersion < 0)
{
return;
}
DateTime tempTime;
//验证数据...
if (!DateTime.TryParse(txtStartDate.Text, out tempTime))
{
return;
}
if (!DateTime.TryParse(txtEndDate.Text, out tempTime))
{
return;
}
//保存到流程引擎
string InstanceName = base.UserValidator.UserName + "的请假申请";//实例名称
//获取流程模板
OThinker.H3.WorkflowTemplate.WorkflowTemplate workflow = OThinker.H3.Server.Engine.WorkflowManager.GetWorkflow(WorkflowPackage, WorkflowName, WorkflowVersion);
string InstanceId=null;
string workItemId = null;
//创建流程实例
OriginateInstance(workflow, InstanceName, ref InstanceId, ref workItemId);
//保存到业务库(这里有个问题,如果业务库的操作失败了怎么办,但该方法又不能写在前面,因为WorkItemId得从H3的接口返回)
Microsoft.Practices.EnterpriseLibrary.Data.Database dataBase = Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase();
string sql = string.Format("insert into [ApplyLeaveInfo] ([startDate],[endDate] ,[ApplyResult],[WorkItemId]) values('{0}','{1}','false','{2}')", txtStartDate.Text, txtEndDate.Text, workItemId);
dataBase.ExecuteNonQuery(System.Data.CommandType.Text, sql);
//返回待处理
Response.Redirect("../../default.aspx");
}其中OriginateInstance为创建流程实例的方法,该方法里保存了实例记录,并且通过Soket通知H3服务一个实例创建的消息,服务接到消息后会在WorkItem中插入一条发起的消息,不过还没完,还得要记录下一步的操作数据,要不然下一步的用户在待处理列表里就看不到了
/// <summary>
/// 启动一个流程实例,并且提交起始活动项
/// </summary>
/// <param name="Workflow">流程模板对象</param>
/// <param name="InstanceName">实例名称</param>
/// <param name="InstanceId">实例编号</param>
/// <param name="workItemId">起始流动项在OT_WorkItem的ID</param>
public void OriginateInstance(OThinker.H3.WorkflowTemplate.WorkflowTemplate Workflow, string InstanceName, ref string InstanceId, ref string workItemId)
{
OThinker.H3.Acl.UserValidator userValidator = this.UserValidator;
if (Workflow == null)
{
throw new ArgumentNullException("流程模板不存在", "Workflow");
}
//开始一个流程实例
InstanceId = OThinker.H3.Server.Engine.InstanceManager.CreateInstance(WorkflowPackage,
WorkflowName,
WorkflowVersion,
InstanceName,
userValidator.UserID,
null,
userValidator.Department,
false,
"",
null,
-1L);
OThinker.H3.Messages.MessageEmergencyType normal = OThinker.H3.Messages.MessageEmergencyType.Normal;
if (Workflow.StartWithSheet)
{
normal = OThinker.H3.Messages.MessageEmergencyType.High;
}
//发送实例消息给服务
OThinker.H3.Messages.StartInstanceMessage message = new OThinker.H3.Messages.StartInstanceMessage(
normal,
InstanceId,
null,
OThinker.H3.Instance.PriorityType.Normal,
false,
0L,
-1L,
null);
OThinker.H3.Server.Engine.InstanceManager.SendMessage(message);
//记录WorkItem,失败后尝试10次
string[] strArray = null;
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1500);
strArray = OThinker.H3.Server.Engine.WorkItemManager.Query(null,
new string[] { InstanceId },
new string[] { userValidator.UserID },
DateTime.MinValue,
DateTime.MaxValue,
OThinker.H3.WorkItem.WorkItemState.Unfinished
);
if ((strArray != null) && (strArray.Length != 0))
{
break;
}
}
if ((strArray == null) || (strArray.Length == 0))
{
throw new Exception("发起流程失败");
}
workItemId = strArray[0];
//提交起始活动项
SubmitWorkItem(Workflow, workItemId);
}
/// <summary>
/// 提交流程步骤
/// </summary>
/// <param name="Workflow">流程模板对象</param>
/// <param name="workItemId">活动项ID</param>
public void SubmitWorkItem(OThinker.H3.WorkflowTemplate.WorkflowTemplate Workflow, string workItemId)
{
OThinker.H3.Acl.UserValidator userValidator = this.UserValidator;
OThinker.H3.WorkItem.WorkItem workItem = OThinker.H3.Server.Engine.WorkItemManager.GetWorkItem(workItemId);
workItem.State = OThinker.H3.WorkItem.WorkItemState.Finished;
//完成活动
OThinker.H3.Server.Engine.WorkItemManager.FinishWorkItem(workItemId, this.UserValidator.UserID, null, OThinker.Data.BoolMatchValue.Unspecified, null);
// 设置操作描述(Portal有这一步骤,不知道去掉后会有影响没)
string description = "submit";
OThinker.H3.Server.Engine.TokenPool.AppendDescription(workItem.InstanceId, workItem.TokenId, description);
OThinker.H3.WorkflowTemplate.ActivityTemplate destActivityTemplate = Workflow.GetActivity(DestActivityName);
//如果地址栏没有传入下一活动名称
if (destActivityTemplate == null)
{
// 需要通知实例事件管理器结束事件
OThinker.H3.Messages.AsyncEndMessage endMessage = new OThinker.H3.Messages.AsyncEndMessage(
OThinker.H3.Messages.MessageEmergencyType.Normal,
workItem.InstanceId,
workItem.ActivityName,
workItem.ReplyID,
true,
this.UserValidator.UserID,
OThinker.Data.BoolMatchValue.Unspecified,
null,
null);
OThinker.H3.Server.Engine.InstanceManager.SendMessage(endMessage);
}
else
{
// 准备触发后面Activity的消息
OThinker.H3.Messages.ActivateActivityMessage activateMessage
= new OThinker.H3.Messages.ActivateActivityMessage(
OThinker.H3.Messages.MessageEmergencyType.Normal,
workItem.InstanceId,
destActivityTemplate.Name,
OThinker.H3.Instance.Token.UnspecifiedID,
null,
new long[] { workItem.TokenId },
false,
OThinker.H3.Messages.ActivateType.Normal,
null);
// 通知该活动已经完成
OThinker.H3.Messages.AsyncEndMessage endMessage =
new OThinker.H3.Messages.AsyncEndMessage(
OThinker.H3.Messages.MessageEmergencyType.Normal,
workItem.InstanceId,
workItem.ActivityName,
workItem.ReplyID,
false,
userValidator.UserID,
OThinker.Data.BoolMatchValue.Unspecified,
activateMessage,
null);
OThinker.H3.Server.Engine.InstanceManager.SendMessage(endMessage);
}
}
源码下源:FlowSite
posted @ 2009-05-15 22:22 colys 阅读(213) 评论(3)
编辑
H3流程开发笔记入门资料
H3流程开发笔记(二)启动一个新流程(下)
前提
1.请假流程模板流程 ,设计如下图

点击工具栏的表单,添加表单页面地址

右击发起结点,在弹出的页面中设置该活动的表单
发布模板
2.创建业务数据库以及请假记录表
数据库名称:H2_BusinessDemo,表ApplyLeaveInfo语句如下
create table ApplyLeaveInfo(
ID int identity , --主键编号
startDate date ,--起始日期
endDate date,--结束日期
ApplyResult bit,--结果
WorkItemId nvarchar(36), --流程项编号,与H3的OT_WorkItem关联
tokenId [int] NULL--步骤编号
)
3.创建网站
新建WebSite,这里取名为FlowSite
添加H3相关DLL的引用 (下图中有WorkSheet.DLL,如果不用H3的表单控件,可不添加之类库)
添加InterPrise的Data和Common的引用,用于操作业务库数据
新建类BasePage,放到App_code,定义一些方法在该类里(比如获取用户信息),然后所有的表单页面继承该类
4.创建登录页面Login.aspx
拉一个登录控件,在登录事件中定义如下
protected void Login1_LoggingIn(object sender, LoginCancelEventArgs e)
{
lblErrorMessage.Text = string.Empty;
string userId= OThinker.H3.Server.Engine.Organization.GetUserIDByAlias(Login1.UserName);
if (string.IsNullOrEmpty(userId))
{
e.Cancel = true;
lblErrorMessage.Text = string.Format("用户{0}不存在", Login1.UserName);
}
else
{
OThinker.Organization.User user = (OThinker.Organization.User)OThinker.H3.Server.Engine.Organization.GetUnit(userId);
if (user == null)
{
e.Cancel = true;
lblErrorMessage.Text = string.Format("用户{0}不存在", Login1.UserName);
}
else
{
if (user.Password != Login1.Password)
{
e.Cancel = true;
lblErrorMessage.Text = string.Format("用户{0}的密码不正确", Login1.UserName);
}
else
{
//记录用户验证到Session
this.Session[BasePage.UserValidatorSessionName] = new OThinker.H3.Acl.DefaultUserValidator(new OThinker.H3.Acl.UserValidator.EngineDelegate(OThinker.H3.Server.GetEngine), user.ObjectID);
//检查流程引擎
try
{
OThinker.H3.EngineState state = OThinker.H3.Server.Engine.State;
}
catch (System.Net.Sockets.SocketException ex)
{
e.Cancel = true;
this.Response.Write("<BR>");
this.Response.Write(
"出错了!" + "<BR>" +
"请检查:" + "<BR>" +
"1、工作流服务器是否启动。" + "<BR>" +
ex.StackTrace.Replace("\r", "<BR>"));
return;
}
catch (System.Reflection.TargetInvocationException ex)
{
e.Cancel = true;
this.Response.Write("<BR>");
this.Response.Write(
"出错了!请检查:" + "<BR>" +
"1、是否安装了.Net 3.0;<BR>" +
"2、数据库是否启动;" + "<BR>" +
"3、数据库连接设置是否正确;" + "<BR>" +
"4、是否可以从本机连接到数据库上。" + "<BR>" +
ex.StackTrace.Replace("\r", "<BR>"));
return;
}
if (OThinker.H3.Server.Engine.SettingManager.Initialized)
{
Response.Redirect("default.aspx?State=" + OThinker.H3.WorkItem.WorkItemState.Unfinished);
}
else
{
this.Response.Write("出错了!流程引擎尚未启动完毕:" + "<BR>");
}
}
}
}
注意其中两地方:
1).获取用户信息和保存用户权限,这里使用Session记录,当然也可以换其它方式,BasePage.UserValidatorSessionName就是一个只读字符串,定义在BasePage中
OThinker.Organization.User user = (OThinker.Organization.User)OThinker.H3.Server.Engine.Organization.GetUnit(userId);
this.Session[BasePage.UserValidatorSessionName] = new OThinker.H3.Acl.DefaultUserValidator(new OThinker.H3.Acl.UserValidator.EngineDelegate(OThinker.H3.Server.GetEngine), user.ObjectID);
2).检测流程引擎是否就绪,这里使用了Try…Catch的方式
5.显示待处理列表
获取流程类型和名称:
// 获取所有工作流模板的包(流程模板类型)
string[] packages = OThinker.H3.Server.Engine.WorkflowManager.GetWorkflowPackages();
//获取流程类型下所有的流程名
string[] names = OThinker.H3.Server.Engine.WorkflowManager.GetWorkflowNames(selectedPackage, OThinker.H3.WorkflowTemplate.WorkflowState.Active);
//查询待处理表
H3中,操作的流程记录放在OT_WorkItem这张表里,里面有流程实例,流程名称,版本,以及发起人,参考者,如果一个活动项的参考者为一个组,那么在完成这个活动的前一个活动后,会插入组内的所有用户的待处理,登录人的待处理只要以自己的ID去查询该表,查询语句如下
SELECT * FROM OT_WorkItem WHERE WorkflowPackage='流程类型' AND WorkflowName='流程名称' AND Participant='参与者ID' AND State!=2 AND State!=3 ORDER BY ReceiveTime DESC
在H3的Portal里有封装这样的方法
public static System.Data.DataTable QueryWorkItem(
string WorkflowPackage, // 流程类型
string WorkflowName, // 流程名称
int WorkflowVersion, // 流程版本
string ActivityName, // 流动项名称(流程步聚名称)
string[] Instances, // 实例ID(启动一个流程产生一个实例)
string[] Participants, // 参与者
System.DateTime From, //开始时间
System.DateTime To, // 结束时间
OThinker.H3.WorkItem.WorkItemState State, //工作项的状态{等待,正在工作中,完成,被取消}
OThinker.H3.Instance.PriorityType Priority, //优先级的类型{低,普通,高}
string InstanceName, // 实例名称,与InstanceId对应
string Receiptor, // 暂时还不知道干嘛的
OThinker.Data.BoolMatchValue Approval, // 是否批准
OThinker.Data.BoolMatchValue Elapsed) //是否计划完成(true的话,就是计划完成时间要小于当前时间)
以下是查询事件内容:
protected void btnSearch_Click(object sender, EventArgs e)
{
OThinker.H3.Acl.UserValidator userValidator = base.UserValidator;
string Sql = "SELECT OT_WorkItem. *,OT_User.Name OriginatorUserName FROM OT_WorkItem left Join OT_User on OT_User.ObjectID = OT_WorkItem.Originator WHERE Participant = '" + userValidator.UserID + "' AND State!=2 AND State!=3 ";
if (ddlFlowType.SelectedIndex > 0)
{
Sql += " and WorkflowPackage='" + ddlFlowType.Text + "'";
}
if (ddlFlowName.SelectedIndex > 0)
{
Sql += " and WorkflowName='" + ddlFlowName.Text + "'";
}
Sql += " ORDER BY ReceiveTime DESC";
OThinker.Data.Database.CommandFactory factory = new OThinker.Data.Database.CommandFactory(OThinker.H3.Configs.Config.Current.DataBase.DBType, OThinker.H3.Configs.Config.Current.DataBase.DBConnString);
OThinker.Data.Database.ICommand command = factory.CreateCommand();
System.Data.DataTable table = command.ExecuteDataTable(Sql);
command.Commit();
this.GridView1.DataSource = table;
this.GridView1.DataBind();
}
源码下源:FlowSite
posted @ 2009-05-15 21:20 colys 阅读(231) 评论(0)
编辑