JavaWeb Servlet

Posted Mr.Aaron

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb Servlet相关的知识,希望对你有一定的参考价值。

1. Servlet介绍

1.1. 百度百科

Servlet是在服务器上运行的小程序。这个词是在Java applet的环境中创造的,Java applet是一种当作单独文件跟网页一起发送的小程序,它通常用于在客户端运行,结果得到为用户进行运算或者根据用户互作用定位图形等服务。

服务器上需要一些程序,常常是根据用户输入访问数据库的程序。这些通常是使用公共网关接口(CGI(Common Gateway Interface))应用程序完成的。然而,在服务器上运行Java,这种程序可使用Java编程语言实现。在通信量大的服务器上,Javaservlet的优点在于它们的执行速度更快于CGI程序。各个用户请求被激活成单个程序中的一个线程,而无需创建单独的进程,这意味着服务器端处理请求的系统开销将明显降低。

1.2. 维基百科

Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

最早支持Servlet标准的是JavaSoft的Java Web Server。此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。

1.3. 什么是Servlet

ServletJavaEE三大组件之一,是使用Java语言编写服务器端的程序,主要用来处理Web应用程序中的请求-响应。Servlet并没有main之类的执行方法,当用户访问服务器的时候,Tomcat是通过调用Servlet的某些方法来完成整个处理过程的。Servlet是运行在Tomcat服务器提供的Servlet容器中的,所以Servlet是不用程序指定调用的。

1.4. TomcatJavaEE

JavaEE的版本与Tomcat服务器的版本是存在一种对应关系的,在开发Web应用程序的时候,需要注意对应版本关系,不然可能引起Web程序报错。

JavaEETomcat服务器的版本对应关系如下表:

Tomcat服务器版本

Servlet\\JSP版本

JavaEE版本

Java运行环境

Tomcat 4.1

Servlet 2.3\\JSP 1.2

JavaEE 1.3

JDK 1.3

Tomcat 5.0

Servlet 2.4\\JSP 2.0

JavaEE 1.4

JDK 1.4

Tomcat 5.5\\6.0

Servlet 2.5\\JSP 2.1

JavaEE 5.0

JDK 5.0

Tomcat 7.0

Servlet 3.0\\JSP 2.2

JavaEE 6.0

JDK 6.0

如果使用Tomcat服务器的高版本时,可以向下兼容Servlet\\JSPJavaEEJava运行环境的版本。目前我们学习研究Servlet,主要是以2.5版本为主,所以使用的JavaEE版本可以是JavaEE 5.0版本。

Tomcat服务器与JavaEE中,分别提供了有关Servlet的帮助文档信息。如果在Tomcat服务器中查看Servlet的相关信息在Tomcat服务器的安装目录中,webapps目录中的docs目录中名为servletapi文件夹中查看。如果在JavaEE中查看有关Servlet的相关信息,需要下载对应JavaEE版本的API帮助文档。

需要注意的是,Servlet 3.0版本在Tomcat服务器和JavaEE都提供帮助文档,但Servlet 2.5版本只有在JavaEE提供了帮助文档,Tomcat并没有提供Servlet 2.5版本的帮助文档。

2. 编写一个Servlet

2.1. 通过Eclipse创建Servlet

开发工具EclipseMyEclipse本身提供了创建Servlet的功能,下面我们首先利用开发工具来创建一个Servlet,具体步骤如下:

  • 首先,我们创建一个Web工程。

 

  • Web工程的src目录下,鼠标右键点击“New”选项,选择“Servlet”选项。

 

  • 弹出创建Servlet的界面窗口,具体内容如下:

 

  • 输入Servlet的包名、名称及相关方法后,点击“Next”按钮进行下一步操作。

 

该界面是配置Servletweb.xml文件中的相关信息,具体内容如下:

    • Servlet/JSP Class NameServlet的完整路径。
    • Servlet/JSP NameServlet的名称。
    • Servlet/JSP Mapping URL:配置Servlet拦截的路径,客户端通过该路径访问Servlet
    • File Path of web.xml:当前工程的web.xml配置文件保存路径。
    • Display Name:显示名称。
    • Description:描述名称。
  • 配置完毕之后,点击Finish”按钮,完成Servlet的创建工作。

创建完成之后,当前Web工程的变化是在src目录下多了一个ServletJava文件,在WEB-INF目录中的web.xml文件中多了Servlet相关配置信息。

创建的ServletJava文件内容:

public class FirstServlet extends HttpServlet {

    public void init() throws ServletException {}
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML >");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.println ("    This is "+ this.getClass()+", using the GET method");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML >");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.println ("    This is "+ this.getClass()+", using the GET method");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
    public void destroy() {}
}

Web工程的配置文件web.xml内容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>FirstServlet</servlet-name>
    <servlet-class>app.java.servlet.FirstServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/servlet/FirstServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

将当前Web应用程序发布到Tomcat服务器,并启动Tomcat服务器运行测试当前创建的Servlet内容。

  • 通过EclipseMyEclipse将当前Web工程发布到Tomcat服务器,并启动Tomcat服务器。

 

  • 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/FirstServlet,访问服务器端的Servlet内容。

2.2. 手动编写一个Servlet

通过EclipseMyEclipse创建Servlet虽然简单,但我们并不知道相关代码是什么含义。所以,下面我们需要研究一下生成出来的代码。

首先, 我们来研究一下创建的Servlet文件源代码,会发现如下内容:

  • 是继承于HttpServlet类。
  • 包含init()doGet()doPost()destroy()方法。

根据上述内容,我们可以手动创建一个ServletJava文件,如下面的代码所示:

public class SecondServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        System.out.println("这是init()方法...");
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("这是doGet()方法...");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是doPost()方法...");
    }
    @Override
    public void destroy() {
        System.out.println("这是destroy()方法...");
    }
}

其次,web.xml配置文件增加的内容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <!-- 
        servlet标签:用于配置Servlet的名称和完整路径.
         * servlet-name标签:用于为对应的Servlet设置名称.
         * servlet-class标签:用于设置对应的Servlet的完整路径.
   -->
  <servlet>
    <servlet-name>SecondServlet</servlet-name>
    <servlet-class>app.java.servlet.SecondServlet</servlet-class>
  </servlet>
  <!-- 
        servlet-mapping标签:用于配置Servlet拦截客户端请求路径.
         * servlet-name标签:用于设置对应使用的Servlet名称.
         * url-pattern标签:用于设置客户端请求的拦截路径.
           * 相对路径:/servlet/FirstServlet
           * 绝对路径:http://localhost:8080/08_servlet/servlet/FirstServlet
   -->
  <servlet-mapping>
    <servlet-name>SecondServlet</servlet-name>
    <url-pattern>/servlet/SecondServlet</url-pattern>
  </servlet-mapping>
      
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

将当前Web应用程序发布到Tomcat服务器,并启动Tomcat服务器运行测试当前创建的Servlet内容。

  • 通过EclipseMyEclipse将当前Web工程发布到Tomcat服务器,并启动Tomcat服务器。
  • 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/SecondServlet,访问服务器端的Servlet内容。

2.3. Servlet的继承链

通过创建ServletJava文件中的代码内容,可以发现创建的Servlet是继承于HttpServlet类,查看JavaEE帮助文档中的HttpServlet内容。

Method Summary

protected  void

doGet(HttpServletRequest req, HttpServletResponse resp) 
          Called by the server (via the service method) to allow a servlet to handle a GET request.

protected  void

doPost(HttpServletRequest req, HttpServletResponse resp) 
          Called by the server (via the service method) to allow a servlet to handle a POST request.

protected  void

service(HttpServletRequest req, HttpServletResponse resp) 
          Receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class.

 void

service(ServletRequest req, ServletResponse res) 
          Dispatches client requests to the protected service method.

通过帮助文档提供的内容,我们可以知道创建Servlet中的doGetdoPost方法是继承于HttpServlet提供的,但还有initdestroy方法没有找到。我们发现HttpServlet是继承于GenericServlet,查看JavaEE帮助文档中的GenericServlet内容。

