spring AOP方式防止表单重复提交

实现原理:

  1. 自定义防止重复提交标记(@AvoidRepeatableCommit)。
  2. 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
  3. 新增Aspect切入点,为@AvoidRepeatableCommit加入切入点。
  4. 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
  5. 重复提交时Aspect会判断当前redis是否有该key,若有则拦截。

自定义标签

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/>

你可能感兴趣的:(spring AOP方式防止表单重复提交)