1、过滤器的概念
Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。
过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题。
2、过滤器的作用
(1)在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。
(2)根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
(3)在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。
(4)根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。
3、应用举例
3.1、过滤器解决中文乱码的问题,统一全站字符编码的过滤器。
(1)首先定义一个EncodingFiler的实现类,实现Filter接口,代码如下:
public class EncodingFilter implements Filter {
private FilterConfig config = null;
private String defaultCharset = "utf-8";
// Filter被释放时的回调方法
public void destroy() {
}
// FilterConfig接口实例中封装了这个Filter的初始化参数
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
// 过滤方法
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String charset = config.getInitParameter("charset");
if(charset==null){
charset = defaultCharset;
}
request.setCharacterEncoding(charset);
//有时候response不用设置编码,因为servlet一般不做输出,
//输出交由jsp来做,所以只要jsp页面设定编码即可
resp.setCharacterEncoding(charset);
resp.setContentType("text/html;charset="+charset);
chain.doFilter(req, resp);
}
}
(2)在 web.xml 文件中实现Filter实现类,并配置初始化。代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
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_2_5.xsd">
<display-name></display-name>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.class3g.web.filter.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
</web-app>
3.2、禁止浏览器缓存所有动态页面
(1)有3个HTTP响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
(2)并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。
Expires:值为GMT时间值,为-1指浏览器不要缓存页面。
Cache-Control响应头有两个常用值:
no-cache:指浏览器不要缓存当前页面。
max-age:xxx指浏览器缓存页面xxx秒。
(3)实现代码如下:
public class NoCacheFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse) res;
response.setDateHeader("expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
chain.doFilter(request, response);
}
public void destroy() {
}
}
3.3、控制浏览器缓存页面中的静态资源的过滤器
有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能。
静态资源(Html、Css、Js等资源):静态资源的缓存可以减轻服务器的负担,浏览器一般会默认缓存,为防止用户禁用缓存,在程序代码中进行对静态资源缓存的控制(包括缓存时间的控制)。
(1)过滤器相关配置:
<filter>
<filter-name>NeedCacheFilter</filter-name>
<filter-class>cn.itcast.filter.example.NeedCacheFilter</filter-class>
<init-param>
<param-name>html</param-name>
<param-value>1</param-value><!-- 单位是小时 -->
</init-param>
<init-param>
<param-name>css</param-name>
<param-value>2</param-value><!-- 单位是小时 -->
</init-param>
<init-param>
<param-name>js</param-name>
<param-value>3</param-value><!-- 单位是小时 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>NeedCacheFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>NeedCacheFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>NeedCacheFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
(2)filter实现代码
//控制html、css、js等静态资源的缓存时间
public class NeedCacheFilter implements Filter {
private FilterConfig filterConfig;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
System.out.println("控制缓存时间的过滤器过滤了");
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//获取html、css、js各自的缓存时间,如果没有,给个默认值是1小时
int time = 1;
String uri = request.getRequestURI();
String extendName = uri.substring(uri.lastIndexOf(".")+1);
if("html".equals(extendName)){
//访问的html资源
String value = filterConfig.getInitParameter("html");
if(value!=null){
time = Integer.parseInt(value);
}
}
if("css".equals(extendName)){
//访问的css资源
String value = filterConfig.getInitParameter("css");
if(value!=null){
time = Integer.parseInt(value);
}
}
if("js".equals(extendName)){
//访问的js资源
String value = filterConfig.getInitParameter("js");
if(value!=null){
time = Integer.parseInt(value);
}
}
response.setDateHeader("Expires", System.currentTimeMillis()+time*60*60*1000);
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
}
3.4、日志过滤
使用Filter记录日志、来访IP、URL和页面执行时间。代码如下:
Public final class LoggingFilter implements Filter{
privateFilterConfigfilterConfig=null;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain
chain) throwsIOException,ServletException{
longstart=System.currentTimeMillis();
Stringaddress=request.getRemoteAddr();
Stringfile=((HttpServletRequest)request).getRequestURI();
chain.doFilter(request,response);
filterConfig.getServletContext().log(
"UserAccess!"+
"UserIP:"+address+
"Resource:"+file+
"Millisecondsused:"+(System.currentTimeMillis()-start)
);
}
publicvoiddestroy(){}
public void init(FilterConfigfilterConfig){
this.filterConfig=filterConfig;
}
}
3.5、登录拦截过滤
用户权限的认证,当用户发送请求时,可以对用户的身份信息进行验证,如果能够通过验证则接下来再进行其它操作,否则直接不进入下一步的处理。
(1)web.xml配置
<!-- 配置登陆过滤器 -->
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.ccse.frame.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/pages/*</url-pattern>
</filter-mapping>
(2)filter代码实现
public class SessionFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException { }
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(true);
// 获得用户请求的URI
String path = servletRequest.getRequestURI();
//System.out.println(path);
// 登陆页面无需过滤
if(path.indexOf("/login.jsp") > -1) {
chain.doFilter(servletRequest, servletResponse);
return;
}
//从session里取的用户名信息
//这句话可以自己修改,看登陆的时候在session里放入什么,就去取什么判断。
String username = (String) session.getAttribute("userId");
//判断如果没有取到用户信息,就跳转到登陆页面
if ((username == null) || "".equals(username)) {
//跳转到登陆页面
res.sendRedirect("http://" + req.getHeader("Host") + "/login.jsp");
} else {
//已经登陆,继续此次请求
chain.doFilter(req, res);
}
}
public void destroy() { }
}