Commit 4b121214 by 陶湘宇

修复重复提交问题

parent f792cf8d
package cn.timer.api.aspect;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import cn.timer.api.config.annotation.RepeatSubmit;
import cn.timer.api.controller.dzht.cn.tign.hz.constant.CacheKeyConstant;
import lombok.extern.slf4j.Slf4j;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@Aspect
public class NoRepeatSubmitAspect {
@Autowired
private RedisTemplate redisTemplate;
/**
* 定义切点
*/
@Pointcut("@annotation(cn.timer.api.config.annotation.RepeatSubmit)")
public void preventDuplication() {}
@Around("preventDuplication()")
public Object around(ProceedingJoinPoint joinPoint) throws Exception {
/**
* 获取请求信息
*/
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 获取执行方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//获取防重复提交注解
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
// 获取token以及方法标记,生成redisKey和redisValue
String token = BeanUtil.toBean(request.getSession().getAttribute(CacheKeyConstant.TOKEN), String.class);
//String refreshToken = BeanUtil.toBean(request.getSession().getAttribute(CacheKeyConstant.REFRESH_TOKEN), String.class);
String url = request.getRequestURI();
/**
* 通过前缀 + url + token + 函数参数签名 来生成redis上的 key
*
*/
String redisKey = CacheKeyConstant.PREVENT_DUPLICATION_PREFIX
.concat(url)
.concat(token)
.concat(getMethodSign(method, joinPoint.getArgs()));
// 这个值只是为了标记,不重要
String redisValue = redisKey.concat(annotation.value()).concat("submit duplication");
if (!redisTemplate.hasKey(redisKey)) {
// 设置防重复操作限时标记(前置通知)
redisTemplate.opsForValue()
.set(redisKey, redisValue, annotation.expireSeconds(), TimeUnit.SECONDS);
try {
//正常执行方法并返回
//ProceedingJoinPoint类型参数可以决定是否执行目标方法,
// 且环绕通知必须要有返回值,返回值即为目标方法的返回值
return joinPoint.proceed();
} catch (Throwable throwable) {
//确保方法执行异常实时释放限时标记(异常后置通知)
redisTemplate.delete(redisKey);
throw new RuntimeException(throwable);
}
} else {
// 重复提交了抛出异常,如果是在项目中,根据具体情况处理。
throw new RuntimeException("请勿重复提交");
}
}
/**
* 生成方法标记:采用数字签名算法SHA1对方法签名字符串加签
*
* @param method
* @param args
* @return
*/
private String getMethodSign(Method method, Object... args) {
StringBuilder sb = new StringBuilder(method.toString());
for (Object arg : args) {
sb.append(toString(arg));
}
return DigestUtil.sha1Hex(sb.toString());
}
private String toString(Object arg) {
if (Objects.isNull(arg)) {
return "null";
}
if (arg instanceof Number) {
return arg.toString();
}
return JSONUtil.toJsonStr(arg);
}
}
\ No newline at end of file
......@@ -66,7 +66,7 @@ public class RequestAop {
long endTime = System.currentTimeMillis();
this.logInfo2Kafka(request, url, bodyArgs, urlArgs, "success", 0, endTime - startTime, true);
} catch (Throwable e) {
e.printStackTrace();
log.error("requestAOPException:",e.getStackTrace());
long endTime = System.currentTimeMillis();
if (e instanceof CustomException) {
/**
......@@ -97,8 +97,6 @@ public class RequestAop {
* @author Rex.Tan
* @date 2018年12月13日 下午2:51:31
* @param url 请求地址
* @param args requestBody中的参数
* @param args2 url中的参数
* @param message 消息
* @param status 接口调用返回状态
* @param executionTime 执行耗时
......
package cn.timer.api.config.annotation;
import java.lang.annotation.*;
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {
/**
* 防重复操作限时标记数值(存储redis限时标记数值)
*/
String value() default "value" ;
/**
* 防重复操作过期时间(借助redis实现限时控制)
*/
long expireSeconds() default 10;
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package cn.timer.api.config.interceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
......@@ -18,6 +19,7 @@ import cn.timer.api.config.annotation.UserBean;
import cn.timer.api.controller.dzht.cn.tign.hz.constant.CacheKeyConstant;
import cn.timer.api.dto.yggl.UserInfo;
@Slf4j
@Component
public class UserMethodArgumentResolver implements HandlerMethodArgumentResolver {
......@@ -49,6 +51,7 @@ public class UserMethodArgumentResolver implements HandlerMethodArgumentResolver
// NativeWebRequest.SCOPE_SESSION);
YgglMainEmp mE = eld.getYgglMainEmp();
log.info("name="+mE.getName()+"Phone="+mE.getPhone()+"BmgwId"+mE.getBmgwId());
UserInfo userInfo = UserInfo.builder().name(mE.getName()).phone(mE.getPhone()).bmgwId(mE.getBmgwId()).build();
return UserBean.builder().token(token).refreshToken(refreshToken).empNum(eld.getId())
......
......@@ -17,4 +17,6 @@ public class CacheKeyConstant {
*/
public static final String REFRESH_TOKEN = "REFRESH_TOKEN";
public static final String PREVENT_DUPLICATION_PREFIX = "PREVENT_DUPLICATION_PREFIX:";
}
......@@ -12,6 +12,7 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -76,6 +77,7 @@ import cn.timer.api.utils.ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@Slf4j
@Api(tags = "3.0[3]考勤打卡")
@RestController
@Transactional
......@@ -157,6 +159,12 @@ public class ClockInController {
ClockCollectData clockt = new ClockCollectData();
//putime: 根据日期 得到打卡所需的详细信息
AttendanceCardListDto attdate = MethodCall(qyid,userid,ClockInTool.paraseStringToDate(sStdIoTime,"yyyy-MM-dd HH:mm:SS"));
if(attdate==null||attdate.getAttsch()==null||attdate.getAttsch().size()<1){
msg = "没有排班信息";
log.error("排班信息没取到attdate=null,qyid="+qyid+"userid="+userid+"时间="+ClockInTool.paraseStringToDate(sStdIoTime,"yyyy-MM-dd HH:mm:SS"));
return ResultUtil.error(msg);
}
// = new SimpleDateFormat("yyyy-MM-dd").format(sStdIoTime);//转换打卡时间格式 年月日
Long puttimeTmp=0L;
if (attdate!=null&&attdate.getAttsch()!=null&&attdate.getAttsch().get(0)!=null)
......@@ -3422,13 +3430,14 @@ public class ClockInController {
KqglAssoDkjl dk = KqglAssoDkjl.builder().build().selectOne(new QueryWrapper<KqglAssoDkjl>().lambda().eq(KqglAssoDkjl::getQyid, userBean.getOrgCode())
.eq(KqglAssoDkjl::getUserId, userBean.getEmpNum()).ge(KqglAssoDkjl::getDktime, startDate).le(KqglAssoDkjl::getDktime, endDate)
.ne(KqglAssoDkjl::getSort, 0).ne(KqglAssoDkjl::getStatus, 2).ne(KqglAssoDkjl::getStatus, 0)
.orderByDesc(KqglAssoDkjl::getSort).last("LIMIT 1"));
.orderByDesc(KqglAssoDkjl::getSort).last("limit 1"));
if(dk != null) {
AttSchedule att = attsch.get(dk.getSort()-1);
att.setIsupdate(1);
AttSchedule attw = attsch.get(dk.getSort()-2);
attw.setIsupdate(0);
if (dk.getSort()>1) {
AttSchedule attw = attsch.get(dk.getSort() - 2);
attw.setIsupdate(0);
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment