跳至主要內容

Servlet入门

guodongAndroid大约 6 分钟

前言

Servlet是JavaWeb开发的基础,本系列文章是笔者学习Servlet的笔记或者视频,本系列以Kotlin开发,从环境配置开始一步步入门Servlet。

开发环境

  • IntelliJ IDEA 2022.2.4 (Ultimate Edition)
  • JDK 8
  • Gradle 7.4.2
  • Kotlin 1.7.21
  • Tomcat 10.1.13

创建项目

new project

打开 IDEA 点击 New Project ,弹出上图的界面,选择 New Project 选项,填写以下内容:

  1. 项目名称,
  2. 项目位置,
  3. 选择 Kotlin 语言,
  4. 选择 Gradle 构建系统,
  5. 选择 JDK 1.8 版本,
  6. Gradle DSL 选择 Kotlin,
  7. 其他的选项暂时不做修改。

最后点击 Create 按钮创建项目,创建完成后如下图:

build.gradle.kts

在上图中,笔者已经编辑了 build.gradle.kts 文件,并添加了 war 插件和 jakarta.servlet-api 依赖:

plugins {
    kotlin("jvm") version "1.7.21"
+   war
}

dependencies {
+   providedCompile("jakarta.servlet:jakarta.servlet-api:6.0.0")
    testImplementation(kotlin("test"))
}

引入 war 插件是因为需要打包成 war 而不是 jar,表示:Java Web Application Archive。

通过 war 插件提供的依赖关系配置 providedCompile 引入Servlet API,表示仅在编译时使用,但不会打包到 .war 文件中,因为在运行期 Web 服务器本身已经提供了 Servlet API相关的 jar 包。

Servlet 版本

要务必注意 servlet-api 的版本。4.0 及之前的 servlet-api 由 Oracle 官方维护,引入的依赖项是 javax.servlet:javax.servlet-api,编写代码时引入的包名为:

import javax.servlet.*;

而 5.0 及以后的 servlet-api 由 Eclipse 开源社区维护,引入的依赖项是 jakarta.servlet:jakarta.servlet-api,编写代码时引入的包名为:

import jakarta.servlet.*;

本系列笔记使用最新的 Servlet 6.0.0 版本,可以在 Maven Central Servlet-APIopen in new window 中查询 Servlet 版本。

Tomcat 版本

Servlet 版本与 Tomcat 版本的对应关系:

ServletTomcatJava
4.09.0.x>= 8
5.010.0.x>= 8
6.010.1.x>= 11

本系列笔记使用最新的 Tomcat 10.1.13 版本,可以在 Apache Tomcat® - Which Versionopen in new window 查询最新的版本。

新建Servlet

main -> kotlin 目录下新建一个名为 servlet 的包并在其中新建一个名为 HelloServlet.kt 的 Kotlin 类,并添加以下代码:

package servlet

import jakarta.servlet.http.HttpServlet

class HelloServlet : HttpServlet() {
}

我们不应该直接实现 Servlet 接口,我们应该继承 HttpServlet 抽象类,然后复写其中的 init()doGet() 函数,并导入相关的类,代码如下所示:

import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse

class HelloServlet : HttpServlet() {

    override fun init() {
    }

    override fun doGet(req: HttpServletRequest, resp: HttpServletResponse) {
    }
}

注意:区分 init() 函数与 Kotlin 中的 init{} 代码块

init() 函数中添加以下代码:

println("HelloServlet init")

init() 函数调用时输出 HelloServlet init 字符串。

doGet() 函数体中添加以下代码:

resp.contentType = "text/html"
with(resp.writer) {
	write("<h1>Hello Servlet!</h1>")
	flush()
}
  • 通过 resp.contentType 设置响应类型,
  • 然后在 with 函数中调用 resp.writer 对象的 write 函数写入响应内容,
  • 最后调用 flush 函数强制输出。

配置文件

低版本

在低版本的 Servlet 中,需要在 web.xml 配置文件中配置我们写好的 Servlet。在 main 目录下新建一个名为 webapp 的目录,在其中再新建名为 WEB-INF 的目录,在 WEB-INF 目录下新建 web.xml 配置文件,目录结构如下:

