Notes

JSP | 04 会话跟踪 & 过滤器

🌸Author Echo Pan


1. HttpSession 会话跟踪技术

1.1. 概念

会话(Session)是指在一段时间内,某一客户与服务器之间一连串相关的交互过程。当前浏览器与服务器之间的多次请求和响应关系被称为一次会话。在一个会话中,用户可以多次访问同一网页,也可以访问该服务器的其他资源。

1.2. 跟踪机制

HttpServlet接口位于javax.servlet.http包,每一个Servlet容器(如Tomcat)都必须实现该接口。

当一个会话开始时,容器会创建一个HttpSession对象,并为该对象分配一个唯一标识,即sessionID。容器会把sessionID保存在客户端的浏览器中。每当客户发出一个HTTP请求时,容器就可以从客户端读取到sessionID,并根据该标识找到对应的HttpSession对象,从而获取客户的状态信息。

1.3. 会话的创建和使用

1.3.1. 获取会话

Httpsession session = HttpServletRequest.getSession([true]|[false]);

当参数为空或true时,如果存在会话则返回该会话,不存在时则创建一个新会话并返回;当参数为false时,如果会话不存在则返回null

1.3.2. 常用方法

setAttribute() 添加属性及属性值

getAttribute() 获取属性值,返回Object类型

getAttributeNames() 获取所有属性名,返回一个数组

removeAttribute() 移除一个属性


getCreationTime() 获取会话创建的时间

getId() 获取会话ID

getLastAccessedTime() 获取最后一次访问会话的时间戳,毫秒

getMaxInactiveInterval() 获取会话有效期

isNew() 打开页面时,判断该页面的session是否是首次创建

setMaxInactiveInterval() 设置最大有效期,单位秒


Invalidate() 释放会话

1.3.3. 简单计数

假设我们在doGet()方法中使用session对象:

//先设置一个可供链接访问该servlet的注解
@WebServlet("/servlet/Counter");

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                        throws ServletException, IOException {
    //设置中文编码
    response.setContentType("text/html;charset=UTF-8");

    //创建一个session
    HttpSession session = request.getSession(true);
    Object count = session.getAttribute("counter");
    int counter=0;

    //判断session参数是否存在
    if(count == null){
      counter=1;//不存在则给计数器赋值1,表示开始计数
      session.setAttribute("Counter",counter);//更新session参数值
    }else{
      counter = Integer.parseInt(String.valueOf(count));//存在则获取session参数
      counter+=1;//并表示计数加1
      session.setAttribute("Counter",counter);//更新session参数
    }

    //下面输出试试看,尝试多刷新几次网页
    PrintWriter out = response.getWriter();
    out.println("计数器测试:第"+session.getAttribute("Counter")+"次");
    out.flush;
    out.close;
}

1.4. 会话的生命周期

  1. 创建
    浏览器访问服务器时,容器即为用户创建一个session对象
  2. 关闭
    1. session.invalidate()方法
    2. 超过有效期
    3. 关闭浏览器

2. 过滤器

2.1. 简介

Servlet 2.3新特性,用于拦截资源文件,实现访问控制、加密、解决中文乱码、日志记录等功能。

2.2. 运行过程

客户端请求: 位于服务器端的过滤器对请求内容进行预处理,再用处理好的请求去获取web资源(由Servlet产生);
服务器响应: web资源的响应经过过滤器后处理,处理好再发送给客户端。

client –> request –> filter –> servlet

servlet –> response –> filter –> client

多个过滤器可以形成一个过滤器链,按照配置的顺序执行,最先截取请求的过滤器最后截取到响应。

2.3. 与Servlet等组件的区别

Servlet组件是需要请求进入到web容器后再对其进行处理的,而filter则是“链接”在处理过程中,即在请求被容器获取并处理之前进行预处理,同理在响应信息被发送回客户端之前也可以进行后处理,是一个典型的处理链。

2.4. Filter API

Filter API 位于javax.servlet包中,一共有三个接口:

2.4.1. Filter接口

所有过滤器都必须实现Filter接口,主要方法:init()doFilter()destroy()

2.4.1.1. init()方法

web容器创建完Filter实例后,会立即调用init()方法,在初始化过程中会向该实例传递一个包含Filter配置和运行环境的FilterConfig对象。

