From 2607f13abeb65f3ae7c2174ad3b9d8c4c0e362f7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Jan 2022 08:27:22 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=96=B0=E5=A2=9E=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E6=96=B0=E5=BB=BA=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceController.http | 13 +++ .../task/BpmProcessInstanceController.java | 35 ++++++ .../BpmProcessInstanceCreateReqVO.java | 23 ++++ .../BpmProcessInstanceMyPageReqVO.java | 6 ++ .../bpm/enums/BpmErrorCodeConstants.java | 10 +- .../task/BpmProcessInstanceService.java | 23 ++++ .../impl/BpmProcessInstanceServiceImpl.java | 100 ++++++++++++++++++ .../system/service/user/SysUserService.java | 8 ++ .../service/user/impl/SysUserServiceImpl.java | 5 + .../core/util/SecurityFrameworkUtils.java | 20 ++-- 10 files changed, 229 insertions(+), 14 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http new file mode 100644 index 000000000..f1a8c0e0c --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http @@ -0,0 +1,13 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/bpm/process-instance/create +Content-Type: application/json +tenant-id: 1 +Authorization: Bearer {{token}} + +{ + "processDefinitionId": "leave:7:20ada39c-6c95-11ec-88b1-cacd34981f8e", + "variables": { + "a": 1, + "b": "2" + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java new file mode 100644 index 000000000..2b8d757d3 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task; + +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "流程实例") // 流程实例,通过流程定义创建的一次“申请” +@RestController +@RequestMapping("/bpm/process-instance") +@Validated +public class BpmProcessInstanceController { + + @Resource + private BpmProcessInstanceService processInstanceService; + + @PostMapping("/create") + @ApiOperation("新建流程实例") + public CommonResult createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { + return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO)); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java new file mode 100644 index 000000000..29620d2e8 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Map; + +@ApiModel("流程实例的创建 Request VO") +@Data +//@EqualsAndHashCode(callSuper = true) +//@ToString(callSuper = true) +public class BpmProcessInstanceCreateReqVO { + + @ApiModelProperty(value = "流程定义的编号", required = true, example = "1024") + @NotEmpty(message = "流程定义编号不能为空") + private String processDefinitionId; + + @ApiModelProperty(value = "变量实例") + private Map variables; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java new file mode 100644 index 000000000..01d16098f --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java @@ -0,0 +1,6 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +public class BpmProcessInstanceMyPageReqVO extends PageParam { +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java index 7706c9c0a..0e78583b3 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java @@ -31,9 +31,13 @@ public interface BpmErrorCodeConstants { ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图"); ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1009003001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图"); ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1009003002, "流程定义不存在"); + ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003002, "流程定义处于挂起状态"); - // ========== 动态表单模块 1-009-004-000 ========== - ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009004000, "动态表单不存在"); - ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009004000, "表单项({}) 和 ({}) 使用了相同的字段名({})"); + // ========== 流程实例 1-009-004-000 ========== + + + // ========== 动态表单模块 1-009-010-000 ========== + ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在"); + ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010000, "表单项({}) 和 ({}) 使用了相同的字段名({})"); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java new file mode 100644 index 000000000..de10dbddd --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.task; + +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO; + +import javax.validation.Valid; + +/** + * 流程实例 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessInstanceService { + + /** + * 创建流程实例 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java new file mode 100644 index 000000000..d3c6b2d4d --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService; +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; +import lombok.extern.slf4j.Slf4j; +import org.activiti.engine.HistoryService; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.TaskService; +import org.activiti.engine.history.HistoricProcessInstanceQuery; +import org.activiti.engine.impl.identity.Authentication; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Task; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_IS_SUSPENDED; +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 流程实例 Service 实现类 + * + * ProcessDefinition & ProcessInstance & Execution & Task 的关系: + * 1. https://blog.csdn.net/bobozai86/article/details/105210414 + * + * HistoricProcessInstance & ProcessInstance 的关系: + * 1.https://my.oschina.net/843294669/blog/719024 + * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { + + @Resource + private RepositoryService repositoryService; + @Resource + private RuntimeService runtimeService; + @Resource + private TaskService taskService; + @Resource + private HistoryService historyService; + + @Resource + private SysUserService userService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + + @Override + public String createProcessInstance(Long userId, BpmProcessInstanceCreateReqVO createReqVO) { + // 校验流程定义 + ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); + if (definition == null) { + throw exception(PROCESS_DEFINITION_NOT_EXISTS); + } + if (definition.isSuspended()) { + throw exception(PROCESS_DEFINITION_IS_SUSPENDED); + } + + // 设置流程发起人 + Authentication.setAuthenticatedUserId(String.valueOf(userId)); + + // 创建流程实例 + Map variables = createReqVO.getVariables(); + variables.put("INITIATOR", userId); // TODO 芋艿:初始化人员 + ProcessInstance instance = runtimeService.startProcessInstanceById(createReqVO.getProcessDefinitionId(), variables); + + // 添加初始的评论 TODO 芋艿:在思考下 + Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult(); + if (task != null) { + SysUserDO user = userService.getUser(userId); + Assert.notNull(user, "用户({})不存在", userId); + String type = "normal"; + taskService.addComment(task.getId(), instance.getProcessInstanceId(), type, + String.format("%s 发起流程申请", user.getNickname())); + // TODO 芋艿:应该不用下面两个步骤 +// taskService.setAssignee(task.getId(), String.valueOf(userId)); +// taskService.complete(task.getId(), variables); + } + return instance.getId(); + } + + public void getMyProcessInstancePage(Long userId) { + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() + .startedBy(String.valueOf(userId)) // 发起人是自己 + .orderByProcessInstanceStartTime().desc(); // 按照发起时间倒序 + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java index a9c0acb82..e95d102ad 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java @@ -107,6 +107,14 @@ public interface SysUserService { */ PageResult getUserPage(SysUserPageReqVO reqVO); + /** + * 获得用户 + * + * @param id 用户编号 + * @return 用户 + */ + SysUserDO getUser(Long id); + /** * 获得用户列表 * diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java index 8901ca022..61bca4cfb 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java @@ -164,6 +164,11 @@ public class SysUserServiceImpl implements SysUserService { return userMapper.selectPage(reqVO, this.getDeptCondition(reqVO.getDeptId())); } + @Override + public SysUserDO getUser(Long id) { + return userMapper.selectById(id); + } + @Override public List getUsers(SysUserExportReqVO reqVO) { return userMapper.selectList(reqVO, this.getDeptCondition(reqVO.getDeptId())); diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java index 1d2ee23c3..f008acf81 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.security.core.util; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import org.springframework.lang.Nullable; @@ -12,7 +11,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; -import java.util.Objects; import java.util.Set; /** @@ -100,15 +98,15 @@ public class SecurityFrameworkUtils { // 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息 WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); - // TODO @jason:使用 userId 会不会更合适哈? - // TODO @芋艿:activiti 需要使用 ttl 上下文 - // TODO @jason:清理问题 - if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) { - org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); - } - // TODO @芋道源码 该值被赋值给 user task 中assignee , username 显示更直白一点 - // TODO @jason:有办法设置 userId,然后 activiti 有地方读取到 username 么?毕竟 username 只是 User 的登陆账号,并不能绝对像 userId 代表一个用户 - org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); +// // TODO @jason:使用 userId 会不会更合适哈? +// // TODO @芋艿:activiti 需要使用 ttl 上下文 +// // TODO @jason:清理问题 +// if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) { +// org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); +// } +// // TODO @芋道源码 该值被赋值给 user task 中assignee , username 显示更直白一点 +// // TODO @jason:有办法设置 userId,然后 activiti 有地方读取到 username 么?毕竟 username 只是 User 的登陆账号,并不能绝对像 userId 代表一个用户 +// org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); } }