day59_BOS项目_11

  • 今天内容安排:
    • 1、流程实例管理(查询流程实例、查看流程实例运行状态)
    • 2、将bos系统中的用户和角色同步到activiti框架的用户表和组表中去
    • 3、设计物流配送流程
    • 4、启动物流配送流程
    • 5、组任务操作(查询、拾取)
    • 6、个人任务操作(查询、办理)

1、流程实例管理

1.1、查询流程实例

第一步:创建一个流程实例管理ProcessInstanceAction,提供list()方法,查询流程实例列表数据

    // 注入Service
    @Autowired
    private RuntimeService runtimeService;

    /**
     * 查询流程实例(同步)
     * @return
     */
    public String list() {
        // 创建流程实例查询对象
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
        query.orderByProcessInstanceId().desc(); // 根据流程实例id排序,降序
        List<ProcessInstance> list = query.list(); // 执行查询,获得流程实例列表数据
        // 将流程实例列表数据压入值栈中
        ActionContext.getContext().getValueStack().set("list", list);
        return "list"; 
    }

第二步:配置struts.xml

    <!-- 流程实例管理:配置processInstanceAction-->
    <action name="processInstanceAction_*" class="processInstanceAction" method="{1}">
        <result name="list">/WEB-INF/pages/workflow/processinstance.jsp</result>
    </action>

第三步:提供processinstance.jsp页面,展示列表数据

<tbody>
    <s:iterator value="list">
        <tr>
            <td>${id}</td><!-- 流程实例id -->
            <td>${processDefinitionId}</td>
            <td>${activityId}</td><!-- 流程id(任务默认id) -->
            <td>
                <div id="div${id}"></div>
                <script type="text/javascript">
                // 根据流程实例id查询流程变量
                $.post("${pageContext.request.contextPath}/processInstanceAction_findData.action",{"id":'${id}'},function(data) {
                    $("#div${id}").html(data);
                });
            </script>
            </td>
            <td>
                <a class="easyui-linkbutton" data-options="iconCls:'icon-search'" onclick="showPng('${id}');" href="#">查看流程图</a>
            </td>
        </tr>
    </s:iterator>
</tbody>

第四步:在ProcessInstanceAction中提供findData()的方法,根据流程实例id查询对应的流程变量数据(ajax)

    // 接收页面提交过来的参数:流程实例id
    private String id;
    public void setId(String id) {
        this.id = id;
    }

    /**
     * 根据流程实例id查询对应的流程变量数据(ajax)
     * @return
     * @throws IOException 
     */
    public String findData() throws IOException {
        Map<String, Object> variables = runtimeService.getVariables(id);
        ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
        ServletActionContext.getResponse().getWriter().print(variables.toString());
        return "none";
    }

浏览器效果如下图所示:

1.2、查询流程实例运行状态

第一步:为“查看流程图”按钮绑定事件,注意:点击查看流程图按钮,实际上发起了2次请求

    <script type="text/javascript">
        function showPng(id) {
            // 弹出新窗口
            window.open("${pageContext.request.contextPath}/processInstanceAction_showPng.action?id=" + id);
        }
    </script>

第二步:在ProcessInstanceAction中提供showPng()方法,根据流程实例id获取部署id、图片名称、图片坐标

    /**
     * 根据流程实例id获取部署id、图片名称、图片坐标
     * 
     * @return
     */
    public String showPng() {
        // 1、根据流程实例id创建流程实例查询对象
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
        query.processInstanceId(id); // 根据流程实例id过滤
        ProcessInstance processInstance = query.singleResult(); // 得到流程实例对象
        // 2、根据流程实例对象获取流程定义id
        String processDefinitionId = processInstance.getProcessDefinitionId();
        // 3、根据流程定义id创建流程定义查询对象 --> 根据流程定义id过滤 --> 得到流程定义对象(链式编程),注意:此方式只查询了流程定义表act_re_procdef
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        // 4、根据流程定义对象获取部署id
        deploymentId = processDefinition.getDeploymentId();
        // 5、根据流程定义对象获取图片名称
        imageName = processDefinition.getDiagramResourceName();
        // 把部署id和图片名称压入值栈后,在image.jsp页面就可以正常获取出来这两个参数,取出来之后该页面又请求新的地址,新的地址又把这两个参数提交过来,我们在Action中又需要接收(设置)这两个参数,是不是有些麻烦呢?
        // 所以针对这种情况,我们需要把部署id和图片名称由局部变量提升为成员变量,并且提供getter和setter方法,终于这两个方法都能用着啦!getter方法用于页面EL表达式获取参数,setter方法用于接收页面提交回来的参数。
        // 因为成员变量本身就在struts的值栈里面,因为struts框架本身将Action对象压入值栈中。

        // 获取坐标
        // 1、获取当前流程实例执行到哪个节点了
        String activityId = processInstance.getActivityId(); // usertask1
        // 2、加载bpmn(xml)文件,获得一个流程定义对象,注意:此方式不仅查询了流程定义表act_re_procdef,还查询了act_ge_bytearray
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId); 
        // 使用流程定义对象的实现类,该实现类里面扩展了很多方法,其中就包括关于坐标的
        // 3、根据activityId获取含有坐标信息的对象
        ActivityImpl findActivity = processDefinitionEntity.findActivity(activityId);
        int x = findActivity.getX();
        int y = findActivity.getY();
        int width = findActivity.getWidth();
        int height = findActivity.getHeight();
        // 将坐标信息压入值栈中
        ActionContext.getContext().getValueStack().set("x", x);
        ActionContext.getContext().getValueStack().set("y", y);
        ActionContext.getContext().getValueStack().set("width", width);
        ActionContext.getContext().getValueStack().set("height", height);

        return "showPng";
    }

第三步:配置struts.xml,跳转到image.jsp页面

    <result name="showPng">/WEB-INF/pages/workflow/image.jsp</result>

第四步:提供image.jsp页面

<body>
    <!-- 1.获取到规则流程图 -->
    <img style="position: absolute;top: 0px;left: 0px;"
         src="processInstanceAction_viewImage?deploymentId=${deploymentId}&imageName=${imageName}">
    <!-- 2.根据当前活动的坐标,动态绘制DIV -->
    <div style="position:absolute;border:1px solid red;top:${y-1}px;left:${x-1}px;width:${width}px;height:${height}px;">
    </div>
</body>

第五步:在ProcessInstanceAction中提供viewImage()方法,根据部署id和图片名称获得对应的输入流

    /**
     * 根据部署id和图片名称获取对应的png输入流
     * @return
     */
    public String viewImage() {
        // 获取png图片对应的输入流
        InputStream pngStream = repositoryService.getResourceAsStream(deploymentId, imageName);
        // 使用Struts框架提供的文件下载功能(文件下载结果集):通过输出流把服务端的资源写到客户端
        // 先把输入流压入值栈,再到页面把流读出来即可
        ActionContext.getContext().getValueStack().set("pngStream", pngStream);
        return "viewImage";
    }

第六步:配置struts.xml

    <result name="viewImage" type="stream">
        <param name="contentType">image/png</param>
        <param name="inputName">pngStream</param><!-- 输入流压栈时起的名字 -->
        <!-- 
        <param name="contentDisposition">attachment;filename="abc.png"</param>
        <param name="bufferSize">1024</param>
         -->
    </result>

浏览器效果如下图所示:

2、将bos系统中的用户和角色同步到activiti框架的用户表和组表中去

2.1、将角色同步到 act_id_group 表中去

修改RoleServiceImpl中的save()方法,如下图所示:

2.2、将用户同步到 act_id_user 表中去

注意:我们在添加用户的时候会选择角色,在activiti框架中对应的是用户表关联组表。 修改UserServiceImpl的save()方法,如下图所示:

3、设计物流配送流程

  • 流程定义的id:
  • 使用排他网关:
  • 使用组任务:
  • 任务的id(对应Action中的方法名):

4、启动物流配送流程

准备工作:

  • 修改工作单类
  • 修改工作单对应的hbm映射文件
  • 为了和我们之前的命名规则一致,修改数据库表auth_function中的“启动配送流程”中的page属性的值为workordermanageAction_list.action

