0%

防止重复提交

防止重复提交

防止重复提交

前端

节流

  • 解释:持续触发高频事件,函数每n秒执行一次。

  • 业务场景

    输入框的模糊查询

  • 目的

    节约流量、内存的损耗,旨在提升性能,在高频率频发的事件中才会用到。

防抖

持续触发高频事件,函数只会执行一次。

后端

  • 目的:防止绕过前端校验持续访问接口。

  • 实现

    1. 切面类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      package com.xiaoruiit.common.aop;

      import com.alibaba.druid.util.StringUtils;
      import com.xiaoruiit.common.utils.IPUtil;
      import com.xiaoruiit.common.utils.IdWorker;
      import com.xiaoruiit.common.utils.Result;
      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.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.concurrent.TimeUnit;

      /**
      * @author hxr
      */
      @Component
      @Aspect // 定义切面类
      public class AvoidDuplicateSubmitAspect {
      @Autowired
      private RedisTemplate redisTemplate;

      @Around("@annotation(com.xiaoruiit.common.aop.AvoidDuplicateSubmit)")
      public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
      // 获取request对象
      HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
      String ip = IPUtil.getIP(request);
      // 获取方法签名
      MethodSignature signature = (MethodSignature) joinPoint.getSignature();
      Method method = signature.getMethod();

      String className = method.getDeclaringClass().getName();
      String methodName = method.getName();
      String ipKey = String.format("%s#%s", className, methodName);
      int hashCode = Math.abs(ipKey.hashCode());
      // 拼接redisKey,如:127.0.0.1_1234984393
      String redisKey = String.format("%s_%d", ip, hashCode);

      String value = (String) redisTemplate.opsForValue().get(redisKey);
      if (!StringUtils.isEmpty(value)) {
      return Result.validateFailed("请勿重复提交");
      }

      // 获取注解
      AvoidDuplicateSubmit avoidDuplicateSubmit = method.getAnnotation(AvoidDuplicateSubmit.class);
      long timeout = avoidDuplicateSubmit.timeout();
      if (timeout < 0) {
      timeout = 5000;
      }
      // 第一次提交,插入redis
      redisTemplate.opsForValue().set(redisKey, IdWorker.nextId(), timeout, TimeUnit.MILLISECONDS);
      // 继续执行方法
      return joinPoint.proceed();
      }

      }
    2. 注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      package com.xiaoruiit.common.aop;

      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;

      /**
      * @author hxr
      */
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface AvoidDuplicateSubmit {
      /**
      * 指定时间内不可重复提交,单位毫秒
      * @return
      */
      long timeout() default 5000;
      }
  • 使用

    1
    2
    3
    方法上加注解 @AvoidDuplicateSubmit
    @AvoidDuplicateSubmit 默认时间5000毫秒
    @AvoidDuplicateSubmit(timeout = 100000) 单位毫秒自己设置控制时间

获取IP真实地址

代理服务器结合java代码

  • 1.nginx配置

    参考:https://segmentfault.com/a/1190000019197577

  • java代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    private static final String[] HEADERS_TO_TRY = {
    "X-Forwarded-For",
    "Proxy-Client-IP",
    "WL-Proxy-Client-IP",
    "HTTP_X_FORWARDED_FOR",
    "HTTP_X_FORWARDED",
    "HTTP_X_CLUSTER_CLIENT_IP",
    "HTTP_CLIENT_IP",
    "HTTP_FORWARDED_FOR",
    "HTTP_FORWARDED",
    "HTTP_VIA",
    "REMOTE_ADDR" };

    private String getClientIpAddress(HttpServletRequest request) {
    for (String header : HEADERS_TO_TRY) {
    String ip = request.getHeader(header);
    if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
    return ip;
    }
    }

    return request.getRemoteAddr();
    }