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>