/*
*filter
*介绍
*定义:拦截浏览器向服务器发送的请求,即可以控制访问权限
*javax.servlet.Filter接口
*这个接口中有一个doFilter(),这个方法是真正用于过滤的
*filter也需要在web.xml中配置
*作用:验证过滤器
日志记录和审计过滤器
图像转换过滤器
数据压缩过滤器
加密过滤器
标记过滤器
触发资源访问事件过滤器
*创建filter:
*创建一个类,实现javax.servlet.Filter接口
*重写接口中的方法
*在web.xml中配置
**filter怎样实现过滤操作
*url-pattern:配置要被filter过滤的资源
*doFilter方法中的第三参数FilterChain,用于控制是否可以访问资源
如果允许访问资源,则调用FilterChain的doFilter方法。
注意:FilterChain的doFilter方法只是和filter的doFilter方法名字相同,并不是递归
*生命周期:
*public void init(FileterConfig fileterConfig) throws ServletException:初始化方法,服务器加载时只执行一次
*public void doFilter(request,response,chain):真正进行拦截的操作
同chain的doFilter方法向下执行
*public void destroy():销毁操作
*FileterConfig:在filter的init方法中的一个参数
*ServletConfig:获得初始化参数
获得servlet名字
获得servletContext对象
*FileterConfig:获得filter的相关配置信息
*初始化参数的获取
getInitParameter(String name)
Enumeration getInitParameterNames()
*filter名称的获取
getFilterName() :获得的是在web.xml中配置的filter名字
*servletContext对象的获取
*getServletContext()
*相关配置
*配置filter
filter名字,可以不使用filter类名
filter类的全类名路径
初始化参数
参数名称
参数值
filter名字
要拦截的资源路径
*filter Chain filter链
*一个web项目中,可以编写多个filter,这些filter组合起来叫做filter链
*多个filter执行的顺序,是按照filter-mapping配置的前后顺序
即,filter-mapping中位置在前面的先执行,位置在后面的后执行
*FilterChain的doFilter:这个代表的是向下执行,如果下一个还是filter,就访问filter
如果当前filter已经是整个filter chain的末尾,才访问web资源
*url-pattern:用于确定拦截过过滤的资源路径
*配置方式
*完全匹配,必须以”/“开始,
*可以使用*通配符 通配符用得比较多,因为filter一般是用于过滤某一类东西或一些东西
*目录匹配 /* 要求必须以“/”开始
*扩展名匹配 *.do 不能以“/”开始,必须以*.xxx结束
*
:针对某一个servlet进行拦截,需要的是servlet的名称
*如果一个filter-mapping中配置了servlet-name,那么它的顺序与url-pattern不一样
*对于tomcat7,如果在一个filter-mapping中配置了servlet-name,还配置了url-pattern
这个filter只执行一次,但是tomcat6会执行两次
*
:设置访问资源方式的拦截
*可以取得的值:
*REQUEST 默认值,代表直接访问资源
*FORWARD 请求转发
*INCLUDE include包含的访问
*ERROR 声明式异常拦截
*
*小示例:设置图片缓存时间
*请求一个带图片的页面要发送几次请求,接收几次响应呢?
*都是两次:一次页面资源,一次图片资源
*让图片缓存的目的:提高访问的性能或效率
response。setDataHeader("expires",时间长度);
*案例
*自动登录:
*首先要有登录功能
*完成自动登录
*登录时判断是否勾选了自动登录选项
*如果勾选了自动登录,将用户名和密码存入cookie中
*CheckBox的value,如果勾选了,后台根据request.getParameter("CheckBox名称")可以获取CheckBox的value
*做一个filter,拦截所有请求
当访问资源时,从cookie中获取用户名和密码,进行登录操作
*问题:
*如果用户已经登录了,还就不需要自动登录了
*在filter中判断用户是否登录了,即从session中获取用户,如果为null,
*如果用户想要进行注册登录操作,也不需要自动登录了
*得到请求资源路径,判断是否是需要自动登录的路径
http://localhost:/day21/demo/success.jsp
String uri=request.getRquestURI(); //day21/demo/success.jsp
String contextPath=request.getContextPaht(); //day21
String path=uri.subString(contextPath.length()); //demo/success.jsp
*如果用户名时中文
*存储时编码 URLEncoder.encoder(username,"utf-8");
*使用时解码 URLDecoder.decoder(username,"utf-8");
*密码的安全性问题
*对密码加密--MD5加密
*好处:理论上不可逆,即不可破解
明文+密钥=密文
public static String md5(String plainText)
{ //明文
byte[] secretBytes = null;
try
{
secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);
for (int i = 0; i < 32 - md5code.length(); i++)
{
md5code = "0" + md5code;
}
return md5code;
}
//哈哈,代码不用背
*url级别权限控制
*权限控制原理:在filter中判断用户是否登录
如果登录了,就可以访问资源
如果没登录,就不可以访问资源
*但是,有的资源,是不需要权限就可以访问的
所以在判断用户之前,先判断是否是需要权限的资源
*全局编码过滤器
*其实就是在request中对编码进行设置,那么,怎么对request进行增强可以解决编码问题呢?
*使用装饰设计模式来对request进行增强
*装饰步骤:
*装饰类于被装饰类要实现同一个接口或继承自同一个父类
*在装饰类中要持有一个被装饰类的引用
*重写方法,功能增强
*代码实现:
*直接实现httpServletRequest接口,需要重写的方法太多
所以,查看httpServletRequest接口是否有其他实现类,就像适配器一样。
直接实现监听器接口,方法太多,所以查找适配器类,继承它,重写我需要的方法
// 装饰类
class MyRequest extends HttpServletRequestWrapper
{
private HttpServletRequest request;
public MyRequest(HttpServletRequest request)
{
super(request);
this.request = request;
}
}
*要重写关于请求参数获取的方法
String getParameter(String name)
String [] getParameterValues(String name)
Map
getParameterMap()
**getParameter和getParameterValues可以依赖于getParameterMap方法
即只需要重点重写getParameterMap方法就可以了
其他两个方法只需要在内部调用getParameterMap方法就可以了
*问题:
*先得到有编码问题的map集合
*遍历map集合,将集合中的所有的value得到并进行转码,解决乱码问题
private boolean flag = true;
public Map getParameterMap()
{
Map
map=request.getParameterMap();
if (flag)
{
for (String key : map.keySet())
{
String[] values = map.get(key);
for (int i = 0; i < values.length; i++)
{
try
{
values[i] = new String(values[i].getBytes("iso8859-1"),"utf-8");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
}
flag = false;
}
return map;
}
*编码处理值需要处理一次,不需要每一次都处理
多次处理反而会出错,所以增加一个类似开关的东西
如果是第二次来,就不进行转码了
*/
我现在果然是在赶进度,代码都是看看,全部没实践。哎。。。