当前位置: 首页 > 知识库问答 >
问题:

Tomcat将servlet转换为javax.servlet.servlet而不是jakarta.servlet.http.httpservlet

方飞鸣
2023-03-14

我一直在尝试实现Tomcat9的jakarta servlet,而不是以前的javax.servlet实现(我的理解是jakarta包是前进的方向),但没有成功。问题是,当我将浏览器指向我的servlet的url时,我会得到以下错误...

java.lang.ClassCastException: class cti.nm.web.Index cannot be cast to class javax.servlet.Servlet (cti.nm.web.Index is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @48c76607; javax.servlet.Servlet is in unnamed module of loader java.net.URLClassLoader @621be5d1)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:432)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.base/java.lang.Thread.run(Thread.java:832)

问题已经足够明显了。Tomcat试图将我的jakarta.servlet.http.HttpServlet转换为javax.servlet.Servlet,这显然是行不通的。我想不通的是如何告诉它servlet实际实现的是什么类。

类本身声明为...

package cti.nm.web;
import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class Index extends HttpServlet {
     
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
      throws IOException, ServletException {

        response.setContentType("text/html");
       //print a bunch of stuff
    }
}

我的web.xml文件如下...

<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_5_0.xsd"
         version="5.0">
         
    <display-name>NMWeb</display-name>
    <description>
       NMWeb Description
    </description>

    <servlet>
        <servlet-name>Index</servlet-name>
        <servlet-class>cti.nm.web.Index</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Index</servlet-name>
        <url-pattern>/NMWeb</url-pattern>
    </servlet-mapping>

</web-app>  

我曾希望在部署描述符中使用适当的jakartaee xml模式会导致使用正确的类,但显然并非如此。战争似乎包含了合适的罐子...

jakarta.jakartaee-api-9.0.0.jar
tomcat-el-api-10.0.0.jar
tomcat-servlet-api-10.0.0.jar jakarta.servlet-api-5.0.0.jar
tomcat-jsp-api-10.0.0.jar

pom指定为...

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cti.nm.NMWeb</groupId>
  <artifactId>NMWeb</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-api</artifactId>
      <version>[9.0.0,)</version>
      
    </dependency>
    <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>[5.0.0,)</version>
      
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jsp-api -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jsp-api</artifactId>
            <version>[10.0.0,)</version>
       
        </dependency>
  </dependencies>
</project>

在网上搜索这个问题的答案已经有好几天了,我似乎找不到任何其他类似的例子。我应该提到这是一个我手动修改的eclipse生成的probject。在部署war文件时,使用maven和eclipse进行构建会生成相同的结果。

共有1个答案

端木存
2023-03-14

您基本上在物理上将特定于Tomcat10.x的库包含在WAR中,然后将WAR部署到Tomcat9.x。这根本不是正确的做法。此外,Tomcat10.x是第一个被Jakartified的版本,而不是Tomcat9.x。

对于Tomcat 9.x,您应该使用javax.*导入,并且整个 部分至少应该如下所示:

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>1.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.security.enterprise</groupId>
        <artifactId>javax.security.enterprise-api</artifactId>
        <version>1.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

对于Tomcat 10.x,您应该使用jakarta.*导入,并且整个 部分至少应该如下所示:

<dependencies>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>5.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.servlet.jsp</groupId>
        <artifactId>jakarta.servlet.jsp-api</artifactId>
        <version>3.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.el</groupId>
        <artifactId>jakarta.el-api</artifactId>
        <version>4.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.websocket</groupId>
        <artifactId>jakarta.websocket-api</artifactId>
        <version>2.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.security.enterprise</groupId>
        <artifactId>jakarta.security.enterprise-api</artifactId>
        <version>2.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

请注意, 为它们显式设置为provided,这意味着Maven不应该在生成的WAR文件的/web-inf/lib中包含物理JAR文件(因为它已经由Tomcat本身提供了!)。否则,您只会在运行时类路径中的重复类导致的运行时冲突中结束。

还请注意,Tomcat不是JEE服务器,因此为Tomcat 9.x导入javax:javaee-api或为Tomcat 10.x导入jakarta.platform:jakarta.jakartae-api都是错误的。因为它允许您针对其他JEE组件(如JSF、JSTL、CDI、BV、EJB、JPA、JAX-RS、JSONB等)编译代码,而Tomcat实际上并不提供这些组件。Tomcat只提供了Servlet、JSP、EL、WS和JASIC,所以您应该只在pom.xml中声明它们。

但是,如果您在为Tomcat开发代码时非常清楚这个限制(即,确保您自己在没有实际将JSTL、CDI、BV、JPA等安装到Tomcat中之前不会意外地使用它们),并且仅仅希望最小化pom.xml样板,那么您也可以使用Tomcat9.x的最小依赖项配置

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>8.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

或者对于Tomcat 10.x:

<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-web-api</artifactId>
        <version>9.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
  • Tomcat版本
  • 什么是Java EE?
 类似资料:
  • 考虑到类有三个字段name(String)、age(int)、salary(double)。 我想创建一个名为键,值为工资的映射(而不是对象本身),如果键不唯一,则使用linkedList保存所有重复键的值。 如何实现这种场景?

  • 我想序列化java.time类型的创建日期。调用spring data rest服务时,LocalDateTime为String。实体的字段用DateTimeFormat(iso=iso.DATE_TIME)进行注释。我还在Spring Configuration类中注册了LocalData到String转换器。 但是没有调用转换器,创建日期被序列化为Json结构,如下所示: 这是实体定义: 简单

  • 问题内容: 有没有一种简单的方法可以避免处理文本编码问题? 问题答案: 您确实无法避免处理文本编码问题,但是Apache Commons中已有一些解决方案: 至: 至: 您只需要选择所需的编码即可。

  • 问题内容: 我是一名PHP开发人员,在我的一个项目中,我需要将一些HTML文档(大约30至50页)转换为PDF文档。 我的搜索找到了以下可能的解决方案。其中包括一些PHP库和一些命令行应用程序。每种都有自己的优点和缺点。 PHP库: fpdf(需要更多的转换努力) tcpdf(需要更多的转换努力) html2fpdf http://html2fpdf.sourceforge.net html2pd

  • 在java中,隐式转换的层次结构是long可以容纳8字节的数据。那么为什么它被隐式地类型化为float,它只能容纳4个字节,而不是double,它可以容纳8个字节。为什么它不被认为是缩小呢? 哪些基元类型将隐式转换为char?

  • 问题内容: 我将JSON库从org.json更改为Jackson,我想迁移以下代码: 现在在杰克逊,我有以下几点: 但是我不喜欢那里的演员,有可能吗?有没有一种等效于的方法,以便在不是数组的情况下进行适当的错误处理? 问题答案: 是的,Jackson手动解析器的设计与其他库完全不同。特别是,您会注意到它具有通常与其他API的数组节点关联的大多数功能。因此,您无需强制转换为即可使用。这是一个例子: