Servlet规范中 Servlet Listener Filter
1.开发Filter
想要开发一个过滤器需要如下两个步骤:
(1)写一个类实现特定的接口Filter
生命周期:当服务器启动时,web应用加载后,立即创建这个web应用中的所有的过滤器,过滤器创建出来后立即调用init方法执行初始化的操作.
创建出来后一直驻留在内存中为后续的拦截进行服务.每次拦截到请求后都会导致doFilter方法执行.
在服务器关闭或web应用被移除出容器时,随着web应用的销毁过滤器对象销毁.销毁之前调用destory方法执行善后工作.
init
FilterConfig:代表web.xml中对当前过滤器的配置信息
~获取ServletContext对象
~获取初始化信息
getInitParameter
getInitParameterNames
doFilter
request
response
FilterChain:
代表过滤器链的对象.
一个资源可能被多个过滤器所拦截到,拦截的顺序和过滤器在web.xml中filter-mapping的配置顺序相同.
所有对当前资源访问进行拦截的过滤器按照拦截顺序就组成了一个过滤器链.这个过滤器链的最后一个节点是要访问的资源.
Filter中调用FilterChain提供了doFilter方法,这个方法一旦被调用就表明当前过滤器没有问题了,请执行过滤器链的下一个节点.如果下一个节点是资源则直接执行了资源
destory
(2)在web.xml中注册一下过滤器
<filter>
<filter-name>Demo1Filter</filter-name> -- 给过滤器起一个名字
<filter-class>com.itheima.filter.Demo1Filter</filter-class> -- 过滤器的处理类
<init-param>--可以配置当前过滤器的初始化信息,可以配置多个,在Filter中利用FilterConfig对象来获取
<param-name>name1</param-name>
<param-value>value1</param-value>
</init-param>
</filter>
<filter-mapping> -- 一个Filter可以配置多个filter-mapping
<filter-name>Demo1Filter</filter-name>
<url-pattern>/servlet/Demo1Servlet</url-pattern> -- 一个Filtermapping中可以配置多个url-partten,这个url-partten的写法和servlet-mapping中的写法相同
<url-pattern>/servlet/*</url-pattern>
<url-pattern>/*</url-pattern>
<url-pattern>*.do</url-pattern>
<servlet-name>Demo3Servlet</servlet-name>
--也可以配置多个servlet-name,其中填入servlet的名字明确的通知要拦截哪个名字的Servlet
<dispatcher>REQUEST</dispatcher>
--配置拦截哪种方式的对资源的访问可以是REQUEST/FORWARD/INCLUDE/ERROR四个值之中的一个,可以配置多个dispatcher,如果一个都不配则默认是REQUEST
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
3、客户端访问被拦截目标资源之前,服务器调用Filter的doFilter方法 ,执行过滤
4、Filter的doFilter方法中传入 FilterChain, 如果调用FilterChain的doFilter 就会执行目标资源,否则目标资源不会执行
chain.doFilter(request, response);
FilterChain
在客户端访问服务器web资源时,服务器端为一个web资源,配置多个过滤器拦截 ,这多个过滤器,就会组成过滤器链 FilterChain, 调用FilterChain的doFilter 表示要执行过滤器链下一个资源,如果当前过滤器已经是链上最后一个过滤器,就会执行目标资源
* web服务器根据Filter在web.xml文件中的注册顺序<mapping>,决定先调用哪个Filter
Filter生命周期 init(FilterConfig) doFilter(request,response,filterChain) destroy()
1、Filter对象在tomcat服务器启动时 创建,调用init方法 (只会创建一个对象,init方法执行一次)
2、doFilter 每次拦截目标资源时,执行
3、destroy 服务器关闭时执行
FilterConfig 作用和 ServletConfig 类似,用来在Filter初始化阶段,将参数传递给过滤器
1、通过 String getInitParameter(String name) 获得过滤器初始化参数
2、通过 ServletContext getServletContext() 获得ServletContext对象
* FilterConfig 提供参数,是Filter类私有参数,Filter2的初始化参数,不能在Filter1 中进行获取
* 配置全局参数,<context-param> 进行配置,通过ServletContext 获得
<filter-mapping> 过滤器拦截配置
1、如果连接目标资源是一个Servlet,可以选择url和servlet名称两种配置方式
<!-- 拦截/hello是Servlet 路径 -->
<url-pattern>/hello</url-pattern>
<!-- 拦截Servlet 还可以通过Servlet 名称进行拦截 -->
<servlet-name>HelloServlet</servlet-name>
2、url-pattern 和 Servlet中路径写法一样,有三种 : 完全匹配、目录匹配、扩展名匹配
3、<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式
容器调用服务器端资源 有四种方式
REQUEST、FORWARD、INCLUDE、ERROR
案例分析:
全站乱码过滤器:
对于get请求,如何处理乱码
ackage com.dzq.filter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; @WebFilter(filterName = "AEncodeFilter", urlPatterns ="/*",initParams={@WebInitParam(name="encode",value="utf-8")}) public class EncodeFilter implements Filter { private FilterConfig config = null; private String encode = null; public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { response.setContentType("text/html;charset="+encode); //--解决响应乱码 chain.doFilter(new MyHttpServletRequest((HttpServletRequest) request), response);//--包装改造request中和获取请求参数相关的方法解决请求参数乱码 } public void init(FilterConfig filterConfig) throws ServletException { this.config = filterConfig; encode = config.getInitParameter("encode") == null ?"utf-8" :config.getInitParameter("encode"); } class MyHttpServletRequest extends HttpServletRequestWrapper{ private HttpServletRequest request = null; private boolean isNotEncode = true; public MyHttpServletRequest(HttpServletRequest request) { super(request); this.request = request; } @Override public Map getParameterMap() { try{ if(request.getMethod().equalsIgnoreCase("POST")){//--如果是post提交,一行代码解决post提交请求参数乱码 request.setCharacterEncoding(encode); return request.getParameterMap(); }else if(request.getMethod().equalsIgnoreCase("GET")){//--如果是get提交,则应该手动编解码解决乱码 Map<String,String[]> map = request.getParameterMap();//获取有乱码的map if(isNotEncode){//只能在第一次解决乱码 for(Map.Entry<String, String[]> entry : map.entrySet()){//遍历map,解决所有值的乱码 String [] vs = entry.getValue(); for(int i=0;i<vs.length;i++){ vs[i] = new String(vs[i].getBytes("iso8859-1"),encode); } } isNotEncode = false;//设置为false,第二次就不会再进这个代码块了 } return map; }else{ return request.getParameterMap(); } }catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } @Override public String[] getParameterValues(String name) { return (String[]) getParameterMap().get(name); } @Override public String getParameter(String name) { return getParameterValues(name) == null ? null : getParameterValues(name)[0]; } } }
30天自动登录过滤器:
package com.dzq.filter; import java.io.IOException; import java.sql.SQLException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import com.dzq.domain.User; import com.dzq.utils.DaoUtils; /** * Servlet Filter implementation class AutoLoginFilter */ @WebFilter(filterName="/AutoLoginFilter",urlPatterns="/*") public class AutoLoginFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest) request; HttpServletResponse res=(HttpServletResponse) response; if(req.getSession(false)==null||req.getSession().getAttribute("user")==null){ Cookie[] cs=req.getCookies(); Cookie findc=null; if(cs!=null){ for(Cookie c:cs){ if("autologin".equals(c.getName())){ findc=c; break; } } } if(findc!=null){ String name=findc.getValue().split(":")[0]; String password=findc.getValue().split(":")[1]; String sql="select * from user where name=? and password =?"; User user=new User(); QueryRunner runner=new QueryRunner(DaoUtils.getSource()); try { user=runner.query(sql, new BeanHandler<User>(User.class),name,password); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } if(user!=null){ req.getSession().setAttribute("user", user); } } } chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { } }