2017.2.28 activiti实战--第七章--Spring容器集成应用实例(五)普通表单

学习资料:《Activiti实战》

第七章  Spring容器集成应用实例(五)普通表单

第六章中介绍了动态表单、外置表单。这里讲解第三种表单:普通表单。

普通表单的特点:

1 把表单内容写在表现层(JSP、JSF、HTML)文件中
2 一个用户任务对应一个页面
3 业务数据和流程数据分离
4 适用于业务相对固定但复杂、流程相对固定但表现层变化多的情况

因为普通表单中,业务数据和流程数据是分离的,所以存在统一事务管理的问题。要保证Activiti和业务数据操作在同一个事务中执行。前面集成Spring时的事务管理器的配置可表明这点。本节基于第六章的主要针请假流程,对数据和表单都分离的情况下,采用普通表单实现该功能。

本节采用Spring、SpringMVC和Hibernete。

7.5.1 业务建模

(1)表结构

(2)其他

DAO和Manger用来针对请假实体的CRUD,Leave-workflowService用来处理流程相关操作。

7.5.2 启动流程

(1)部署流程

在启动流程之前,先部署流程。

第六章已经实现过这个页面,不再提。总之,点击浏览,选择文件,然后submit,将chapter7/leave.bpmn和leave.png打包部署。部署完毕之后,在该列表页面中,会出现一个新的processDefinition记录。

(2)jsp

普通表单使用时,需要将表单内容保存在一个单独的文件中。这里采用jsp文件格式。

表单设计如下:

 1     <form action="${ctx }/chapter7/leave/start" class="form-horizontal" method="post" onsubmit="beforeSend()">
 2         <input type="hidden" name="startTime" />
 3         <input type="hidden" name="endTime" />
 4         <fieldset>
 5             <legend><small>请假申请</small></legend>
 6             <div id="messageBox" class="alert alert-error input-large controls" style="display:none">输入有误,请先更正。</div>
 7             <div class="control-group">
 8                 <label for="loginName" class="control-label">请假类型:</label>
 9                 <div class="controls">
10                     <select id="leaveType" name="leaveType" class="required">
11                         <option>公休</option>
12                         <option>病假</option>
13                         <option>调休</option>
14                         <option>事假</option>
15                         <option>婚假</option>
16                     </select>
17                 </div>
18             </div>
19             <div class="control-group">
20                 <label for="name" class="control-label">开始时间:</label>
21                 <div class="controls">
22                     <input type="text" id="startDate" class="datepicker input-small" data-date-format="yyyy-mm-dd" />
23                     <input type="text" id="startTime" class="time input-small" />
24                 </div>
25             </div>
26             <div class="control-group">
27                 <label for="plainPassword" class="control-label">结束时间:</label>
28                 <div class="controls">
29                     <input type="text" id="endDate" class="datepicker input-small" data-date-format="yyyy-mm-dd" />
30                     <input type="text" id="endTime" class="time input-small" />
31                 </div>
32             </div>
33             <div class="control-group">
34                 <label for="groupList" class="control-label">请假原因:</label>
35                 <div class="controls">
36                     <textarea name="reason"></textarea>
37                 </div>
38             </div>
39             <div class="form-actions">
40                 <button type="submit" class="btn"><i class="icon-play"></i>启动流程</button>
41             </div>
42         </fieldset>
43     </form>
form

webapp/WEB-INF/views/chapter7/leave/leaveApply.jsp如下:

 1 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2 <!DOCTYPE html>
 3 <html>
 4 <head>
 5     <%@ include file="/common/global.jsp"%>
 6     <%@ include file="/common/meta.jsp" %>
 7     <%@ include file="/common/include-base-styles.jsp" %>
 8     <link rel="stylesheet" href="${ctx}/js/common/plugins/timepicker.css">
 9     <title>请假申请</title>
10     <script type="text/javascript" src="${ctx }/js/common/jquery.js"></script>
11     <script type="text/javascript" src="${ctx }/js/common/bootstrap.min.js"></script>
12     <script type="text/javascript" src="${ctx }/js/common/bootstrap-datepicker.js"></script>
13     <script type="text/javascript" src="${ctx }/js/common/plugins/bootstrap-timepicker.js"></script>
14     <script type="text/javascript">
15     $(function() {
16         $('.datepicker').datepicker();
17         $('.time').timepicker({
18             minuteStep: 10,
19             showMeridian: false
20         });
21     });
22 
23     function beforeSend() {
24         $('input[name=startTime]').val($('#startDate').val() + ' ' + $('#startTime').val());
25         $('input[name=endTime]').val($('#endDate').val() + ' ' + $('#endTime').val());
26     }
27     </script>
28 </head>
29 <body>
30     <c:if test="${not empty message}">
31         <div id="message" class="alert alert-success">${message}</div>
32         <!-- 自动隐藏提示信息 -->
33         <script type="text/javascript">
34         setTimeout(function() {
35             $('#message').hide('slow');
36         }, 5000);
37         </script>
38     </c:if>
39     <form>
40         <!--表单的代码放在这里-->
41     </form>
42 </body>
43 </html>
View Code

