宅急送 项目第十一天 JBPM应用

1. 中转流程业务分析

基础设置模块: 为其他模块提供基础数据

取派模块(业务受理) : 接收客户配送请求,自动分单,由指定取派员去客户家取货, 送货和客户签收
中转模块

这里写图片描述

上海到北京进行物流, 途径南京, 货物在上海出发进行打包,到达南京后,进行拆包 ,将南京为目的地货物,就地配送,将南京到北京货物重新和 上海到北京货物重新合包,进行配送,到达每个地域,货物要拆包和合包,涉及到入库和出库的问题

建议完成 仓库管理系统

练习重点: 结合中转配送流程, 讲解一套JBPM项目解决方案 (应用JBPM )

需要: 各位先将JBPM 整合到项目 (课程第九天 )

2. 流程定义管理模块

使用工作流框架,将业务流程管理起来,实现业务流程自动化(基于表单提交和任务办理 )
该模块,与业务无关 ,先通过这个模块,将业务流程部署工作流系统中!

2.1. 业务流程定制和部署

2.1.1. 流程定制

设计流程分为在线设计和线下设计
在线设计: 打开网页 ,通过HTML和CSS、JS制作设计器,在线设计业务流程, 直接将流程发布到系统
线下设计:MyEclipse 安装GPD插件,设计流程生成 jpdl.xml 和 png 图片,将设计好流程,制作zip压缩包,通过文件上传的方式,将业务流程部署JBPM中

2.1.2. 编写流程定义发布功能

BOS项目,提供流程定义管理 模块

这里写图片描述

发布新流程、 流程定义列表查看、流程图查看

/WEB-INF/pages/workflow/processdefinition_deploy.jsp 发布新业务流程页面

这里写图片描述

编写服务器代码 ,建立workflow包,提供 ProcessDefinitionAction

public class ProcessDefinitionAction extends BaseAction {
}

发布新流程定义 RepositoryService
在 BaseAction 注入 ProcessEngine 对象
编写业务流程发布代码

这里写图片描述

2.2. 流程定义信息查看

datagrid 不用json ,直接对HTML 数据渲染

不是Ajax 流程,在访问 list页面前,先访问Action ,查询所有流程定义,放入值栈,跳转到jsp显示

在 ProcessDefinitionAction 中,提供 list方法
问题: 只显示每个相同key的最高版本的流程

// 查询所有流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION).list(); // 所有流程定义

// 每个相同key的流程,只显示最高版本
// map 的key 就是 pdKey 流程关键字, map的value 就是 流程定义
Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>();
for (ProcessDefinition processDefinition : list) {
    map.put(processDefinition.getKey(), processDefinition);
}

// 放入值栈返回
ActionContext.getContext().put("processDefinitions", map.values());

在 struts-workflow.xml 配置 result

<!-- 流程定义管理 -->
<action name="processdefinition_*" class="processDefinitionAction" method="{1}">
    <!-- 发布新流程 -->
    <result name="deploySUCCESS" type="redirectAction">processdefinition_list</result>
    <!-- 查询所有流程定义 -->
    <result name="listSUCCESS">/WEB-INF/pages/workflow/processdefinition_list.jsp</result>
</action>

修改 admin.json 中 “流程定义管理” 链接

{ "id":"1004", "pId":"100", "name":"

流程定义管理”, "t":"","page":"processdefinition_list.action"},

2.3. 流程图查看

这里写图片描述

查看流程图,需要发布id 和 图片资源name

<s:a action="processdefinition_viewpng" namespace="/" cssClass="easyui-linkbutton" data-options="iconCls:'icon-search'">查看流程图
        <s:param name="deploymentId" value="deploymentId" />
        <s:param name="imageResourceName" value="imageResourceName" />
</s:a>

点击按钮,服务器查询图片,将图片返回,不要下载

在 ProcessDefinitionAction 添加 viewpng
文件下载,涉及一个流,两个头信息
ContentType 设置 MIME类型
ContentDisposition 打开方式 ,默认值 inline,设置 attachment 弹出下载窗口

// 获得图片资源流
RepositoryService repositoryService = processEngine.getRepositoryService();
in = repositoryService.getResourceAsStream(deploymentId, imageResourceName);

配置结果

<!-- 查看图片 -->
<result name="viewpngSUCCESS" type="stream">
    <param name="contentType">image/png</param>
</result>

3. 中转业务流程管理分析

3.1. 分析业务流程,绘制jpdl.xml 业务流程图

这里写图片描述

3.2. 分析JBPM开发中考虑问题

