From 954f36d98228df6db4f83552dac0f43790793260 Mon Sep 17 00:00:00 2001 From: wangli Date: Sat, 9 Dec 2023 22:39:27 +0800 Subject: [PATCH] =?UTF-8?q?update=20-=20=E6=B7=BB=E5=8A=A0=E9=98=B2?= =?UTF-8?q?=E9=87=8D=E6=8F=90=E4=BA=A4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/BpmnProcessTaskServiceImpl.java | 18 ++++- .../common/annotation/RepeatSubmit.java | 27 +++++++ .../server/common/config/ResourcesConfig.java | 25 ++++++ .../intercepter/RepeatSubmitInterceptor.java | 60 +++++++++++++++ .../impl/SameUrlDataInterceptor.java | 76 +++++++++++++++++++ .../server/controller/web/TestController.java | 3 + .../web/bpmn/BpmnProcessTaskController.java | 39 +++++----- 7 files changed, 224 insertions(+), 24 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/RepeatSubmit.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/config/ResourcesConfig.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/RepeatSubmitInterceptor.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/impl/SameUrlDataInterceptor.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 27af65f27..a0713413e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -334,7 +334,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { taskService.complete(task.getId()); } - //add by zuoqinbo 处理加签任务,分为向前加签和向后加签 + //add by zuoqinbo 处理加签[分为向前加签和向后加签]或转交的任务 String parentTaskId = task.getParentTaskId(); if (StringUtils.hasLength(parentTaskId)) { List subTasks = taskService.getSubTasks(parentTaskId); @@ -356,13 +356,25 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { this.createSubTask(taskEntity, parentTaskId, remainAssigner); taskService.setVariable(taskEntity.getId(), COUNTERSIGN_REMAIN_ASSIGNER_LIST, remainAssignerList); } else { - // TODO 这里还需要递归上去直到没有 parentId - taskService.complete(parentTaskId); + // 递归上去直到没有 parentId + recursionCompleteParentTask(parentTaskId); } } } } + private void recursionCompleteParentTask(String parentTaskId) { + if (!StringUtils.hasLength(parentTaskId)) { + return; + } + taskService.complete(parentTaskId); + Task parentTask = getTask(parentTaskId, null, null); + if (Objects.nonNull(parentTask)) { + recursionCompleteParentTask(parentTaskId); + } + } + + /** * 创建加签子任务 * A加签给A A再加签给A diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/RepeatSubmit.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/RepeatSubmit.java new file mode 100644 index 000000000..66824cc31 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/RepeatSubmit.java @@ -0,0 +1,27 @@ +package cn.axzo.workflow.server.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解防止表单重复提交 + * + * @author wangli + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + int interval() default 5000; + + /** + * 提示消息 + */ + String message() default "不允许重复提交,请稍后再试"; +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/config/ResourcesConfig.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/config/ResourcesConfig.java new file mode 100644 index 000000000..c2fa00d56 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/config/ResourcesConfig.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.server.common.config; + +import cn.axzo.workflow.server.common.intercepter.RepeatSubmitInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.annotation.Resource; + +/** + * 通用配置 + * + * @author wangli + * @since 2023/12/9 22:18 + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer { + @Resource + private RepeatSubmitInterceptor repeatSubmitInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/RepeatSubmitInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/RepeatSubmitInterceptor.java new file mode 100644 index 000000000..572e3c768 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/RepeatSubmitInterceptor.java @@ -0,0 +1,60 @@ +package cn.axzo.workflow.server.common.intercepter; + +import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; + +/** + * 防止重复提交拦截器 + * + * @author wangli + */ +@Component +public abstract class RepeatSubmitInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) { + if (this.isRepeatSubmit(request, annotation)) { + CommonResponse commonResponse = CommonResponse.error(annotation.message()); + renderString(response, JSON.toJSONString(commonResponse)); + return false; + } + } + return true; + } else { + return true; + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param request 请求对象 + * @param annotation 防复注解 + * @return 结果 + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception; + + private static String renderString(HttpServletResponse response, String string) { + try { + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/impl/SameUrlDataInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/impl/SameUrlDataInterceptor.java new file mode 100644 index 000000000..b3c9a1a31 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/intercepter/impl/SameUrlDataInterceptor.java @@ -0,0 +1,76 @@ +package cn.axzo.workflow.server.common.intercepter.impl; + +import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.axzo.workflow.server.common.intercepter.RepeatSubmitInterceptor; +import com.alibaba.fastjson.JSON; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.HashMap; +import java.util.Map; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author ruoyi + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor { + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + public final String SESSION_REPEAT_KEY = "repeatData"; + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception { + // 本次参数及系统时间 + String nowParams = JSON.toJSONString(request.getParameterMap()); + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + + // 请求地址(作为存放session的key值) + String url = request.getRequestURI(); + + HttpSession session = request.getSession(); + Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY); + if (sessionObj != null) { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) { + return true; + } + } + } + Map sessionMap = new HashMap(); + sessionMap.put(url, nowDataMap); + session.setAttribute(SESSION_REPEAT_KEY, sessionMap); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap, int interval) { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < interval) { + return true; + } + return false; + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index d3a14be89..19b840ecf 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; +import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; import org.flowable.common.engine.impl.util.IoUtil; @@ -38,12 +39,14 @@ public class TestController { @Autowired private RepositoryService repositoryService; + @RepeatSubmit @GetMapping("/test") public void test(@RequestParam String processInstanceId) { List flowElements = forecastService.performProcessForecasting(processInstanceId, null); System.out.println("flowElements = " + flowElements); } + @RepeatSubmit @GetMapping("/test2") public void test2(@RequestParam String processInstanceId) { List detailVOS = instanceService.getProcessInstanceNodeForecast(processInstanceId, "296"); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index ab922295d..542860be7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -15,6 +15,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import cn.axzo.workflow.core.service.BpmnProcessTaskService; +import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; @@ -71,6 +72,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { */ @PutMapping("/approve") @Override + @RepeatSubmit public CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto) { log.info("同意 approveTask===>>>参数:{}", dto); bpmnProcessTaskService.approveTask(dto); @@ -82,6 +84,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { */ @PutMapping("/reject") @Override + @RepeatSubmit public CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto) { log.info("驳回 rejectTask===>>>参数:{}", dto); bpmnProcessTaskService.rejectTask(dto); @@ -94,6 +97,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @Operation(summary = "直接修改审批任务的审批人") @PutMapping("/transfer") @Override + @RepeatSubmit public CommonResponse transferTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto) { bpmnProcessTaskService.transferTask(dto); return success(true); @@ -102,7 +106,10 @@ public class BpmnProcessTaskController implements ProcessTaskApi { /** * 评论 */ + @Operation(summary = "审批流程评论") + @PutMapping("/comment") @Override + @RepeatSubmit public CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO commentDTO) { bpmnProcessTaskService.commentTask(commentDTO); return success(true); @@ -112,40 +119,30 @@ public class BpmnProcessTaskController implements ProcessTaskApi { /** * 加签 */ + @Operation(summary = "审批任务加签") @Override @PutMapping("/countersign") + @RepeatSubmit public CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) { bpmnProcessTaskService.countersignTask(countersignDTO); return success(true); } + /** + * 催办 + * + * @param dto + * @return + */ + @Operation(summary = "审批流程催办") + @PutMapping("/api/process/task/remind") @Override + @RepeatSubmit public CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto) { bpmnProcessTaskService.remindTask(dto); return success(true); } - // @Override -// public CommonResponse copyTask(BpmnTaskAssigneeDTO dto) { -// return null; -// } -// -// @Override -// public CommonResponse rollbackTask(BpmnTaskAssigneeDTO dto) { -// return null; -// } -// -// @Override -// public CommonResponse revocationTask(BpmnTaskAssigneeDTO dto) { -// return null; -// } -// -// @Override -// public CommonResponse remindTask(BpmnTaskAssigneeDTO dto) { -// return null; -// } - - /** * 获取指定流程实例的审批过程信息 *