(3)Controller

 在上面的流程定义列表页面中,增加一个字段"操作",里面包含两个button,一个是启动,一个是删除。

当点击"启动时",应该要显示表单,并且点击申请时,流程启动。

 1 @Controller
 2 @RequestMapping(value = "/chapter7/leave")
 3 public class LeaveController {
 4 
 5     private Logger logger = LoggerFactory.getLogger(getClass());
 6 
 7     @Autowired
 8     private LeaveManager leaveManager;
 9 
10     @Autowired
11     private LeaveWorkflowService leaveService;
12 
13     @Autowired
14     private TaskService taskService;
15 
16     @Autowired
17     private RuntimeService runtimeService;
18 
19     @RequestMapping(value = {"apply", ""})
20     public String createForm(Model model) {
21         model.addAttribute("leave", new Leave());
22         return "/chapter7/leave/leave-apply";
23     }
24 
25     /**
26      * 启动请假流程
27      */
28     @RequestMapping(value = "start", method = RequestMethod.POST)
29     public String startWorkflow(Leave leave, RedirectAttributes redirectAttributes, HttpSession session) {
30         try {
31             User user = UserUtil.getUserFromSession(session);
32             Map<String, Object> variables = new HashMap<String, Object>();
33             ProcessInstance processInstance = leaveService.startWorkflow(leave, user.getId(), variables);
34             redirectAttributes.addFlashAttribute("message", "流程已启动,流程ID:" + processInstance.getId());
35         } catch (ActivitiException e) {
36             if (e.getMessage().indexOf("no processes deployed with key") != -1) {
37                 logger.warn("没有部署流程!", e);
38                 redirectAttributes.addFlashAttribute("error", "没有部署请假流程");
39             } else {
40                 logger.error("启动请假流程失败:", e);
41                 redirectAttributes.addFlashAttribute("error", "系统内部错误!");
42             }
43         } catch (Exception e) {
44             logger.error("启动请假流程失败:", e);
45             redirectAttributes.addFlashAttribute("error", "系统内部错误!");
46         }
47         return "redirect:/chapter7/leave/apply";
48     }
49     
50     ...
51 }

(4)Service

前面提过,这里要实现业务和流程数据的分离。即业务数据存在一个表里,流程数据存在另一个表。但是又要将二者联系起来。

这里采取的办法是:

1 业务表:增加一个字段process_instance_id,方便从业务层面查询流程数据。
2 流程表:用entity的ID作为processDefinitionKey,方便从流程层面查询业务数据。

可以从代码中看出来,这里不只是单纯的启动流程。还进行了数据的存储与关联。

 1 @Service
 2 @Transactional
 3 public class LeaveWorkflowService {
 4 
 5     private Logger logger = LoggerFactory.getLogger(getClass());
 6 
 7     @Autowired
 8     LeaveManager leaveManager;
 9 
10     @Autowired
11     private IdentityService identityService;
12 
13     @Autowired
14     private RuntimeService runtimeService;
15 
16     @Autowired
17     private TaskService taskService;
18 
19     @Autowired
20     private RepositoryService repositoryService;
21 
22     /**
23      * 保存请假实体并启动流程
24      */
25     public ProcessInstance startWorkflow(Leave entity, String userId, Map<String, Object> variables) {
26         if (entity.getId() == null) {
27             entity.setApplyTime(new Date());
28             entity.setUserId(userId);
29         }
30         leaveManager.save(entity);//持久化请假实体
31         String businessKey = entity.getId().toString();//实体保存后的ID,作为流程中的业务key
32 
33         // 用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中
34         identityService.setAuthenticatedUserId(userId);
35 
36         ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables);//将业务主ID设置为流程实例的key
37         String processInstanceId = processInstance.getId();
38         entity.setProcessInstanceId(processInstanceId);// 将流程实例的ID保存至业务表
39         logger.debug("start process of {key={}, bkey={}, pid={}, variables={}}", new Object[]{"leave", businessKey, processInstanceId, variables});
40         leaveManager.save(entity);
41         return processInstance;
42     }
43 
44     ...
45 }

 7.5.3 任务读取

原文地址:https://www.cnblogs.com/lyh421/p/6484373.html