问题: 如何启动业务流程 ?
工作单审核, 将WorkOrderManage 的 managerCheck 改为 1 ,启动流程

问题: 启动流程后,流程中很多任务节点,有谁来办理任务 ?
使用JBPM 组任务方式 candidate-groups 属性

问题: 办理任务,填写form表单 ,如何做到不同任务有不同的表单 ?
使用 <task> 节点 form属性,执行任务对应表单

问题: form提交存在业务数据,业务数据如何JBPM流程实例关联 ?
对每一个任务表单 设计一张表,通过一张流程实例整体对象,关联所有任务节点的table
transferinfo 表
instore 表
outstore 表
receivegoodsinfo 表
定义 总表 ZhongZhuanInfo 关联以上四张表数据

3.3. 发布中转流程

<task name="中转环节" g="196,99,92,52" candidate-groups="业务员" form="page_zhongzhuan__transferinfo.action">
   <transition name="to 入库" to="入库" g="-47,-17"/>
</task>
<task name="入库" g="381,118,92,52" candidate-groups="仓库管理员" form="page_zhongzhuan__instore_complete.action">
   <transition name="to 出库" to="出库" g="-47,-17"/>
</task>
<task name="出库" g="383,198,92,52" candidate-groups="仓库管理员" form="page_zhongzhuan__outstore_complete.action">
   <transition name="to 配送签收" to="配送签收" g="-71,-17"/>
</task>
<task name="配送签收" g="382,277,92,52" candidate-groups="取派员" form="page_zhongzhuan__receiveinfo_complete.action">
   <transition name="to end1" to="end1" g="-47,-17"/>
</task>

4. 中转配送流程实例启动 —- 工作单审核

4.1. 未审核工作单列表查询

这里写图片描述

在auth_function 表,已经准备了 工作单审核 Action 地址
查看所有未审核工作单信息 ,跳转 /WEB-INF/pages/zhongzhuan/check.jsp

编写 WorkOrderManageAction 工作单管理,添加 list 方法

<query name="WorkOrderManage.listUnChecked">
        <![CDATA[from WorkOrderManage where managerCheck = '0']]>
</query>

配置结果页面

<!-- 工作单审核列表 -->
<result name="listSUCCESS">
    /WEB-INF/pages/zhongzhuan/check.jsp
</result>

这里写图片描述

4.2. 对未审核工作单审核

一个工作单,对应一个中转配送流程 实例 ! 审核工作 启动中转流程 !

<s:a action="workordermanage_check" cssClass="easyui-linkbutton" iconCls="icon-edit">审核
    <s:param name="id" value="#workOrderManage.id"></s:param>
</s:a>

编写 WorkOrderManageAction 提供 check 方法
—- 启动流程,使用ExecutionService
—- 将 ProcessEngine 对象,注入 BaseService

问题: 在启动流程实例,创建全局变量对象 ZhongZhuanInfo 关联流程实例
对ZhongZhuanInfo 持久化, 需要将ZhongZhuanInfoDAO 注入 BaseService

@Override
public void check(WorkOrderManage workOrderManage) {
    // 操作一 : 将 工作单 managerCheck 属性值 设置为 1
    WorkOrderManage persistWorkOrderManage = workOrderManageDAO.findById(workOrderManage.getId()); // 持久工作单对象
    persistWorkOrderManage.setManagerCheck("1");

    // 操作二 : 启动中转配送流程
    ExecutionService executionService = processEngine.getExecutionService();
    // 在启动流程时,关联流程实例 对应 全局 中转信息对象
    ZhongZhuanInfo zhongZhuanInfo = new ZhongZhuanInfo();
    zhongZhuanInfo.setArrive("0");// 未到达
    zhongZhuanInfo.setWorkOrderManage(persistWorkOrderManage);// 关联工作单 信息
    // 对ZhongZhuanInfo 进行持久化
    zhongZhuanInfoDAO.save(zhongZhuanInfo);

    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("zhongZhuanInfo", zhongZhuanInfo);

    executionService.startProcessInstanceByKey("transfer", variables);
}

5. JBPM系统用户初始化

问题: 使用组任务办理方式 ,JBPM系统中没有用户和组的信息 ,保存

这里写图片描述

<task name="中转环节" g="196,99,92,52" candidate-groups="业务员" form="page_zhongzhuan__transferinfo.action">
   <transition name="to 入库" to="入库" g="-47,-17"/>
</task>

如何让JBPM用户认证功能和 系统用户统一起来 ,参考 14.3
方案一:

这里写图片描述

方案二: 将系统用户管理 与 JBPM 用户管理同步起来
用户管理 ,添加用户时,向 jbpm4_id_users 表插入一条数据
权限管理 ,添加角色时,向 jbpm4_id_groups 表插入一条数据
为用户授予角色时, 向 jbpm4_id_memebershipt 表插入一条数据

5.1. 修改 UserServiceImpl 添加用户,建立JBPM用户

使用 IdentityService

这里写图片描述

@Override
public void saveUser(User user) {
    // 防止 Role的id 为空串
    if (user.getRole() != null && user.getRole().getId() != null && user.getRole().getId().trim().length() == 0) {
        user.setRole(null);
    }
    // 对密码 进行 md5 加密
    user.setPassword(MD5Utils.md5(user.getPassword()));
    userDAO.save(user);

    // 在添加用户的同时,向 JBPM系统插入一个用户
    IdentityService identityService = processEngine.getIdentityService();
    identityService.createUser(user.getId(), user.getUsername(), user.getUsername()); // 建立JBPM用户
    if (user.getRole() != null) {
        // 在添加用户时,建立了和角色关系
        Role role = roleDAO.findById(user.getRole().getId());
        // 建立关系,JBPM 组id 使用 角色name属性
        identityService.createMembership(user.getId(), role.getName());
    }
}

5.2. 修改RoleServiceImpl 添加角色,建立JBPM 组

使用 IdentityService

这里写图片描述

@Override
public void saveRole(Role role, String functionIds) {
    // 将role信息保存角色表
    roleDAO.save(role); // 持久态
    // 建立 role 和 function联系,向role_function 中间表插入数据
    if (functionIds != null) {
        String[] ids = functionIds.split(",");
        for (String id : ids) {
            Function function = funtionDAO.findById(id); // 功能权限
            role.getFunctions().add(function); // 多对多关联,向中间表插入数据
        }
    }
    // 建立JBPM 系统 组信息
    IdentityService identityService = processEngine.getIdentityService();
    identityService.createGroup(role.getName());
}

5.3. 为用户授予角色,建立用户和组的关系

修改 UserServiceImpl
为用户授予角色,先删除 JBPM 该用户和之前组关系

这里写图片描述

@Override
public void grantRole(User user) {
    User exist = userDAO.findById(user.getId());
    exist.setRole(user.getRole()); // 关联角色 自动更新

    // 建立 JBPM 用户和组关系 一个用户只属于一个组
    // 先删除 这个用户和原来组关系,建立新关系
    IdentityService identityService = processEngine.getIdentityService();
    // 获得用户原来的组
    List<Group> list = identityService.findGroupsByUser(exist.getId());
    for (Group group : list) {
        identityService.deleteMembership(exist.getId(), group.getId(), null);
    }
    // 建立新关系
    Role role = roleDAO.findById(user.getRole().getId());
    identityService.createMembership(exist.getId(), role.getName());
}

5.4. 重新构建用户和角色信息

删除 user表 和 role表 所有信息

建立 zhangsan、lisi、wangwu 三个用户
jbpm4_id_user 建立数据

建立 业务员 、仓库管理员、取派员 三个角色
Jbpm4_id_group建立数据

建立关系 jbpm4_id_membership
zhangsan —- 业务员
lisi —- 仓库管理员
wangwu —- 取派员

6. 中转流程中 任务办理

6.1. 组任务列表查询

查看 auth_function 数据表

这里写图片描述

为 组任务添加 访问地址 task_findgrouptask.action

编写服务器端代码,添加TaskAction 提供 findgrouptask 方法
使用 TaskService 提供 findGroupTasks 方法查询 组任务

这里写图片描述

查询组任务:

// 查询组任务,使用 TaskService
TaskService taskService = processEngine.getTaskService();
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
List<Task> tasks = taskService.findGroupTasks(user.getId());

配置结果 :

<!-- 任务管理 -->
<action name="task_*" class="taskAction" method="{1}">
    <!-- 查询组任务 -->
    <result name="findgrouptaskSUCCESS">/WEB-INF/pages/workflow/grouptask.jsp</result>
</action>

这里写图片描述

问题: 如果页面是这样,用户怎么知道该去拾取哪个任务,没有显示任何业务数据 ?
页面获得 task对象,在查看Task接口API 后,没有显示业务数据的方法
如果显示业务数据,参考 TaskServiceImpl 实现 API

这里写图片描述

这里写图片描述

<s:iterator value="#tasks" var="task">
    <tr>
        <td><s:property value="id"/> </td>
        <td><s:property value="name"/></td>
        <td>
            <!-- task.getVariables 返回 map -->
            <s:iterator value="variables" var="entry">
                <s:property value="key"/>=<s:property value="value"/><br/>
            </s:iterator>
        </td>
        <td><a href="#" class="easyui-linkbutton">拾取</a></td>
    </tr>
