将Servlet类放入 package
首先,将servlet类放入Java中package
。你应该总是将可公共重用的Java类放在包中,否则它们对于包中的类(例如服务器本身)是不可见的。这样,您就可以消除潜在的特定于环境的问题。无软件包servlet仅在特定的Tomcat + JDK组合中工作,并且永远不应依赖于此。
如果是“普通” IDE项目,则需要将该类放在其包结构中的“ Java Resources”文件夹中,而不是 “ WebContent”中,这是针对Web文件(如JSP)的。下面是在导航器视图中看到的默认Eclipse Dynamic Web Project文件夹结构的示例:
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
在一个Maven项目的情况下,类需要被放置在其封装结构内main/java
并因此不例如main/resources
,这是对于非类文件。下面是一个默认的Maven webapp项目的文件夹结构示例,如Eclipse的Navigator视图所示:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
请注意,该/jsps
子文件夹不是严格必需的。您甚至可以不使用它,而将JSP文件直接放在webcontent / webapp根目录中,但是我只是从您的问题中接管该文件。
在中设置servlet URL url-pattern
servlet URL被指定为servlet映射的“ URL模式”。根据定义,它绝对不是servlet类的类名/文件名。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
,请改用URL模式/servlet/*
。另请参阅Servlet和路径参数,例如/ xyz / {value} / test,如何在web.xml中进行映射?
@WebServlet
仅适用于Servlet 3.0或更高版本
为了使用@WebServlet
,您只需要确保您的web.xml
文件(如果有的话(从Servlet 3.0起是可选的))声明为符合Servlet 3.0+版本,因此不符合2.5版或更低版本。下面是与Servlet 4.0兼容的一个(与Tomcat 9 +,WildFly 11 +,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;
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的配置将覆盖基于注释的配置。
验证构建/部署
如果您正在使用诸如Eclipse和/或Maven之类的构建工具,则需要绝对确保已编译的Servlet类文件位于其/WEB-INF/classes
生成的WAR文件的文件夹中的包结构中。如果是这样package com.example; public class YourServlet
,它必须位于中/WEB-INF/classes/com/example/YourServlet.class
。否则,您也将面临@WebServlet
404错误或<servlet>
HTTP 500错误的情况,如下所示:
HTTP状态500
实例化servlet类com.example.YourServlet时出错
并在服务器日志中找到a java.lang.ClassNotFoundException: com.example.YourServlet
,然后是a java.lang.NoClassDefFoundError: com.example.YourServlet
,依次是javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
。
验证servlet是否正确编译并放置在classpath中的一种简单方法是让构建工具生成WAR文件(例如,右键单击项目,在Eclipse中为Export> WAR文件),然后使用ZIP工具检查其内容。如果缺少servlet类/WEB-INF/classes
,或者如果导出导致错误,则说明该项目配置错误或某些IDE /项目配置默认值被错误地还原(例如,在Eclipse中已禁用“ 项目”>“自动生成”)。
您还需要确保项目图标上没有红叉指示构建错误。您可以在“ 问题” 视图(“ 窗口”>“显示视图”>“其他...”)中找到确切的错误。通常错误消息是可以正常使用的。如果您没有任何线索,最好是从头开始,并且不要触摸任何IDE /项目配置默认值。如果您使用的是Eclipse,则可以在如何在Eclipse项目中导入javax.servlet API中找到说明。
分别测试servlet
假设服务器在上运行localhost:8080
,并且WAR成功部署在上下文路径/contextname
(默认为IDE项目名称,区分大小写!)上,并且Servlet初始化未失败(读取服务器日志以获取任何deploy / servlet成功/失败消息以及实际的上下文路径和servlet映射),则网址为的servlet /servlet
可以在http://localhost:8080/contextname/servlet
。
您可以直接在浏览器的地址栏中输入它,以进行个性化测试。如果doGet()
正确覆盖并实现了它,那么您将在浏览器中看到其输出。或者,如果您没有任何内容doGet()
或调用不正确super.doGet()
,则此URL不支持HTTP 405:HTTP方法GET ”错误(与404相比,它比404更好,因为它表明Servlet是405本身被发现)。
service()
除非您重新发明了MVC框架,否则重写是一个坏习惯,除非您刚开始使用servlet并且对于当前问题中描述的问题一无所知,否则覆盖是非常不可能的;)另请参见基于Web的设计模式应用程序。
无论如何,如果该servlet在进行不定期测试时已经返回404,那么尝试使用HTML表单是完全没有意义的。从逻辑上讲,因此在有关Servlet的404错误的问题中包含任何HTML表单也是毫无意义的。
从HTML引用servlet URL
一旦确认servlet单独调用时可以正常工作,就可以使用HTML。至于HTML表单的具体问题,该<form action>
值必须是有效的URL。同样适用于<a href>
。您需要了解绝对/相对URL的工作方式。您知道,URL是一个网址,您可以在浏览器的地址栏中输入/查看。如果您要指定一个相对URL作为表单操作,即没有http://
方案,那么它将变成相对于当前 URL的相对,如您在Web浏览器的地址栏中看到的那样。因此,它绝对不像许多初学者认为的那样相对于服务器的WAR文件夹结构中的JSP / HTML文件位置。
因此,假设与HTML表单的JSP页面被打开http://localhost:8080/contextname/jsps/page.jsp
,你需要提交给位于一个servlet http://localhost:8080/contextname/servlet
,下面是一些例子(注意,你可以放心地替代<form action>
与<a href>
这里):
表单操作会以斜杠提交到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相对于域,这样,当您碰巧将JSP文件移动到另一个文件夹时,就无需再次修复URL。
<form action="${pageContext.request.contextPath}/servlet">
这将产生
<form action="/contextname/servlet">
因此,它将始终提交到正确的URL。
在HTML中使用直引号
你需要绝对确保你使用的直引号在HTML属性,如action="..."
或action='...'
因而不能像弯引号action=”...”
或action=’...’
。HTML不支持使用弯引号,它们只是成为值的一部分。
也可以看看:
HTTP状态404错误的其他情况: