客户端频繁的访问网站,会对网站资源造成很大的压力,所以,需要限制时间段内的访问次数,如果访问过于频繁,应该禁止访问,采用redis实现这一需要,redis中,可以使用expire设置key的生存时间,这一特性很好的满足我们的需求,解决代码如下:
工具类:
package cn.sniper.tjfxpt.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisDataException;
public class RedisUtil {
private static JedisPool jedisPool;
//每分钟允许最大访问次数
private static int MAX_ALLOWED_TIMES = 60;
static {
String host = "192.168.31.231";
int port = 6379;
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(100);
poolConfig.setMaxTotal(500);
poolConfig.setMaxWaitMillis(20000);
poolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(poolConfig, host, port);
}
/**
* 如果key不存在,设置值,如果key存在,覆盖值
* @param key
* @param value
*/
public static void set(String key, String value) {
Jedis jedis = jedisPool.getResource();
jedis.set(key, value);
//用完后放回连接池
jedisPool.returnResourceObject(jedis);
}
/**
* 如果key不存在,设置值,如果key存在,不做任何操作
* @param key
* @param value
*/
public static void setIfNotExists(String key, String value) {
Jedis jedis = jedisPool.getResource();
jedis.setnx(key, value);
//用完后放回连接池
jedisPool.returnResourceObject(jedis);
}
/**
* 自加1
* @param key
* @param value
*/
public static void incrByOne(String key) {
Jedis jedis = jedisPool.getResource();
try {
//如果key对应的值不是数值型,会报异常
jedis.incr(key);
} catch(JedisDataException e) {
e.printStackTrace();
}
//用完后放回连接池
jedisPool.returnResourceObject(jedis);
}
/**
* 判断键是否存在
* @param key
* @return
*/
public static boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
return jedis.exists(key);
}
/**
* 是否允许访问
* @param key
* @return
*/
public static boolean ifAllowed(String key) {
boolean flag = true;
Jedis jedis = jedisPool.getResource();
if(exists(key)) {
//key对应的value自加1
jedis.incr(key);
//取得key对应的value
String value = jedis.get(key);
try {
//如果在60秒的生存周期内的访问次数大于MAX_ALLOWED_TIMES,则不允许访问
if(Integer.parseInt(value) > MAX_ALLOWED_TIMES) {
flag = false;
}
} catch(RuntimeException e) {
e.printStackTrace();
}
} else {
//第一次访问,设置初始值1
jedis.set(key, "1");
//设置生存时间60秒
jedis.expire(key, 60);
}
//用完记得放回,否则池很快就用完
jedisPool.returnResourceObject(jedis);
return flag;
}
public static void main(String[] args) {
//setIfNotExists("sniper", "ccc");
//set("sniper", "ccc");
//incrByOne("sniper");
//System.out.println(exists("sniper"));
for(int i=0; i<70; i++) {
System.out.println(i + "" + ifAllowed("sniper"));
}
}
}
filter拦截器:
package cn.sniper.webkit.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.sniper.tjfxpt.utils.RedisUtil;
public class SecureFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
boolean ifAllowed = true;
try {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
String uri = req.getRequestURI();
//ip地址
String ip = "";
if (req.getHeader("x-forwarded-for") == null) {
ip = req.getRemoteAddr();
} else {
ip = req.getHeader("x-forwarded-for");
}
ip = "0:0:0:0:0:0:0:1".equals(ip)?"127.0.0.1":ip;
String key = ip + "-" + uri;
ifAllowed = RedisUtil.ifAllowed(key);
if(!ifAllowed) {
req.getSession().invalidate();
resp.sendRedirect(req.getContextPath() + "/gotoError.xhtml");
} else {
chain.doFilter(request, response);
}
//防止因为redis异常导致服务不可用
} catch(Throwable e) {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}