Servlet API概述
Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口。Servlet接口定义了Servlet与Servlet容器之间的契约,归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。在一个应用程序中,每种Servlet类型只有一个实例。
用户请求致使Servlet容器调用Servlet的Service方法,并传入一个ServletRequest实例和一个ServletResponse实例。
对于每个应用程序,Servlet容器还会创建一个ServletContext实例,封装了上下文(应用程序)的环境详情。每个上下文只有一个ServletContext,每个Servlet实例也都有一个封装Servlet配置的ServletConfig。
Servlet
Servlet接口中定义了以下5种方法:
- void init(ServletConfig config) throws ServletException
- void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException
- void destroy()
- java.lang.String getServletInfo()
- ServletConfig getServletConfig()
init,service,destroy是生命周期方法。Servlet容器根据以下规则调用这3个方法:
- init:当该Servlet第一次被请求时,Servlet容器会调用这个方法,在后续的请求中不会再被调用,利用这个方法执行一些初始化的工作。
- service:每当请求Servlet时,Servlet容器会调用这个方法
- destroy:当要销毁Servlet时,Servlet容器就会调用这个方法,在这个方法中编写一些清除代码。
Servlet中另外2个方法是非生命周期的,即getServletInfo和getServletConfig:
- getServletInfo:这个方法返回Servlet的描述
- getServletConfig:这个方法返回由Servlet容器传给init方法的ServletConfig
Servlet中的类:
- ServletRequest:对于每个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的service方法。其中getParameter是在ServletRequest中最常用的方法,用于返回HTML表单域的值。
- ServletResponse:在调用Servlet的service方法前,Servlet容器首先创建一个ServletResponse,隐藏了向浏览器发送响应的过程。
- ServletConfig:当Servlet容器初始化Servlet时,会给Servlet的init方法传入一个ServConfig,封装了可以通过@WebServlet或者部署描述符传给Servlet的配置信息(初始参数)
- ServletContext:表示Servlet应用程序,每个Web应用程序只有一个上下文,保持在ServletContext中的对象被称为属性。
HttpServlet
HttpServlet覆盖GenericServlet中的service方法,添加了一个新的service方法:
|
|
HttpServlet中的service方法会检查用来发送请求的HTTP方法(request.getMethod),并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。所以,我们不需要覆盖service方法,而是覆盖doGet,doPost(最常用)即可。
部署描述符
Web应用的部署描述符总是命名为web.xml,并且放在WEB-INF目录下,在里面可以配置Servlet的路径映射等等,同时部署描述符还允许覆盖在Servlet注解中定义的值。
会话管理
我们知道HTTP协议是无状态性的协议,默认情况下,Web服务器是无法区分一个HTTP请求是否为第一次访问的。会话管理是Web应用开发一个无可避免的话题,以下介绍4种会话管理的方法。
URL重写
顾名思义,URL重写将一个或多个token添加到URL的查询字符串中,每个token通常为key=value形式,URL和token之间用问号(?)分割,token之间用与号(&),如下:
url?key-1=value-1&key-2=value-2 … &key-n=value-n
根据上面的描述,URL重写来管理会话适合于信息仅在少量页面间传递,且信息本身不敏感的情况。URL重写需要在服务端上完成,所有的链接都带值,也就是说,静态页面很难传值。
隐藏域
使用隐藏域来保持状态类似于URL重写技术,但不是将值附加到URL上,而是放到HTML表单的隐藏域中(post方法提交)。当表单提交时,隐藏域的值也同时提交到服务器,同样也不适合跨越多个界面。
cookies
URL重写和隐藏域仅适合保存无须跨越太多页面的信息。如果需要在多个页面间传递,我们可以适用cookies,cookies作为HTTP header的一部分,其传输有HTTP协议控制。
要适用cookies,需要熟悉javax.servlet.http.Cookie类。我们可以通过传递name和value两个参数给Cookie类的构造函数,创建一个cookies:
|
|
创建完一个cookies之后,我们还可以设置cookies的有效时间maxAge,和domain,path等特性。
要将cookies发送给浏览器:
|
|
服务器通过HttpServletReq的getCookies方法读取cookies,该方法返回一个Cookie数组,遍历查找所需要的cookies即可。
HTTPSession
HTTPSession对象在用户第一次访问网站的时候自动被创建,可以通过HttpServletRequest的getSession方法获取该对象,一个用户可以有且最多有一个HttpSession,放入到HttpSession的值,是存储在内存中的,也可以在服务器端转储到二级存储中。放到HttpSession的值不限于String类型,可以是任意实现java.io.Serializable的java对象,因为在内存不够用的时候,要将这些值放入文件或者数据库中。
大部分情况下,应该设置会话过期时间或者主动销毁无用的会话,以便释放相应的内存。
所有保存在HttpSession的数据不会被发送到客户端,Servlet容器为每个HttpSession生成唯一的标识,并将该标识发送给浏览器,或创建一个名为JSESSIONID的cookie,或者在URL后面附加一个名为jsessionid的参数,在后续的请求中,浏览器只需要将标识id发给服务器即可。