</s:iterator>

6.2. 将组任务拾取为个人任务

通过 TaskService 提供

这里写图片描述

修改 grouptask.jsp 为拾取按钮,添加 参数传递

<s:a action="task_takeTask" namespace="/" cssClass="easyui-linkbutton">拾取
        <s:param name="taskId" value="id"></s:param>
</s:a>

编写服务器,在TaskAction 添加 takeTask 的方法

// 调用 TaskService 方法 进行组任务拾取
TaskService taskService = processEngine.getTaskService();
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
taskService.takeTask(taskId, user.getId());

配置结果

<!-- 拾取组任务 -->
<result name="takeTaskSUCCESS" type="redirectAction">
    task_findgrouptask
</result>

6.3. 个人任务列表查询

功能和 组任务列表查询非常类似
查询个人任务
参考auth_function 数据表

这里写图片描述

在TaskAction 添加 findpersonaltask 业务方法
使用 TaskService

这里写图片描述

// 使用TaskService 查询个人任务
TaskService taskService = processEngine.getTaskService();
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
List<Task> tasks = taskService.findPersonalTasks(user.getId());

配置跳转结果:

<!-- 查询个人任务列表 -->
<result name="findpersonaltask">
    /WEB-INF/pages/workflow/personaltask.jsp
</result>

这里写图片描述

在绘制流程图,为每个任务节点,指定form属性,办理任务,根据流程任务节点指定 form属性,跳转到不同页面去办理 !!!

6.4. 个人任务办理

6.4.1. 跳转到 任务对应 form表单页面

<task name="中转环节" g="196,99,92,52" candidate-groups="业务员" form="page_zhongzhuan__transferinfo.action">
      <transition name="to 入库" to="入库" g="-47,-17"/>
</task>

获取form属性
Task 提供 getFormResourceName 方法

修改 personaltask.jsp

<!-- formResourceName 和 id 都是从struts2 值栈获得   -->
<a href="${pageContext.request.contextPath }/${formResourceName}?taskId=${id}" class="easyui-linkbutton">
                        办理任务
</a>

这里写图片描述

transferinfo.jsp 提供 隐藏域,用来保存 当前办理任务id
填写中转环节表单,提交

 ${pageContext.request.contextPath }/task_saveTransferinfo.action

编写服务器代码, 在TaskAction 添加 saveTransferinfo的 方法 (完成中转环节 任务)

非常重要!
当前按照form属性 编写form 进行提交后,服务器代码通常完成三件事
1、 将业务数据持久化
2、 将业务数据 关联流程实例上 (成为流程变量 )
3、 办理任务,流程自动向后流转

public interface BosTaskService {
}
public class BosTaskServiceImpl extends BaseService implements BosTaskService {
}

将 BosTaskService 注入 BaseAction
将 TransferInfoDAO 注入 BaseService

业务实现代码

public void completeTransferInfoTask(TransferInfo transferInfo, String taskId) {
    // 1 、业务数据持久化
    transferInfoDAO.save(transferInfo);

    // 2、将业务数据 关联到 流程变量
    TaskService taskService = processEngine.getTaskService();
    ZhongZhuanInfo zhongZhuanInfo = (ZhongZhuanInfo) taskService.getVariable(taskId, "zhongZhuanInfo");
    zhongZhuanInfo.setArrive(transferInfo.getArrive());
    zhongZhuanInfo.getTransferInfos().add(transferInfo); // 向集合中添加一个中转环节信息

    // 3、 办理任务,自动流转
    if (zhongZhuanInfo.getArrive().equals("0")) {
        // 未到达, 继续中转
        // 使用自由流转实现
        Task task = taskService.getTask(taskId);
        completeTaskByCreateTransiton(task, "中转环节", "to 中转环节xxx");
    } else {
        // 到达
        taskService.completeTask(taskId, "to 入库"); // 流向入库
    }
}

办理任务后,重新跳回个人任务列表

<!-- 办理 中转环节  -->
<result name="saveTransferinfoSUCCESS" 
type="redirectAction">task_findpersonaltask</result>

其它

课前资料

这里写图片描述

Ehcache二级缓存

这里写图片描述

阅读资料

这里写图片描述

课后资料

这里写图片描述

中转配送流程

这里写图片描述

流程中循环结构

这里写图片描述

整个JBPM流程开发注意问题

这里写图片描述

课程视频内容

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值