Filter

1. 过滤器简介

1. 过滤器是Java Web三大组件之一,它在很多方面都与Servlet相似
2. 过滤器可以理解成拦截器,其实过滤器的代码是环绕在被访问资源的前后,为被访问的资源提供增强的作用(比如过滤器就像楼层中保安,所有人员经过楼层必须经过保安)
3. 过滤器的应用场景:
	1). 执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作
	2). 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用
	3). 在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理

2. 过滤器编写步骤

1. 编写一个类实现javax.servlet.Filter接口。在doFilter方法中编写过滤代码
2. 在web.xml中配置哪些资源要经过该过滤器
	<filter>
		<filter-name>命名</filter-name>
		<filter-class>包名.类名</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>命名</filter-name>
		<url-pattern>拦截的资源</url-pattern>
	</filter-mapping>

一个目标资源可以指定多个过滤器,过滤器的执行顺序是在web.xml文件中的</filter-mapping>部署顺序

3. 过滤器的执行过程和生命周期

1、过滤器是在应用启动时就完成了实例化和初始化
2、对于过滤范围内资源的每次访问都会调用doFilter
3、应用被卸载时会调用destory方法

4. FilterConfig&FilterChain

ServletConfig
	ServletContext getServletContext():获取ServletContext的方法;
	String getFilterName():获取Filter的配置名称;与<filter-name>元素对应;
	String getInitParameter(String name):获取Filter的初始化配置,与<init-param>元素对应;
	Enumeration getInitParameterNames():获取所有初始化参数的名称
FilterChain
	doFilter()方法的参数中有一个类型为FilterChain的参数,它只有一个方法:doFilter(ServletRequest,ServletResponse)
区别:
	1.个数不同  
		Filter接口doFilter是3个参数:			ServletRequest,ServletResponse,FilterChain
		FilterChian的doFilter是2个参数:			ServletRequest,ServletResponse
	2.作用不同
		Filter接口doFilter拦截作用
		FilterChian中doFilter起放行作用

5. 过滤器其他配置

过滤四个类型:REQUEST FORWARD INCLUDE  ERROR
<filter-mapping>
    <filter-name>Filter06_Typetest</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>	<!-- 默认REQUEST,如果配置了其他类型,默认的就没有了 -->
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

6. 巩固包装设计模式

1、装饰模式口诀
	a、定义一个类实现与被包装类相同的接口
	b、定义一个变量记住被包装类对象的引用
	c、定义构造方法,传入被包装类对象的实例
	d、对于要改写的方法,改写即可
	e、对于不需要改写的方法,调用被包装对象的对应方法
2、装饰模式变化
	改写的方法所在的类,本身就是个包装类
	a、定义一个类,继承要包装的类
	b、定义一个变量,记住被包装类的引用
	c、定义构造方法,传入被包装类的实例
	d、覆盖要改写的方法

过滤器的案例

1. 过滤器简单案例(编码/静态和动态缓存控制)

1. 过滤器中实现设置编码
	强转request和response
	强转request和response、初始化容器时赋值config属性
	String encoding = config.getInitParameter("encoding");
	request.setCharacterEncoding(encoding);
	response.setContentType("text/html;charset="+encoding);
	chain.doFilter(request, response);

2. 全站动态资源无缓存
	强转request和response
	response.setHeader("Expires", "0");
	response.setHeader("Cache-Control", "no-cache");
	response.setHeader("pragma", "no-cache");
	chain.doFilter(request, response);

3. 静态资源设置缓存时间
	强转request和response
	String uri = request.getRequestURI();
	String extendsionName = uri.substring(uri.lastIndexOf(".")+1);
	
	String time = "0";
	time = config.getInitParameter(extendsionName);
	request.setCharacterEncoding("UTF-8");
	response.setContentType("text/html;charset=UTF-8");
	
	if(time != null) {
		response.setDateHeader("Expires", System.currentTimeMillis()+Integer.parseInt(time)*60*60*1000);
	}
	
	chain.doFilter(request, response);

最后勿忘配置web.xml文件

2. 用户自动登录

用户自动登录案例
1. 新建数据库中的表和对应的JavaBean对象
	create database day19;
	use day19;
	create table user(
		id int primary key,
		username varchar(100) not null unique,
		password varchar(100) not null
	);
	
	private int id;
	private String username;
	private String password;
2. 数据访问层UserDaoImpl类
	void save(User user)
	User find(String username, String password)
3. 工具类
	引入DBUtils/C3P0Util/EncodingUtil工具类
4. 业务逻辑层BusinessServiceImpl类
	public void register(User user)
	public User findUser(String username, String password)
5. LoginServlet类
	过滤器解决乱码问题
	5.1 获取请求参数
	5.2 调用业务逻辑判断是否登录成功
	5.3 将用户名和密码设置在cookie信息中Cookie c = new Cookie("loginInfo",loginInfo);
	5.4 判断用户选择的方式,设置相应的有效期
	5.5 设置cookie路径
	5.6 将cookie添加到响应头中
	5.7 重定向到首页
	
6. LogoutServlet类
	6.1 移除session域中的user
	6.2 新建空的cookie信息,设置cookie的有效期为过期0,设置cookie路径,添加到response头信息中
	6.3 重定向到首页

7. 过滤器类,处理编码
	7.1 获取初始化的参数
	7.2 设置编码之后再放行
	
8. 自动登录过滤器类AutoLoginFilter
	8.1 强制request,response
	8.2 获取请求的uri信息
	8.3 如果请求的参数不是以login.jsp登录
	8.4 获取session域中的user
	8.5 如果user为空
	8.6 获取请求的cookie信息
	8.7 如果获取的cookie为空重定向登录页面
	8.8 遍历所有cookie,如果为是用户的cookie就赋值为新cookie,break;
	8.9 如果赋值的新cookie不为空,获取cookie中的值
	8.10 切割value获取username和password中的值
	8.11 解码用户名,调用业务逻辑层方法判断用户名和密码
	8.12 如果获得的用户名不为空,将用户设置到session域中
	8.13 chain放行
	
	
页面设计
	1. login.jsp	用户登录页面提供选择有效期,提交到LoginServlet类
	2. top.jsp		头部,如果session域中的用户为空,提示登录,如果不为空,提示欢迎界面,提供注销功能
	3. index.jsp	引入top.jsp,提供帖子链接
	4. 1.jsp 		帖子链接

3. 过滤器拓展案例(全站编码/敏感词汇/html标签过滤)

1. 全站编码问题
	1). 强转request/response
	2). 设置编码为了解决post编码问题
	3). 若解决get提交编码问题,在doFilter放行之前包装一下request对象
	4). 定义MyHttpServletRequest继承HttpServletRequestWrapper
	5). 重写getParameter方法
		super.getParameter(name);接收用户请求的的参数的值
		如果为空直接返回null
		判断请求的方式super.getMethod(),如果get请求,将请求的值编码再解码
		
2. 敏感词汇过滤
	1). 强转request/response
	2). 在doFilter放行之前包装一下request对象
	3). 定义MyHttpServletRequest继承HttpServletRequestWrapper
	4). 定义词库词汇
	5). 获取请求参数的值,如果为空,直接返回空
	6). 遍历词库,替换请求参数的值
	7). 最后返回请求参数的值
	
3. HTML标签过滤
	1). 强转request/response
	2). 在doFilter放行之前包装一下request对象
	3). 定义MyHtmlServletRequest继承HttpServletRequestWrapper
	4). 调用filter方法替换请求参数的值
	5). filter方法在tomcat\webapps\examples\WEB-INF\classes\util\HTMLFilter.java

4. 全站压缩

1. 建立GZIP压缩过滤类GzipFilter
2. 在放行之前改写response,然后把改写之后的response传给doFilter
3. 针对HttpServletResponseWrapper,改写类为MyHttpServletResponse,重写其中的getOutputStream和getWriter方法
	3.1 定义临时容器
	3.2 定义获取临时容器的数据getBufferByte()
6. 针对临时容器,实现HttpServletResponseWrapper,提供write方法将数据写到临时容器中