4.1、查询工作单列表数据

第一步:在工作单管理Action中提供list()方法,查询流程状态start为0的工作单(即未启动的工作单)

    /**
     * 查询流程状态start为0的工作单(即未启动的工作单)
     * @return
     */
    public String list() {
        List<Workordermanage> list = workordermanageService.findListNotStart();
        ActionContext.getContext().getValueStack().set("list", list); // 将查询到的结果压栈
        return "list";
    }

Service层代码:

    /**
     * 查询流程状态start为0的工作单(即未启动的工作单)
     */
    public List<Workordermanage> findListNotStart() {
        // 创建离线条件查询对象
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Workordermanage.class);
        // 向离线条件查询对象中封装查询条件
        detachedCriteria.add(Restrictions.eq("start", "0"));
        return workordermanageDao.findByCriteria(detachedCriteria );
    }

第二步:配置struts.xml

    <!-- 工作单管理:配置workordermanageAction-->
    <action name="workordermanageAction_*" class="workordermanageAction" method="{1}">
        <result name="list">/WEB-INF/pages/workflow/startransfer.jsp</result>
    </action>

第三步:提供startransfer.jsp页面,展示工作单列表数据

浏览器显示效果:

4.2、根据key启动流程实例

第一步:修改列表页面中“启动按钮”绑定事件

    <td> 
        <s:a action="workordermanageAction_start" cssClass="easyui-linkbutton" iconCls="icon-edit">启动
            <s:param name="id" value="#workOrderManage.id"></s:param>
        </s:a>
    </td>

第二步:在工作单Action中提供start()方法,启动物流配送流程对应的流程实例 注意:修改工作单中的start值为1,启动流程实例,设置流程变量”为多个数据库表的操作,所以尽量不要在Action中写这么复杂的逻辑,为什么呢? 答:建议写在service里面去,因为涉及到多个数据库表的操作,这样可以保证事务控制。

    /**
     * 启动物流配送流程
     * @return
     */
    public String start() {
        // 获取工作单id
        String id = model.getId();
        // 注意:“修改工作单中的start值为1,启动流程实例,设置流程变量”为多个数据库表的操作,所以尽量不要在Action中写这么复杂的逻辑,为什么呢?
        // 答:建议写在service里面去,因为涉及到多个数据库表的操作,这样可以保证事务控制。
        // 启动流程实例
        workordermanageService.start(id);
        return "toList";
    }

第三步:在工作单Service中提供start()方法,实现数据库操作

    /**
     * 修改工作单中的start值为1,设置流程变量,启动流程实例
     */
    public void start(String workorderId) {
        // 修改工作单中的start值为1
        Workordermanage workordermanage = workordermanageDao.findById(workorderId);
        workordermanage.setStart("1");

        // 设置流程变量
        String processDefinitionKey = "transfer"; // 流程定义key == 画图时给图起的id,这个不需要查询数据库,为已知数据
        String businessKey = workorderId; // 业务主键 == 业务表(工作单)的主键值,因为实际当中携带的数据往往是业务表中数据 ==> 业务主键存在实例流程表中,工作流框架通过业务主键可以找到业务数据
        Map<String, Object> variables = new HashMap<String, Object>(); // 流程变量
        variables.put("业务数据", workordermanage); // 我们在流程变量里面也存一份业务数据,就是说,“业务数据”我可以存在业务主键中,也可以存在流程变量中
        // 启动流程实例
        runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
    }

如下图所示:

5、组任务操作

5.1、查询组任务

第一步:创建一个TaskAction类,提供查询组任务的方法findGroupTask()

    @Autowired
    private TaskService taskService;

    /**
     * 查询组任务
     * @return
     */
    public String findGroupTask() {
        // 创建任务查询对象
        TaskQuery query = taskService.createTaskQuery();
        String candidateUser = BOSContext.getLoginUser().getId(); // 获取当前登录用户的id
        query.taskCandidateUser(candidateUser); // 根据组任务过滤,即根据候选人过滤
        List<Task> list = query.list(); // 执行查询,获得任务列表数据
        // 将任务列表数据压入值栈中
        ActionContext.getContext().getValueStack().set("list", list);
        return "grouptasklist";
    }