main
├── kotlin
│   └── servlet
│       └── HelloServlet.kt
├── resources
└── webapp
    └── WEB-INF
        └── web.xml

然后在 web.xml 配置文件中添加以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
  version="6.0"
  metadata-complete="true">

    <servlet>
        <servlet-name>Hello</servlet-name>
        <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Hello</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
  • <servlet> 标签中通过 <servlet-name>HelloServlet 起了一个别名,其中 <servlet-class> 标签中的内容是 HelloServlet.kt 的全限定名(Full Qualified Name),
  • 通过 <servlet-mappig> 标签为 Servlet 配置 URL 地址映射,其中的 <servlet-name> 是 Servlet 的别名,<url-pattern> 是对应的 URL 地址映射。

高版本

在高版本的 Servlet 中可以使用注解的方式配置 Servlet,而不需要再通过 web.xml 配置文件配置了。

注意:如果存在 web.xml 配置文件,优先使用 web.xml 配置文件,这是对低版本的兼容。

接下来修改 HelloServlet.kt 为其增加以下注解:

@WebServlet(name = "Hello", value = arrayOf("/servlet"))
class HelloServlet : HttpServlet() {
    ... // 剩余代码
}

我们为 HelloServlet 类增加了 WebServlet 注解,其中的:

  • name 参数对应 web.xml 中的 <servlet-name> 标签,此处为 Hello
  • value 或者 urlPatterns 参数对应 web.xml 中的 <url-pattern> 标签,此处为 /servlet

运行Servlet

在项目根目录下运行 Gradle 命令 ./gradlew :clean :war,然后在 /build/libs 目录下得到名为 learn-servlet-1.0-SNAPSHOT.war 文件,这个文件就是我们编译打包后的 Web 应用程序。

我们将在 Tomcat 10.1.13 Web 服务器运行这个 war 包。

首先需要创建一个 Tomcat Server,点击 Edit Configurations 按钮:

edit configurations

然后在弹出的对话框中点击左上角 + 号,下滑选择 Tomcat Server -> Local,如下图:

new-tomcat-server-local

点击 Local 按钮后,弹出以下界面:

config-tomcat-server-local

  • 上图标记1处,JRE要选择为 Java 11,因为 Tomcat 10.1.x 版本最低支持 Java 11,如果低于 Java 11 服务器将无法启动,
  • 上图标记2处,HTTP port 默认是 8080,因与我本地的 Vuepress 项目端口冲突,所以改为 8081。

然后切换到 Deployment 标签页:

config-tomcat-server-deployment

点击左上角 + 号按钮,在对话框中选择 Artifact,然后再弹出的对话框中选择第一个工件,如下图:

select-artifact-to-deploy

完成后如下图:

edit-application-context

修改 Application context 为:/,最后点击 OK 按钮完成配置,然后启动服务器。

~/Spring/apache-tomcat-10.1.13/bin/catalina.sh run
服务器版本: Apache Tomcat/10.1.13
服务器版本号:      10.1.13.0
操作系统名称:      Mac OS X
OS.版本:           11.5
架构:              x86_64
Java虚拟机版本:    11.0.12+8-LTS-237
JVM.供应商:        Oracle Corporation

........................... 其他启动日志

初始化协议处理器 ["http-nio-8081"]
服务器在[657]毫秒内初始化
正在启动服务[Catalina]
正在启动 Servlet 引擎:[Apache Tomcat/10.1.13]
开始协议处理句柄["http-nio-8081"]
[91]毫秒后服务器启动
Connected to server

........................... 其他日志

HelloServlet init

在浏览器中访问 http://localhost:8081/servlet, 即可看到 HelloServlet 的输出:

safari-servlet

我们在 HelloServletWebServlet 注解中为其配置了 url-pattern,所以访问时的路径是 /servlet

总结

本文学习了如何编写 Servlet 来处理 HTTP 请求,同时学习了如何在 Tomcat 服务器中运行 Servlet。

Servlet API 提供了 HttpServet 接口方便我们处理各种 HTTP 请求方法,同时也提供了 HttpServletRequestHttpServletResponse 两个接口来封装 HTTP 的请求和响应。

注意 Servlet 版本的不同,相应的包名也不同。

Tomcat 版本对 Servlet 和 Java 版本敏感,需要我们配置对应的版本才能正常启动。