专栏首页Vamei实验室Java网络02 Servlet开胃酒

Java网络02 Servlet开胃酒

Tomcat初次尝试中,我们搭建了用于测试Servlet和JSP的基本环境。我们现在要转向网络应用的具体开发。

厨师

Web服务器的基本工作方式是请求-处理-回复。请求和回复是在网络上,以HTTP协议为基础的通信(参考HTTP协议)。请求是客户点菜,回复像是服务员上菜,而处理则是在后厨中,厨师根据请求的菜单,准备菜品的过程。

厨师通常是服务器上的一个应用程序。这个应用程序可以提取请求中的信息,并根据这些信息准备回复。这样的应用程序可以是许多中语言写成的,比如C, C++, Perl, Ruby, Python, Ruby, PHP等等。由于不同语言的设计理念和编译器特征的不同,这些语言写成的应用程序也有不同的特点(各种各样的厨师)。比如C和C++语言会有比较高的运行效率,PHP的Web应用广泛,Ruby和Python开发方便等等。

(在语言之争中,Web服务器的“后厨”是一块兵家必争之地)

Servlet是Java语言提供的的“厨师”。在Java中,“一切皆对象”。Servlet是一类特殊的Java对象。Java语言利用Servlet对象,来实现对HTTP请求的处理。

样例

下面是一个简单的Servlet例子,源文件为TestPage.java:

package foo;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class TestPage extends HttpServlet {

    public void doGet(HttpServletRequest request,
                     HttpServletResponse response)
                throws IOException, ServletException
    {
        PrintWriter out = response.getWriter();
        out.println("<html><body>" +
           "<p>Hello World!</p>" + "</body></html>");
    }
}

这个Servlet的功能是回复字符串"<html><body><p>Hello World!</p></body></html>"。这一段字符串实际上是一个HTML文本。它将作为HTTP回复的主体部分,发回给客户端。

这里定义了一个TestPage类,该类继承HttpServlet抽象类(参考HttpServlet)。我们覆盖了doGet()方法。doGet()方法处理GET方法的HTTP请求。如果HTTP请求的方法为POST,则应该覆盖doPost()方法。每个Servlet都应该覆盖doGet()和doPost()之一。doGet()和doPost()方法接收两个参数request和response,分别为HttpServletRequest类型和HttpServletResponse类型。这两个参数分别代表该次HTTP通信的请求和回复。

HttpServletRequest和HttpServletResponse为两个接口。在方法的内部,我们可以操作request和response对象。比如,通过response的getWriter方法,来获得Writer,从而写入HTML文本。这些写入的文本将作为HTTP回复的主体传递回客户端。再比如,我们可以使用request的getMethod()方法来获知HTTP请求的方法。可以参考下面的官方文档:

HttpServletRequest的更多方法

HttpServletResponse的更多方法

此外,PrintWriter类来自java.io包。参考Java IO

doGet()是真正的工作室。我们通过定义该方法(或者doPost())方法,来让厨师做特定的事情。Servlet编写的关键在于写出一个符合需求的doGet()方法或者doPost()方法。

doGet()与doPost()

正如第一行package语句所说明的(参考Java包),TestPage类被放入到foo包中。我们还import了其他的Java包。Servlet是基于Java的,所以它可以借助Java语言所提供的丰富的工具。

编译

使用下面命令编译TestPage.java

$javac -classpath /path-to-tomcat/lib/servlet-api.jar:classes:. TestPage.java

上面的path-to-tomcat是Tomcat的安装路径。我们需要包括servlet-api.jar,原因是,javax.servlet包属于J2EE,它并不属于JSE。

将编译生成的TestPage.class文件放入到下面的文件夹中。(如果文件夹不存在,需要自行创建):

/path-to-tomcat/webapps/test/WEB-INF/classes/foo

(在TesPage.java中,利用package语句,说明该类在foo包中。这里的路径符合之前的package定义。)

修改或者新建/path-to-tomcat/webapps/test/WEB-INFO/web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
 Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<web-app 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_3_0.xsd"
  version="3.0"
  metadata-complete="true">

  <servlet>
    <servlet-name>Test</servlet-name>
    <servlet-class>foo.TestPage</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Test</servlet-name>
    <url-pattern>/MyServlet</url-pattern>
  </servlet-mapping> 

