目录
1.1 什么是Servlet:
Servlet全称Java Servlet 是用Java编写在服务端程序,主要是动态生成Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
下图:

1.2.Servlet的主要任务:
- 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
- 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
- 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
- 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
- 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
2.1 Servlet简介:
我们讲的Servlet就是一个所有的Servlet类直接或者间接必须实现的接口。而实现Servlet有三种方式:
当我们实现Servlet时,Servlet容器(服务器,现阶段Tomcat)会将Servlet类加载,并且产生一个Servlet实例以及调用具体的方法,Servlet实现类不需要程序员自己创建对象,在Servlet容器就已经创建好对象了。
实现javax.servlet.Servlet接口;
继承javax.servlet.GenericServlet类;
继承javax.servlet.http.HttpServlet类;(这个是我们主要用的)
注意点:
1.每一个Servlet类只能有一个实例对象(由容器创建)。
2.2 Servlet的工作流程:
当客户端发送请求到服务端时,服务器都会创建一个request对象,response对象,并把请求数据封装到request中,response对象用来对客户端进行响应,然后在调用Servlet.service()方法时传递给service()方法 ,调用sevice()方法之后把进行数据处理,形成动态数据,之后通过response对象对客户端进行响应。
request的主要功能:
封装了请求头数据;
封装了请求正文数据,如果是GET请求,那么就没有正文;
request是一个域对象,可以把它当成Map来添加获取数据;
request提供了请求转发和请求包含功能。

