update - 添加防重提交功能

This commit is contained in:
wangli 2023-12-09 22:39:27 +08:00
parent b2ac834a9f
commit 954f36d982
7 changed files with 224 additions and 24 deletions

View File

@ -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<Task> 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

View File

@ -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 "不允许重复提交,请稍后再试";
}

View File

@ -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("/**");
}
}

View File

@ -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;
}
}

View File

@ -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<String, Object> nowDataMap = new HashMap<String, Object>();
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<String, Object> sessionMap = (Map<String, Object>) sessionObj;
if (sessionMap.containsKey(url)) {
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) {
return true;
}
}
}
Map<String, Object> sessionMap = new HashMap<String, Object>();
sessionMap.put(url, nowDataMap);
session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
return false;
}
/**
* 判断参数是否相同
*/
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) {
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
String preParams = (String) preMap.get(REPEAT_PARAMS);
return nowParams.equals(preParams);
}
/**
* 判断两次间隔时间
*/
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> 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;
}
}

View File

@ -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<FlowElement> flowElements = forecastService.performProcessForecasting(processInstanceId, null);
System.out.println("flowElements = " + flowElements);
}
@RepeatSubmit
@GetMapping("/test2")
public void test2(@RequestParam String processInstanceId) {
List<ProcessNodeDetailVO> detailVOS = instanceService.getProcessInstanceNodeForecast(processInstanceId, "296");

View File

@ -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<Boolean> 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<Boolean> 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<Boolean> 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<Boolean> 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<Boolean> 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<Boolean> remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto) {
bpmnProcessTaskService.remindTask(dto);
return success(true);
}
// @Override
// public CommonResponse<Boolean> copyTask(BpmnTaskAssigneeDTO dto) {
// return null;
// }
//
// @Override
// public CommonResponse<Boolean> rollbackTask(BpmnTaskAssigneeDTO dto) {
// return null;
// }
//
// @Override
// public CommonResponse<Boolean> revocationTask(BpmnTaskAssigneeDTO dto) {
// return null;
// }
//
// @Override
// public CommonResponse<Boolean> remindTask(BpmnTaskAssigneeDTO dto) {
// return null;
// }
/**
* 获取指定流程实例的审批过程信息
* <p>