过滤器和监听器
过滤器
1.Servlet最激动人心三大技术:Servlet,Filter,Listener
2.过滤器(Filter):Servlet三大技术之一,在服务器可以管理所有web资源,本质特殊java类.
WEB开发人员通过Filter技术,对web服务器管理 的所有web资源:例如Jsp, Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊 的功能。
过滤器的作用:实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功 能。
3.过滤器工作原理:
4.手动写过滤类:
4.1:先创建一个Java类,实现javax.servlet.Filter接口;
4.2:实现接口中init(),doFilter(),destroy();
4.3:在web.xml中注册过滤器
注意:配置版的过滤器在过滤器链中顺序由注册顺序.
eg:<!--注册过滤器-->
<filter>
<filter-name>FirstFilter</filter-name><!--过滤器注册名-->
<filter-class>com.qf.day46.filter.FirstFilter</filter-class><!--过滤器全限制类名:包名+类名-->
</filter>
<!--配置过滤过滤请求的路径-->
<filter-mapping>
<filter-name>FirstFilter</filter-name><!--过滤器的注册名,与上面注册名相同-->
<url-pattern>/*</url-pattern><!--过滤所有请求-->
</filter-mapping>
//等同于用注解在类名上注册
@WebFilter(filterName = “SecondFilter”,value = “/")//配置注册信息和映射请求
简写为:@WebFilter("/”)
注意:注解版的过滤器在过滤器链中顺序由注册过滤器名称决定.
5.过滤器的生命周期:当项目发布时,由服务器容器调用构造方法,实例化过滤器,再由服务器容器通过过滤实例调用init()初始过滤器,当客户端发送请求到服务器时,由服务器容器通过过滤器实例调用doFilter方法,再将请求传到Servlet中处理,Servlet处理完请求响应信息,由服务器容器通过过滤器实例调用doFilter方法,再将响应信息传到客户端.当web项目停止发布时就调由服务器容器通过过滤器实例调用destroy()销毁过滤器实例.
(与web项目同生共死)
6.Servlet3.0之后,注解的过滤器:在过滤类上面配置注解@WebFilter,可配置属性
7.字符编码过滤器:
原来实现:请求和响应对象是在Servlet中处理编码
现在实现:在过滤器中处理编码,将处理好编码的请求和响应对象传Servlet中,Servlet就 不会再处理编码
实现思路:声明一个字符编码过滤器,在过滤器中将响应的编码和请求编码提前编码后,后 面在将请求和响应对象传Servlet中就不用处理编码.注意,因为get请求的 编码无法统一在类中设置,所以就想重写获得请求中数据的方法.因为要重 写获得请求中数据的方法,所以请求对象要用装饰都模式.
eg:/**
* 字符编码过滤器
*/
@WebFilter("/*")
public class EncoddingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
/**
* 过滤方法
* @param request
* @param response
* @param chain
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
//统一处理响应编码
response.setCharacterEncoding("utf-8");
/*处理请求编码*/
//将请求对象转换为HttpServletRequest
HttpServletRequest request2=(HttpServletRequest)request;
//获得请求方法类型
if ("GET".equalsIgnoreCase(request2.getMethod())){
//创建请求的装饰者对象,将原来的请求对象作为构造方法的参数
MyRequest mr=new MyRequest(request2);
chain.doFilter(mr, response);
}else if("POST".equals(request2.getMethod())){//post请求
request2.setCharacterEncoding("utf-8");
chain.doFilter(request2, response);
}
}
/**
* 装饰者请求类(成员内部类)
*/
public class MyRequest extends HttpServletRequestWrapper{
public HttpServletRequest request;
public MyRequest(HttpServletRequest request) {
super(request);
this.request=request;
}
/**
* 重写获得单个请求值的方法
* @param name
* @return String
*/
@Override
public String getParameter(String name) {
//获得请求中值
String value=super.getParameter(name);
try {
if(value!=null&&!value.equals("")){
//重写编码
value=new String(value.getBytes("ISO-8859-1"),"utf-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}
/**
* 重写获得请求中一组数据值的方法
* @param name
* @return String
*/
@Override
public String[] getParameterValues(String name) {
//获得请求中一组数据值
String[] values=super.getParameterValues(name);
//将数据值一一编码
if (values!=null||values.length!=0){
for (int i=0;i<values.length;i++){
try {
values[i]=new String(values[i].getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return values;
}
/**
* 重写获得请求中所有值的方法
* @return String
*/
@Override
public Map<String, String[]> getParameterMap() {
Map<String,String[]> hmap1=super.getParameterMap();
//处理请求中每个数据的编码
for (String key:hmap1.keySet()){
//通过key得到value值
String[] values=hmap1.get(key);
//将数据值一一编码
if (values!=null||values.length!=0){
for (int i=0;i<values.length;i++){
try {
values[i]=new String(values[i].getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
return hmap1;
}
}
}
8.权限验证过滤器
原来效果:无论用户是否登录都可以直接访问首页,或其他页面.
实现效果:只有登录过的用户才能访问首页和其他页面,没有登录过的用户,如果直接访问 首页或其他页面,让其3秒跳转到登录页并提示你还没有登录,无法作其他操作.
实现原理:因为每次请求时都要先经过过滤器再经过Servlet,所以就想一个权限验证过滤 器,在这个过滤器中作判断,判断只有登录过的用户才放行调用
chain.doFilter (mr, response);,否则让用户跳转到登录页面.
就超市系统来说:只有登录的页面,登录的请求方法,已经登录过的用户,css,js,img放行
eg:/**
* 权限验证过滤器
*/
@WebFilter("/*")
public class AccessFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将请求和响应对象转换为子类对象
HttpServletRequest request=(HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse)resp;
//获得session登录的用户信息
Object ob=request.getSession().getAttribute("u");
//获得请求的uri
String uri=request.getRequestURI();
//获得请求的方法名
String method=request.getParameter("method");
//如果是默认起始页,/web_market/login.jsp,登录请求,已经登录过的用户也要放行
if("/web_market/".equals(uri)||"/web_market/login.jsp".equals(uri)||"login".equals(method)||ob!=null){
//放行,继续执行请求
chain.doFilter(request, response);
}else{//没登录,无法处理后面的请求,就要三秒跳转到登录页面
//设置响应的内容类型
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("你还没有登录,无法进行其他操作,3秒后跳转到登录页面");
response.setHeader("refresh","3;url=login.jsp");
}
}
public void init(FilterConfig config) throws ServletException {
}
}
监听器
1.监听器:Servlet的三大技术之一,本质是一种特殊Java类.
作用:监听器用于监听web应用中某些对象(request,session,application(相当于Servlet中ServletContext对象))、信息的创建、销毁、增加,修改,删除等动作 的发生,然后作出相应的响应处理。
事件监听涉及到三个组件:事件源、事件参数、事件监听器.
2.监听器的分类:
2.1:ServletContextListener接口; ServletContext对象监听器,监听ServletContext对 象创建和销毁.
2.2:ServletContextAttributeListener接口; ServletContext对象的属性监听器,监听 ServletContext对象的属性添加,修改,删除操作
2.3:HttpSessionListener接口;Session对象监听器,监听session对象创建和销毁.
2.4:HttpSessionAttributeListener接口;Session对象的属性监听器,监听session对象 的属性添加,修改,删除操作
2.5:ServletRequestListener接口; Request对象监听器,监听Request对象创建和销毁.
2.6:ServletRequestAttributeListener; Request对象的属性监听器,监听Request对象 的属性添加,修改,删除操作
3.手写监听器
3.1:创建一个Java类,实现监听器接口.
3.2:重写监听器接口中方法.
3.3:在web.xml中注册监听器.
eg:<!--注册监听器-->
<listener>
<listener-class>com.qf.day46.listener.FirstLintener</listener-class>
</listener>
4.注解版监听器:在监听器类上面配置@WebListener
5.监听器生命周期:项目发布时就创建监听器实例对象,当监听的对象创建时就调用监听方法, 当监听对象销毁时,就调用监听对象的销毁方法,但监听器实例还在,当项目停止发 布时,就销毁监听器对象.(与web项目同生共死)
6.统计网站访问总量
分析:来了一个客户端,访问总量就加一.
通过session对象判断是否来了客户.
访问总量数据存在全局对象中.
eg:/**
* 注解版的监听器
*/
@WebListener
public class SecondListener implements HttpSessionListener{
public SecondListener() {
System.out.println("SecondListener实例化方法");
}
public void sessionCreated(HttpSessionEvent e) {
System.out.println("来了一个客户端...");
//获得全局对象中访问总量
Object ob=e.getSession().getServletContext().getAttribute("count");
if (ob==null){//你是第一个访问的客户端
e.getSession().getServletContext().setAttribute("count",1);
}else{//不是第一个访问
//声明一个变量存访问总量
Integer num=Integer.valueOf(ob.toString())+1;
e.getSession().getServletContext().setAttribute("count",num);
}
System.out.println("当前网站访问总量为:"+e.getSession().getServletContext().getAttribute("count"));
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("走了一个客户端");
}
}
7.监听器监听属性:
eg:/**
* 属性监听器
*/
@WebListener
public class AtrributeListener implements ServletRequestAttributeListener, HttpSessionAttributeListener {
/**
* 请求对象中添加属性
* @param e
*/
@Override
public void attributeAdded(ServletRequestAttributeEvent e) {
System.out.println("向请求对象添加属性名:"+e.getName()+",属性值:"+e.getValue());
}
/**
* 请求对象中删除属性
* @param e
*/
@Override
public void attributeRemoved(ServletRequestAttributeEvent e) {
System.out.println("删除请求对象中属性为:"+e.getName()+",属性值为:"+e.getValue());
}
/**
* 请求对象中修改属性
* @param e
*/
@Override
public void attributeReplaced(ServletRequestAttributeEvent e) {
System.out.println("修改请求对象中属性为:"+e.getName()+",属性值为:"+e.getValue());
}
/**
* 会话对象中添加属性
* @param e
*/
@Override
public void attributeAdded(HttpSessionBindingEvent e) {
System.out.println("向会话对象添加属性名:"+e.getName()+",属性值:"+e.getValue());
}
/**
* 会话对象中删除属性
* @param e
*/
@Override
public void attributeRemoved(HttpSessionBindingEvent e) {
System.out.println("删除会话对象中属性为:"+e.getName()+",属性值为:"+e.getValue());
}
/**
* 会话对象中修改属性
* @param e
*/
@Override
public void attributeReplaced(HttpSessionBindingEvent e) {
System.out.println("修改会话对象中属性为:"+e.getName()+",属性值为:"+e.getValue());
}
}