之前在 IntelliJ IDEA Community Edition 配置好了 Tomcat,接下来就要开始写接口了,Spring 的框架暂时还没用上,先简单写个 Servlet。

import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@WebServlet("/hello")
class HelloServlet: HttpServlet() {
    override fun doGet(req: HttpServletRequest?, resp: HttpServletResponse?) {
        println("HelloServlet doGet")
        resp?.writer?.write("Hello Servlet")
    }
}

部署上去发现,根页面可以正常访问,但是却无法访问 Servlet。

根页面访问正常
Servlet 访问失败

其实这个问题的答案早已写在 Apache Tomcat 官网 Tomcat 10 的下载页,只不过大多数人在下载的时候都没有注意到:

Users of Tomcat 10 onwards should be aware that, as a result of the move from Java EE to Jakarta EE as part of the transfer of Java EE to the Eclipse Foundation, the primary package for all implemented APIs has changed from javax.* to jakarta.*. This will almost certainly require code changes to enable applications to migrate from Tomcat 9 and earlier to Tomcat 10 and later.

Tomcat 10 及以后版本的用户应注意,作为 Java EE 向 Eclipse 基金会转移的一部分,Java EE 已从 Java EE 迁移到 Jakarta EE,因此所有已实施 API 的主包已从 javax.* 变为 jakarta.*。这几乎肯定需要修改代码,以使应用程序能从 Tomcat 9 及更早版本迁移到 Tomcat 10 及更高版本。

Java Servlet API 是由 Sun Microsystems / Oracle 开发和维护的,其包名以 javax.servlet 开头。从 Java EE 8 开始,Servlet API 的维护权转交给了 Eclipse Foundation 的 Jakarta EE 社区,因此,在最新的 Jakarta EE 版本中,Servlet API 的包名已经更改为 jakarta.servlet

也就是说 javax.servlet 是旧版本的包名,而 jakarta.servlet 是新版本的包名。这个变化是为了反映 Jakarta EE 作为一个独立的开源项目,并且将标准 Java 技术规范的发展移交给了 Jakarta EE 社区。

我们只需在项目中替换对应的依赖及包名即可:

dependencies {
//    implementation("javax.servlet:javax.servlet-api:4.0.1")
    implementation("jakarta.servlet:jakarta.servlet-api:6.0.0")
}
// 修改包名
import jakarta.servlet.annotation.WebServlet
import jakarta.servlet.http.HttpServlet
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse

@WebServlet("/hello")
class HelloServlet: HttpServlet() {
    override fun doGet(req: HttpServletRequest?, resp: HttpServletResponse?) {
        println("HelloServlet doGet")
        resp?.writer?.write("Hello Servlet")
    }
}

重新部署,访问成功:

Servlet 访问成功

写这篇文章的时候发现网上很多博主遇到该问题的时候都采用了降级到 Tomcat 9 的方式来避免该问题的发生,这实际上是一种惰性思维,因为他们并没有解决问题而是逃避问题。

我理解许多程序员因为开发任务繁重而不得不选择一种能尽快让项目运行起来的方法,但一定不要养成放弃思考的习惯。