我的 WebContent/jsps
文件夹中的 JSP 文件中有一个 HTML 表单。我在 src
文件夹的默认包中有一个 servlet 类 servlet.java
。在我的 web.xml
中,它被映射为 /servlet
。
我在 HTML 表单的 action
属性中尝试了几个 URL:
<form action="/servlet">
<form action="/servlet.java">
<form action="/src/servlet.java">
<form action="../servlet.java">
但这些都不起作用。它们都在 Tomcat 6/7/8 中不断返回 HTTP 404 错误,如下所示:
HTTP 状态 404 — /servlet 描述:请求的资源 (/servlet) 不可用。
或者在 Tomcat 8.5/9 中如下所示:
HTTP 状态 404 - 未找到消息:/servlet 描述:源服务器未找到目标资源的当前表示或不愿意透露存在的表示
或者在 Tomcat 10 中如下所示:
HTTP 状态 404 - 未找到 类型:状态报告消息:请求的资源 (/servlet) 不可用 描述:源服务器没有找到目标资源的当前表示或不愿意透露存在的表示
为什么它不起作用?
介绍
这可能有很多原因,在以下部分中进行了细分:
将 servlet 类放在一个包中
在 url-pattern 中设置 servlet URL
@WebServlet 仅适用于 Servlet 3.0 或更高版本
javax.servlet.* 在 Servlet 5.0 或更高版本中不再工作
确保编译的 *.class 文件存在于构建的 WAR 中
在没有任何 JSP/HTML 页面的情况下单独测试 servlet
使用域相对 URL 从 HTML 引用 servlet
在 HTML 属性中使用直引号
将 servlet 类放在一个包中
首先,将 servlet 类放入 Java package
。您应该始终将可公开重用的 Java 类放入包中,否则它们对于包中的类(例如服务器本身)是不可见的。通过这种方式,您可以消除潜在的特定环境问题。无包 servlet 仅在特定的 Tomcat+JDK 组合中工作,永远不应依赖这一点。
对于“普通”IDE 项目,该类需要放在“Java Sources”文件夹内的包结构中,not 在“Web Content”文件夹内,该文件夹用于存放 Web 文件,例如JSP。下面是在 Navigator 视图中看到的默认 Eclipse Dynamic Web Project 的文件夹结构示例(“Java Sources”文件夹默认位于此类项目中,由 { 1} 文件夹):
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
如果是 Maven 项目,则需要将类放在 main/java
内的包结构中,因此 not main/resources
、this is for non-class files 和绝对也 not { 4},这是针对网络文件的。下面是在 Eclipse 的 Navigator 视图中看到的默认 Maven webapp 项目的文件夹结构示例:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
请注意,/jsps
子文件夹并非绝对必要。您甚至可以不使用它并将 JSP 文件直接放在 webcontent/webapp 根目录中,但我只是从您的问题中接管了这个。
在 url-pattern 中设置 servlet URL
servlet URL 被指定为 servlet 映射的“URL 模式”。绝对不是servlet类的类名/文件名。 URL 模式将被指定为 @WebServlet
注释的值。
package com.example; // Use a package!
import jakarta.servlet.annotation.WebServlet; // or javax.*
import jakarta.servlet.http.HttpServlet; // or javax.*
@WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet { // Must be public and extend HttpServlet.
// ...
}
如果您想支持 /servlet/foo/bar
等路径参数,请改用 /servlet/*
的 URL 模式。另请参阅Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?
@WebServlet 仅适用于 Servlet 3.0 或更高版本
为了使用 @WebServlet
,您只需确保您的 web.xml
文件(如果有)(从 Servlet 3.0 开始是可选的)被声明为符合 Servlet 3.0+ 版本 and thus not conform e.g. 2.5 version or lower。下面是一个 Servlet 5.0 兼容的(匹配 Tomcat 10+、WildFly 22+(预览版)、GlassFish/Payara 6+ 等)。
<?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_5_0.xsd"
version="5.0">
<!-- Config here. -->
</web-app>
下面是一个 Servlet 4.0 兼容的(匹配 Tomcat 9+、WildFly 11+、GlassFish/Payara 5+ 等)。
<?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"
>
<!-- Config here. -->
</web-app>
或者,如果您还没有使用 Servlet 3.0+(例如 Tomcat 6 或更早版本),请删除 @WebServlet
注释。
package com.example;
import javax.servlet.http.HttpServlet;
public class YourServlet extends HttpServlet {
// ...
}
并在 web.xml
中注册 servlet,如下所示:
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>yourServlet</servlet-name>
<url-pattern>/servlet</url-pattern> <!-- This is the URL of the servlet. -->
</servlet-mapping>
因此请注意,您不应同时使用这两种方式。使用基于注释的配置或基于 XML 的配置。当您同时拥有两者时,基于 XML 的配置将覆盖基于注释的配置。
javax.servlet.* 在 Servlet 5.0 或更高版本中不再工作
从 Jakarta EE 9 / Servlet 5.0(Tomcat 10、TomEE 9、WildFly 22 Preview、GlassFish 6、Payara 6、Liberty 22 等)开始,javax.*
包已重命名为 jakarta.*
包。
换句话说,请绝对确保您不会仅仅为了编译 javax.*
包而将不同服务器的 JAR 文件随机放入您的 WAR 项目中,例如 tomcat-servlet-api-9.xxjar。这只会带来麻烦。完全删除它并编辑您的 servlet 类的导入
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
至
import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.*;
如果您使用的是 Maven,您可以在此答案中找到适用于 Tomcat 10+、Tomcat 9-、JEE 9+ 和 JEE 8- 的正确 pom.xml
声明示例:Tomcat casting servlets to javax.servlet.Servlet instead of jakarta.servlet.http.HttpServlet。另一种方法是将服务器降级到旧版本,例如从 Tomcat 10 降到 Tomcat 9 或更旧版本,但这显然不是推荐的方法。
确保编译的 *.class 文件存在于构建的 WAR 中
如果您使用的是 Eclipse 和/或 Maven 等构建工具,那么您需要绝对确保编译后的 servlet 类文件位于生成的 WAR 文件的 /WEB-INF/classes
文件夹中的包结构中。如果是 package com.example; public class YourServlet
,它必须位于 /WEB-INF/classes/com/example/YourServlet.class
。否则,如果出现 @WebServlet
,您将面临 404 错误,或者如果出现 <servlet>
,您将面临 HTTP 500 错误,如下所示:
HTTP 状态 500 实例化 servlet 类 com.example.YourServlet 时出错
并在服务器日志中找到 java.lang.ClassNotFoundException: com.example.YourServlet
,然后是 java.lang.NoClassDefFoundError: com.example.YourServlet
,然后是 jakarta.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
。
验证 servlet 是否正确编译并放置在类路径中的一种简单方法是让构建工具生成一个 WAR 文件(例如右键单击项目,在 Eclipse 中 Export > WAR 文件),然后检查其内容使用 ZIP 工具。如果 /WEB-INF/classes
中缺少 servlet 类,或者导出导致错误,则项目配置错误或某些 IDE/项目配置默认值被错误地还原(例如 项目 > 自动构建已在 Eclipse 中禁用)。
您还需要确保项目图标没有指示构建错误的红叉。您可以在 Problems 视图中找到确切的错误(Window > Show View > Other...)。通常错误消息很好谷歌搜索。如果您不知道,最好从头开始,不要触及任何 IDE/项目配置默认值。如果您使用的是 Eclipse,您可以在 How do I import the javax.servlet / jakarta.servlet API in my Eclipse project? 中找到说明
在没有任何 JSP/HTML 页面的情况下单独测试 servlet
前提是服务器在 localhost:8080
上运行,并且 WAR 已成功部署在 /contextname
的上下文路径上(默认为 IDE 项目名称,区分大小写!),并且 servlet 没有初始化失败(读取任何部署/servlet 成功/失败消息和实际上下文路径和 servlet 映射的服务器日志),然后在 http://localhost:8080/contextname/servlet
处提供具有 /servlet
的 URL 模式的 servlet。
您可以直接在浏览器的地址栏中输入它来单独测试它。如果它的 doGet()
被正确覆盖和实现,那么您将在浏览器中看到它的输出。或者,如果您没有任何 doGet()
或者它错误地调用了 super.doGet()
,则会显示“HTTP 405: HTTP method GET is not supported by this URL”错误(这仍然比 404 更好,因为 405 证明 servlet 本身实际上是成立)。
覆盖 service()
是一种不好的做法,除非您正在重新发明 MVC 框架 — 如果您刚开始使用 servlet 并且对当前问题中描述的问题一无所知,这不太可能;)另请参阅 Design Patterns web based applications .
无论如何,如果 servlet 在单独测试时已经返回 404,那么尝试使用 HTML 表单是完全没有意义的。因此,从逻辑上讲,在有关 servlet 的 404 错误的问题中包含任何 HTML 表单也是完全没有意义的。
使用域相对 URL 从 HTML 引用 servlet
一旦您确认 servlet 在单独调用时工作正常,您就可以前进到 HTML。至于 HTML 表单的具体问题,<form action>
值必须是有效的 URL。这同样适用于 <a href>
、<img src>
、<script src>
等。您需要了解绝对/相对 URL 的工作原理。您知道,URL 是一个网址,您可以在网络浏览器的地址栏中输入/查看。如果您将相对 URL 指定为表单操作,即没有 http://
方案,那么它会相对于您在 Web 浏览器地址栏中看到的 当前 URL。因此,它与许多初学者似乎认为的服务器的 WAR 文件夹结构中的 JSP/HTML 文件位置绝对无关。
因此,假设带有 HTML 表单的 JSP 页面由 http://localhost:8080/contextname/jsps/page.jsp
打开(因此 not 由 file://...
打开),并且您需要提交到位于 http://localhost:8080/contextname/servlet
中的 servlet,这里是几种情况(请注意,您可以在此处安全地将 <form action>
替换为 <a href>
、<img src>
、<script src>
等):
表单操作提交到带有前导斜杠的 URL。
场景 #1:您在 tomcat 已经运行时意外地从命令行重新部署。
简答:停止Tomcat,删除目标文件夹,mvn包,然后重新部署
场景#2:request.getRequestDispatcher("MIS_SPELLED_FILE_NAME.jsp")
简短答案:检查文件名拼写,确保大小写正确。
场景#3:类未找到异常(答案放在这里,因为:问题# 17982240)(java.lang.ClassNotFoundException for servlet in tomcat with eclipse)(被标记为重复并在此处指示我)
简短答案 #3.1:web.xml 在 servlet-class 标记中有错误的包路径。
简短答案 #3.2:java 文件有错误的导入语句。
以下是场景 #1 的更多详细信息:
1:停止Tomcat
选项 1:通过终端中的 CTRL+C。
选项2:(终端关闭而tomcat仍在运行)
------------ 2.1:按:Windows+R --> 输入:“services.msc”
------------ 2.2:在列表的名称栏中找到“Apache Tomcat #.# Tomcat#”。
------------ 2.3:右键-->“停止”
2:删除“目标”文件夹。 (这里 mvn clean 帮不了你)
3:mvn包
4:YOUR_DEPLOYMENT_COMMAND_HERE
(我的:java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war)
完整的故事:
不小心打开了一个新的 git-bash 窗口并尝试通过以下方式为我的 heroku 项目部署一个 .war 文件:
java -jar 目标/依赖/webapp-runner.jar --port 5190 目标/*.war
部署失败后,我意识到我打开了两个 git-bash 窗口,并且没有使用 CTLR+C 来停止之前的部署。
我遇到了:
HTTP 状态 404 - 未找到类型状态报告消息 /if-student-test.jsp 描述 源服务器没有找到目标资源的当前表示或不愿意透露存在的表示。 Apache Tomcat/8.5.31
以下是场景 #3 的更多详细信息:
场景 3.1:您的 web.xml 文件中的 servlet 类包路径错误。
它应该匹配 java servlet 类顶部的包语句。
文件:my_stuff/MyClass.java:
package my_stuff;
文件:PRJ_ROOT/src/main/webapp/WEB-INF/web.xml
<servlet-class>
my_stuff.MyClass
</servlet-class>
场景 3.2:
您将错误的“包”语句放在 myClass.java 文件的顶部。
例如:
文件位于:“/my_stuff”文件夹
你错误地写:
package com.my_stuff
这很棘手,因为:
1:maven build(mvn包)这里不会报错。
2:web.xml 中的servlet-class 行可以有正确的包路径。例如:
<servlet-class>
my_stuff.MyClass
</servlet-class>
使用的堆栈:Notepad++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10:
检查您是否输入了 Web.xml 中指定的正确 URL 映射
例如:
在 web.xml 中,您的 servlet 声明可能是:
<servlet>
<servlet-name>ControllerA</servlet-name>
<servlet-class>PackageName.ControllerA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControllerA</servlet-name>
<url-pattern>/theController</url-pattern>
</servlet-mapping>
此代码段的作用是<url-pattern>/theController</url-pattern>
将设置用于从前端(例如:表单)通过 URL 调用 servlet 的名称。因此,当您在前端引用 servlet 时,为了确保请求到达 servlet“ControllerA”,它应该从表单中引用指定的 URL 模式“theController”。
例如:
<form action="theController" method="POST">
</form>
如果您使用的是 IntelliJ,这就是为我解决的问题:
https://i.stack.imgur.com/flFCk.png
https://i.stack.imgur.com/J3nA6.png
https://i.stack.imgur.com/4tHpi.png
NetBeans IDE 中 HTTP Status 404
的解决方案:右键单击您的项目并转到您的项目属性,然后单击运行,然后输入您的项目相对 URL,如 index.jsp
。
Project->Properties 点击 Run Relative URL:/index.jsp (选择你的项目根 URL)
https://i.stack.imgur.com/7hKaO.png
我的问题是我的方法缺少 @RequestBody 注释。添加注释后,我不再收到 404 异常。
执行以下两个步骤。我希望它能解决 java servlet 应用程序开发过程中 tomcat 服务器中的“404 not found”问题。
第 1 步:Right click on the server(in the server explorer tab)->Properties->Switch Location from workspace metadata to tomcat server
第 2 步:Double Click on the server(in the server explorer tab)->Select Use tomcat installation option inside server location menu
我删除了旧的 web 库,例如 spring 框架库。并建立图书馆的新路径。然后它工作。
一个旧线程,但由于我在其他地方没有找到它,这里还有一种可能性:
如果您使用的是 servlet-api 3.0+,那么您的 web.xml 必须 NOT 包含 metadata-complete="true"
属性
https://i.stack.imgur.com/yqGgjl.png
这告诉 tomcat 使用 web.xml
中给出的数据而不是使用 @WebServlet
注释来映射 servlet。
首先,以管理员身份运行 IDE。之后,右键单击项目文件夹 -> Project Facets 并确保 Java 版本设置正确。在我的电脑上。 (例如 1.8)现在它应该可以工作了。
不要只使用 cmd 启动服务器,例如 Wildfly。它必须在 IDE 中启动,现在访问您的 localhost URL。示例:http://localhost:8080/HelloWorldServlet/HelloWorld
对我有用的修复是(如果您使用的是 Maven):右键单击您的项目,Maven -> 更新项目。这可能会给您在 JDK 和其他库(在我的情况下是 MySQL 连接器)方面带来一些其他错误,但是一旦您修复它们,您的原始问题应该得到修复!
如果您想在不使用“表单”和“提交”按钮的情况下使用 javascript 打开一个 servlet,下面是以下代码:
var button = document.getElementById("<<button-id>>");
button.addEventListener("click", function() {
window.location.href= "<<full-servlet-path>>" (eg. http://localhost:8086/xyz/servlet)
});
钥匙:
1) button-id :在 html/jsp 文件中为按钮指定的“id”标签。
2)full-servlet-path:单独运行servlet时在浏览器中显示的路径
在 web.xml 中映射是我所做的:-
如果为新程序制作了另一个软件包,那么我们必须提到:-
xml 文件中 servlet-class 标记的打开和关闭之间的 packagename.filename。
如果您在 xml 中映射文件并且它们不工作或显示错误,请在相应文件中的代码注释行上进行注释。
两种方法都不能互相工作,所以我要么使用我们创建servlet时提到的文件的注释方法,要么使用映射的方式,然后我删除或注释注释行。例如:
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>performance.FirstServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/FirstServ</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s2</servlet-name>
<servlet-class>performance.SecondServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s2</servlet-name>
<url-pattern>/SecondServ</url-pattern>
</servlet-mapping>
如果已完成 xml 中的映射,请在相应文件中注释代码的注释行。
//@WebServlet("/FirstServ")
//@WebServlet("/SecondServ")
如果有人在这里使用 MySQL,并且感觉代码在前一天可以工作,而现在却不行,那么我想你必须打开 MySQL CLI 或 MySQL Workbench,然后只连接一次数据库。连接后,数据库也会连接到 Java 应用程序。我曾经收到 Hibernate Dialect 错误,说明 com.mysql.jdbc.Driver 有问题。我认为某些计算机中的 MySQL 存在启动问题。这为我解决了。
如果您是一名学生并且刚接触 Java,那么您的 web.xml 文件可能会出现一些问题。
尝试删除 web.xml 文件。其次检查您的路径变量是否设置正确。重启tomcat服务器或者你的PC。
你的问题一定会解决的。
我也遇到了这个问题,当访问我知道链接到 Servlet 的 URL 模式时,我收到了 404。原因是因为我有 2 个 Servlet,它们的 @WebServlet name
参数设置为相同的字符串。
@WebServlet(name = "ServletName", urlPatterns = {"/path"})
public class ServletName extends HttpServlet {}
@WebServlet(name = "ServletName", urlPatterns = {"/other-path"})
public class OtherServletName extends HttpServlet {}
两个 name
参数相同。如果您使用 name 参数,请确保它们与应用程序中的所有其他 Servlet 相比是唯一的。
我遇到过同样的问题。尝试了所有这些但没有帮助。我设法通过在 xml 文件的开头和结尾添加元素标签来解决这个问题。生病将我的 xml 文件留在下面以供参考。
<?xml version="1.0" encoding="UTF-8"?>
<element>
<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_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>InsertServlet</servlet-name>
<servlet-class>com.worklog.InsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InsertServlet</servlet-name>
<url-pattern>/insert</url-pattern>
</servlet-mapping>
</web-app>
</element>
我遇到了同样的问题。我正在开发一个基于 mvc 的 REST API,其中没有明确的 html 配置或文件。 API 使用 Swagger 生成用户界面。当我介绍 Swagger 版本“3.0.0”时,问题就开始了。我恢复到 Swagger "2.9.2" 这解决了我的问题。
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
请检查上下文根不能为空。
如果您使用的是 Eclipse:右键单击,选择属性,然后选择 Web 项目设置。检查上下文根不能为空