Java Web Servlet

本文将介绍如何使用 Servlet 。

一、什么是 Servlet ?

  • Servlet 是用 Java 编写的服务器端程序,其主要功能是交互式的浏览和修改数据,生成动态 Web 内容

  • Servlet 是 HTTP 请求和数据库之间的中间层

  • 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
    public class 实现类 implements Servlet {
    @Override
    public void init(ServletConfig config) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
    return null;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    }

    @Override
    public String getServletInfo() {
    return null;
    }

    @Override
    public void destroy() {

    }
    }

二、执行流程

  • 客户端发送请求至服务器

  • 当客户端发送请求至服务器时(或当服务器启动时),Servlet 被加载并实例化

    默认情况下,Servlet 以单实例多线程的方式处理多个请求

  • 服务器调用 Servlet

    服务器为此次请求创建 Request 对象和 Response 对象,并在 Request 对象中放入请求信息;

    然后服务器调用 Servlet 对象的 service() 方法,并将 Request 对象和 Response 对象作为参数传入

  • Servlet 接受客户端请求,生成响应内容并传给服务器

    Servlet 接受 Request 对象和 Response 对象,

    • 通过 Request 对象获取请求信息
    • 在 Response 对象中放入响应信息
  • 服务器将响应信息发送至客户端

三、生命周期方法

1. 生命周期

  • 启动后调用 init() 方法(一次)
  • 客户端请求时调用 service() 方法(零次或多次)
  • 销毁前调用 destory() 方法(一次)

2. init()

1
2
3
public void init() throws ServletException {
···
}

init() 只会在第一次创建 Servlet 时被调用,一般用于加载资源。

Servlet 可以在用户第一次访问 Servlet 对应的 URL 时创建,也可以在服务器启动时创建。

3. service()

1
2
3
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{
···
}

service() 是执行实际任务的方法,每一次 Servlet 被访问时都将执行。

4. destory()

destory() 只会被调用一次,它将会在 Servlet 被销毁之前调用,一般用于释放资源。

四、步骤

  • 安装与配置 Tomcat

    环境配置 Tomcat

  • 创建 Java EE 项目

  • 定义类,实现 Servlet 接口

  • 配置 Servlet

    可以使用 XML 配置或注解配置

  • 启动并查看:打开浏览器,输入 http://localhost:8080/项目路径/访问路径

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
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {

}

@Override
public ServletConfig getServletConfig() {
return null;
}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("Hello");
}

@Override
public String getServletInfo() {
return null;
}

@Override
public void destroy() {

}
}

web.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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>
<servlet-name>demo</servlet-name>
<servlet-class>com.example._60_ServletXml.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>demo</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
</web-app>

查看:

在浏览器输入 http://localhost:8080/_60_ServletXml_war_exploded/demo,访问 Servlet 的对应 URL,即可在控制台看见 service() 方法的输出。

五、配置

在 Servlet 3.0 之前,Servlet 的配置需要通过复杂的 web.xml 文件:

1
2
3
4
5
6
7
8
9
<servlet>
<servlet-name>名字</servlet-name>
<servlet-class>全类名</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>名字</servlet-name>
<url-pattern>/访问路径</url-pattern>
</servlet-mapping>

在 Servlet 3.0 之后,Servlet 可以通过注解进行简单的配置。

在 Servlet 实现类上使用 @WebServlet 进行注解:

1
@WebServlet("/访问路径")

六、Servlet 的实现类

1. GenericServlet

GenericServlet 是 Servlet 接口的实现类,GenericServlet 是一个抽象类。

该类对 Servlet 中的大部分方法进行了“空实现”。

因此,继承 GenericServlet 类只需要实现一个 service() 方法即可。

1
2
3
4
5
6
public class 类名 extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

}
}

2. HttpServlet

HttpServlet 是 GenericServlet 类的子类。

HttpServlet 类对 service() 方法进行了重写。

在方法中,判断请求方法为 XXX,并调用对应的 doXXX() 方法。

因此,继承 HttpServlet 类只需要选择性地重写 doXXX() 方法即可,一般重写 doGet()doPost()

1
2
3
4
5
6
7
8
9
10
11
public class 类名 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
···
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
···
}
}

七、静态资源和 Servlet

1. 示例

index.html:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>我是HTML</h2>
</body>
</html>

Servlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@WebServlet("/index")
public class Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
String message = "Servlet";
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}

结果:

直接访问项目:

访问 项目/index.html

访问 项目/index

2. 原理

在 Servlet 看来,资源一共分三种:

  • Servlet,由 InvokerServlet 类处理
  • JSP,由 JSPServlet 类处理
  • 静态资源,由 DefaultServlet 类处理

在处理请求时,

  • 首先判断请求是不是对应 Servlet,当请求对应 Servlet 时,由对应的 Servlet 处理,

    InvokerServlet 根据路径寻找到对应的 Servlet,实例化该对象,将 request 和 response 交由它处理

  • 再判断请求是否对应 JSP,当请求对应 JSP 时,由 JSPServlet 处理,

    JSPServlet 将 JSP 转换为 Servlet,交由该 Servlet 处理

  • 最后判断请求是否对应静态资源,当请求对应静态资源时,由 DefaultServlet 处理,

    DefaultServlet 将静态资源写入 response 中,发送给客户端

参考