1. 确定用什么来统计网站的访问次数?
因为网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,也就是说统计工作在任何的资源被访问之前都要执行,所以使用过滤器比较方便。而且我们的这个过滤器不需要任何的拦截操作,只需要统计次数就可以了。
2. 用什么来存储网站中每个IP的访问次数?
我们需要用什么来装载统计数据呢?答案是Map<String,Integer>,我们可以在过滤器中创建一个Map,key就是IP地址,value就是对应IP地址访问的次数。
当有用户访问时,就获取请求的IP地址:如果这个IP在map中存在,就说明以前访问过,就在访问次数上+1;如果IP在map中不存在,就设置访问次数为1。
3. Map怎么创建?存放在哪里?
这个Map什么时候创建呢,我们可以使用监听器,也就是使用ServletContextListener,在服务器启动的时候完成创建,并且存放到ServletContext中。
创建一个Listener监听器,并再服务器启动的时候创建map集合
package com.yunhe.listener; /**
* @author by houbing
* @date 2021/12/25 18:00
* @Classname ${NAME}
* @Description TODO
*/
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.HashMap;
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
/* This method is called when the servlet context is initialized(when the Web application is deployed). */
//在服务器创建的时候创建servletContext上下文对象
ServletContext servletContext = sce.getServletContext();
HashMap<String, Integer> map = new HashMap<>();
//将map集合添加到servletContext中
servletContext.setAttribute("map",map);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
/* This method is called when the servlet Context is undeployed or Application Server shuts down. */
}
}
创建一个Filter过滤器,并在Filter中书写相应代码
package com.yunhe.filter; /**
* @author by houbing
* @date 2021/12/25 17:54
* @Classname ${NAME}
* @Description TODO
*/
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.HashMap;
@WebFilter(filterName = "/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
//创建servletContext对象
ServletContext servletContext = request.getServletContext();
//从servletContext中获取map属性,并将map转成集合
HashMap<String,Integer> map = (HashMap<String, Integer>) servletContext.getAttribute("map");
//获取当前客户端IP地址
String ip = request.getRemoteAddr();
System.out.println(ip);
//若IP在map集合已经存在
if (map.containsKey(ip)){
Integer count = map.get(ip);
count++;
map.put(ip,count);
}else{
//ip不存在
map.put(ip,1);
}
servletContext.setAttribute("map",map);
chain.doFilter(request, response);
}
}
创建一个servlet进行访问,并打印到页面
package com.yunhe.servle; /**
* @author by houbing
* @date 2021/12/25 18:45
* @Classname ${NAME}
* @Description TODO
*/
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = request.getServletContext();
HashMap<String,Integer> map = (HashMap<String, Integer>) servletContext.getAttribute("map");
PrintWriter writer = response.getWriter();
//Set<String> ip = map.keySet();
for (String ip:map.keySet()) {
writer.write(ip+" x"+map.get(ip)+"<br>");
System.out.println(ip+" x"+map.get(ip));
}
// request.getRequestDispatcher("show.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
也可以选择直接用访问jsp在页面显示
<%--
Created by IntelliJ IDEA.
User: houbing
Date: 2021/12/25
Time: 18:46
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>网站访问量</title>
</head>
<body>
<h1 align="center">显示结果</h1>
<table align="center" width="60%" border="1">
<tr>
<th>IP地址</th>
<th>访问次数</th>
</tr>
<c:forEach items="${applicationScope.map }" var="entry">
<tr>
<td>${entry.key }</td>
<td>${entry.value }</td>
</tr>
</c:forEach>
</table>
</body>
</html>