Servlet系列(一):简介

Web 介绍

目前的Web运行都是基于服务端/客户端模式,即将资源和网页文件存储在服务器上,用户访问服务器将资源下载到本地,然后浏览器渲染出网页。以访问https://www.baidu.com/为例,当用户在浏览器输入网址到出现页面的具体过程如下:

  1. 首先客户端通过「DNS协议」查询到域名对应的服务器IP地址。
  2. 客户端通过「HTTP协议」向上述IP地址的相应端口(默认80端口)发送请求。
  3. 服务器返回相应资源(包括页面以及页面中引用的图片等资源)。
  4. 浏览器将上述资源渲染并显示。

HTTP 协议

这里主要介绍HTTP协议,其全称为超文本传输协议,是基于TCP协议的应用层传输协议。通俗理解,客户端和服务器之间通过TCP协议来传输相应资源,在这个过程中双方需要约定一个共同的请求和回复格式。这个格式就是HTTP协议所规定的内容。

网络上的资源通过「统一资源定位符 (Uniform Resource Locator, URL) 」来完全定位,其格式如下:

1
2
<!-- 访问host主机上port端口的path路径 -->
http://host[":"port][path]

在浏览器输入URL访问资源时,浏览器通过HTTP协议发送请求报文,服务器返回响应报文。HTTP报文可以分为「报文首部」和「报文主体」两部分,报文首部和报文主体之间通过CR+LF分割。需要注意的是报文主体部分并不是必须的,报文首部是需要我们特别关注的。

这里还是以访问https://www.baidu.com/为例,在我的电脑上,浏览器发送的请求以及回复如下:
HTTP请求

可以看到浏览器向服务器发送的请求首部为:

1
2
3
4
5
6
7
8
9
10
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
......

服务器发回的响应首部如下:

1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0xb5176b1e0015f1d6
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Tue, 22 Feb 2022 09:40:01 GMT
......

可以看到上述首部内容由以下数据组成:

  • 请求行,包含用于请求的方法,请求资源URI和HTTP版本,上面是GET方法,请求的URI是/,协议为HTTP/1.1
  • 状态行,包含响应结果和状态码,原因短语和HTTP版本,上述响应状态码为200,表示成功响应。不同数字开头的状态码有不同含义,一般来说,2XX表示请求成功,3XX表示重定向,4XX表示客户端请求错误,5XX表示服务器错误。
  • 首部字段,包含表示请求和响应的各种条件和属性的各类字段,如浏览器标识、主机、资源类型等等。
  • 其它,如Cookie等。

Tomcat介绍和安装

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的轻量级Web 应用服务器。

通常所说的web服务器,如Apache、Nginx等,只提供http(s)服务,用户能够访问静态资源,如HTML文档、图片等,不能执行程序也不能访问数据库。而Tomcat服务器能够处理动态请求,主要解析JSP/Servlet,当然它也支持静态资源访问,但是效率不如Apache服务器高。

因此为了开发Java动态服务器运行Servlet代码,需要安装Tomcat。进入Tomcat官网下载Tomcat 9,此版本支持8以及更高版本的jdk。

Tomcat 9下载

下载完解压后就可以运行Tomcat服务器了。

解压后得到的文件夹有以下几个子目录:

子目录 说明
bin 用于存放Tomcat命令,以.sh结尾的为linux系统的shell脚本,以.bat结尾的为Windows系统下的命令。该目录包含启动和终止服务器运行的脚本。
conf 主要用于存放Tomcat的配置文件,如设置端口号、加载的项目等。
lib 存放Tomcat运行时需要加载的jar包。
logs 存放 Tomcat 在运行过程中产生的日志文件。
temp 存放 Tomcat 在运行过程中产生的临时文件。
webapps 存放Web应用程序,Tomcat启动时加载该目录下的项目。
work 存放Tomcat在运行时的编译文件,即class字节码。

Servlet 介绍及第一个Servlet程序

Servlet 介绍

Servlet是Server+Applet的组合,是Java Servlet的简称,是使用Java编写的运行在服务端的程序,能够接收网页表单的输入、访问数据库并动态的创建网页,其相较于使用CGI有性能更好、更易使用的优点。

实际上,Servlet是用Java语言实现的一个接口,一般情况下,也将任何实现了Servlet接口的类称为一个Servlet,一个Servlet对应了一个动态页面。

Servlet容器

这里的Servlet容器也具有传统意义上的Web服务器的接受静态资源访问的能力,如Tomcat,它是Servlet容器,能够根据配置文件(web.xml)找到对应的Servlet类实例化处理用户请求并返回;也能对于静态资源访问直接返回。

通过源码可以看到Servlet接口如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package javax.servlet;

import java.io.IOException;

public interface Servlet {
void init(ServletConfig var1) throws ServletException;

ServletConfig getServletConfig();

void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

String getServletInfo();

void destroy();
}

所有Servlet类都需要直接或间接的实现以上接口。

一个Servlet的生命周期如下:

  1. Servlet初始化后调用init()方法。
  2. Servlet调用service()方法处理用户请求,该方法是编写Servlet实现的重点。
  3. Servlet销毁前调用destroy()方法。
  4. Servlet销毁并被JVM垃圾回收。

开发时,直接实现Servlet接口并不是很方便,需要实现所有5个方法,因此Servlet包下又内置了两个Servlet接口的抽象实现类。分别是GenericServlet和HttpServlet,其中HttpServlet类继承了GenericServlet类,并在覆写service()方法时分成了doGet()doPost()等方法,因此实际开发时通常只需继承HttpServlet类。

Hello Servlet !

接下来编写第一个Servlet项目,首先在IDEA中创建一个空的Maven项目,然后导入相关依赖:

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>

右键项目名称添加Web框架支持,添加后自动生成包含了WEB-INF目录和index.jsp文件的web文件夹。
项目结构

之后编写HelloServlet.java,即我们的第一个Servlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.fxd;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.getWriter().println("<html>\n" +
" <head>\n" +
" <title>Hello World</title>\n" +
" </head>\n" +
" <body>\n" +
" Hello World!\n" +
" </body>\n" +
"</html>");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
// 将Post请求交给doGet处理
doGet(req, resp);
}
}

编写完Servlet之后,需要在web.xml配置文件中注册Servlet,前面也提到了,当用户向服务器发送请求时,Servlet容器将根据这个配置文件实例化响应的Servlet并调用其中的方法进行请求处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<!-- 注册servlet,包括name和所属的class -->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.fxd.HelloServlet</servlet-class>
</servlet>

<!-- servlet和访问路径的映射关系,访问/hello时会交至helloServlet处理 -->
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

完成之后,配置Tomcat服务器并启动进行验证,访问项目根目录下的/hello路径,页面输出Hello World!

项目结构

总结

本篇博客首先介绍了HTTP协议的相关内容,然后介绍了Java后端开发常用的Tomcat服务器,它作为一种Servlet容器十分常用;最后介绍了Servlet在客户端服务端通信之间的角色,最后编写了第一个Servlet程序。

参考链接

  1. 图解HTTP,该书以生动的图表介绍了HTTP协议。
  2. C语言中文网Servlet教程
  3. 菜鸟教程Servlet教程
  4. 廖雪峰Java教程Web开发章节