##
* Activiti 7 需要Spring Security, 所以需要加入Spring Security相關依賴包。原因: 流程一般是需要人簽核的
* 繪制的流程圖文件放在 resources/processes 文件夾中, 會自動部署流程到數據庫
* 默認歷史表不會自動生成,需要手動開啟配置。
```
db-history-used: true
```
https://github.com/LiXiongGithub/springboot_activiti/tree/master/src/main
```
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService());
}
public UserDetailsService myUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
String[][] usersGroupsAndRoles = { { "oscar", "1", "ROLE_ACTIVITI_USER", "GROUP_activitiTraining" },
{ "admin", "1", "ROLE_ACTIVITI_ADMIN" }, };
for (String[] user : usersGroupsAndRoles) {
List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return inMemoryUserDetailsManager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
```
/** 流程定義和部署相關的存儲服務 */
@Autowired
private RepositoryService repositoryService;
/** 流程運行時相關的服務 */
@Autowired
private RuntimeService runtimeService;
/** 節點任務相關操作接口 */
@Autowired
private TaskService taskService;
/** 流程圖生成器 */
//@Autowired
private ProcessDiagramGenerator processDiagramGenerator;
/** 歷史記錄相關服務接口 */
@Autowired
private HistoryService historyService;
/**
* <p>
* 跳轉到測試主頁面
* </p>
*
* @return String 測試主頁面
* @author FRH
* @time 2018年12月10日上午11:12:28
* @version 1.0
*/
@RequestMapping(value = "/toIndex.html")
public String toTestPage() {
return "/index";
}
/**
* <p>
* 跳轉到上級審核頁面
* </p>
*
* @return String 上級審核頁面
* @author FRH
* @time 2018年12月5日下午2:31:42
* @version 1.0
*/
@RequestMapping(value = "/toLeave")
public String employeeLeave() {
return "/employeeLeave";
}
/**
* <p>
* 啟動請假流程(流程key即xml中定義的ID為leaveProcess)
* </p>
*
* @return String 啟動的流程ID
* @author FRH
* @time 2018年12月10日上午11:12:50
* @version 1.0
*/
@RequestMapping(value = "/start")
@ResponseBody
public String start() {
/*
* xml中定義的ID
*/
String instanceKey = "leaveProcess";
logger.info("開啟請假流程...");
/*
* 設置流程參數,開啟流程
*/
Map<String, Object> map = new HashMap<String, Object>();
map.put("jobNumber", "A1001");
map.put("busData", "bus data");
ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);// 使用流程定義的key啟動流程實例,key對應helloworld.bpmn文件中id的屬性值,使用key值啟動,默認是按照最新版本的流程定義啟動
logger.info("啟動流程實例成功:{}", instance);
logger.info("流程實例ID:{}", instance.getId());
logger.info("流程定義ID:{}", instance.getProcessDefinitionId());
/*
* 驗證是否啟動成功
*/
// 通過查詢正在運行的流程實例來判斷
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
// 根據流程實例ID來查詢
List<ProcessInstance> runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId())
.list();
logger.info("根據流程ID查詢條數:{}", runningList.size());
/*
* 返回流程ID
*/
return instance.getId();
}
/**
* <p>
* 查看當前流程圖
* </p>
*
* @param instanceId 流程實例
* @param response void 響應
* @author FRH
* @time 2018年12月10日上午11:14:12
* @version 1.0
*/
@ResponseBody
@RequestMapping(value = "/showImg")
public void showImg(String instanceId, HttpServletResponse response) {
/*
* 參數校驗
*/
logger.info("查看完整流程圖!流程實例ID:{}", instanceId);
if (StringUtils.isBlank(instanceId))
return;
/*
* 獲取流程實例
*/
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(instanceId).singleResult();
if (processInstance == null) {
logger.error("流程實例ID:{}沒查詢到流程實例!", instanceId);
return;
}
// 根據流程對象獲取流程對象模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
/*
* 查看已執行的節點集合 獲取流程歷史中已執行節點,并按照節點在流程中執行先后順序排序
*/
// 構造歷史流程查詢
HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(instanceId);
// 查詢歷史節點
List<HistoricActivityInstance> historicActivityInstanceList = historyInstanceQuery
.orderByHistoricActivityInstanceStartTime().asc().list();
if (historicActivityInstanceList == null || historicActivityInstanceList.size() == 0) {
logger.info("流程實例ID:{}沒有歷史節點信息!", instanceId);
outputImg(response, bpmnModel, null, null);
return;
}
// 已執行的節點ID集合(將historicActivityInstanceList中元素的activityId字段取出封裝到executedActivityIdList)
List<String> executedActivityIdList = historicActivityInstanceList.stream().map(item -> item.getActivityId())
.collect(Collectors.toList());
/*
* 獲取流程走過的線
*/
// 獲取流程定義
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
List<String> flowIds = ActivitiUtils.getHighLightedFlows(bpmnModel, processDefinition,
historicActivityInstanceList);
/*
* 輸出圖像,并設置高亮
*/
outputImg(response, bpmnModel, flowIds, executedActivityIdList);
}
/**
* <p>
* 員工提交申請
* </p>
*
* @param request 請求
* @return String 申請受理結果
* @author FRH
* @time 2018年12月10日上午11:15:09
* @version 1.0
*/
@RequestMapping(value = "/employeeApply")
@ResponseBody
public String employeeApply(HttpServletRequest request) {
/*
* 獲取請求參數
*/
String taskId = request.getParameter("taskId"); // 任務ID
String jobNumber = request.getParameter("jobNumber"); // 工號
String leaveDays = request.getParameter("leaveDays"); // 請假天數
String leaveReason = request.getParameter("leaveReason"); // 請假原因
/*
* 查詢任務
*/
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
logger.info("任務ID:{}查詢到任務為空!", taskId);
return "fail";
}
/*
* 參數傳遞并提交申請
*/
Map<String, Object> map = new HashMap<String, Object>();
map.put("days", leaveDays);
map.put("date", new Date());
map.put("reason", leaveReason);
map.put("jobNumber", jobNumber);
taskService.complete(task.getId(), map);
logger.info("執行【員工申請】環節,流程推動到【上級審核】環節");
/*
* 返回成功
*/
return "success";
}
/**
* <p>
* 跳轉到上級審核頁面
* </p>
*
* @return String 頁面
* @author FRH
* @time 2018年12月5日下午2:31:42
* @version 1.0
*/
@RequestMapping(value = "/viewTask")
public String toHigherAudit(String taskId, HttpServletRequest request) {
/*
* 獲取參數
*/
logger.info("跳轉到任務詳情頁面,任務ID:{}", taskId);
if (StringUtils.isBlank(taskId))
return "/higherAudit";
/*
* 查看任務詳細信息
*/
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
logger.info("任務ID:{}不存在!", taskId);
return "/higherAudit";
}
/*
* 完成任務
*/
Map<String, Object> paramMap = taskService.getVariables(taskId);
request.setAttribute("task", task);
request.setAttribute("paramMap", paramMap);
return "higherAudit";
}
/**
* <p>
* 跳轉到部門經理審核頁面
* </p>
*
* @param taskId 任務ID
* @param request 請求
* @return String 響應頁面
* @author FRH
* @time 2018年12月6日上午9:54:34
* @version 1.0
*/
@RequestMapping(value = "/viewTaskManager")
public String viewTaskManager(String taskId, HttpServletRequest request) {
/*
* 獲取參數
*/
logger.info("跳轉到任務詳情頁面,任務ID:{}", taskId);
if (StringUtils.isBlank(taskId))
return "/manageAudit";
/*
* 查看任務詳細信息
*/
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
logger.info("任務ID:{}不存在!", taskId);
return "/manageAudit";
}
/*
* 完成任務
*/
Map<String, Object> paramMap = taskService.getVariables(taskId);
request.setAttribute("task", task);
request.setAttribute("paramMap", paramMap);
return "manageAudit";
}
/**
* <p>
* 上級審核
* </p>
*
* @param request 請求
* @return String 受理結果
* @author FRH
* @time 2018年12月10日上午11:19:44
* @version 1.0
*/
@ResponseBody
@RequestMapping(value = "/higherLevelAudit")
public String higherLevelAudit(HttpServletRequest request) {
/*
* 獲取請求參數
*/
String taskId = request.getParameter("taskId");
String higherLevelOpinion = request.getParameter("sug");
String auditStr = request.getParameter("audit");
logger.info("上級審核任務ID:{}", taskId);
if (StringUtils.isBlank(taskId))
return "fail";
/*
* 查找任務
*/
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
logger.info("審核任務ID:{}查詢到任務為空!", taskId);
return "fail";
}
/*
* 設置局部變量參數,完成任務
*/
Map<String, Object> map = new HashMap<String, Object>();
map.put("audit", "1".equals(auditStr) ? false : true);
map.put("higherLevelOpinion", higherLevelOpinion);
taskService.complete(taskId, map);
return "success";
}
/**
* <p>
* 部門經理審核
* </p>
*
* @param request 請求
* @return String 受理結果
* @author FRH
* @time 2018年12月10日上午11:20:44
* @version 1.0
*/
@ResponseBody
@RequestMapping(value = "/divisionManagerAudit")
public String divisionManagerAudit(HttpServletRequest request) {
/*
* 獲取請求參數
*/
String taskId = request.getParameter("taskId");
String opinion = request.getParameter("sug");
String auditStr = request.getParameter("audit");
logger.info("上級審核任務ID:{}", taskId);
if (StringUtils.isBlank(taskId))
return "fail";
/*
* 查找任務
*/
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
logger.info("審核任務ID:{}查詢到任務為空!", taskId);
return "fail";
}
/*
* 設置局部變量參數,完成任務
*/
Map<String, Object> map = new HashMap<String, Object>();
map.put("audit", "1".equals(auditStr) ? false : true);
map.put("managerOpinion", opinion);
taskService.complete(taskId, map);
return "success";
}
/**
* <p>
* 查看任務
* </p>
*
* @param request 請求
* @return String 任務展示頁面
* @author FRH
* @time 2018年12月10日上午11:21:33
* @version 1.0
*/
@RequestMapping(value = "/toShowTask")
public String toShowTask(HttpServletRequest request) {
/*
* 獲取請求參數
*/
List<Task> taskList = taskService.createTaskQuery().list();
if (taskList == null || taskList.size() == 0) {
logger.info("查詢任務列表為空!");
return "/task";
}
/*
* 查詢所有任務,并封裝
*/
List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
for (Task task : taskList) {
Map<String, String> map = new HashMap<String, String>();
map.put("taskId", task.getId());
map.put("name", task.getName());
map.put("createTime", task.getCreateTime().toString());
map.put("assignee", task.getAssignee());
map.put("instanceId", task.getProcessInstanceId());
map.put("executionId", task.getExecutionId());
map.put("definitionId", task.getProcessDefinitionId());
resultList.add(map);
}
/*
* 返回結果
*/
logger.info("返回集合:{}", resultList.toString());
request.setAttribute("resultList", resultList);
return "/task";
}
/**
* <p>
* 輸出圖像
* </p>
*
* @param response 響應實體
* @param bpmnModel 圖像對象
* @param flowIds 已執行的線集合
* @param executedActivityIdList void 已執行的節點ID集合
* @author FRH
* @time 2018年12月10日上午11:23:01
* @version 1.0
*/
private void outputImg(HttpServletResponse response, BpmnModel bpmnModel, List<String> flowIds,
List<String> executedActivityIdList) {
InputStream imageStream = null;
try {
imageStream = processDiagramGenerator.generateDiagram(bpmnModel, executedActivityIdList, flowIds, "宋體",
"微軟雅黑", "黑體", true, "png");
// 輸出資源內容到相應對象
byte[] b = new byte[1024];
int len;
while ((len = imageStream.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
response.getOutputStream().flush();
} catch (Exception e) {
logger.error("流程圖輸出異常!", e);
} finally { // 流關閉
try {
imageStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* <p>
* 判斷流程是否完成
* </p>
*
* @param processInstanceId 流程實例ID
* @return boolean 已完成-true,未完成-false
* @author FRH
* @time 2018年12月10日上午11:23:26
* @version 1.0
*/
public boolean isFinished(String processInstanceId) {
return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId)
.count() > 0;
}
```
- 引入篇
- 基礎篇
- 快速入手
- 名詞解釋
- Vue語法
- Vue安裝
- Vue實例
- 模板語法
- 計算屬性和偵聽器
- Class與Style綁定
- 條件渲染
- 列表渲染
- 事件處理
- 表單輸入綁定
- 組件基礎
- 進階篇
- 常用模塊
- 單文件組件
- 快速學會Vue Router路由
- Vue Route 進階使用
- Vuex 與狀態管理
- Axios
- Mock.js
- data數據顯示在頁面
- Vue生命周期
- Vue按需加載組件
- 國際化
- 頁面加載進度條 -NProgress
- 自定義主題顏色
- 開發篇
- Vue入門——創建并運行一個Vue項目
- Vue + Element UI 項目創建
- 使用Vue ui項目創建工具在網頁中創建Vue項目
- Vue項目創建入門實例
- Vue CLI
- 創建項目
- 使用Visual Studio Code 開發Vue項目
- 高級篇
- 組件深入
- Vue+Element
- Vue + ElementUI 主題顏色切換
- 工具篇
- 在線代碼編輯器
- 開發工具(IDE,集成開發環境)
- npm(JavaScript包管理工具)介紹
- Node.js(npm)在Windows下安裝
- webpack介紹
- webpack快速實例
- webpack
- 快速入門實例
- 安裝
- 概念
- Nodejs
- 基礎
- npm
- 命令參考
- 命令
- 模塊安裝
- Babel
- 問題解決篇
- ERROR Failed to get response from https://registry.yarnpkg.com/vue-cli-version -marker
- Vue常見問題
- You are using the runtime-only build of Vue where the template compiler is not
- yarn 報unable to get local issuer certificate
- yarn There appears to be trouble with your network connection. Retrying
- Expected Boolean, got String with value "true".
- 項目篇
- 項目創建
- 項目設計
- 頁面
- 開發問題
- 后端
- Spring Boot + Activiti 工作流框架搭建之一
- Spring Boot + Activiti 工作流框架搭建之二
- 工作流
- Java流程框架
- Activiti
- 頁面風格
- green
- blue
- orange
- 參考篇
- 好的Git項目
- Vue的在線js
- 指令
- 開發說明
- JavaScript 高級
- export和import
- JS模塊化規范對比以及在Node.js的實現
- Storage
- ES2015
- scss
- CSS、Sass、SCSS