这里写目录标题
前言
在写这篇博客之前,我也写过一些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将只返回最后一个值。