1. Introduction au servlet
Servlet est une technologie fournie par Sun Company pour développer des ressources Web dynamiques.
Le soleil fournit une interface servlet dans son API. Si les utilisateurs souhaitent envoyer une ressource Web dynamique (c'est-à-dire développer un programme Java pour produire des données au navigateur), ils doivent suivre les deux étapes suivantes:
1. Écrivez une classe Java pour implémenter l'interface servlet.
2. Déployez les classes Java développées sur le serveur Web.
Selon une habitude de nom conventionnel, nous appelons généralement des programmes Java qui mettent en œuvre le servlet Interface Servlet.
2. Le processus de fonctionnement du servlet
Le programme servlet est appelé par le serveur Web. Une fois que le serveur Web a reçu la demande d'accès au servlet du client:
①Le serveur Web vérifie d'abord s'il a été chargé et a créé un objet d'instance du servlet. Si c'est le cas, exécutez directement l'étape 4; Sinon, exécutez l'étape 2.
② Chargez et créez un objet d'instance du servlet.
③Allez la méthode init () de l'objet d'instance servlet.
④ Créez un objet HTTPServletRequest pour encapsulant des messages de demande HTTP et un objet HTTPServletResponse représentant des messages de réponse HTTP, puis appelez la méthode Service () du servlet et transmettez les objets de demande et de réponse sous forme de paramètres.
⑤ Avant que l'application Web ne soit arrêtée ou redémarrée, le moteur de servlet désinstallera le servlet et appellera la méthode de destruction () du servlet avant de désinstaller.
3. Diagramme d'appel servlet
4. Développer le servlet dans Eclipse
Créer un nouveau projet Web dans Eclipse, et Eclipse créera automatiquement la structure du répertoire illustré dans la figure ci-dessous:
4.1. Classe d'implémentation d'interface servlet
Servlet Interface Sun Company définit deux classes d'implémentation par défaut, à savoir: GenericServlet et Httpservlet.
HTTPServlet fait référence à un servlet qui peut gérer les demandes HTTP. Il ajoute quelques méthodes de traitement du protocole HTTP à l'interface de servlet d'origine, qui est plus puissante que l'interface servlet. Par conséquent, lors de l'écriture de servlets, les développeurs doivent généralement hériter de cette classe et éviter d'implémenter directement l'interface servlet.
Lorsque HttpServlet implémente l'interface servlet, il remplace la méthode de service. Le code du corps de la méthode déterminera automatiquement la méthode de demande de l'utilisateur. S'il s'agit d'une demande GET, la méthode DOGGET de HttpServlet est appelée. S'il s'agit d'une demande de post, la méthode DOSTOST sera appelée. Par conséquent, lors de l'écriture de servlets, les développeurs n'ont généralement qu'à écraser la méthode DOGET ou DOPOST au lieu de remplacer la méthode de service.
4.2. Créer et écrire des servlets via Eclipse
Sélectionnez le package gacl.servlet.study, clic droit → Nouveau → servlet, comme indiqué dans la figure ci-dessous:
De cette façon, nous utiliserons Eclipse pour nous aider à créer un servlet avec le nom ServletDemo1. Il y aura le code suivant dans le servletdemo01 créé:
Package gacl.servlet.study; import java.io.ioexception; import java.io.printwriter; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; javax.servlet.http.httpservletResponse; public class servletdemo1 étend httpservlet {/ ** * la méthode doget du servlet. <br> * * Cette méthode est appelée lorsqu'un formulaire a sa méthode de valeur de balise équivaut à obtenir. * * @param demande la demande envoyée par le client au serveur * @param réponse la réponse envoyée par le serveur au client * @throws servlexception si une erreur s'est produite * @throws ioException Si une erreur s'est produite * / public void doget (httpservletRequest demande, httpservletResponse réponse) threws Servlexception, ioexception {réponse.setSetTentType (" Printwriter out = réponse.getWriter (); out.println ("<! doctype html public /" - // w3c // dtd html 4.01 transitional // en / ">"); out.println ("<adread> <itle> un servlet </Title> </A-head>"); out.println ("<porce>"); Out.print ("This is"); out.print (this.getClass ()); out.println (", en utilisant la méthode GET"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); } / ** * La méthode DOSTOST du servlet. <br> * * Cette méthode est appelée lorsqu'un formulaire a sa méthode de valeur de balise équivaut à publier. * * @param demande la demande envoyée par le client au serveur * @param réponse la réponse envoyée par le serveur au client * @throws servleTexception si une erreur s'est produite * @throws ioException si une erreur s'est produite * / public void dopost (httpservletRequest request, httpsertReSponse réponse) lance Servilexception, ioexception { réponse.setContentType ("Text / HTML"); Printwriter out = réponse.getWriter (); out.println ("<! doctype html public /" - // w3c // dtd html 4.01 transitional // en / ">"); out.println ("<html>"); out.println ("<adread> <itle> un servlet </Title> </A-head>"); out.println ("<porce>"); out.println ("<porce>"); out.println ("This is"); out.print (this.getClass ()); out.println (", en utilisant la méthode post"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); }}Ces codes sont automatiquement générés par Eclipse, et il y a deux paires de balises dans le fichier web.xml, <Serplet> </Servlet> et <Servlet-Mapping> </servlet-mapping>. Ces deux paires de balises sont configurées avec ServletDemo1, comme indiqué dans la figure ci-dessous:
Ensuite, nous pouvons accéder au servlet ServletDemo1 via le navigateur, comme indiqué dans la figure ci-dessous:
5. Faites attention aux détails du développement des servlets
5.1. Configuration du mappage d'URL d'accès au servlet
Étant donné que le client accède aux ressources du serveur Web via une adresse URL, si le programme de servlet souhaite être accessible par le monde extérieur, il doit cartographier le programme Servlet à une adresse URL. Ce travail est effectué dans le fichier web.xml à l'aide de l'élément <Servlet> et de l'élément <Servlet-Mapping>.
L'élément <Serplet> est utilisé pour enregistrer un servlet. Il contient deux éléments enfants principaux: <servlet-name> et <servlet-Class>, qui sont utilisés pour définir respectivement le nom d'enregistrement du servlet et le nom complet de la classe du servlet.
Un élément <frlet-mapping> est utilisé pour cartographier un chemin d'accès externe à un servlet enregistré. Il contient deux éléments enfants: <Servlet-Name> et <URL-Pattern>, qui sont utilisés pour spécifier le nom d'enregistrement du servlet et le chemin d'accès externe du servlet. Par exemple:
<Serplet> <Servlet-Name> ServletDemo1 </ Servlet-Name> <Servlet-Class> GACL.Servlet.Study.servletDemo1 </ Servlet-Class> </ Servlet> <Servlet-Mapping> <Servlet-Name> ServletDemo1 </ Servlet-Name> <Url-Pattern> </Servlet-Mapping> Le même servlet peut être mappé à plusieurs URL, c'est-à-dire que la valeur de réglage de l'élément enfant <Serplet-Name> de plusieurs éléments <Servlet-Mapping> peut être le nom d'enregistrement du même servlet. Par exemple: <Serplet> <Servlet-Name> ServletDemo1 </ Servlet-Name> <Servlet-Class> gacl.servlet.study.servletDemo1 </ servlet-Class> </ servlet> </ servlet> <servlet-mapping> <servlet-name> ServletDemo1 </servlet-name> <Url-Pattern> / Servlet / ServletDemo1 </ url-Pattern> </ Servlet-Mapping> <Serplet-Mapping> <Servlet-Name> ServletDemo1 </ Servlet-Name> <Url-Pattern> /1.htm </ url-Pattern> </ Servlet-Mapping> <Servlet> <Serplet-Name> <URL-PATTERN> /2.JSP </ url-Pattern> </ Servlet-Mapping> <Servlet-Mapping> <Serplet-Mapping> <Servlet-Name> ServletDemo1 </ Servlet-Name> <Url-Pattern> /3P-Mapping> <Arl-Pattern> </ ServletDemo1 </ Servlet-Mapping> <Serplet-Name> ServletDemo1 </ Servletlet> <Serplet> <Serplet-Name> ServletDemo1 </ Servletlet> <Serplet> <Serplet-Name> ServletDemo1 </ Servlettlet> <URL-Pattern> /4.aspx </ url-stern> </ servlet-mapping>
Grâce à la configuration ci-dessus, lorsque nous voulons accéder à un servlet avec le nom ServletDemo1, nous pouvons utiliser les adresses suivantes pour accéder:
http: // localhost: 8080 / javaweb_servlet_study_20140531 / servlet / servletdemo1
http: // localhost: 8080 / javaweb_servlet_study_20140531 / 1.htm
http: // localhost: 8080 / javaweb_servlet_study_20140531 / 2.jsp
http: // localhost: 8080 / javaweb_servlet_study_20140531 / 3.php
http: // localhost: 8080 / javaweb_servlet_study_20140531 / 4.aspx
ServletDemo1 est mappé à plusieurs URL.
5.2. Utiliser * Mappage générique pour les URL d'accès au servlet
Le caractère * Wildcard peut également être utilisé dans les URL auxquels le servlet mappe, mais il ne peut y avoir que deux formats fixes: l'un est le "*. Extension", et l'autre est le début d'une barre oblique (/) et se terminant par un "/ *". Par exemple:
<Serplet> <Servlet-Name> ServletDemo1 </vrlett-name> <servlet-class> gacl.servlet.study.servletdemo1 </ servlet-class> </ servlet> <servlet-mapping> <servlet-name> servletdemo1 </vrlett-name> <url-Pattern> / * </url-platern>
* Il peut correspondre à n'importe quel caractère, vous pouvez donc utiliser n'importe quelle URL pour accéder au servlet ServletDemo1, comme indiqué dans la figure ci-dessous:
Pour certaines relations de cartographie ci-dessous:
Servlet1 Maps à / ABC / *
Servlet2 mappe à / *
Servlet3 maps à / ABC
Servlet4 mappe à * .do
question:
Lorsque l'URL de demande est "/abc/a.html", "/ ABC / *" et "/ *" Match, dont le servlet répond au moteur servlet appellera servlet1.
Lorsque l'URL de demande est "/ ABC", la correspondance "/ ABC / *" et "/ ABC", que Servlet répond au moteur Servlet appellera Servlet3.
Lorsque l'URL de demande est "/abc/a.do", "/ ABC / *" et "* .do" Match, dont le servlet répond au moteur servlet appellera servlet1.
Lorsque l'URL de demande est "/a.do", "/ *" et "* .do" correspond à ce que le servlet répond au moteur servlet appellera servlet2.
Lorsque l'URL de demande est "/xxx/yyy/a.do", "/ *" et "* .do" Match, que Servlet répond au servlet moteur appellera servlet2.
Le principe de l'appariement est "Celui qui ressemble plus trouvera celui qui a l'air plus"
5.3. La différence entre les cours de servlet et de Java ordinaires
Servlet est une classe Java pour l'appel par d'autres programmes Java (servlet moteurs). Il ne peut pas s'exécuter indépendamment et son fonctionnement est entièrement contrôlé et programmé par le moteur servlet.
Pour plusieurs demandes de servlet au client, le serveur ne créera généralement qu'un objet d'instance de servlet. C'est-à-dire que, une fois l'objet d'instance de servlet créé, il résidera dans la mémoire et servira d'autres demandes ultérieures. L'objet d'instance de servlet ne sera pas détruit tant que le conteneur Web sorta.
Pendant toute la vie d'un servlet, la méthode init du servlet n'est appelée qu'une seule fois. Chaque demande d'accès à un servlet fait que le moteur servlet appelle la méthode du service de servlet une fois. Pour chaque demande d'accès, le moteur Servlet créera un nouvel objet de demande HTTPServletRequest et un nouvel objet de réponse HTTPServletResponse, puis transmettent ces deux objets sous forme de paramètres à la méthode Service () du servlet qu'il appelle. La méthode de service appelle ensuite la méthode DOXXX en fonction de la méthode de demande.
Si un élément <onde-sur-startup> est configuré dans l'élément <Serplet>, alors lorsque l'application Web démarre, elle chargera et créera l'objet d'instance Servlet et appellera la méthode init () de l'objet d'instance servlet.
Par exemple:
<Serplet> <Servlet-Name> invoker </vrlett-name> <servlet-class> org.apache.catalina.servlets.invokerservlet </vrlett-class> <charge-on-startup> 1 </ charge-on-startup> </ serplet>
Objectif: Écrivez un initservlet pour l'application Web. Ce servlet est configuré pour charger le démarrage pour créer les tables et données de base de données nécessaires pour l'ensemble de l'application Web.
5.4. Servlet par défaut
Si le chemin de mappage d'un servlet n'est qu'une barre oblique avant (/), ce servlet devient le servlet par défaut de l'application Web actuelle.
Toute URL de l'élément de correspondance <Servlet-mapping> qui ne peut être trouvé dans le fichier web.xml, leurs demandes d'accès seront remises au servlet par défaut pour le traitement, c'est-à-dire que le servlet par défaut est utilisé pour gérer les demandes d'accès qui ne sont pas traitées par d'autres servlets. Par exemple:
<VerTlet> <Servlet-Name> ServletDemo2 </vrlett-name> <servlet-class> gacl.servlet.study.servletdemo2 </ servlet-class> <charge-on-startup> 1 </ load-on-startup> </ servlet> <! - Configurer servletDemo2 comme servlet par défaut -> <servlet-mappage> <Servlet-Name> ServletDemo2 </ Servlet-name> <URL-Pattern> / </url-Pattern> </ Servlet-Mapping>
Lorsque vous accédez à un servlet inexistant, le servlet par défaut configuré est utilisé pour le traitement, comme indiqué dans la figure ci-dessous:
Dans le fichier <Tomcat Installation> /conf/web.xml, un servlet nommé org.apache.catalina.servlets.defaultServlet est enregistré, et ce servlet est défini comme servlet par défaut.
<VerTlet> <Servlet-Name> Default </ Servlet-Name> <Servlet-Class> org.apache.catalina.servlets.defaultServlet </ Servlet-Class> <Init-Param> <Am param-Name> Debug </onsam-name> <param-value> 0 </ param-valent> </it init-param> <IniT-Param> <Am param-Value> False </ Param-Value> </nitt-Param> <Office-On-Startup> 1 </ Load-on-Startup> </Servlet> <! - Le mappage du servlet par défaut -> <Serplet-Mapping> </ Servlet-name> par défaut </ Servlet-name> <Url-Pattern> / </url-Pattern> </vrlett-mapping>
Lorsque vous accédez à un fichier et à une image HTML statiques dans le serveur Tomcat, vous accédez réellement à ce servlet par défaut.
5.5. Problèmes de sécurité des filetages du servlet
Lorsque plusieurs clients accèdent simultanément au même servlet, le serveur Web créera un thread pour la demande d'accès de chaque client et appellera la méthode de service du servlet sur ce thread. Par conséquent, si la même ressource est accessible dans la méthode de service, elle peut entraîner des problèmes de sécurité du thread. Par exemple, le code suivant:
Code qui n'a pas de problèmes de sécurité des fils:
package gacl.servlet.study; import java.io.ioexception; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; javax.servlet.http.httpservletResponse; classe publique ServletDemo3 étend httpservlet {public void doget (httpservletRequest request, httpservletResponse réponse) lance Servlexception, ioException {/ ** * Lorsque plusieurs threads accèdent au code dans cette méthode concurtivement, il y aura des problèmes de sécurité threads? La variable I est accessible simultanément par plusieurs threads, mais il n'y a pas de problème de sécurité de thread, car I est une variable locale dans la méthode DoGet. * Lorsque plusieurs threads accèdent simultanément à la méthode DoGet, chaque thread a sa propre variable I, * chaque thread fonctionne sa propre variable I, il n'y a donc pas de problème de sécurité du thread * lorsque plusieurs threads accèdent à une certaine méthode simultanément, si certaines ressources (variables, collections, etc.) sont définies à l'intérieur de la méthode * alors chaque thread a ces éléments, donc il n'y a pas de problème de sécurité du thread * / int i = 1; i ++; réponse.getWriter (). WRITE (i); } public void doPost (requête HttpServletRequest, réponse httpservletResponse) lève ServletException, ioException {doget (request, réponse); }} Code avec des problèmes de sécurité du fil:
Package gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; public Javax.servlet.http.httpleserSerSerSERSERSPERS HttpServlet {int i = 1; public void doGet (demande httpservletRequest, réponse httpservletResponse) lève ServletException, ioException {i ++; essayez {thread.sleep (1000 * 4); } catch (InterruptedException e) {e.printStackTrace (); } réponse.getWriter (). Write (i + ""); } public void doPost (requête HttpServletRequest, réponse httpservletResponse) lève ServletException, ioException {doget (request, réponse); }}Définissez I comme une variable globale. Lorsque plusieurs threads accèdent à la variable i simultanément, il y aura des problèmes de sécurité des fils, comme le montre la figure ci-dessous: Allumez deux navigateurs en même temps pour simuler un accès simultané au même servlet. Normalement, le premier navigateur devrait voir 2, et le deuxième navigateur devrait voir 3, mais les deux navigateurs voient 3, ce qui n'est pas normal.
Les problèmes de sécurité des threads n'existent que lorsque plusieurs threads fonctionnent simultanément la même ressource. Par conséquent, lors de l'écriture d'un servlet, si une certaine ressource (variable, collection, etc.) est accessible simultanément, il y aura des problèmes de sécurité des fils. Alors, comment résoudre ce problème?
Jetons un coup d'œil au code suivant:
Package gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; public Javax.servlet.http.httpleserSerSerSERSERSPERS HttpServlet {int i = 1; public void doGet (demande httpservletRequest, réponse httpservletResponse) lève ServletException, ioException {/ ** * Une fois que la synchronisation est ajoutée, il n'y a pas de problème de sécurité de thread lorsque l'accès simultané à i. * Pourquoi n'y a-t-il pas de problème de sécurité de thread après que la synchronisation est ajoutée? * S'il y a un thread accédant maintenant à l'objet servlet, il obtiendra d'abord le verrou de l'objet servlet * Une fois qu'il sera exécuté, il renverra le verrou à l'objet servlet. Puisqu'il obtient la première fois le verrou de l'objet servlet, * Ainsi, lorsqu'un autre thread accède à l'objet servlet, puisque le verrou a été enlevé par le fil précédent, le thread suivant ne peut qu'attendre en ligne * * / synchronisé (this) {// dans Java, chaque objet a un verrou, et cela se réfère ici à l'objet Servlet I ++; essayez {thread.sleep (1000 * 4); } catch (InterruptedException e) {e.printStackTrace (); } réponse.getWriter (). Write (i + ""); }} public void doPost (httpsservletRequest request, httpservletResponse réponse) lève ServletException, ioException {doGet (request, réponse); }}Maintenant, cette approche consiste à ajouter un verrou à l'objet servlet, en veillant à ce qu'un seul thread accéde aux ressources de l'objet servlet à tout moment, il n'y aura donc pas de problèmes de sécurité du fil, comme le montre la figure ci-dessous:
Bien que cette approche résout les problèmes de sécurité des filetages, l'écriture de servlets ne doit pas gérer les problèmes de sécurité des filetages de cette manière. Si 9999 personnes accèdent au servlet en même temps, ces 9999 personnes doivent faire la queue pour accéder en séquence.
En réponse au problème de sécurité du fil des servlets, Sun fournit une solution: laissez le servlet implémenter une interface SingleThreadModel. Si un servlet implémente l'interface SingleThreadModel, le moteur servlet appellera sa méthode de service en mode unique.
En regardant l'API SEVLET, vous pouvez voir que l'interface SingleThreadModel ne définit aucune méthode ou constante. Dans Java, une interface qui ne définit aucune méthode ou constante est appelée interface de balise. L'une des interfaces TAG les plus typiques que vous voyez souvent est "sérialisable". Cette interface ne définit également aucune méthode ou constante. Quelle est l'utilisation des interfaces de balise en Java? La fonction principale est de marquer un objet et de dire au JVM ce que cet objet peut faire. Par exemple, l'objet de la classe qui implémente l'interface "sérialisable" peut être sérialisé, et il existe également une interface "clonable", qui est également une interface de balise. Par défaut, les objets en Java ne sont pas autorisés à être clonés, tout comme les gens dans la vraie vie, le clonage n'est pas autorisé, mais tant que l'interface "clonable" est implémentée, l'objet peut être cloné.
Laissez le servlet implémenter l'interface SingleThreadModel, ajoutez simplement la déclaration pour implémenter l'interface SingleThreadModel à la définition de la classe Servlet.
Pour les servlets qui implémentent l'interface SingleThreadModel, le moteur Servlet prend toujours en charge l'accès simultané à plusieurs threads au servlet. La méthode consiste à générer plusieurs objets d'instance de servlet, et chaque thread simultané appelle séparément un objet d'instance de servlet indépendant.
La mise en œuvre de l'interface SingleThreadModel ne peut pas vraiment résoudre le problème de sécurité des filetages des servlets, car le moteur de servlet créera plusieurs objets d'instance de servlet et résolvant vraiment le problème de sécurité multi-thread fait référence au problème qu'un objet d'instance de servlet est appelé par plusieurs threads en même temps. En fait, dans Servlet API 2.4, SingleThreadModel a été marqué comme obsolète (obsolète).
Ce qui précède concerne cet article, j'espère qu'il sera utile à l'apprentissage de tout le monde.