Placez la classe de servlet dans un package
Tout d'abord, placez la classe servlet dans un Java package
. Vous devez toujours placer les classes Java réutilisables publiquement dans un package, sinon elles sont invisibles pour les classes qui sont dans un package, comme le serveur lui-même. De cette façon, vous éliminez les problèmes potentiels spécifiques à l'environnement. Les servlets sans paquet ne fonctionnent que dans des combinaisons Tomcat + JDK spécifiques et il ne faut jamais s'y fier.
Dans le cas d'un projet IDE "simple", la classe doit être placée dans sa structure de package dans le dossier "Java Resources" et donc pas "WebContent", c'est pour les fichiers Web tels que JSP. Vous trouverez ci-dessous un exemple de la structure de dossiers d'un projet Web dynamique Eclipse par défaut, comme indiqué dans la vue Navigateur :
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Dans le cas d'un projet Maven, la classe doit être placée dans sa structure de package à l'intérieur main/java
et donc pas par exemple main/resources
, c'est pour les fichiers non-classe . Vous trouverez ci-dessous un exemple de la structure de dossiers d'un projet Webapp Maven par défaut, comme illustré dans la vue Navigateur d'Eclipse :
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Notez que le /jsps
sous-dossier n'est pas strictement nécessaire. Vous pouvez même vous en passer et placer le fichier JSP directement dans la racine webcontent / webapp, mais je reprends simplement cela à partir de votre question.
Définir l'URL du servlet dans url-pattern
L'URL du servlet est spécifiée comme "modèle d'URL" du mappage de servlet. Ce n'est absolument pas par définition le nom de classe / nom de fichier de la classe de servlet. Le modèle d'URL doit être spécifié comme valeur d' @WebServlet
annotation.
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.
// ...
}
Si vous souhaitez prendre en charge des paramètres de chemin tels que /servlet/foo/bar
, utilisez /servlet/*
plutôt un modèle d'URL . Voir aussi Servlet et paramètres de chemin comme / xyz / {value} / test, comment mapper dans web.xml?
@WebServlet
fonctionne uniquement sur Servlet 3.0 ou plus récent
Pour l'utiliser @WebServlet
, vous devez seulement vous assurer que votre web.xml
fichier, le cas échéant (il est facultatif depuis Servlet 3.0), est déclaré conforme à la version Servlet 3.0+ et donc non conforme, par exemple la version 2.5 ou inférieure . Vous trouverez ci-dessous un compatible Servlet 4.0 (qui correspond à 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>
Ou, si vous n'êtes pas encore sur Servlet 3.0+ (par exemple Tomcat 6 ou plus ancien), supprimez l' @WebServlet
annotation.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
Et enregistrez le servlet à la place web.xml
comme ceci:
<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>
Notez donc que vous ne devez pas utiliser les deux méthodes. Utilisez une configuration basée sur des annotations ou une configuration basée sur XML. Lorsque vous avez les deux, la configuration basée sur XML remplace la configuration basée sur les annotations.
Vérification de la construction / du déploiement
Si vous utilisez un outil de construction tel qu'Eclipse et / ou Maven, vous devez vous assurer absolument que le fichier de classe de servlet compilé réside dans sa structure de package dans le /WEB-INF/classes
dossier du fichier WAR produit. Dans le cas de package com.example; public class YourServlet
, il doit être situé dans /WEB-INF/classes/com/example/YourServlet.class
. Sinon, vous serez confronté en cas d' @WebServlet
erreur 404 ou en cas d' <servlet>
erreur HTTP 500 comme ci-dessous:
État HTTP 500
Erreur lors de l'instanciation de la classe de servlet com.example.YourServlet
Et trouvez dans le journal du serveur a java.lang.ClassNotFoundException: com.example.YourServlet
, suivi de a java.lang.NoClassDefFoundError: com.example.YourServlet
, à son tour suivi de javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
.
Un moyen simple de vérifier si le servlet est correctement compilé et placé dans classpath est de laisser l'outil de construction produire un fichier WAR (par exemple, cliquez avec le bouton droit sur le projet, Exporter> Fichier WAR dans Eclipse) et ensuite inspecter son contenu avec un outil ZIP. Si la classe de servlet est manquante dans /WEB-INF/classes
, ou si l'exportation provoque une erreur, le projet est mal configuré ou certaines valeurs par défaut de configuration IDE / projet ont été rétablies par erreur (par exemple, Projet> Construire automatiquement a été désactivé dans Eclipse).
Vous devez également vous assurer que l'icône du projet n'a pas de croix rouge indiquant une erreur de construction. Vous pouvez trouver l'erreur exacte dans la vue Problèmes ( Fenêtre> Afficher la vue> Autre ... ). Habituellement, le message d'erreur est bien Googlable. Dans le cas où vous n'avez aucune idée, le mieux est de redémarrer à partir de zéro et de ne pas toucher aux valeurs par défaut de configuration IDE / projet. Si vous utilisez Eclipse, vous pouvez trouver des instructions dans Comment importer l'API javax.servlet dans mon projet Eclipse?
Tester le servlet individuellement
À condition que le serveur s'exécute localhost:8080
et que le WAR soit déployé avec succès sur un chemin de contexte de /contextname
(qui par défaut est le nom du projet IDE, sensible à la casse!), Et que le servlet n'a pas échoué son initialisation (lire les journaux du serveur pour tout déploiement / les messages de réussite / échec du servlet et le chemin de contexte réel et le mappage de servlet), puis un servlet avec un modèle d'URL /servlet
est disponible sur http://localhost:8080/contextname/servlet
.
Vous pouvez simplement le saisir directement dans la barre d'adresse du navigateur pour le tester de manière individuelle. S'il doGet()
est correctement remplacé et implémenté, vous verrez sa sortie dans le navigateur. Ou si vous n'en avez pas doGet()
ou s'il appelle incorrectement super.doGet()
, une erreur " HTTP 405: Méthode HTTP GET n'est pas prise en charge par cette URL " sera affichée (ce qui est toujours mieux qu'un 404 car un 405 est la preuve que le servlet se trouve réellement).
Le remplacement service()
est une mauvaise pratique, à moins que vous ne réinventiez un framework MVC - ce qui est très peu probable si vous débutez avec des servlets et que vous n'avez aucune idée du problème décrit dans la question actuelle;) Voir aussi les applications Web Design Patterns .
Quoi qu'il en soit, si le servlet renvoie déjà 404 lorsqu'il est testé individuellement, il est alors totalement inutile d'essayer avec un formulaire HTML à la place. Logiquement, il est donc également totalement inutile d'inclure un formulaire HTML dans des questions sur les erreurs 404 d'un servlet.
Référencer l'URL du servlet à partir du HTML
Une fois que vous avez vérifié que le servlet fonctionne correctement lorsqu'il est appelé individuellement, vous pouvez passer au HTML. Quant à votre problème concret avec le formulaire HTML, la <form action>
valeur doit être une URL valide. La même chose s'applique à <a href>
. Vous devez comprendre le fonctionnement des URL absolues / relatives. Vous savez, une URL est une adresse Web comme vous pouvez la saisir / la voir dans la barre d'adresse du navigateur Web. Si vous spécifiez une URL relative comme action de formulaire, c'est-à-dire sans le http://
schéma, elle devient relative à l' URL actuelle comme vous le voyez dans la barre d'adresse de votre navigateur Web. Ce n'est donc absolument pas relatif à l'emplacement du fichier JSP / HTML dans la structure des dossiers WAR du serveur comme de nombreux débutants semblent le penser.
Donc, en supposant que la page JSP avec le formulaire HTML est ouverte par http://localhost:8080/contextname/jsps/page.jsp
, et que vous devez vous soumettre à un servlet situé dans http://localhost:8080/contextname/servlet
, voici plusieurs cas (notez que vous pouvez remplacer en toute sécurité <form action>
par <a href>
ici):
L'action de formulaire se soumet à une URL avec une barre oblique en tête.
<form action="/servlet">
La barre oblique principale /
rend l'URL relative au domaine, ainsi le formulaire sera soumis à
http://localhost:8080/servlet
Mais cela entraînera probablement un 404 car il est dans le mauvais contexte.
L'action de formulaire est soumise à une URL sans barre oblique.
<form action="servlet">
Cela rend l'URL relative au dossier actuel de l'URL actuelle, ainsi le formulaire sera soumis à
http://localhost:8080/contextname/jsps/servlet
Mais cela entraînera probablement un 404 car il se trouve dans le mauvais dossier.
L'action de formulaire se soumet à une URL qui monte d'un dossier.
<form action="../servlet">
Cela ira d'un dossier vers le haut (exactement comme dans les chemins du système de fichiers du disque local!), Ainsi le formulaire sera soumis à
http://localhost:8080/contextname/servlet
Celui-ci doit fonctionner!
L'approche canonique, cependant, consiste à rendre l'URL relative au domaine afin que vous n'ayez pas besoin de réparer les URL à nouveau lorsque vous déplacez les fichiers JSP dans un autre dossier.
<form action="${pageContext.request.contextPath}/servlet">
Cela générera
<form action="/contextname/servlet">
Lequel se soumettra donc toujours à la bonne URL.
Utilisez des guillemets droits en HTML
Vous devez absolument vous assurer que vous utilisez des guillemets droits dans les attributs HTML comme action="..."
ou action='...'
et donc pas des guillemets bouclés comme action=”...”
ou action=’...’
. Les guillemets bouclés ne sont pas pris en charge en HTML et feront simplement partie de la valeur.
Voir également:
Autres cas d'erreur HTTP Status 404: