JavaWeb学习——Servlets

一、Servlet 介绍

    Java Servlet技术简称Servlet技术,是Java开发Web应用的底层技术。由Sun公司1996年发布,用来代替CGI。CGI技术的主要问题是每个Web请求都需要启动一个进程来处理。而Servlet有着比CGI程序更好的性能,因为Servlet在创建后(处理第一个请求时)就一直保持在内存中。

    Servlet是一个Java程序,一个Servlet应用有一个或多个Servlet程序。Servlet应用无法独立运行,必须运行在Servlet容器中。Servlet容器将用户请求传递给Servlet应用,并将结果返回给用户。

JavaWeb学习——Servlets

二、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。

JavaWeb学习——Servlets

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

--- 天若有情天亦老,人间正道是沧桑 ---