</web-app>

这样的一个xml文件被称作部署描述(DD, Deployment Descriptor)。DD告诉Container如何运行Servlet和JSP。

上面的<servlet>标签是将该Servlet(foo.TestPage.class)命名为Test。

在<servlet-mapping>标签中,我们将Test这个Servlet对应于URL: /MyServlet。这说明,当有请求访问该URL时,则将请求传递给Test这个Servlet处理。

上面修改的主要目的,是说明Servlet与URL的对应关系。

随后,可以访问localhost:8080/test/MyServlet,来查看访问页面。

过程

看一下Servlet完成一次请求处理的过程:

从客户端(Guest)向服务器发送HTTP请求,该HTTP请求传递给Servlet Container。该Container负责:

  • 分析HTTP请求的信息,并新建request对象,将HTTP请求中的信息放入request对象
  • 新建response对象
  • 根据web.xml,查找URL对应的Servlet对象。如果Servlet对象不存在,则新建相应Servlet对象。
  • 创建新的线程,用于处理本次请求。线程拥有指向request和response对象的引用。

线程将调用Servlet的doGet()或者doPost()方法。线程运行结束后,response对象将传回给Container。Container根据response对象中的信息,生成一个符合HTTP协议的回复,传回给客户端。

注意,即使是新建的Servlet对象,它也不会随着线程的结束而结束。Servlet将继续存在。下次相同的URL访问将不必新建Servlet。

总结

上面制作了一个简单的Servlet,主要用于说明制作Servlet的过程。Servlet的许多强大功能还有待以后展开。

每个Servlet就像是后厨的一个厨师。我们可以用不同的URL对应来选择不同的厨师。一个复杂的网站往往需要许多个不同功能的Servlet。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python深入03 对象的属性

    Python一切皆对象(object),每个对象都可能有多个属性(attribute)。Python的属性有一套统一的管理方案。 属性的__dict__系统 对...

    Vamei
  • 协议森林15 先生,要点单吗? (HTTP协议概览)

    我在TCP流通信中说明了,TCP协议实现了数据流的传输。然而,人们更加习惯以文件为单位传输资源,比如文本文件,图像文件,超文本文档(hypertext docu...

    Vamei
  • Java网络01 Tomcat初次尝试

    Tomcat是一套开源软件,它由Apache Software Foundation(ASF)开发,用于实现Java Servlet和JavaServer Pa...

    Vamei
  • RPG设计(人物构造与Abstract Factory模式)

    在前一节,我们介绍了Strategy模式,并使用此模式实现了一个根据角色的职业来分配技能的范例(实际也就是动态地为类分配方法)。作为一款奇幻RPG,有了职业,我...

    张子阳
  • 想有自己的博客吗?浏览器支持 MarkDown和语法高亮的最简单示例(使用markdown-it、highlight.js和mermaid)

    MarkDown,写作神器,还是有必要掌握一下。写作也是一种很重要的能力,需要长久坚持和锻炼。

    特立独行的猫a
  • HP-UX基础命令3

    crontab -e 编辑schedule列表   5    *    *    *    *    /opt/psb/bin/restart_logserv....

    py3study
  • Android RxJava操作符详解 系列:功能性操作符

    上述所有的Demo源代码都存放在:Carson_Ho的Github地址:RxJava2_功能性操作符

    Carson.Ho
  • [android] 手机卫士号码归属地查询完成

    ^以某开头,[] 字符集(匹配中括号里面的任意字符),\d是任意一个数字,{n}表示出现了多少次,$结尾

    陶士涵
  • SpringCloud-Hystrix【解决灾难性雪崩-熔断】

      熔断其实是在降级的基础上引入了重试的机制。当某个时间内失败的次数达到了多少次就会触发熔断机制,具体的流程如下

    用户4919348
  • AMD深度学习库MIOpen更新,支持CNN加速

    吴唯 编译自 GitHub 量子位 出品 | 公众号 QbitAI 农企的深度学习加速库MIOpen 1.0更新了,它现在已经能支持对CNN的加速。 ROCm全...

    量子位

扫码关注云+社区

领取腾讯云代金券