写过Web程序的你,真的了解Servlets吗?

前言

      在写这篇博客之前,我也写过一些Web程序,丰富的画面激发了我的学习兴趣,也终于可以告别控制台的黑白框了。但是虽然加了一些前端,让程序以网页的形式显示,但其中的很多操作都不太理解,只是有人告诉你,要实现什么功能需要添加什么代码。而我也是孰能生巧的记住了这些套路,仅此而已。现在打算通过这一专栏把Web相关知识梳理一遍,而掌握Servlet API是成为一名强大的Java web开发者的基本条件,你必须熟悉ServletAPI中定义的核心接口和类。

1.Servlet API概览

      Servlet API有以下4个java包:

  • javax.servlet,其中包含定义Servlet和Servlet容器之间契约的类和接口。
  • javax.servlet.http,其中包含定义HTTPServlet和Servlet容器之间契约的类和接口。
  • javax.servlet.annotation,其中包含标注Servlet、Filter、Listener的标注。它还为被标注元件定义元数据。
  • javax.servlet.descriptor,其中包含提供程序登录Web应用程序的配置信息的类型。

图1.1中展示了javax.servlet中的主要类型。
在这里插入图片描述
Servlet接口定义了Servlet与Servlet容器之间的契约。这个契约归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。在一个应用程序中,每种Servlet类型只能有一个实例。
      用户请求致使Servlet容器调用Servlet的service方法,并传入一个ServletRequest实例和一个ServletResponse实例。ServletRequest封装了当前的HTTP请求,ServletResponse表示当前用户的HTTP响应。对于每一个应用程序,Servlet容器还会创建一个ServletContext实例。这个对象中封装了上下文(应用程序)的环境详情。每个上下文只有一个ServletContext。每个Servlet实例也都有一个封装Servlet配置的ServletConfig。下面来看Servlet接口。

2.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容器就会调用这个方法。编写代码时,是假设Servlet要在这里被请求。第一次请求Servlet时,Servlet容器调用init方法和service方法。后续的请求将只调用service方法。
  • destroy,当要销毁Servlet时,Servlet容器就会调用这个方法。当要卸载应用程序,或者当要关闭Servlet容器时,就会发生这种情况。一般会在这个方法中编写清除代码。
  • getServletInfo,这个方法会返回Servlet的描述。你可以返回有用或为null的任意字符串。
  • getServletConfig,这个方法会返回由Servlet容器传给init方法的ServletConfig。但是,为了让getServletConfig返回一个非null值,必须将传给init方法的ServletConfig赋给一个类级变量。注意线程安全性。Servlet实例会被一个应用程序中的所有用户共享,因此不建议使用类级变量,除非它们是只读的。

3.ServletRequest

      对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。
      ServletRequest接口中有一些方法:

public int getContentLength();//返回请求主体的字节数。如果不知道字节长度,这个方法就会返回-1
public java.lang.String getContentType();//返回请求主体的MIME类型,如果不知道类型,则返回null
public java.lang.String getParameter(java.lang.String name);//返回指定请求参数的值
public java.lang.String getProtocol();//返回这个HTTP请求的协议名称和版本

      getParameter是在ServletRequest中最常用的方法。该方法通常用于返回HTML表单域的值。
      getParameter也可以用于获取查询字符串的值。例如,利用下面的URI调用Servlet:
http://domain/context/servletName?id=123
      利用下面这个语句,可以通过Servlet内部获取id值:
String id=request.getParameter(“id”);//注意,如果该参数不存在,getParameter将返回null。
      除了getParameter外,还可以使用getParameterNames、getParameterMap和getParameterValues获取表单域名、值以及查询字符串。

4.ServletResponse

      javax.servlet.ServletResponse接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。在ServletResponse中定义的方法之一是getWriter方法,它返回了一个可以向客户端发送文本的java.io.PrintWriter。默认情况下,PrintWriter对象使用ISO-8859-1编码。
      在发送任何HTML标签前,应该先调用setContentType方法,设置响应的内容类型,并将“text/html”作为一个参数传入。这是在告诉浏览器,内容类型为HTML。在没有内容类型的情况下,大多数浏览器会默认将响应渲染成HTML。但是,如果没有设置响应内容类型,有些浏览器就会将HTML标签显示为普通文本。

5.ServletConfig

      将Servlet容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig。ServletConfig.Servlet封装可以通过@WebServlet或者部署描述符传给Servlet的配置信息。这样传入的每一条信息就叫一个初始参数。一次初始参数有key和value两个元件。
      为了从Servlet内部存取到初始参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。getInitParameter的方法签名如下:

java.lang.String getInitParameter(java.lang.String name)

      此外,getInitParameterNames方法则是返回所有初始参数名称的一个Enumeration

java.util.Enumberation<java.lang.String> getInitParameterNames()

6.ServletContext

      ServletContext表示Servlet应用程序。每个Web应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上上的Web应用都会有一个ServletContext对象。通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。
      有了ServletContext,就可以共享从应用程序中的所有资料处访问到的信息,并且可以注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。保存在ServletContext中的对象被称作属性:
      ServletContext中的下列方法读者处理属性:

