Filter也称之为过滤器,开发人员通过Filter技术,对web服务器管理的所有web资源:例如 Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
第一步:创建Filter处理类;
package com.prosay.filter;
import java.io.IOException;
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.http.HttpServletRequest;
/**
* 统一的编码处理程序
* @author jame
* 1.实现Filter接口
* 2.在Web.xml中配置
*/
public class EncodingFilter implements Filter{
private String encoding;
/**
* 过滤器被执行的核心方法
* tomcat接收的每一个请求都会建立一个子线程处理,子线程创建的调用Dofilter(request response)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("编码过滤器开始………………");
//在前面设置好编码
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
response.setCharacterEncoding("UTF-8");
//EncodingWrapper wrapper = new EncodingWrapper((HttpServletRequest)request);
//chain.doFilter(wrapper, response);
//执行下一个步骤(另外一个过滤器或者是真实的资源)
chain.doFilter(request, response);
System.out.println("编码过滤器结束………………");
}
@Override
public void init(FilterConfig config){
encoding = config.getInitParameter("encoding");
System.out.println("过滤器被初始化!!…………………………");
}
}
package com.prosay.filter;
/**
* 用户的权限校验
* @author jame
*
*/
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@SuppressWarnings("serial")
public class UserFilter extends HttpFilter{
@Override
public void doFilter(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException{
//request中去获取session
HttpSession session = request.getSession();
ServletContext application = request.getServletContext();
String userName = (String)session.getAttribute("userName");
System.out.println("用户权限过滤器开始………………");
//说明当前会话中存在用户名(表示已经登陆了)
if(userName!=null){
chain.doFilter(request, response);
}else{
response.sendRedirect("../index.html");
}
System.out.println("用户权限过滤器结束………………");
//this.getServletContext();
}
}
第二步:web.xml文件中配置Filter。
配置Filter时要声明filter-name(filter的别名)和filter-class(filter的类路径),也可以设置属性,然后在filter类取出来。
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>com.prosay.filter.EncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>userFilterfilter-name>
<filter-class>com.prosay.filter.UserFilterfilter-class>
filter>
<filter-mapping>
<filter-name>userFilterfilter-name>
<url-pattern>/chatroom/*url-pattern>
filter-mapping>
当请求一个资源时,服务器会查询web.xml中所有对此资源路径进行过滤的filter,并根据在web.xml中的先后顺序形成一个filter链(filterchain)。就是按写在web.xml中的filter类顺序执行。
监听器也叫Listener,是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。
ServletContextListener是ServletContext的监听者,它能够监听ServletContext对象的生命周期,也就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件
由 ServletContextListener 来处理 。
package com.prosay.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 配置load-on-starup的Servlet可以跟随Tomcat的启动初始化
* ServletContextListener能够比他更早启动
* @author jame
* 1.实现ServletContextListener接口
* 2.实现对应的方法
* 监听的是上下文的对象生命周期(初始化和销毁)
*/
public class InitListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent event){
System.out.println("项目从容器中卸载了…………");
}
@Override
public void contextInitialized(ServletContextEvent event){
System.out.println("项目被容器加载…………");
System.out.println("***********聊天室服务器初始化开始***********");
ServletContext application = event.getServletContext();
//第一次访问(初始化)创建一个ArrayList用来存储消息列表,然后将这个ArrayList实例存入Servlet上下文中
List msgs = new ArrayList();
//servletContext存属性方式 setAttribute(String attrName,Object attr)
application.setAttribute("msgs",msgs);
//servletContext httpSession 对象的存储 整个应用生命周期中存储属性 httpsession 整个会话中的存储属性
//在线用户列表
List userList = new ArrayList();
application.setAttribute("users",userList);
System.out.println("***********聊天室服务器初始化完毕***********");
}
}
package com.prosay.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class SecondListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
System.out.println(event.getSource()+"#####");
}
}
package com.prosay.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
/**
*
* @author jame
*
*/
public class ApplicationAttrListener implements ServletContextAttributeListener{
/**
* 监听servletContext实例的新添加的属性
*/
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("上下文中增加了:"+scae.getName()+":"+scae.getValue());
}
/**
* 监听ServletContext实例移除的属性
*/
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("上下文中移除了属性:"+scae.getName()+":"+scae.getValue());
}
/**
* 监听ServletContext实例中的属性被替换时发生
*/
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("上下文中增加了:"+scae.getName()+":"+scae.getValue());
}
}
<listener>
<description>上下文监听器,来替换InitServletdescription>
<listener-class>com.prosay.listener.InitListenerlistener-class>
listener>
<listener>
<listener-class>com.prosay.listener.SecondListenerlistener-class>
listener>
<listener>
<description>上下文属性监听器description>
<listener-class>com.prosay.listener.ApplicationAttrListenerlistener-class>
listener>
web.xml中的listener的这个声明顺序,运行后的输出为:
项目被容器加载…………
*********** 聊天室服务器初始化开始***********
上下文中增加了:msgs:[]
上下文中增加了:users:[]
***********聊天室服务器初始化完毕***********
org.apache.catalina.core.ApplicationContextFacade@4a3631f8#####
过滤器被初始化!!…………………………
如果把SecondListener提到前面输出结果为:
org.apache.catalina.core.ApplicationContextFacade@4a3631f8#####
项目被容器加载…………
*********** 聊天室服务器初始化开始***********
上下文中增加了:msgs:[]
上下文中增加了:users:[]
***********聊天室服务器初始化完毕***********
过滤器被初始化!!…………………………
把ApplicationAttrListener提到前面输出结果为:
项目被容器加载…………
*********** 聊天室服务器初始化开始***********
上下文中增加了:msgs:[]
上下文中增加了:users:[]
***********聊天室服务器初始化完毕***********
过滤器被初始化!!…………………………
org.apache.catalina.core.ApplicationContextFacade@4a3631f8#####
说明,写在web.xml前面的监听器先检测到,代码先运行,但是如果写在前面,监听的内容没有触发的话代码也是不会先运行的。
HttpSessionListener监听HttpSession的操作。
当创建一个Session时,激发session Created(HttpSessionEvent se)方法;
当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。
服务器向浏览器发送一个302状态码及一个Location消息头,浏览器在收到后会立即向这个地址发送请求。
sendRedirect(String location)
转发:服务器将客户端的请求转发到另外一个页面
request.getRequestDispatcher(String path)
forward(HttpServletRequest request, HttpServletResponse response)
1) 重定向时,客户端发送了两个请求;而转发时,客户端只发送了一个请求(本质区别)
2) 重定向时,客户端浏览器的地址栏有变化,而转发时,客户端浏览器的地址栏没有变化
3) 重定向发生在客户端,而转发是发生在服务端,客户端不知道
1) 只是页面跳转的话,且没有业务请求处理参数等,可以使用重定向,也可以使用转发过去。
2,如果请求跳转页面有业务处理,则必须使用转发,但是有两点需要处理:
1)如果我们的action请求的jsp页面的有业务逻辑处理或者请求其他命名空间的action时,在不同的命名空间里面,那么必须使用”../”来跳出当前的路径请求,在进入其他的命名空间+其他的action请求,这样才会使页面的其他导入文件才不会有丢失的情况;
2)当然,如果要跳转到注册,或者表单提交页面时,最后使用重定向比较好,这样不会有属性冲突,造成数据提交异常,但有时候却要转发过去,具体看是否需要当前的request请求参数;