##
* 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