java.lang.Object getAttribute(java.lang.String name)
java.util.Enumeration<java.lang.String> getAttributeNames()
void setAttribute(java.lang.String name,java.lang.Object object()
void removeAttribute(java.lang.String name);

7.Http Servlets

      大多数应用程序都要与HTTP结合起来使用。这意味着可以利用HTTP提供的特性。javax.servlet.http包是Servlet API中的第二个包,其中包含了用于编写Servlet应用程序的类和接口。javax.servlet.http中的许多类型都继承了javax.servlet中的类型。图2展示了javax.servlet.http中的主要类型。
在这里插入图片描述
(1)HttpServlet
      HttpServlet类继承了javax.servlet.GenericServlet类。使用HttpServlet时,还要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。HttpServletRequest接口扩展javax.servlet.ServletRequest,HttpServletResponse扩展javax.servlet.ServletResponse。
      HttpServlet覆盖GenericServlet中是service方法,并通过下列签名再添加一个service方法:

protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,java.io.IOException

      新service方法和javax.servlet.Servlet中的service方法之间的区别在于,前者接收HttpServletRequest和HttpServletResponse,而不是ServletRequest和ServletResponse。向往常一样,Servlet容器调用javax.servlet.Servlet中原始的Service方法。HttpServlet中的编写方法如下:

public void service(ServletRequest req,ServletResponse res)throws ServletException,IOException
{
  HttpServletRequest request;
  HttpServletResponse response;
  try{
    reqeust=(HttpServletRequest)req;
    response=(HttpServletResponse)res;
  }catch(ClassCastException e)
  {
    throw new ServletException("non-HTTP" request or response");
  }
  service(request,response);
}

      原始service方法将Servlet容器的request和response对象分别转换成HttpServletRequest和HttpServletResponse,并调用新的service方法。这种转换总是会成功的,因为在调用Servlet的service方法时,Servlet容器总谁传入一个HttpServletRequest和一个HttpServletResponse,预备使用HTTP。即便正在实现javax.servlet.servlet,或者扩展javax.servlet.GenericServlet,也可以将传给service方法的servlet request和servlet response分别转换成HttpServletRequest和HeepServletResponse。然后HttpServlet中的service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod),并调用以下方法之一:doGet、doPost、doHead、doPut、doTrace、doOptions和doDelete。这7种方法中,每一种方法都表示一个HTTP方法。doGet和doPost是最常用的。因此,不再需要覆盖Service方法了,只要覆盖doGet或者doPost,或者覆盖doGet和doPost即可。
(2)HttpServletRequest
      HttpServletRequest表示HTTP环境中的Servlet请求。它扩展javax.servlet.ServletRequest接口,并添加了几个方法。新增的部分方法如下:

java.lang.String getContextPath();//返回表示请求上下文的请求URI部分。
Cookie[] getCookies();//返回一个Cookie对象数组
java.lang.String getHeader(java.lang.String name);//返回指定HTTP标题的值
java.lang.String getMethod();//返回生成这个请求的HTTP方法名称
java.lang.String getQueryString();//返回请求URL的查询字符串
HttpSession getSession();//返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象。
HttpSession getSession(boolean create);//返回与这个请求相关的会话对象。如果没有,并且create参数为true,将创建一个新的会话对象

(3)HttpservletResponse
      HttpServletResponse表示HTTP环境中的Servlet响应。下面是它里面定义的部分方法

void addCookie(Cookie cookie);//给这个响应对象添加一个Cookie
void addHeader(java.lang.String name,java.lang.String value);//给这个响应对象添加一个header
void sendRedirect(java.lang.String location);//发送一条响应码,将浏览器跳转到指定的位置。

8.处理HTML表单

      一个Web应用程序几乎总会包含一个或者多个HTML表单,供用户输入值。你可以轻松地将一个HTML表单从一个Servlet发送到浏览器。当用户提交表单时,在表单元素中输入的值就会被当做请求参数发送到服务器。
      HTML输入域(文本域、隐藏域或者密码域)或者文本区的值,会被当做字符串发送到服务器。空的输入域或者文本域会发送空的字符串。因此,有输入域名称的,ServletRequest.getParameter绝对不会返回nul。
      HTML的select元素也想header发送了一个字符串。如果select元素中没有任何选项被选中,那么就会发出所显示的这个选项值。
      包含多个值的select元素(允许选择多个选项并且用select multiple表示的select元素)发出一个字符串数组。并且必须通过SelectRequest.getParameterValues处理。
      复选框比较奇特。核查过的复选框会发送字符串“on”到服务器。未经核查的复选框则不向服务器发送任何内容,ServletRequest.getParameter(fieldName)返回null。
      单选框将被选中按钮的值发送到服务器。如果没有选择任何按钮,将没有任何内容被发送到服务器,并且ServletRequest.getParameter(fieldName)返回null。
      如果一个表单中包含多个输入同名的元素,那么所有值都会被提交,并且必须利用ServletRequest.getParameterValues来获取它们。ServletRequest.getParameter将只返回最后一个值。

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/105943658