其实最为常用的就是REQUEST和FORWARD两种拦截方式,而INCLUDE和ERROR都比较少用!其中INCLUDE比较好理解,我们这里不再给出代码,学员可以通过FORWARD方式修改,来自己测试。而ERROR方式不易理解,下面给出ERROR拦截方式的例子:
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/b.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<error-page>
<error-code>500</error-code>
<location>/b.jsp</location>
</error-page>
<body>
<h1>a.jsp</h1>
<%
if(true)
throw new RuntimeException("嘻嘻~");
%>
</body>
6 过滤器的应用场景
过滤器的应用场景:
l 执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作;
l 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;
l 在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理;
7 设置目标资源在web.xml文件中部署Filter时,可以通过“*”来执行目标资源:
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这一特性与Servlet完全相同!通过这一特性,我们可以在用户访问敏感资源时,执行过滤器,例如:<url-pattern>/admin/*<url-pattern>,可以把所有管理员才能访问的资源放到/admin路径下,这时可以通过过滤器来校验用户身份。
还可以为<filter-mapping>指定目标资源为某个Servlet,例如:
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>cn.itcast.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/abc</url-pattern>
</servlet-mapping>
<filter>
<filter-name>myfilter</filter-name>
<filter-class>cn.itcast.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter</filter-name>
<servlet-name>myservlet</servlet-name>
</filter-mapping>
当用户访问:8080/filtertest/abc时,会执行名字为myservlet的Servlet,这时会执行过滤器。
8 Filter小结Filter的三个方法:
l void init(FilterConfig):在Tomcat启动时被调用;
l void destroy():在Tomcat关闭时被调用;
l void doFilter(ServletRequest,ServletResponse,FilterChain):每次有请求时都调用该方法;
FilterConfig类:与ServletConfig相似,用来获取Filter的初始化参数
l ServletContext getServletContext():获取ServletContext的方法;
l String getFilterName():获取Filter的配置名称;
l String getInitParameter(String name):获取Filter的初始化配置,与<init-param>元素对应;
l Enumeration getInitParameterNames():获取所有初始化参数的名称。
FilterChain类:
l void doFilter(ServletRequest,ServletResponse):放行!表示执行下一个过滤器,或者执行目标资源。可以在调用FilterChain的doFilter()方法的前后添加语句,在FilterChain的doFilter()方法之前的语句会在目标资源执行之前执行,在FilterChain的doFilter()方法之后的语句会在目标资源执行之后执行。
四各拦截方式:REQUEST、FORWARD、INCLUDE、ERROR,默认是REQUEST方式。
l REQUEST:拦截直接请求方式;
l FORWARD:拦截请求转发方式;
l INCLUDE:拦截请求包含方式;
l ERROR:拦截错误转发方式。
过滤器应用案例 分ip统计网站的访问次数 1 说明网站统计每个IP地址访问本网站的次数。
2 分析因为一个网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,所以使用过滤器最为方便。
因为需要分IP统计,所以可以在过滤器中创建一个Map,使用IP为key,访问次数为value。当有用户访问时,获取请求的IP,如果IP在Map中存在,说明以前访问过,那么在访问次数上加1,即可;IP在Map中不存在,那么设置次数为1。
把这个Map存放到ServletContext中!
3 代码index.jsp
<body>
<h1>分IP统计访问次数</h1>
<table align=http://www.likecs.com/"center" width=http://www.likecs.com/"50%" border=http://www.likecs.com/"1">
<tr>
<th>IP地址</th>
<th>次数</th>
</tr>
<c:forEach items="${applicationScope.ipCountMap }" var=http://www.likecs.com/"entry">
<tr>
<td>${entry.key }</td>
<td>${entry.value }</td>
</tr>
</c:forEach>
</table>
</body>
IPFilter
public class IPFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
context = fConfig.getServletContext();
Map<String, Integer> ipCountMap = Collections
.synchronizedMap(new LinkedHashMap<String, Integer>());
context.setAttribute("ipCountMap", ipCountMap);
}
@SuppressWarnings("unchecked")
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String ip = req.getRemoteAddr();
Map<String, Integer> ipCountMap = (Map<String, Integer>) context
.getAttribute("ipCountMap");
Integer count = ipCountMap.get(ip);
if (count == null) {
count = 1;
} else {
count += 1;
}
ipCountMap.put(ip, count);
context.setAttribute("ipCountMap", ipCountMap);
chain.doFilter(request, response);
}
public void destroy() {}
}
<filter>
<display-name>IPFilter</display-name>
<filter-name>IPFilter</filter-name>
<filter-class>cn.itcast.filter.ip.IPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>IPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
粗粒度权限控制(拦截是否登录、拦截用户名admin权限) 1 说明
我们给出三个页面:index.jsp、user.jsp、admin.jsp。
l index.jsp:谁都可以访问,没有限制;
l user.jsp:只有登录用户才能访问;
l admin.jsp:只有管理员才能访问。
2 分析设计User类:username、password、grade,其中grade表示用户等级,1表示普通用户,2表示管理员用户。
当用户登录成功后,把user保存到session中。
创建LoginFilter,它有两种过滤方式:
l 如果访问的是user.jsp,查看session中是否存在user;
l 如果访问的是admin.jsp,查看session中是否存在user,并且user的grade等于2。
3 代码User.java
public class User {
private String username;
private String password;
private int grade;
…
}
为了方便,这里就不使用数据库了,所以我们需要在UserService中创建一个Map,用来保存所有用户。Map中的key中用户名,value为User对象。
UserService.java
public class UserService {
private static Map<String,User> users = new HashMap<String,User>();
static {
users.put("zhangSan", new User("zhangSan", "123", 1));
users.put("liSi", new User("liSi", "123", 2));
}
public User login(String username, String password) {
User user = users.get(username);
if(user == null) return null;
return user.getPassword().equals(password) ? user : null;
}
}
login.jsp
<body>
<h1>登录</h1>
<p>${msg }</p>
<form action=http://www.likecs.com/"<c:url value=http://www.likecs.com/\'/LoginServlet\'/>" method=http://www.likecs.com/"post">
用户名:<input type=http://www.likecs.com/"text" name=http://www.likecs.com/"username"/><br/>
密 码:<input type=http://www.likecs.com/"password" name=http://www.likecs.com/"password"/><br/>
<input type=http://www.likecs.com/"submit" value=http://www.likecs.com/"登录"/>
</form>
</body>
index.jsp
<body>
<h1>主页</h1>
<h3>${user.username }</h3>
<hr/>
<a href=http://www.likecs.com/"<c:url value=http://www.likecs.com/\'/login.jsp\'/>">登录</a><br/>
<a href=http://www.likecs.com/"<c:url value=http://www.likecs.com/\'/user/user.jsp\'/>">用户页面</a><br/>
<a href=http://www.likecs.com/"<c:url value=http://www.likecs.com/\'/admin/admin.jsp\'/>">管理员页面</a>
</body>
/user/user.jsp
<body>
<h1>用户页面</h1>
<h3>${user.username }</h3>
<hr/>
</body>
/admin/admin.jsp
<body>
<h1>管理员页面</h1>
<h3>${user.username }</h3>
<hr/>
</body>
LoginServlet
public class LoginServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
UserService userService = new UserService();
User user = userService.login(username, password);
if(user == null) {
request.setAttribute("msg", "用户名或密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
} else {
request.getSession().setAttribute("user", user);
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
}
}
LoginUserFilter.java
<filter>
<display-name>LoginUserFilter</display-name>
<filter-name>LoginUserFilter</filter-name>
<filter-class>cn.itcast.filter.LoginUserFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginUserFilter</filter-name>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
public class LoginUserFilter implements Filter {
public void destroy() {}
public void init(FilterConfig fConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
HttpServletRequest req = (HttpServletRequest) request;
User user = (User) req.getSession().getAttribute("user");
if(user == null) {
response.getWriter().print("您还没有登录");
return;
}
chain.doFilter(request, response);
}
}
LoginAdminFilter.java
<filter>
<display-name>LoginAdminFilter</display-name>
<filter-name>LoginAdminFilter</filter-name>
<filter-class>cn.itcast.filter.LoginAdminFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginAdminFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
public class LoginAdminFilter implements Filter {
public void destroy() {}
public void init(FilterConfig fConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
HttpServletRequest req = (HttpServletRequest) request;
User user = (User) req.getSession().getAttribute("user");
if(user == null) {
response.getWriter().print("您还没有登录!");
return;
}
if(user.getGrade() < 2) {
response.getWriter().print("您的等级不够!");
return;
}
chain.doFilter(request, response);
}
}
禁用资源缓存
浏览器只是要缓存页面,这对我们在开发时测试很不方便,所以我们可以过滤所有资源,然后添加去除所有缓存!
public class NoCacheFilter extends HttpFilter {
public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
response.setHeader("cache-control", "no-cache");
response.setHeader("pragma", "no-cache");
response.setHeader("expires", "0");
chain.doFilter(request, response);
}
}