Ponga la clase de servlet en un package
En primer lugar, coloque la clase de servlet en Java package
. Usted debe siempre poner clases reutilizables públicamente Java en un paquete, si no que son invisibles a las clases que se encuentran en un paquete, como el propio servidor. De esta forma, elimina posibles problemas específicos del entorno. Los servlets sin paquete funcionan solo en combinaciones específicas de Tomcat + JDK y nunca se debe confiar en esto.
En el caso de un proyecto IDE "simple", la clase debe colocarse en su estructura de paquete dentro de la carpeta "Recursos Java" y, por lo tanto, no en "WebContent", esto es para archivos web como JSP. A continuación se muestra un ejemplo de la estructura de carpetas de un proyecto web dinámico de Eclipse predeterminado como se ve en la vista del navegador :
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
En el caso de un proyecto Maven, la clase debe colocarse en su estructura de paquete dentro main/java
y, por lo tanto, nomain/resources
, por ejemplo , esto es para archivos que no son de clase . A continuación se muestra un ejemplo de la estructura de carpetas de un proyecto de aplicación web Maven predeterminado como se ve en la vista del navegador de Eclipse :
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Tenga en cuenta que la /jsps
subcarpeta no es estrictamente necesaria. Incluso puede prescindir de él y poner el archivo JSP directamente en la raíz webcontent / webapp, pero solo me estoy haciendo cargo de esto de su pregunta.
Establecer URL de servlet en url-pattern
La URL del servlet se especifica como el "patrón de URL" del mapeo del servlet. No es en absoluto, por definición, el nombre de clase / nombre de archivo de la clase de servlet. El patrón de URL se especificará como valor de @WebServlet
anotación.
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.
// ...
}
En caso de que desee admitir parámetros de ruta como /servlet/foo/bar
, utilice un patrón de URL de /servlet/*
. Vea también Servlet y parámetros de ruta como / xyz / {value} / test, ¿cómo mapear en web.xml?
@WebServlet
funciona solo en Servlet 3.0 o más reciente
Para usarlo @WebServlet
, solo necesita asegurarse de que su web.xml
archivo, si lo hay (es opcional desde Servlet 3.0), se declara conforme con la versión Servlet 3.0+ y, por lo tanto, no es conforme, por ejemplo, la versión 2.5 o inferior . A continuación se muestra uno compatible con Servlet 4.0 (que coincide con Tomcat 9+, WildFly 11+, Payara 5+, etc.).
<?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>
O, en caso de que aún no esté en Servlet 3.0+ (por ejemplo, Tomcat 6 o anterior), elimine la @WebServlet
anotación.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
Y registre el servlet en su lugar web.xml
así:
<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>
Por lo tanto, tenga en cuenta que no debe utilizar ambas formas. Utilice una configuración basada en anotaciones o una configuración basada en XML. Cuando tenga ambos, la configuración basada en XML anulará la configuración basada en anotaciones.
Verificando la construcción / implementación
En caso de que esté utilizando una herramienta de compilación como Eclipse y / o Maven, debe asegurarse absolutamente de que el archivo de clase de servlet compilado resida en su estructura de paquete en la /WEB-INF/classes
carpeta del archivo WAR producido. En caso de package com.example; public class YourServlet
, debe estar ubicado en /WEB-INF/classes/com/example/YourServlet.class
. De lo contrario, se enfrentará también en caso de @WebServlet
un error 404, o en caso de <servlet>
un error HTTP 500 como el siguiente:
Estado HTTP 500
Error al crear una instancia de la clase de servlet com.example.YourServlet
Y busque en el registro del servidor a java.lang.ClassNotFoundException: com.example.YourServlet
, seguido de a java.lang.NoClassDefFoundError: com.example.YourServlet
, seguido de javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
.
Una manera fácil de verificar si el servlet está correctamente compilado y colocado en classpath es dejar que la herramienta de compilación produzca un archivo WAR (por ejemplo, haga clic con el botón derecho en el proyecto, Exportar> Archivo WAR en Eclipse) y luego inspeccione su contenido con una herramienta ZIP. Si falta la clase de servlet /WEB-INF/classes
, o si la exportación causa un error, entonces el proyecto está mal configurado o algunos valores predeterminados de configuración de IDE / proyecto se han revertido por error (por ejemplo, Proyecto> Construir automáticamente se ha deshabilitado en Eclipse).
También debe asegurarse de que el icono del proyecto no tenga una cruz roja que indique un error de compilación. Puede encontrar el error exacto en la vista Problemas ( Ventana> Mostrar vista> Otro ... ). Por lo general, el mensaje de error se puede buscar en Google. En caso de que no tenga ni idea, lo mejor es reiniciar desde cero y no tocar ningún IDE / configuración predeterminada del proyecto. En caso de que esté utilizando Eclipse, puede encontrar instrucciones en ¿Cómo importo la API javax.servlet en mi proyecto Eclipse?
Probando el servlet individualmente
Siempre que el servidor se ejecute localhost:8080
y que el WAR se implemente con éxito en una ruta de contexto de /contextname
(que por defecto es el nombre del proyecto IDE, distingue entre mayúsculas y minúsculas), y el servlet no ha fallado en su inicialización (lea los registros del servidor para cualquier implementación / mensajes de éxito / error del servlet y la ruta de contexto real y el mapeo del servlet), entonces hay un servlet con el patrón de URL /servlet
disponible en http://localhost:8080/contextname/servlet
.
Puede ingresarlo directamente en la barra de direcciones del navegador para probarlo de forma individual. Si doGet()
se reemplaza e implementa correctamente, verá su salida en el navegador. O si no tiene ninguno doGet()
o si llama incorrectamente super.doGet()
, se mostrará un error " HTTP 405: el método HTTP GET no es compatible con esta URL " (que es mejor que un 404, ya que un 405 es evidencia de que el servlet sí mismo se encuentra realmente).
Anular service()
es una mala práctica, a menos que esté reinventando un marco MVC, lo cual es muy poco probable si recién está comenzando con servlets y no tiene ni idea del problema descrito en la pregunta actual;) Consulte también Diseñar patrones de aplicaciones basadas en web .
Independientemente, si el servlet ya devuelve 404 cuando se prueba de forma individual, entonces no tiene sentido intentarlo con un formulario HTML. Lógicamente, por lo tanto, tampoco tiene sentido incluir ningún formulario HTML en preguntas sobre errores 404 de un servlet.
Hacer referencia a la URL del servlet desde HTML
Una vez que haya verificado que el servlet funciona bien cuando se invoca individualmente, puede avanzar a HTML. En cuanto a su problema concreto con el formulario HTML, el <form action>
valor debe ser una URL válida. Lo mismo se aplica a <a href>
. Debe comprender cómo funcionan las URL absolutas / relativas. Ya sabes, una URL es una dirección web que puedes ingresar / ver en la barra de direcciones del navegador web. Si especifica una URL relativa como acción de formulario, es decir, sin el http://
esquema, entonces se vuelve relativa a la URL actual como ve en la barra de direcciones de su navegador web. Por lo tanto, no es en absoluto relativo a la ubicación del archivo JSP / HTML en la estructura de carpetas WAR del servidor, como parecen pensar muchos principiantes.
Entonces, asumiendo que la página JSP con el formulario HTML es abierta por http://localhost:8080/contextname/jsps/page.jsp
, y necesita enviarla a un servlet ubicado en http://localhost:8080/contextname/servlet
, aquí hay varios casos (tenga en cuenta que puede sustituir <form action>
con seguridad <a href>
aquí):
La acción del formulario se envía a una URL con una barra inclinada.
<form action="/servlet">
La barra inclinada /
hace que la URL sea relativa al dominio, por lo que el formulario se enviará a
http://localhost:8080/servlet
Pero esto probablemente resultará en un 404 ya que está en el contexto incorrecto.
La acción de formulario se envía a una URL sin una barra inclinada.
<form action="servlet">
Esto hace que la URL sea relativa a la carpeta actual de la URL actual, por lo que el formulario se enviará a
http://localhost:8080/contextname/jsps/servlet
Pero esto probablemente resultará en un 404 ya que está en la carpeta incorrecta.
La acción del formulario se envía a una URL que sube una carpeta.
<form action="../servlet">
Esto subirá una carpeta (¡exactamente como en las rutas del sistema de archivos del disco local!), Por lo que el formulario se enviará a
http://localhost:8080/contextname/servlet
¡Este debe funcionar!
El enfoque canónico, sin embargo, es hacer que la URL sea relativa al dominio para que no necesite corregir las URL una vez más cuando mueva los archivos JSP a otra carpeta.
<form action="${pageContext.request.contextPath}/servlet">
Esto generará
<form action="/contextname/servlet">
Por lo tanto, siempre se enviará a la URL correcta.
Utilice comillas rectas en HTML
Debe asegurarse absolutamente de que está utilizando comillas rectas en atributos HTML como action="..."
o action='...'
y, por lo tanto, no comillas como action=”...”
o action=’...’
. Las comillas curvas no son compatibles con HTML y simplemente se convertirán en parte del valor.
Ver también:
Otros casos de error HTTP Status 404: