一、Servlet 介绍
Java Servlet技术简称Servlet技术,是Java开发Web应用的底层技术。由Sun公司1996年发布,用来代替CGI。CGI技术的主要问题是每个Web请求都需要启动一个进程来处理。而Servlet有着比CGI程序更好的性能,因为Servlet在创建后(处理第一个请求时)就一直保持在内存中。
Servlet是一个Java程序,一个Servlet应用有一个或多个Servlet程序。Servlet应用无法独立运行,必须运行在Servlet容器中。Servlet容器将用户请求传递给Servlet应用,并将结果返回给用户。
二、Servlet API 概览
Servlet API 有以下四个Java包:
- javax.servlet,其中包含定义Servlet和Servlet容器之间契约的类和接口。
- javax.servlet.http,其中包含定义HTTPServlet和Servlet容器之间契约的类和接口。
- javax.servlet.annotation,其中包含标注Servlet、Filter、Listener的标注。它还为被标注元件定义元数据。
- javax.servlet.descriptor,其中包含提供程序化登录web应用程序的配置信息的类型。
Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口。
Servlet接口定义了Servlet与Servlet容器之间的契约。这个契约归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。在一个应用程序中,每种Servlet类型只能有一个实例。
三、Servlet 接口
Servlet接口定义了5个方法(init、service和destroy是生命周期方法,另外两个方法不是):
方法名 | 定义 |
void init(ServletConfig congfig) throws ServletException |
当Servlet第一次被请求时,Servlet容器会调用这个方法。 这个方法后续不会被调用。我们利用这个方法进行初始化。 Servlet容器会传入一个ServletConfig。 |
void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException |
每当请求Servlet时,Servlet容器就会调用这个方法。 编写代码时,是假设Servlet要在这里被请求。 第一次请求Servlet时,调用init和service方法,后续请求 只调用service方法。 |
void destroy() |
当要销毁Servlet时,Servlet容器就会调用这个方法。 当要卸载应用程序,或关闭Servlet容器时,就会发生这种情况。 一般在这个方法中编写清除代码。 |
java lang.String getServletInfo() |
这个方法会返回Servlet的描述。你可以返回有用或null的任意字符串。 |
ServletConfig getServletConfig() |
这个方法返回由Servlet容器传给init方法的ServletConfig。 但是为了让getServletConfig返回一个非null值,必须将传给init方法 的ServletConfig赋给一个类级变量。 |
四、编写基础的Servlet应用程序
要运行Servlets,不仅需要Java有关的IDE,还需要一个Servlet容器,例如Tomcat。
MyServlet类
1 package com.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.Servlet; 7 import javax.servlet.ServletConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 import javax.servlet.annotation.WebServlet; 12 13 14 @WebServlet(name = "MyServlet", urlPatterns = {"/my"}) 15 public class MyServlet implements Servlet{ 16 17 private transient ServletConfig servletConfig; 18 19 @Override 20 public void init(ServletConfig servletConfig) throws ServletException{ 21 this.servletConfig = servletConfig; 22 } 23 24 @Override 25 public ServletConfig getServletConfig(){ 26 return servletConfig; 27 } 28 29 @Override 30 public String getServletInfo(){ 31 return "My Servlet"; 32 } 33 34 @Override 35 public void service(ServletRequest requset, ServletResponse response) 36 throws ServletException, IOException{ 37 String servletName = servletConfig.getServletName(); 38 response.setContentType("text/html"); 39 PrintWriter writer = response.getWriter(); 40 writer.print("<html><head></head>" + "<body>Hello from " + servletName + "</body></html>"); 41 } 42 43 @Override 44 public void destroy(){} 45 }
WebServlet标注类型用来声明一个Servlet。name属性通常用Servlet类的名称;urlPatterns属性告诉容器如何(例:/my)调用Servlet。
五、ServletRequest
对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它穿给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。
ServletRequest接口中的一些方法:
方法 | 定义 |
public int getContentLength() | 返回请求主体的字节数,如果不知道类型,就会返回-1 |
public java.lang.String getContentType() | 返回请求主体的MIME类型,如果不知道类型,则返回null |
public java.lang.String getProtocol() | 返回这个HTTP请求的协议名和版本 |
public java.lang.String getParameter(String name) | 返回指定请求参数的值 |
public Enumeration getParameterNames() | 返回请求中所有参数的名字 |
public String[] getParameterValues(String name) | 返回请求参数中name的所有值 |
六、ServletResponse
javax.serlvet.ServletResponse 接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。ServletResponse隐藏了向浏览器发送响应的复杂过程。
方法 | 定义 |
void setCharacterEncoding(String charset) | 设置响应正文的字符编码。响应正文的默认字符编码为ISO-8859-1 |
void setContentLength(int len) | 设置响应正文的长度 |
void setContentType(String type) | 设置响应正文的MIME类型 |
void setBufferSize(int size) | 设置用于存放响应正文数据的缓存区的大小 |
void reset() | 清空缓存区内的正文数据,并且清空响应状态代码及响应头 |
void resetBuffer() | 仅仅清空缓存区内的正文数据,不清空响应状态代码及响应头 |
void flushBuffer() | 强制性地把缓存区内的响应正文数据发送到客户端 |
PrintWriter getWriter() | 返回一个PrintWriter对象,Servlet用它来向客户端发送文本 |
七、ServletConfig
当Servlet容器初始化Servlet时,Servlet容器会给 Servlet 的 init 方法传入一个ServletConfig。ServletConfig 封装可以通过@WebServlet 或者部署描述符传给Servlet的配置信息。这样传入的每一条信息就叫一个初始参数,一个初始参数有key和value两个元件。
方法 | 定义 |
void getInitParameter(String name) | 返回从servlet内部获取初始参数的值 |
Enumeration<String> getInitParameterNames() | 返回所有初始参数名称的一个Enumeration |
ServletConfig getServletConfig() | 返回从servlet内部获取的ServletConfig |
八、ServletContext
ServletContext表示Servlet应用程序。每个Web应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。
有了ServletContext,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。
方法 | 定义 |
Object getAttribute(String name) | 返回对应属性名称的值 |
Enumeration<String> getAttributeNames() | 返回所有属性名称 |
void setAttribute(String name, Object object) | 设置属性名称和值 |
void removeAttribute(String name) | 清除属性 |
九、GenericServlet
GenericServlet实现了Servlet和ServletConfig接口,并完成了以下任务:
- 将 init 方法中的ServletConfig 赋给一个类级变量,以便可以通过调用getServletConfig获取。
- 为Servlet接口中的所有方法提供了默认实现。
- 提供方法,包括ServletConfig中的方法。
GenericServlet中有两种init方法,init(servletConfig) 和 init() ,通常可以通过覆盖没有参数的init方法来编写初始化代码,ServletConfig仍由GenericServlet实例保存。
十、HttpServlets
为了将应用程序与HTTP结合起来使用,利用HTTP提供的特性。
10.1 HttpServlet
HttpServlet类继承了javax.servlet.GenericServlet类。使用HttpServlet时,还要借助分别代表Servlet请求和响应的HttpServletRequest和HttpServletResponse对象。HttpServletRequest接口扩展javax.servlet.ServletRequest,HttpServletResponse扩展javax.servlet.ServletResponse。
HttpServlet覆盖了GenericServlet中的service方法。新service方法和javax.servlet.Servlet中的service方法之间的区别在于,前者接受HttpServletRequest和HttpServletResponse,而不是ServletResquest和ServletResponse。
Servlet容器调用javax.servlet.Servlet中的原始的Service方法。HttpServlet中的编写方法如下:
1 public void service(ServletRequest req, ServletResponse res) 2 throws ServletException, IOException { 3 HttpServletRequest resquest; 4 HttpServletResponse response; 5 try{ 6 resquest = (HttpServletRequest) req; 7 response = (HttpServletResponse) res; 8 } catch(ClassCastException e) { 9 throw new ServletException("non-HTTP request or response"); 10 } 11 service(request, response); 12 }
原始Service方法将Servlet容器的request和response对象分别转换成HttpServletRequest和HttpServletResponse,并调用新的service方法。这种转换总是会成功的,因为在调用Servlet的service方法时,Servlet容器总会传入一个HttpServletRequest和HttpServletResponse,预备使用HTTP。
然后,HttpServlet中的service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod),并调用以下方法之一:doGet、doPost、doHead、doPut、doOptions、doTrace和doDelete。这七个方法每一种都表示一个HTTP请求。因此,不再需要覆盖Service方法,只要覆盖这些方法中的部分即可。
总之,HttpServlet的两个特性是GenericServlet所不具备的:
- 不用覆盖service方法,而是覆盖doGet或者doPost,或者覆盖doGet和doPost。
- 使用HttpServletRequest和HttpServletResponse。
10.2 HttpServletRequest
HttpServletRequest表示HTTP环境中的Servlet请求。它扩展javax.servlet.ServletRequest接口,并添加了几个方法。
方法 | 定义 |
String getContextPath() | 返回表示请求上下文的请求URL部分 |
Cookie[] getCookie() | 返回一个Cookie对象数组 |
String getHeader(String name) | 返回指定HTTP标题的值 |
String getMethod() | 返回生成这个请求的HTTP方法名称 |
String getQueryString() | 返回请求URL中的查询字符串 |
HttpSession getSession() | 返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象 |
10.3 HttpServletResponse
HttpServletResponse表示HTTP环境中的Servlet响应。
方法 | 定义 |
void addCookie(Cookie cookie) | 给这个响应对象添加一个Cookie |
void addHeader(String name, String value) | 给这个响应对象添加一个header |
void sendRedirect(String location) | 发送一条响应码,将浏览器跳转到指定位置 |
十一、使用部署描述符
部署的一个方面是用一个路径配置Servlet的映射。如WebServlet标注类型。
使用部署描述符是配置Servlet应用程序的另一种方法。
Web应用程序的部署描述文件的名称都是web.xml。
<servlet></servlet>声明一个Servlet的信息,子元素有:
- <servlet-name> Servlet的名称,必须是唯一的。
- <servlet-class> 指定Servlet类的全路径名。
- <load-on-startup></load-on-startup> 指定当Web应用启动时,装载Servlet的次序。当值为正数或零时,Servlet容器先加载数值小的Servlet。当值为负或未定义时,Servlet容器将在Web客户首次访问这个Servlet时加载它。
<servlet-mapping></servlet-mapping>用来定义Servlet对应的URL,子元素有:
- <servlet-name> 指定要映射的Servlet的名称。
- <url-pattern> 指定servlet所对应的URL。
使用部署描述符的好处:
- 可以将在@WebServlet中没有对等的元素,如load-on-startup元素。
- 可以将初始参数传给一个Servlet,并且不需要重新编译Servlet类,就可以对它们进行编译。
PS:部署描述符还允许覆盖Servlet标注中定义的值。
--- 天若有情天亦老,人间正道是沧桑 ---