问题描述
我的 WebContent/jsps
文件夹中的 JSP 文件中有一个 HTML 表单。我在 src
文件夹的默认包中有一个 servlet 类 servlet.java
。在我的 web.xml
中,它被映射为/servlet
。
我在 action
的 HTML 表单中尝试了几个 URL:
<form action="/servlet">
<form action="/servlet.java">
<form action="/src/servlet.java">
<form action="../servlet.java">
但没有一个工作。他们都不断返回 HTTP 404 错误,如下所示:
HTTP Status 404
The requested resource (/servlet) is not available.
为什么不起作用?
最佳解决方案
将 servlet 类放在 package
中
首先,将 servlet 类放在 Java package
中。您应该始终将公开可重用的 Java 类放在一个包中,否则它们对于包中的类 (如服务器本身) 是不可见的。这样就可以消除潜在的 environment-specific 问题。无包 Servlet 仅在特定的 Tomcat + JDK 组合中工作,这绝对不会被依赖。
在”plain” IDE 项目的情况下,该类需要放置在”Java Resources” 文件夹中的包结构中,因此不需要”WebContent”,这适用于 JSP 等 Web 文件。以下是 “导航器” 视图中所示的默认 Eclipse 动态 Web 项目的文件夹结构示例:
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
在 Maven 项目的情况下,需要将类放置在 main/java
内的包装结构中,因此不需要。 main/resources
,这是用于 non-class 文件。以下是 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 root 中,但是我只是从你的问题中接手。
在 url-pattern
中设置 servlet URL
servlet URL 被指定为 servlet 映射的”URL pattern” 。 servlet 类的 classname /filename 绝对不是每个定义。 URL 模式将被指定为 @WebServlet
注释的值。
package com.example; // Use a package!
@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+版本,因此不符合例如。 2.5 版本或更低版本。下面是一个 Servlet 3.1 兼容的 (它匹配 Tomcat 8+,WildFly 8+,GlassFish 4+等) 。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1"
>
<!-- Config here. -->
</web-app>
或者,如果您不是 Servlet 3.0+(不是 Tomcat 7 或更新版本,而是 Tomcat 6 或更早版本),请删除 @WebServlet
注释。
package com.example;
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 的配置。
验证构建/部署
如果您使用的是 Eclipse 和/或 Maven 等构建工具,则需要确保已编译的 servlet 类文件位于生成的 WAR 文件的/WEB-INF/classes
文件夹中的包结构中。否则您将面临 HTTP 500 错误,如下所示:
HTTP Status 500
Error instantiating servlet class com.example.YourServlet
并在服务器日志中找到一个 java.lang.ClassNotFoundException: com.example.YourServlet
,其次是 java.lang.NoClassDefFoundError: com.example.YourServlet
,然后是 javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
。
验证 servlet 是否正确编译并放置在 classpath 中的简单方法是让构建工具生成一个 WAR 文件 (例如,右键单击项目,Eclipse 中的 Export> WAR 文件),然后使用 ZIP 工具检查其内容。如果/WEB-INF/classes
中缺少 servlet 类,则该项目配置不正确或某些 IDE /项目配置默认值被错误地还原 (例如,在 Eclipse 中 “自动生成” 已被禁用) 。如果您没有线索,最好是从头开始重新启动,不要触摸任何 IDE /项目配置默认值。
单独测试 servlet
如果服务器在 localhost:8080
上运行,并且 WAR 成功部署在/contextname
的上下文路径上 (默认为 IDE 项目名称,区分大小写),并且 servlet 未初始化失败 (读取任何服务器日志部署/servlet 成功/失败消息和实际的上下文路径和 servlet 映射),则/servlet
的 URL 模式的 servlet 可以在 http://localhost:8080/contextname/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 已经通过 invidivually 测试返回 404,那么用 HTML 表单来尝试一下就完全没有意义了。从逻辑上来说,在 servlet 的 404 错误问题中包含任何 HTML 表单也是毫无意义的。
从 HTML 引用 servlet URL
一旦验证了 Servlet 在单独调用时工作正常,那么您可以前进到 HTML 。对于 HTML 表单的具体问题,<form action>
值需要是一个有效的 URL 。同样适用于<a href>
。您需要了解绝对/相对 URL 的工作原理。你知道,一个 URL 是一个网址,可以在 webbrowser 的地址栏中输入/查看。如果您将相对 URL 指定为表单操作,即没有使用 http://
方案,则它将与您在 Webbrowser 的地址栏中看到的当前 URL 相关。因此绝对不会像服务器的 WAR 文件夹结构中的 JSP /HTML 文件位置那么多,因为许多启动程序似乎都认为。
因此,假设具有 HTML 表单的 JSP 页面由 http://localhost:8080 /contextname /jsps /page.jsp 打开,您需要提交到位于 http://localhost:8080 /contextname /servlet,这里有几种情况 (请注意,您可以在这里安全地用< a href> 替换< form action>):
-
表单操作提交到带有主要斜杠的 URL 。
<form action="/servlet">
主要斜杠
/
使 URL 相对于域,因此表单将提交到http://localhost:8080/servlet
但是,由于错误的情况,这可能会导致 404 。
-
表单操作提交到一个 URL,而不带领导斜杠。
<form action="servlet">
这使得 URL 相对于当前 URL 的当前文件夹,因此表单将提交给
http://localhost:8080/contextname/jsps/servlet
但这可能会导致 404,因为它在错误的文件夹。
-
表单操作提交到一个文件夹的 URL 。
<form action="../servlet">
这将一个文件夹 (完全像本地磁盘文件系统路径!),因此表单将提交到
http://localhost:8080/contextname/servlet
这一个必须工作!
-
然而,规范的方法是使 URL domain-relative,以便在碰巧将 JSP 文件移动到另一个文件夹时,不需要再次修复 URL 。
<form action="${pageContext.request.contextPath}/servlet">
这将产生
<form action="/contextname/servlet">
这将始终提交到正确的 URL 。
在 HTML 中使用直接引号
您需要确保您在 HTML 属性 (如 action="..."
或 action='...'
) 中使用直接引号,因此不会像 action=”...”
或 action=’...’
那样 curl 引号。 HTML 中不支持 curl 引号,它们只会成为该值的一部分。
也可以看看:
-
Our servlets wiki page – 包含一些你好世界的例子
-
How do I pass current item to Java method by clicking a hyperlink or button in JSP page?
HTTP 状态 404 的其他情况错误:
-
HTTP Status 404 – The requested resource (/ProjectName/) is not available
-
HTTP Status 404 – The requested resource (/) is not available
-
JSP in /WEB-INF returns “HTTP Status 404 The requested resource is not available”
-
Referencing a resource placed in WEB-INF folder in JSP file returns HTTP 404 on resource
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。