Method Summary

 void

destroy() 
          Called by the servlet container to indicate to a servlet that the servlet is being taken out of service.

 void

init() 
          A convenience method which can be overridden so that there\'s no need to call super.init(config).

abstract  void

service(ServletRequest req, ServletResponse res) 
          Called by the servlet container to allow the servlet to respond to a request.

通过帮助文档提供的内容,我们可以知道initdestroy方法是源于GenericServlet。但是其实GenericServlet都实现了Servlet接口。

Method Summary

 void

destroy() 
          Called by the servlet container to indicate to a servlet that the servlet is being taken out of service.

 ServletConfig

getServletConfig() 
          Returns a ServletConfig object, which contains initialization and startup parameters for this servlet.

 String

getServletInfo() 
          Returns information about the servlet, such as author, version, and copyright.

 void

init(ServletConfig config) 
          Called by the servlet container to indicate to a servlet that the servlet is being placed into service.

 void

service(ServletRequest req, ServletResponse res) 
          Called by the servlet container to allow the servlet to respond to a request.

所以,initdestroy方法是Servlet接口提供的方法。通过上述的查找,我们已经很清晰的知道了Servlet的继承关系,具体如下图:

 

2.4. Servlet工作流程

利用Servlet完成的Web应用的实际工作流程是通过Tomcat服务器发布服务,客户端与服务器端之间的交互遵循Http协议完成的。具体工作流程如下:

  • 客户端浏览器向服务器端发送请求。
  • 服务器端由Tomcat服务器提供的Servlet容器解析接收到的请求。
  • 通过Web应用程序的配置文件web.xml,解析到对应执行的Servlet
  • Servlet完成客户端发送的请求逻辑,并完成向客户端发送的响应内容。
  • Tomcat服务器提供的Servlet容器向客户端浏览器进行响应。

我们也可以通过下面的图来理解Servlet具体的工作流程。

 

2.5. Servlet注意事项

值得注意的是Servlet内容是属于JavaEE内容,和使用JavaSE内容一样,都是需要引入JAR包的。使用EclipseMyEclipse创建Web应用程序的时候,会发现已经导入了JavaEE所需要的JAR包。其中javaee.jar包中包含了使用Servlet的所有内容。

但是,当把Web应用程序发布到Tomcat服务器的时候,发现对应的目录中并没有javaee.jar包。我们知道无论是编译还是运行都是需要这些JAR包的,这说明Tomcat服务器本身提供了Servlet运行所需要的环境。在Tomcat服务器的安装目录中的lib目录中可以找到servlet-api.jar包,该JAR包也提供了Servlet运行所需的环境。

我们如果想要手动编译Servlet的话,需要做以下及步:

  • Tomcat安装目录中的webapps目录创建Web工程名称及目录结构。
  • 在命令行中利用命令编译Servlet文件。
javac -classpath C:\\Tools\\apache-tomcat-7.0.55\\lib\\servlet-api.jar -d . Servlet.java
  • 在对应Web工程目录的WEB-INF目录中的web.xml进行配置。

3. 深入掌握Servlet

3.1. Servlet的生命周期

一般情况下,自定义Servlet都是继承HttpServlet。但通过HttpServlet的继承链,我们知道HttpServlet是实现了Servlet接口,下面列表是Servlet接口提供的所有方法。

Method Summary

 void

destroy() 
          Called by the servlet container to indicate to a servlet that the servlet is being taken out of service.

 ServletConfig

getServletConfig() 
          Returns a ServletConfig object, which contains initialization and startup parameters for this servlet.

 String

getServletInfo() 
          Returns information about the servlet, such as author, version, and copyright.

 void

init(ServletConfig config) 
          Called by the servlet container to indicate to a servlet that the servlet is being placed into service.

 void

service(ServletRequest req, ServletResponse res) 
          Called by the servlet container to allow the servlet to respond to a request.

