转载请标明出处:
https://blog.youkuaiyun.com/weixin_41965979/article/details/90720405
本文出自付付讶的博客
这两天因为公司需求需要加一个限制ip请求次数的功能,限制某些ip一天只能访问10次,现在总结一下(因为是老项目所以用的是servlet)
用到的jar包:commons-lang3-3.8.1.jar
用到的技术:过滤器(Filter)
思路:数据库里创建2字段,一个ip,一个请求次数,并给他们填上值:ip写上你要拦截的ip,次数全部填0;
代码里创建一个Map,用来存放要拦截的ip地址,通过反向代理得到当前请求的ip,拿到ip查询当前次数,然后判断Map 里包不包括当前请求的Ip地址,有的话则计算请求次数,然后在数据库里添加一个定时器每天0点清空次数 (https://blog.youkuaiyun.com/weixin_41965979/article/details/90700370这篇文章有写数据库怎么添加一个自动定时器),这样的话次数都是当天的,最后判断次数大于10就给它跳错误页面就行了;
下面直接上代码,有问题可以留言交流;
配置文件(web.xml):
<!-- 配置过滤器-->
<filter>
<filter-name>IPFilter</filter-name>
<filter-class>com.roadLeader.filter.IPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>IPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
新建一个过滤器类(IPFilter):
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import com.roadLeader.jdbc.LinkDB;
/**
* @Description 自定义过滤器,用来判断IP访问次数是否超限。<br>
* @author fling
* @date 2019年5月28日
* @since JDK : 1.7
*/
public class IPFilter implements Filter{
private FilterConfig config;
//统计ip请求次数
int count;
Integer numbers;
//存储ip
Map<String, Integer> ipMap=new HashMap<String, Integer>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
//以下是我要拦截的ip(由于工作业务原因,不方便展示真实ip,以下全部用127.0.0.1代替,实际上
是5个不同的客户的ip,此ip跟数据库要对上哟)
ipMap.put("127.0.0.1", count);
ipMap.put("127.0.0.1", count);
ipMap.put("127.0.0.1", count);
ipMap.put("127.0.0.1", count);
ipMap.put("127.0.0.1", count);
}
/**
* @Description 核心处理代码
*/
@SuppressWarnings("unchecked")
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
ServletContext context = config.getServletContext();
//得到当前请求的ip
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(ip) && !"unKnow".equalsIgnoreCase(ip)) {
//多次反向代理后会有多个ip值,第一个ip才是真实ip
String[] ipList1 = ip.split(",");
ip = ipList1[0];
} else {
ip = request.getHeader("X-Real-IP");
if (StringUtils.isEmpty(ip) || "unKnown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
}
//查询ip和次数
String aliIp="";
int number=0;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection conn = new LinkDB().getConnection();
String sql = "SELECT number,ip FROM ipTable WHERE ip='"+ip+"'";
PreparedStatement pre = conn.prepareStatement(sql);
ResultSet rs = pre.executeQuery();
while (rs.next()) {
aliIp = rs.getString("ip");
number = rs.getInt("number");
};
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
//判断如果包括当前请求ip则计算请求次数
if(ipMap.containsKey(ip)){
numbers = number+1;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection conn = new LinkDB().getConnection();
String sql = "update ipTable set number=? where ip=?";
PreparedStatement pre = conn.prepareStatement(sql);
pre.setInt(1, numbers);
pre.setString(2, ip);
pre.executeUpdate();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}else{
ipMap.put(ip, 1);
}
context.setAttribute("ipMap", ipMap);
chain.doFilter(request, response);
//判断大于10次跳错误页面
if(numbers>10){
request.getRequestDispatcher("WEB-INF/error.jsp").forward(request, response);
}
}
@Override
public void destroy() {
}
}
测试:
当我发送第一次请求时,数据库次数变成了1,这时应该响应成功(数据私密性这里打上马赛克);
当我发送到第11次请求时 ,这时候数据库次数变成11,响应返回报错页面;