Spring AOP方式フォームの重複提出防止
21875 ワード
実現原理:カスタム重複コミット防止フラグ(@AvoidRepeatableCommit). この注釈は、重複コミットを防止する必要があるCongtroller内のmappingメソッドに加えられる. Aspect切り込みポイントを追加し、@AvoidRepeatableCommitに切り込みポイントを追加します. フォームが発行されるたびに、Aspectは現在のキーをreidsに保存します(有効期限を設定する必要があります). 繰り返しコミットすると、Aspectは現在のredisにそのキーがあるかどうかを判断し、ある場合はブロックします.
カスタムラベル
カスタムカットポイントAspect
spring mvcプロファイルを見つけます
プロファイルに追加
カスタムラベル
package com.youxiang.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @InterfaceName: AvoidRepeatableCommit
* @Description:
* @Author youxiang
* @Date 2020/4/9 15:58
* @Copyright niwodai © 2019
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidRepeatableCommit {
/**
* ,
* @return
*/
long timeout() default 3;
}
カスタムカットポイントAspect
package com.youxiang.common;
import org.springframework.data.redis.core.RedisTemplate;
import com.youxiang.exception.BusinessException;
import com.youxiang.util.UUIDUtil;
import com.youxiang.util.IpUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @ClassName: AvoidRepeatableCommitAspect
* @Description: aop
* @Author youxiang
* @Date 2020/4/9 16:02
* @Copyright niwodai © 2019
*/
@Aspect
@Component
public class AvoidRepeatableCommitAspect {
private static Logger log = LoggerFactory.getLogger(AvoidRepeatableCommitAspect.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* @param point
*/
@Around("@annotation(com.youxiang.common.AvoidRepeatableCommit)")
public Object around(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String ip = IpUtil.getIpAddr(request);
//
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
// 、
String className = method.getDeclaringClass().getName();
String name = method.getName();
String methodKey = String.format("%s#%s",className,name);
int hashCode = Math.abs(methodKey.hashCode());
String key = String.format("%s_%d",ip,hashCode);
log.info("methodKey={},hashCode={},key={}",methodKey,hashCode,key);
AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
long timeout = avoidRepeatableCommit.timeout();
if (timeout < 0){
// 5
timeout = 60*5;
}
Object value = redisTemplate.opsForValue().get(key);
if (value != null && StringUtils.isNotBlank(String.valueOf(value))){
throw new BusinessException(" ");
}
redisTemplate.opsForValue().set(key, UUIDUtil.uuid(), timeout, TimeUnit.SECONDS);
//
Object object = point.proceed();
return object;
}
}
spring mvcプロファイルを見つけます
<servlet>
<servlet-name>springServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
プロファイルに追加
<aop:aspectj-autoproxy proxy-target-class="true" />
<context:component-scan base-package="com.youxiang"/>
<task:annotation-driven/>