通过FilterConfig对象可以获得ServletContext对象(相当于applicaiton范围)及过滤器的init-param(通过getInitParameter()方法)。

public void init(FilterConfig filterConfig) throws ServletException;
2.4.1.2. doFilter()方法
public void doFilter(ServletRequest request,ServletResponse,FilterChain chain)
                     throws IOException,ServletException;

其中requestresponse是传递过来的请求或响应,参数chain代表当前Filter对象的链,在该对象的doFilter()方法中调用chain.doFilter(request,response)方法可以把请求(响应)转发给下一个Filter或目标程序去处理。

2.4.1.3. destroy()方法
public void destroy();

2.4.2. FilterChain接口

代表Filter链,只有一个doFilter()方法,是Servlet容器提供的。用来调用下一个过滤器或目标资源。

2.4.3. FilterConfig接口

用于检索过滤器名、初始化参数以及当前的Servlet上下文。

返回部署的过滤器名:

public String getFilterName();

返回调用者所处的servlet上下文

public ServletContext getServletContext();

返回初始化参数,不存在时返回null;返回初始化参数集合,不存在时返回空值。

public String getInitParameter(String name);//name为参数名
public Enumeration getInitParameterNames();//返回所有初始化参数名称的集合,没有则返回空值

2.5. Filter简单应用

过滤器实质上是一个实现了javax.servlet.Filter接口的java类。最原始的创建步骤是:

  1. 创建一个类,实现Filter接口
  2. 重写所有接口方法(3个方法)
  3. 在部署描述符或者注解中配置过滤器
  4. 发布并访问

2.5.1. Myeclipse创建过滤器

  1. 新建 - 其他 - web - 过滤器

  2. 也可以现创建一个类,继承(implements)Filter接口,再快速修复

由于过滤器在服务器启动时初始化,故修改后需要重启服务器生效。

2.5.2. 过滤器配置

2.5.2.1. 在web.xml中配置
<filter>
<filter-name>过滤器名</filter-name>
<filter-class>过滤器类</filter-class>
<init-param>
<param-name>参数名</param-name>
<param-value>参数值</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>过滤器名</filter-name>
<url-patterm>拦截的URL</url-pattern>
<servlet-name>拦截的servlet</servlet-name>
<dispatcher>拦截的调用方式</dispatcher>
</filter-mapping>

dispatcher标签的参数取值为REQUESTERRORINCLUDEFORWARD,根据容器中目标资源被调用的方式决定是否触发过滤器。

注: 组件书写顺序不影响实际顺序,实际顺序参考 节点加载顺序 。对于拥有相同filter-namefilterfilter-mapping配置节而言,filter-mapping必须出现在filter之后,否则当解析到filter-mapping时,它所对应的filter-name还未定义。

配置加载顺序Filter的web.xml配置详解


2.5.2.2. 在@WebFilter中配置
@WebFilter(filterName="FilterDemo1",
            urlPatterns={"/*"},
            servletNames={"MyServlet"},
            initParams={
              @WebInitParam(name="param1",value="value1")
            }
          )

其中,urlPattern是匹配客户端请求URLservletNames是匹配servlet

2.5.3. 应用示例

要求:创建一个过滤器,被执行时在控制台输出”您的请求已被拦截!“。

  1. 在源码的src文件夹中创建包和类
  2. 该类实现Filter接口并实现方法
  3. doFilter()方法中编写预处理代码,
    如:System.out.println("您的请求已被拦截!");
@WebFilter(urlPatterns="/*",
			initParams= {
					@WebInitParam(name="student",value="echo")
			}	)
public class FilterDemo1 implements Filter {

  public FilterDemo1() {
  }
	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
			throws IOException, ServletException {
		System.out.println("您的请求已被拦截!");
		chain.doFilter(request, response);
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

}

2.5.4. 解决中文乱码问题

我们可以通过Filter统一解决中文乱码问题,只需要用过滤器拦截网页请求,然后把请求的编码格式替换成UTF-8再继续提交就可以了。

request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");

2.5.5. 获取session对象

HttpServletRequest httpRequest=(HttpServletRequest)request;
HttpSession session=httpRequest.getSession();
String value=(String)session.getAttribute("value");

上一章:03.创建Servlet、配置、常见问题

下一章:05.MVC设计模式&JavaBean

返回目录