redis限流实现;使用springMVC拦截器RedisTemplate

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 限流注解
 * @see AccessLimitInterceptor
 * @author
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {

    /**
     * 时间段(秒)
     * @return
     */
    int seconds();

    /**
     * 时间段内最大请求次数
     * @return
     */
    int maxCount();

}

import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.weifengqi18.commons.web.util.WebTools;
import com.dmore.exception.BizErrorException;

/**
 * 限流实现
 * 尽量设置短key的过期时间,减少误差
 *
 * @author
 */
public class AccessLimitInterceptor implements HandlerInterceptor {


    @Autowired
    private RedisTemplate<String, Integer> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod hm = (HandlerMethod) handler;
        AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
        if (Objects.isNull(accessLimit)) {
            return true;
        }
        int seconds = accessLimit.seconds();
        int maxCount = accessLimit.maxCount();
        //
        String key = new StringBuffer("channelId:")
                .append(WebTools.getChannelId().get())
                .append("userId:")
                .append(WebTools.getUserId().get())
                .append("uri:")
                .append(request.getServletPath())
                .toString();

        //第一次访问,设置key、值、过期时间
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);
            return true;
        }
        int count = redisTemplate.opsForValue().get(key);
        // 如果访问次数<最大次数,则加1操作
        if (count < maxCount) {
            redisTemplate.opsForValue().increment(key);
            return true;
        }
        //超过最大值返回操作频繁
        if (count >= maxCount) {
            throw new BizErrorException("服务器繁忙请稍后重试");
        }
        return true;
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * spring mvc 配置类
 */
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    @Autowired
    private ServerProperties serverProperties;
    @Autowired
    AccessLimitInterceptor accessLimitInterceptor;
  
    @Bean
    public AccessLimitInterceptor accessLimitInterceptor() {
        return new AccessLimitInterceptor();
    }
    /**
     * 配置拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(accessLimitInterceptor)
                .excludePathPatterns(serverProperties.getError().getPath());
    }
}

使用

@RestController
@RequestMapping(value = "/")
public class UserController {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private IUserService userService;

    @RequestMapping(value = "test")
    @AccessLimit(seconds = 1,maxCount = 2)
    public String test(){
        return "[email protected]";
    }

}

你可能感兴趣的:(实战,spring,redis,java,限流,springMVC拦截器,RedisTemplate)