第二步:配置struts.xml

    <!-- 任务管理:配置taskAction-->
    <action name="taskAction_*" class="taskAction" method="{1}">
        <result name="grouptasklist">/WEB-INF/pages/workflow/grouptask.jsp</result>
    </action>

第三步:提供grouptask.jsp页面,展示任务列表数据

第三步:在任务Action中,提供显示业务数据的方法showData()

    // 接收页面提交过来的参数:任务id
    private String taskId;
    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    /**
     * 根据任务id查询对应的流程变量数据(ajax)
     * @return
     * @throws IOException 
     */
    public String showData() throws IOException {
        Map<String, Object> variables = taskService.getVariables(taskId);
        ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
        ServletActionContext.getResponse().getWriter().print(variables.toString());
        return "none";
    }

浏览器显示效果:

5.2、拾取组任务

第一步:修改jsp页面中“拾取按钮”事件

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

第二步:在TaskAction中提供拾取任务的方法takeTask()

    /**
     * 拾取组任务
     * @return
     */
    public String takeTask() {
        String userId = BOSContext.getLoginUser().getId(); // 获取当前登录用户的id
        taskService.claim(taskId, userId);
        return "togrouptasklist";
    }

第三步:配置struts.xml

    <!-- 任务管理:配置taskAction-->
    <action name="taskAction_*" class="taskAction" method="{1}">
        <result name="grouptasklist">/WEB-INF/pages/workflow/grouptask.jsp</result>
        <result name="togrouptasklist" type="redirectAction">
            taskAction_findGroupTask
        </result>
    </action>

6、个人任务操作

6.1、查询个人任务

第一步:在TaskAction中提供findPersonalTask()方法,查询当前登录用户的个人任务

    /**
     * 查询个人任务
     */
    public String findPersonalTask() {
        // 创建任务查询对象
        TaskQuery query = taskService.createTaskQuery();
        String assignee = BOSContext.getLoginUser().getId(); // 获取当前登录用户的id
        query.taskAssignee(assignee); // 根据个人任务过滤
        List<Task> list = query.list(); // 执行查询,获得任务列表数据
        // 将任务列表数据压入值栈中
        ActionContext.getContext().getValueStack().set("list", list);
        return "personaltasklist";
    }

第二步:配置struts.xml

    <result name="personaltasklist">/WEB-INF/pages/workflow/personaltask.jsp</result>

第三步:提供personaltask.jsp页面,展示个人任务列表数据 图片同查询组任务中的第三步。 浏览器显示效果:

6.2、办理个人任务

6.2.1、办理审核工作单任务

第一步:修改personaltask.jsp页面中“办理任务”按钮的事件

第二步:在TaskAction中提供checkWorkOrderManage()方法,办理审核工作单任务

    // 接收页面提交过来的参数:check
    // 审核结果:1 表示审核通过,0表示审核不通过
    private Integer check;
    public Integer getCheck() {
        return check;
    }
    public void setCheck(Integer check) {
        this.check = check;
    }

    /**
     * 办理审核工作单任务(实际上是跳转到审核工作单页面 + 真正办理审核工作单任务)
     */
    public String checkWorkOrderManage() {
        // 根据传递过来的任务id获取任务对象(任务查询对象 --> 根据任务id过滤 --> 任务对象)
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 根据任务对象获取流程实例id
        String processInstanceId = task.getProcessInstanceId();
        // 根据流程实例id获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String workorderId = processInstance.getBusinessKey(); // 业务主键 == 工作单id
        // 根据工作单id获取工作单对象
        Workordermanage workordermanage = workordermanageService.findId(workorderId);

        if (check == null) {
            // 说明需要跳转到审核页面
            // 将工作单数据压入值栈中
            ActionContext.getContext().getValueStack().set("map", workordermanage);
            // 跳转到一个审核工作单页面,展示当前对应的工作单信息
            return "check";
        } else {
            // 真正办理审核工作单任务
            workordermanageService.checkWorkOrderManage(taskId, check, workorderId);
            return "topersonaltasklist"; // 重新回显查询个人任务
        }
    }

第三步:如果是跳转到审核页面,配置struts.xml

    <result name="check">/WEB-INF/pages/workflow/check.jsp</result>

第四步:提供check.jsp页面,展示审核工作单表单页面

第五步:在工作单Service中提供checkWorkOrderManage()方法,处理审核工作单任务 注意:spring配置文件中需要注入historyService。

    // 注入service
    @Autowired
    private TaskService taskService;

    // 注入service
    @Autowired
    private HistoryService historyService;

    /**
     * 办理审核工作单任务
     */
    public void checkWorkOrderManage(String taskId, Integer check, String workorderId) {
        // 如果审核不通过,修改工作单中的start值为0
        Workordermanage workordermanage = workordermanageDao.findById(workorderId);

        // 根据传递过来的任务id获取任务对象(任务查询对象 --> 根据任务id过滤 --> 任务对象)
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 根据任务对象获取流程实例id
        String processInstanceId = task.getProcessInstanceId();

        Map<String, Object> variables = new HashMap<String, Object>();
        // 设置流程变量:check,check会在排他网关中使用
        variables.put("check", check);
        // 办理审核工作单任务
        taskService.complete(taskId, variables);

        if (check == 0) {
            // 说明审核不通过
            workordermanage.setStart("0");
            // 删除历史流程实例数据
            historyService.deleteHistoricProcessInstance(processInstanceId);
        }
    }

6.2.2、办理其他任务

我们简写了。

    /**
     * 办理出库任务
     */
    public String outStore() {
        taskService.complete(taskId);
        return "topersonaltasklist";
    }

    /**
     * 办理配送任务
     */
    public String transferGoods() {
        taskService.complete(taskId);
        return "topersonaltasklist";
    }

    /**
     * 办理签收任务
     */
    public String receive() {
        taskService.complete(taskId);
        return "topersonaltasklist";
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LEo的网络日志

tempfile.NamedTemporaryFile创建临时文件在windows没有权限打开

4968
来自专栏顶级程序员

Linux中高效编写Bash脚本的10个技巧

Linux开源社区(微信号:cn_linux) 英文:Aaron Kili,翻译:Linux中国/ch-cn 链接:linux.cn/article-8618...

3525
来自专栏FreeBuf

渗透测试中利用基于时间差反馈的远程代码执行漏洞(Timed Based RCE)进行数据获取

在最近的渗透测试项目中,为了进一步验证漏洞的可用性和危害性,我们遇到了这样一种情形:构造基于时间差反馈的系统注入命令(OS command injection ...

2229
来自专栏博客园

.NET面试题解析(07)-多线程编程与线程同步

转自:http://www.cnblogs.com/anding/p/5301754.html

1484
来自专栏安恒网络空间安全讲武堂

bugkuctf_web_writeup(部分)--上

bugkuctf平台10个较简单的web题目writeup,适合新手入门,可以找来试试http://ctf.bugku.com/bbs 。 Web2 题目描述:...

9075
来自专栏沈唁志

ThinkPHP5框架与ThinkPHP3.2的对比区别

6452
来自专栏腾讯Bugly的专栏

《Android 创建线程源码与OOM分析》

| 导语 企鹅FM近几个版本的外网Crash出现很多OutOfMemory(以下简称OOM)问题,Crash的堆栈都在Thread::start方法上。该文详细...

1.1K5
来自专栏C++

python笔记:#002#第一个python程序

1244
来自专栏阿杜的世界

Redis学习札记

Redis支持两种持久化方式,一种是RDB方式(快照:根据指定的规则“定时”将内存中的数据存储在硬盘上),另一种是AOF方式(在每次执行命令后都将命令本身记录下...

1323
来自专栏编程

近期做的比较好的web

? 本文作者:p0desta。 感谢p0desta。来稿,本文稿费100元。持续小广告:各位大佬有安全方面新的创作都可以向小编砸过来,将文章以Word形式发送...

2218

扫码关注云+社区

领取腾讯云代金券