上述所有方法中,init()service()destroy()方法叫做Servlet的生命周期。下面我们分别讨论一下有关生命周期的三个方法:

  • init()方法
    • Servlet实例化之后,Servlet容器会调用init()方法,主要是用来完成处理客户端请求之前的初始化工作。
    • init()方法在Servlet的生命周期中只被执行一次。
  • service()方法
    • Servlet容器调用service()方法来处理客户端发送的请求。在service()方法被调用之前,必须保证init()方法被正确执行。
    • service()方法在每次客户端发送请求之后,会被执行一次。
  • destroy()方法
    • Servlet容器检测到当前Servlet实例被移除时,会调用destroy()方法,以便让Servlet实例可以释放所使用的所有资源。
    • destroy()方法在Servlet的生命周期中也只被执行一次。

下面我们通过实际操作来讨论关于Servlet的生命周期是怎么样的:

  • 首先,创建一个Servlet文件,具体如下。
public class LifeServlet implements Servlet {

    public LifeServlet(){
        System.out.println("这里创建了一个Servlet实例对象...");
    }

    public void init(ServletConfig config) throws ServletException {
        System.out.println("这是init()方法...");
    }

    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        System.out.println("这是service()方法...");
    }

    public void destroy() {
        System.out.println("这是destroy()方法...");
    }
    
    public ServletConfig getServletConfig() {
        return null;
    }
    public String getServletInfo() {
        return null;
    }
}
  • web.xml文件中,配置有关Servlet信息。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>LifeServlet</servlet-name>
    <servlet-class>com.servlet.LifeServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>LifeServlet</servlet-name>
    <url-pattern>/servlet/LifeServlet</url-pattern>
  </servlet-mapping>
</web-app>
  • Web应用程序发布到Tomcat服务器,并启动Tomcat服务器。
  • 启动Tomcat服务器之后,我们可以查看Tomcat服务器启动的日志内容,并没有有关Servlet信息。

 

十一月 20, 2017 1:22:48 下午 org.apache.catalina.core.AprLifecycleListener init
INFO: Loaded APR based Apache Tomcat Native library 1.2.12.
十一月 20, 2017 1:22:48 下午 org.apache.catalina.core.AprLifecycleListener init
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
十一月 20, 2017 1:22:49 下午 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-apr-8080"]
十一月 20, 2017 1:22:49 下午 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-apr-8009"]
十一月 20, 2017 1:22:49 下午 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1914 ms
十一月 20, 2017 1:22:49 下午 org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
十一月 20, 2017 1:22:49 下午 org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.27
十一月 20, 2017 1:22:49 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\08_servlet
十一月 20, 2017 1:22:50 下午 com.sun.faces.config.ConfigureListener contextInitialized
INFO: 初始化上下文 \'/08_servlet\' 的 Mojarra 2.0.3 (FCS b03)
十一月 20, 2017 1:22:51 下午 com.sun.faces.spi.InjectionProviderFactory createInstance
INFO: JSF1048:有 PostConstruct/PreDestroy 注释。标有这些注释的 ManagedBeans 方法将表示注释已处理。
十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\docs
十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\examples
十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: attributeAdded(\'org.apache.jasper.compiler.TldLocationsCache\', \'org.apache.jasper.compiler.TldLocationsCache@526509bf\')
十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\host-manager
十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\manager
十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory E:\\apache-tomcat-7.0.27\\webapps\\ROOT
十一月 20, 2017 1:22:52 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-apr-8080"]
十一月 20, 2017 1:22:52 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-apr-8009"]
十一月 20, 2017 1:22:52 下午 org.apache.catalina.startup.Catalina start
INFO: Server startup in 2333 ms
  • 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/LifeServlet,并查看控制台信息。

 

  • 重新刷新页面,再次发送请求,调用Servlet内容。

 

  • 停止Tomcat服务器,并查看控制台信息。

 

以上是关于JavaWeb Servlet的主要内容,如果未能解决你的问题,请参考以下文章

JSP基础学习

JavaWeb实现用户登录注册功能实例代码(基于Servlet+JSP+JavaBean模式)

JavaWeb-servlet

javaWeb中servlet开发——Servlet生命周期

JavaWeb之JSP

JavaWeb核心——Servlet