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";
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章