response的主要功能:
设置响应头信息;
发送状态码;
设置响应正文;
重定向;
2.3 Servlet接口的方法:
Servlet接口定义了五种方法:
- * 实现Servlet的第一种方式
- * 实现javax.servlet.Servlet接口
-
- public class AServlet implements Servlet {
- private ServletConfig servletConfig; //默认null
-
- /**
- * 初始化方法 生命周期方法, 由Tomcat调用 做初始化操作
- * 在Servlet创建之后调用, 调用一次
- * @param servletConfig
- * @throws ServletException
- */
- @Override
- public void init(ServletConfig servletConfig) throws ServletException {
- System.out.println("555~~555,我出生了...");
- this.servletConfig = servletConfig;
- }
-
- /**
- * 得到ServletConfig对象 (Servlet的配置)
- *
- * @return
- */
- @Override
- public ServletConfig getServletConfig() {
- return servletConfig;
- }
-
- /**
- * 最重要的方法, 接收用户请求,处理用户请求, 响应结果
- * Tomcat调用: 生命周期方法 , 每请求一次,执行一次
- * @param servletRequest
- * @param servletResponse
- * @throws ServletException
- * @throws IOException
- */
- @Override
- public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
- System.out.println("AServlet 正在服务...");
- //获取Servlet配置
- //System.out.println("Servlet的名字:"+servletConfig.getServletName());
- //获取初始化参数
- //根据初始化参数名获取值
- String name = servletConfig.getInitParameter("name");
- System.out.println("name:"+name);
- //获取所有的初始化参数名
- Enumeration
names = servletConfig.getInitParameterNames(); - //遍历
- while(names.hasMoreElements()){
- String key = names.nextElement(); //参数名
- String value = servletConfig.getInitParameter(key);
- System.out.println("key:"+key+"--value:"+value);
- }
-
- }
-
- /**
- * 没什么意义
- * 得到Servlet的描述
- * @return
- */
- @Override
- public String getServletInfo() {
- return null;
- }
-
- /**
- * 销毁方法, 释放资源
- * 生命周期方法, Tomcat调用,
- * 在Servlet销毁之前调用, 只执行一次
- */
- @Override
- public void destroy() {
- System.out.println("555~555~我走了...");
- }
- }
这五个方法描述了Servlet的生命周期,从生到死的过程:
出生:默认情况下,第一次请求时,由Tomcat创建。
调用init方法。
运行:用户每请求一次这个Servlet, tomcat调用一次service()方法。
死亡:当Tomcat服务器关闭之前, 销毁它创建的所有对象,包含创建Servlet, 在Servlet销毁之前, 调用destroy()
2.4 ServletConfig接口:
当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。 ServletConfig对象,由服务器创建。
主要方法:
String getServletName():获取Servlet在web.xml文件中的配置名称,即
指定的名称; ServletContext getServletContext():用来获取ServletContext对象,
String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;
2.5 ServletContext对象:
ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。
ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。
通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。
在HttpServlet中可以直接调用 getServletConfig()方法,因为HttpServlet继承了GenericServlet,而GenericServlet实现了ServletConfig,并且GenericServlet有 getServletConfig(),所以在HttpServlet中可以直接调用得到ServletContext对象。
ServletContext servletContext = getServletConfig().getServletContext();
3.1 GenericServlet抽象类 :
我们编写Servlet一直是通过实现Servlet接口来编写的,但是,使用这种方法,则必须要实现Servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护ServletConfig这个对象的引用。因此,这样去实现Servlet是比较麻烦的。
而GenericServlet抽象类则有三个好处:1.为Servlet接口中的所有方法提供了默认的实现,则程序员需要什么就直接改什么,不再需要把所有的方法都自己实现了。
2.并且提供方法,包围ServletConfig对象中的方法。
3.将init( )方法中的ServletConfig参数赋给了一个内部的ServletConfig引用从而来保存ServletConfig对象,不需要程序员自己去维护ServletConfig了。
注:但是我们很少用 GenericServlet抽象类,因为主要使用HttpServlet
以下是 GenericServlet抽象类代码:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by Fernflower decompiler)
- //
-
- package javax.servlet;
-
- import java.io.IOException;
- import java.io.Serializable;
- import java.util.Enumeration;
-
- public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
- private static final long serialVersionUID = 1L;
- private transient ServletConfig config;
-
- public GenericServlet() {
- }
-
- public void destroy() {
- }
-
- public String getInitParameter(String name) {
- return this.getServletConfig().getInitParameter(name);
- }
-
- public Enumeration
getInitParameterNames() { - return this.getServletConfig().getInitParameterNames();
- }
-
- public ServletConfig getServletConfig() {
- return this.config;
- }
-
- public ServletContext getServletContext() {
- return this.getServletConfig().getServletContext();
- }
-
- public String getServletInfo() {
- return "";
- }
-
- public void init(ServletConfig config) throws ServletException {
- this.config = config;
- this.init();
- }
-
- public void init() throws ServletException {
- }
-
- public void log(String message) {
- this.getServletContext().log(this.getServletName() + ": " + message);
- }
-
- public void log(String message, Throwable t) {
- this.getServletContext().log(this.getServletName() + ": " + message, t);
- }
-
- public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
-
- public String getServletName() {
- return this.config.getServletName();
- }
- }
3.2 HttpServlet抽象类:
HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse方法。
HttpServlet中的service方法把接收到的ServletRequsest类型的对象转换成了HttpServletRequest类型的对象,把ServletResponse类型的对象转换成了HttpServletResponse类型的对象。之所以能够这样强制的转换,是因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest对象和HttpServletResponse对象,预备使用HTTP。因此,转换类型当然不会出错了。
转换之后,service方法把两个转换后的对象传入了另一个service方法,那么我们再来看看这个方法是如何实现的:
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String method = req.getMethod();
- long lastModified;
- if (method.equals("GET")) {
- lastModified = this.getLastModified(req);
- if (lastModified == -1L) {
- this.doGet(req, resp);
- } else {
- long ifModifiedSince;
- try {
- ifModifiedSince = req.getDateHeader("If-Modified-Since");
- } catch (IllegalArgumentException var9) {
- ifModifiedSince = -1L;
- }
-
- if (ifModifiedSince < lastModified / 1000L * 1000L) {
- this.maybeSetLastModified(resp, lastModified);
- this.doGet(req, resp);
- } else {
- resp.setStatus(304);
- }
- }
- } else if (method.equals("HEAD")) {
- lastModified = this.getLastModified(req);
- this.maybeSetLastModified(resp, lastModified);
- this.doHead(req, resp);
- } else if (method.equals("POST")) {
- this.doPost(req, resp);
- } else if (method.equals("PUT")) {
- this.doPut(req, resp);
- } else if (method.equals("DELETE")) {
- this.doDelete(req, resp);
- } else if (method.equals("OPTIONS")) {
- this.doOptions(req, resp);
- } else if (method.equals("TRACE")) {
- this.doTrace(req, resp);
- } else {
- String errMsg = lStrings.getString("http.method_not_implemented");
- Object[] errArgs = new Object[]{method};
- errMsg = MessageFormat.format(errMsg, errArgs);
- resp.sendError(501, errMsg);
- }
-
- }
这个service方法的参数是HttpServletRequest对象和HttpServletResponse对象,刚好接收了上一个service方法传过来的两个对象。我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析HttpServletRequest中的方法参数,并调用以下方法doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doGet或者doPost就好了。所以我们只需要写doget和doPost方法了。这样使代码更加简洁。
- public class aServlet extends HttpServlet {
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
- }
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
- }
- }