springboot集成redis防止页面重复提交

  • Post author:
  • Post category:其他


1:配置pom文件

<!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.0.1</version>
        </dependency>

2:配置redis链接,application.yml

  redis:
    host: 192.168.0.70
    port: 6379
    password:
    database: 13
    timeout: 6000

3:添加JedisPool配置类

package com.sword.storageproduce.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @ClassName RedisCacheConfiguration
 * @Description TODO
 * @Author wangcc
 * @Date 2022/5/20 10:37
 * @Version 1.0
 **/
@Configuration
@EnableCaching
public class RedisCacheConfiguration extends CachingConfigurerSupport {
    public static final Logger logger = LoggerFactory.getLogger(RedisCacheConfiguration.class);

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.database}")
    private int database;

    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, null,database);
        return jedisPool;
    }
}

4:添加redis处理类

package com.sword.storageproduce.redis;

public interface JedisClient {

    String set(String key, String value);
    String get(String key);
    Boolean exists(String key);
    Long expire(String key, int seconds);
    Long ttl(String key);
    Long incr(String key);
    Long hset(String key, String field, String value);
    String hget(String key, String field);
    Long hdel(String key, String... field);
}
package com.sword.storageproduce.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

/**
 * @ClassName JedisClientPool
 * @Description TODO
 * @Author wangcc
 * @Date 2022/3/18 10:44
 * @Version 1.0
 **/
@Component
public class JedisClientPool implements JedisClient {

    @Autowired
    private RedisCacheConfiguration configuration;

    @Override
    public String set(String key, String value) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        String result = jedis.set(key, value);
        jedis.close();
        return result;
    }

    @Override
    public String get(String key) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        String result = jedis.get(key);
        jedis.close();
        return result;
    }

    @Override
    public Boolean exists(String key) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Boolean result = jedis.exists(key);
        jedis.close();
        return result;
    }

    @Override
    public Long expire(String key, int seconds) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Long result = jedis.expire(key, seconds);
        jedis.close();
        return result;
    }

    @Override
    public Long ttl(String key) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Long result = jedis.ttl(key);
        jedis.close();
        return result;
    }

    @Override
    public Long incr(String key) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Long result = jedis.incr(key);
        jedis.close();
        return result;
    }

    @Override
    public Long hset(String key, String field, String value) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Long result = jedis.hset(key, field, value);
        jedis.close();
        return result;
    }

    @Override
    public String hget(String key, String field) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        String result = jedis.hget(key, field);
        jedis.close();
        return result;
    }

    @Override
    public Long hdel(String key, String... field) {
        Jedis jedis = configuration.redisPoolFactory().getResource();
        Long result = jedis.hdel(key, field);
        jedis.close();
        return result;
    }
}

5:添加注解类,并且定义默认访问次数,有效时间,在这里直接修改时间就可以。

package com.sword.storageproduce.common.interfices;

import java.lang.annotation.*;

/**
 * @ClassName LimitUserRequest
 * @Description 限制某个用户在某个时间段内请求某个方法的次数
 * @Author wangcc
 * @Date 2022/3/18 10:23
 * @Version 1.0
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface LimitUserRequest {

    /**
     * 限制某时间段内可以访问的次数,默认设置1
     * @return
     */
    int limitCounts() default 1;

    /**
     * 限制访问的某一个时间段,单位为秒,默认值1分钟即可
     * @return
     */
    int timeSecond() default 60;
}

6:添加切点

package com.sword.storageproduce.common.aop;

import com.sword.storageproduce.common.exceptions.LimitUserRequestException;
import com.sword.storageproduce.common.interfices.LimitUserRequest;
import com.sword.storageproduce.redis.JedisClient;
import com.sword.storageproduce.util.UserHelper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName LimitUserRequestDisplay
 * @Description 限制用户重复调用方法的aop
 * @Author wangcc
 * @Date 2022/3/18 10:25
 * @Version 1.0
 **/
@Aspect
@Component
public class LimitUserRequestDisplay {

    public static final Logger logger = LoggerFactory.getLogger(LimitUserRequestDisplay.class);

    @Autowired
    private JedisClient jedis;
    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.sword.storageproduce.common.interfices.LimitUserRequest)")
    public void before(){
        logger.info("进入切面工程");
    }


    @Before("before()")
    public void requestLimit(JoinPoint joinPoint) throws LimitUserRequestException {
        logger.info("开始切面操作");
        try {
            // 获取HttpRequest
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            logger.info("url={}", request.getRequestURI());
            HttpServletResponse response = attributes.getResponse();

            // 判断request不能为空
            if (request == null) {
                throw new LimitUserRequestException("HttpServletRequest有误...");
            }

            LimitUserRequest limit = this.getAnnotation(joinPoint);
            if(limit == null) {
                return;
            }

            String userId = UserHelper.getLoginUserId();
            String uri = request.getRequestURI().toString();
            String redisKey = "limit-user-request:" + uri + ":" + userId;
            // 设置在redis中的缓存,累加1
            long count = jedis.incr(redisKey);

            // 如果该key不存在,则从0开始计算,并且当count为1的时候,设置过期时间
            if (count == 1) {
                jedis.expire(redisKey, limit.timeSecond());
                redisTemplate.expire(redisKey, limit.timeSecond(), TimeUnit.MILLISECONDS);
            }

            // 如果redis中的count大于限制的次数,则报错
            if (count > limit.limitCounts()) {
                InetAddress address = InetAddress.getLocalHost();
                 logger.info("用户IP[" + address.getHostAddress() + "]访问地址[" + uri + "]超过了限定的次数[" + limit.limitCounts() + "]");
                throw new LimitUserRequestException("当前用户重复访问");
            }
        } catch (LimitUserRequestException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @Description: 获得注解
     * @param joinPoint
     * @return
     * @throws Exception
     *
     * @author wangcc
     * @date 2022年3月18日 上午9:55:32
     */
    private LimitUserRequest getAnnotation(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(LimitUserRequest.class);
        }
        return null;
    }

}

7:测试

@LimitUserRequest
    @GetMapping(value = "/testChange")
    public String user(@RequestParam Map<String,Object> param) {
        return "成功调用接口";
    }



版权声明:本文为wangcc_原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。