package mpaasapp.aspect;
import java.lang.annotation.*;
/**
* 限制重复点击
* @author lixh
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BpmFlowRestriction {
String msg();
int ttl();
}
package mpaasapp.aspect;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import mpaasapp.exception.BaseException;
import mpaasapp.utils.constants.CacheConstants;
import mpaasapp.utils.redis.RedisService;
import mpaasapp.utils.result.ResultCode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
/**
* @author lixh
*/
@Aspect
@Component
@Order(3)
@Slf4j
public class FlowRestrictionAspect {
@Autowired
private RedisService redisService;
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Pointcut(value = "@annotation(mpaasapp.aspect.BpmFlowRestriction)")
public void methodPointcut(){}
@Around(value = "methodPointcut() && @annotation(flowRestriction)")
public Object around(ProceedingJoinPoint jp,BpmFlowRestriction flowRestriction) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Object result = null;
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("authorization");
Object userId = redisService.get(CacheConstants.ACCESS_TOKEN + token);
if (StringUtils.isEmpty(token) || userId == null) {
throw new BaseException(ResultCode.UN_AUTHORIZED, ResultCode.UN_AUTHORIZED.getMessage(), "".equals(token) ? null : token);
}
//获取项目的根路径后的接口路径
String servletPath = request.getServletPath();
String key = userId + "_" + JSONObject.toJSONString(servletPath);
log.info("BpmFlowRestriction-key为:{}",key);
//防止重复点击
Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(key, userId, flowRestriction.ttl(), TimeUnit.SECONDS);
if(Boolean.FALSE.equals(ifAbsent)){
throw new BaseException(flowRestriction.msg());
}
try {
result = jp.proceed();
} finally {
redisTemplate.delete(key);
}
}
return result;
}
}
调用
@BpmFlowRestriction(msg = "提交出差申请频繁,请稍后再试~",ttl = 8)
@ApiOperation("提交-出差申请")
@PostMapping("/submitEvectionApply")
public R<Long> submitEvectionApply(HttpServletRequest request, @RequestBody EvectionApplyModel evectionApplyModel) throws Exception {
restrictingAccess(evectionApplyModel);
Assert.notNull(evectionApplyModel);
Assert.notNull(evectionApplyModel.getEvectionApply(), "申请单基础信息不能为空");
Integer userId = (Integer) redisService.get(CacheConstants.ACCESS_TOKEN + request.getHeader("authorization"));
Assert.fail(userId == null , "获取用户APPID失败!");
//检测该用户下是否有异常单据
List<AppErrorLog> list = appErrorLogService.list(new QueryWrapper<AppErrorLog>().eq("user_id", userId).eq("error_code", AppErrorLogEnum.EVCTION_APPLY.getCode()));
if(!list.isEmpty()){
throw new BaseException("您的商旅账号存在问题,请联系科技部处理~");
}
evectionApplyModel.getEvectionApply().setApplyUserId(Long.valueOf(userId));
// 说明:不能因为校验执行异常,程序执行失败,必须保障容错;先满足业务正常流转
// 行程校验:相同起止日期 出现次数是否超限
dingtalkEvectionApplyService.tripDateOverrunVerification(evectionApplyModel.getTripInfoItem());
// 加载用户UPMS信息:出差申请单-同步UPMS信息
dingtalkEvectionApplyService.assembleUPMSUserInfo(evectionApplyModel);
//获取主体参数
appFirmService.getAppFirmByFirmId(evectionApplyModel);
// 保存出差申请单
evectionApplyModel.getEvectionApply().setEvectionStatus(EvectionStatusEnum.UNDER_APPROVAL.getEvectionStatus());
// 保存(添加/修改)出差申请单
dingtalkEvectionApplyService.saveEvectionApply(evectionApplyModel);
try {
// 出差申请单 ->> 同步钉钉商旅
dingtalkEvectionApplyService.aliTripDataNotify(evectionApplyModel, evectionApplyModel.getEvectionApply().getEvectionApplyId(), 0l);
// 数据同步至 hodometer
dingtalkEvectionApplyService.hodometerDataNotify(evectionApplyModel, evectionApplyModel.getEvectionApply().getEvectionApplyId());
// 发起工作流
Integer auditPathKey = dingtalkEvectionApplyService.startBpm(evectionApplyModel, evectionApplyModel.getEvectionApply().getEvectionApplyId());
// 工作流数据同步:钉钉商旅/hodometer
dingtalkEvectionApplyService.bpmDataNotify(auditPathKey, evectionApplyModel, evectionApplyModel.getEvectionApply().getEvectionApplyId());
// 给相关审批领导发送待办
//dingtalkEvectionApplyService.submitEvectionApplySendToBacklog(evectionApplyModel, evectionApplyModel.getEvectionApply().getEvectionApplyId());
} catch (Exception ex) {
if (ex instanceof BaseException) {
evectionApplyModel.getEvectionApply().setEvectionStatus(((BaseException) ex).getCode());
}
evectionApplyModel.setException(ex);
appErrorLogService.saveErrorLogByEvectionApply(evectionApplyModel);
throw ex;
} finally {
dingtalkEvectionApplyService.updateDingtalkEvectionApply(evectionApplyModel.getEvectionApply());
}
return new R<>(evectionApplyModel.getEvectionApply().getEvectionApplyId());
}