javawebday55(filter过滤器 通过监听和Filter实现统计IP访问次数 )

JavaWeb三大组件
1、都需要在web.xml中进行配置
    Servlet
    Listener(2个感知监听器不需要配置)
    Filter
2、过滤器
    它会在一组资源(jsp、servlet、.class、.html)的前面执行
    可以让请求得到目标资源,也可以不让请求达到
        过滤器有拦截请求的能力
    如果在拦截范围内 那么都会拦一次
    登录:
        允许它访问AServlet、BServlet、CServlet

过滤器如何编写
1、写一个类实现Filter
2、在web.xml中进行配置

Filter

void init(FilterConfig)
    创建之后马上执行 Filter会在服务器启动时就创建
void destroy()
    销毁之前执行。在服务器关闭时
void doFilter(ServletRequest,ServletResponse,FilterChain)
    每次过滤时都会执行

Filter是单例的。 
web.xml
<filter>
    <filter-name>xxx</filter-name>
    <filter-calss>my.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>xxx</filter-name>
    <url-patter>/*</url-pattern
</filter-mapping>

FilterConfig(与ServletConfig相似)
    获取初始化参数:getInitParameter()
    获取过滤器名称:getFilterName()
    获取application:getServletContext()

FilterChain
    doFilter(ServletRequest,ServletResponse):放行
    放行,就相当于调用了目标的   Servlet的service()方法

多过滤器
    FilterChain#doFilter()方法
        执行目标资源,或是执行下一个过滤器。如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器

过滤器的四种拦截方式
    请求 REQUEST
    转发 FORWARD
    包含 INCLUDE
    错误 ERROR
        <dispatcher>REQUEST</dispatcher> 默认的 如果有其他的那么没默认的
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
在<filter-mapping>里面配置   

多个过滤器的执行顺序
在<filter-mapping>的配置顺序决定了过滤器的执行顺序

过滤器的应用场景
    执行目标资源之前做预处理工作,例如设置编码,这种通常会放行,几乎所有的Servlet中都需要写request.setCharacterEncoding()可以放到Filter中
    通过条件判断是否放行,例如检验当前用户是否登录 或者用户ip是否被禁用
    在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理:回程连接

在<servlet-mapping>中可以使用<servlet-name></servlet-name>    过滤指定的servlet

分ip统计网站的访问次数

统计工作需要在所有资源之前都执行,那么就可以放到Filter中了
我们的过滤器不打算做拦截操作。因为只是统计的
用什么来装载统计的数据? Map<String,Integer>
只要一个Map即可
Map什么时候创建?(使用ServletContextListener,在服务器启动时完成创建,并保存到ServletContext中)保存在?(Map保存到ServletContxt中   )
    Map需要在Filter中用来保存数据
    Map需要在页面中使用,打印Map中的数据

    因为一个网站可能有多个页面,无论那个页面被访问,都要统计访问次数,所以使用过滤器最为方便
    因为需要分ip统计,所以可以在过滤器中创建一个Map,使用ip为key,访问次数为value。当有用户访问时,获取请求的ip,如果ip在map中存在,说明以前访问过,那么在访问次数上加1即可。如果不存在 设置次数为1
    把Map放在ServletContxt
public class AFilter implements Filter {
    /**
     * 销毁之前执行,对非内存资源进行释放
     */
    public void destroy() {
    }
    /**
     * 每次过滤时都会执行
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("过滤器A#start");
        chain.doFilter(request, response);//放行
        System.out.println("过滤器A#end");
    }
    /**
     * 创建之后马上执行,用来做初始化 
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

}

AFilter

/**
 * 从application中获取Mao
 * 从request中得到当前客户端的IP
 * 进行统计工作,结果保存到Map中
 * @author Administrator
 *
 */
public class AFilter implements Filter {

    private FilterConfig config;

    /**
     * 在服务器启动时就会执行本方法,而且本方法只执行一次
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        /*
         * 1、得到application中的map
         * 2、从request中获取当前客户端的ip地址
         * 3、查看map中是否存在这个ip对应的访问次数,如果存在,把次数+1再保存回去
         * 4、如果不存在这个ip,那么说明是第一次访问本站,设置访问次数为1
         */
        /*
         * 1、得到application
         */
        ServletContext app = config.getServletContext();
        Map<String,Integer> map = (Map<String, Integer>) app.getAttribute("map");
        /*
         * 2、获取客户端的ip地址
         */
        String ip =req.getRemoteAddr();
        /*
         * 3、进行判断
         */
        if(map.containsKey(ip)){//这个ip在map中存在,说明不是第一次访问
            int cnt =map.get(ip);
            map.put(ip, cnt+1);
        }else{//这个ip在map不存在,说明是第一次访问
            map.put(ip, 1);
        }
        app.setAttribute("map", map);//把map再放回到app中
        filterChain.doFilter(req, res);//肯定放行
    }

AListener

public class AListener implements ServletContextListener {

    public void contextDestroyed(ServletContextEvent sce) {

    }
    /**
     * 在服务器启动时 创建Map,保存到ServletContext
     */
    public void contextInitialized(ServletContextEvent sce) {
        //创建Map
        Map<String,Integer> map = new LinkedHashMap<String,Integer>();
        //得到ServletContext
        ServletContext application = sce.getServletContext();
        //把map保存到application中
        application.setAttribute("map", map);
    }

}   

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

 <listener>
    <listener-class>my.filter.AListener</listener-class>
 </listener>

  <filter>
    <filter-name>AFilter</filter-name>
    <filter-class>my.filter.AFilter</filter-class>
  </filter>
    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
</web-app>

show.jsp

  <body>
 <h1>显示结果</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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值