在第一篇博客没有说的是,主要学习教程是《Servlet、JSP和Spring MVC初学指南》,只是感觉光看书没有记住,所以简单的做一下博客整理一下。
这篇博客的目的也是主要整理一下Servlet中的主要的类的常用方法与使用方法。见下:
对于每一个HTTP请求, Servlet容器都会创建一个ServletRequest实例, 并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。
ServletRequest接口中常用方法如下:
其中,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获取表单域名、 值以及查询字符串。 这些方法的使用范例请可以参考后续“Http Servlets”小节。
javax.servlet.ServletResponse接口表示一个Servlet响应。 在调用Servlet的Service方法前, Servlet容器首先创建一个ServletResponse, 并将它作为第二个参数传给Service方法。 ServletResponse隐藏了向浏览器发送响应的复杂过程。
在ServletResponse中定义的方法之一是getWriter方法, 它返回了一个可以向客户端发送文本的java.io.PrintWriter。 默认情况下, PrintWriter对象使用ISO-8859-1编码。
还有一个方法可以用来向浏览器发送输出, 它就是getOutputStream。 但这个方法是用于发送二进制数据的, 因此, 大多数情况使用的是getWriter, 而不是getOutputStream。我之前就是使用这个来向浏览器传递图片。
在发送任何HTML标签前, 应该先调用setContentType()方法, 设置响应的内容类型, 并将“text/html”作为一个参数传入。 这是在告诉浏览器,内容类型为HTML。 在没有内容类型的情况下, 大多数浏览器会默认将响应渲染成HTML。 但是, 如果没有设置响应内容类型, 有些浏器就会将HTML标签显示为普通文本。
在向客户端发送响应时, 大多数时候是将它作为HTML发送。 因此, 你必须非常熟悉HTML。
ServletConfig代表当前Servlet在web.xml中的配置信息
当Servlet容器初始化Servlet时, Servlet容器会给Servlet的init方法传入一个ServletConfig。 ServletConfig封装可以通过@WebServlet或者部署描述符传给Servlet的配置信息。 这样传入的每一条信息就叫一个初始参数。 一个初始参数有key和value两个元件。
为了从Servlet内部获取到初始参数的值, 要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。
java.lang.String getInitParameter(java.lang.String name)
此外、getInitParameterNames方法则是返回所有初始参数名称的一个Enumeration:
java.util.Enumeration.lang.String> getInitParameterNames()
ServletConfig还提供了另一个很有用的方法:getServletContext。 利用这个方法可以从Servlet内部获取ServletContext。
下面有一个Servlet程序用来演示如何利用@WebServlet给Servlet传入初始属性,并通过getServletConfig()方法来获得ServletConfig,并显示:
package app01a;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
@WebServlet(name="ServletConfigDemoServlet", urlPatterns= {"/servletConfigDemo"},
initParams = {
@WebInitParam(name="admin", value="Harry Taciak"),
@WebInitParam(name="email", value="[email protected]")
}
)
public class ServletConfigDemoServlet implements Servlet {
private transient ServletConfig servletConfig;
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("" +"Admin:" + admin +"
Email:" + email +"");
}
@Override
public String getServletInfo() {
return "ServletConfig demo";
}
@Override
public void destroy() {
}
}
在@WebServlet的initParams属性中, 给Servlet传入了两个初始参数(admin和email),利用下面这个URL, 可以调用ServletConfigDemoServlet:
http://localhost:8080/app01a/servletConfigDemo
需要注意的是设置ServletConfig属性另一种方法是, 在部署描述符中传入初始参数。 在这里使用部署描述符, 比使用@WebServlet更容易, 因为部署描述符是一个文本文件, 不需要重新编译Servlet类, 就可以对它进行编辑。这里应该说的就是web.xml配置文件。
ServletContext表示Servlet应用程序。 每个Web应用程序只有一个上下文。 在将一个应用程序同时部署到多个容器的分布式环境中, 每台Java虚拟机上的Web应用都会有一个ServletContext对象。
通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。
有了ServletContext, 就可以共享从应用程序中的所有资料处访问到的信息, 并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。保存在ServletContext中的对象被称作属性。
ServletContext中的下列方法负责处理属性:
之前的例子必须给Servlet中的所有方法都提供实现, 即便其中有一些根本就没有包含任何代码。 此外, 还需要将ServletConfig对象保存到类级变量中。
GenericServlet抽象类的出现。 本着尽可能使代码简单的原则, GenericServlet实现了Servlet和ServletConfig接口, 并完成以下任务:
GenericServlet通过将ServletConfig赋给init方法中的类级变量servletConfig, 来保存ServletConfig。 下面就是GenericServlet中的init实现:
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
this.init();
}
但是, 如果在类中覆盖了这个方法, 就会调用Servlet中的init方法, 并且还必须调用super.init(servletConfig)来保存ServletConfig。 为了避免上述麻烦,GenericServlet提供了第二个init方法, 它不带参数。 这个方法是在ServletConfig被赋给servletConfig后, 由第一个init方法调用:
public void init() throws ServletException {
}
以上可以在GenericServlet的Java源代码中找到。
后面实现GenericServletDemoServlet类是对上一个例子中ServletConfigDemoServlet类的改写。 注意, 这个新的Servlet扩展了GenericServlet, 而不是实现Servlet。代码如下:
package app01a;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
@WebServlet(name="GenericServletDemoServlet", urlPatterns= {"/generic"},
initParams= {@WebInitParam(name="admin", value="Harry Taciak"),
@WebInitParam(name="email", value="[email protected]")
}
)
public class GenericServletDemoServlet extends GenericServlet{
private static final long serialVersionID = 62500890L;
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("" +"Admin:" + admin +"
Email:" + email +"");
}
}
通过调用URL可以调用这个Servlet类。
http://localhost:8080/app01a/generic
运行结果如下:
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 {
request = (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和HttpServletResponse。
HttpServlet中的Service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod) , 并调用以下方法之一: doGet、 doPost、 doHead、 doPut、doTrace、 doOptions和doDelete。 这7种方法中, 每一种方法都表示一个HTTP方法。 doGet和doPost是最常用的。 因此, 不再需要覆盖Service方法了, 只要覆盖doGet或者doPost, 或者覆盖doGet和doPost即可。
总之, HttpServlet有两个特性是GenericServlet所不具备的:
HttpServletRequest表示HTTP环境中的Servlet请求。 它扩展javax.servlet.ServletRequest接口, 并添加了几个方法。 新增的部分方法如下:
HttpServletResponse表示HTTP环境中的Servlet响应。 下面是它里面定义的部分方法:
这一篇博客整理挺多内容的,其中涉及到HttpServlet部分是我在之前的项目实践中确实用到了的,通过今天的整理,对他们之间的联系有了一定得了解。