一、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标注中定义的值。