Spring AOP方式フォームの重複提出防止

21875 ワード

実現原理:
  • カスタム重複コミット防止フラグ(@AvoidRepeatableCommit).
  • この注釈は、重複コミットを防止する必要があるCongtroller内のmappingメソッドに加えられる.
  • Aspect切り込みポイントを追加し、@AvoidRepeatableCommitに切り込みポイントを追加します.
  • フォームが発行されるたびに、Aspectは現在のキーをreidsに保存します(有効期限を設定する必要があります).
  • 繰り返しコミットすると、Aspectは現在のredisにそのキーがあるかどうかを判断し、ある場合はブロックします.

  • カスタムラベル
    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/>