Dans l'article précédent, j'ai écrit une simple implémentation de serveur Web Java, qui ne peut gérer que certaines demandes de ressources statiques. Le conteneur servlet implémenté dans cet article a été légèrement modifié en fonction du serveur précédent, ajoutant le traitement des demandes de servlet.
Étapes d'exécution du programme
1. Créez un objet SERVERSOCKET;
2. Appelez la méthode Accept de l'objet Serversocket et attendez la connexion. Si la connexion est réussie, un objet Socket sera retourné, sinon il sera bloqué et attendu;
3. Obtenez les flux d'octets InputStream et OutputStream à partir de l'objet Socket, et ces deux flux correspondent respectivement à la demande de demande et à la réponse de réponse;
4. Traitez la demande: Lisez les informations de flux d'octets InputStream, convertissez-la en un formulaire de chaîne et analysez-la. L'analyse ici est relativement simple, et il n'obtient que les informations URI (identifiant de ressources uniformes);
5. Traitez la réponse (en deux types, réponse statique de la demande de ressources ou réponse de la demande de servlet): S'il s'agit d'une demande de ressources statique, en fonction des informations URI analysées, trouvez le fichier de ressources de ressources demandé dans le répertoire Web_root, lisez le fichier de ressources et écrivez dans le flux OutputStream Byte; S'il s'agit d'une demande de servlet, générez d'abord un chargeur de classe UrlClassloader, chargez la classe de servlet demandée, créez l'objet servlet et exécutez la méthode de service (écrivez les données de réponse à OutputStream);
6. Fermez l'objet de socket;
7. Passez à l'étape 2 et continuez à attendre la demande de connexion;
Implémentation du code:
Ajouter des dépendances:
<! - https://mvnrepository.com/artifact/javax.servlet/servlet-api -> <dependency> <proupId> javax.servlet </proupId> <ArtefactId> Servlet-API </ artifactid> <version> 2.3 </-version> </Dedency>
Code du serveur:
package ex02.pyrmont.first; import java.net.socket; import java.net.serversocket; import java.net.inetaddress; import java.io.inputstream; import ex02.pyrmont.request; Ex02.pyrmont.StaticResourceProcessor; public class httpServer1 {// close service Commande de service final statique private strict shutdown_command = "/ shutdown"; public static void main (String [] args) {httpServer1 server = new httpServer1 (); // en attente de la demande de connexion Server.Await (); } public void Await () {Serversocket Serversocket = null; int port = 8080; try {// server socket objet SERVERSOCKET = new serversocket (port, 1, inetAddress.getByName ("127.0.0.1")); } catch (ioException e) {e.printStackTrace (); System.exit (1); } // boucle pour attendre la demande while (true) {socket socket = null; InputStream input = null; OutputStream output = null; essayez {// attendez la connexion, une fois la connexion réussie, renvoyez un socket objet socket = serversocket.accept (); input = socket.getInputStream (); output = socket.getOutputStream (); // Créer un objet de demande et une demande d'analyse de demande = nouvelle demande (entrée); request.parse (); // Vérifiez s'il s'agit d'une commande de service d'arrêt if (request.getUri (). Equals (shutdown_command)) {break; } // Créer la réponse de l'objet Response = nouvelle réponse (sortie); Response.SetRequest (demande); if (request.getUri (). startSwith ("/ servlet /")) {// request uri commence par / servlet /, indiquant que servlet demande servletprocessor1 processeur = new servletprocessor1 (); processeur.process (demande, réponse); } else {// STATIC RESSERCERERESORCEPROCESSOR Processeur = new staticResourceProcessor (); processeur.process (demande, réponse); } // fermer socket socket.close (); } catch (exception e) {e.printStackTrace (); System.exit (1); }}}}Classe constante:
package ex02.pyrmont; import java.io.file; public class constants {public static final string web_root = System.getProperty ("user.dir") + file.separator + "webroot"; Public Static Final String web_servlet_root = System.getProperty ("user.dir") + file.separator + "cible" + file.separator + "classes"; }Demande:
Package Ex02.pyrmont; Importer java.io.inputStream; Importer java.io.ioException; Importer java.io.buffereDader; Importer java.io.unsupportedEncodingException; Importer Java.util.enumeration; Importer Java.util.locale; import Java.util.map; import Java. javax.servlet.servletInputStream; import javax.servlet.servletRequest; la demande de classe publique implémente servletRequest {private inputStream entrée; URI de chaîne privée; Demande publique (InputStream Input) {this.input = input; } public String getUri () {return uri; } / ** * * Le formulaire de requestString est le suivant: * get /index.html http / 1.1 * hôte: localhost: 8080 * Connexion: keep-alive * cache-control: max-age = 0 * ... * Le but de cette fonction est pour obtenir /index.html string * / private String Parceuri (String requestString) {int index1, index2; index1 = requestString.Indexof (''); if (index1! = -1) {index2 = requestString.Indexof ('', index1 + 1); if (index2> index1) return requestString.substring (index1 + 1, index2); } return null; } // Lisez un ensemble de caractères de la socket stringbuffer demande = new StringBuffer (2048); int i; octet [] tampon = nouveau octet [2048]; essayez {i = input.read (tampon); } catch (ioException e) {e.printStackTrace (); i = -1; } pour (int j = 0; j <i; j ++) {request.append (((char) buffer [j]); } System.out.print (request.toString ()); uri = paseuri (request.toString ()); } / * Implémentation de ServLetRequest * / Objet public getAttribute (String Attribut) {return null; } Public Enumeration <?> GetAtTrributeNames () {return null; } public String getRealPath (String Path) {return null; } public requestDispatcher getRequestDispatcher (String Path) {return null; } public boolean issesecure () {return false; } public String getCacteRencoding () {return null; } public int getContentLength () {return 0; } public String getContentType () {return null; } public servleTInputStream getInputStream () lève ioException {return null; } public public getLocale () {return null; } publication publique <?> getLocales () {return null; } public String getParAmètre (nom de chaîne) {return null; } Map public <?,?> getParameTermap () {return null; } public énumération <?> getParameTernames () {return null; } public String [] getParameTervalues (paramètre de chaîne) {return null; } public String getProtoCol () {return null; } public BufferedReader getReader () lève ioException {return null; } public String getRemoteaddr () {return null; } public String getRemoteHost () {return null; } public String getSheme () {return null; } public String getServerName () {return null; } public int getServerport () {return 0; } public void remoVeAtTribute (String Attribut) {} public void setAttribute (clé de chaîne, valeur d'objet) {} public void setCharacTeRencoding (String Encoding) lance unppordedencodingException {}}Réponse:
package ex02.pyrmont; import java.io.outputstream; import java.io.ioException; import java.io.fileinputStream; import java.io.filenotfoundException; import java.io.file; import java.io.printwriter; import java.util.locale; import Java javax.servlet.servletOutStream; La réponse de classe publique implémente servletResponse {private static final int buffer_size = 1024; Demande de demande; OutputStream output; Écrivain de gravure; Réponse publique (OutputStream Output) {this.Output = output; } public void setRequest (request request) {this.request = request; } // Écrivez le fichier Web dans le flux de sortie de sortie de l'octet public void SendStaticResource () lève ioException {byte [] bytes = new byte [buffer_size]; FileInputStream fis = null; try {/ * request.geturi a été remplacé par request.getRequestruri * / fichier file = new File (constants.web_root, request.geturi ()); fis = new FileInputStream (fichier); / * * Http Response = Status-Line ((General-Header | Response-Header | * Entity-Header) CRLF) CRLF [Message-Body] Status-Line = * Http-Version SP-Code-Code SP Reason-Phrase CRLF * / int ch = fis.read (bytes, 0, buffer_size); while (ch! = -1) {output.write (octets, 0, ch); ch = fis.read (octets, 0, buffer_size); }} catch (filenotfoundException e) {String errorMessage = "HTTP / 1.1 404 Fichier non trouvé / r / n" + "Content-Type: Text / html / r / n" + "Content-Length: 23 / r / n" + "/ r / n" + "<h1> Fichier introuvable </ h1>"; output.write (errorMessage.getBytes ()); } enfin {if (fis! = null) fis.close (); }} / ** L'implémentation de servletResponse * / public void flushbuffer () lève ioException {} public int getBuffeSize () {return 0; } public String getCacteRencoding () {return null; } public public getLocale () {return null; } public servletOutputStream getOutputStream () lève ioException {return null; } public printwriter getWriter () lève ioException {// AutofLush est vrai, println () rincera, // mais print () ne le fera pas. écrivain = new PrintWriter (output, true); écrivain de retour; } public boolean isCommitted () {return false; } public void reset () {} public void resetBuffer () {} public void SetBuffeSize (int size) {} public void setContentLength (int longueur) {} public void SetContentType (Type de chaîne) {} public void SetLocale (Llove Llove) {}}Traitement de la demande de ressources statiques:
package ex02.pyrmont; import java.io.ioException; classe publique staticResourceProcessor {public void process (request request, réponse réponse) {try {réponse.SendStaticResource (); } catch (ioException e) {e.printStackTrace (); }}}Traitement de la demande de servlet:
package ex02.pyrmont.first; import java.net.url; import java.net.urlclassloader; import java.net.urlstreamhandler; import java.io.ioexception; import javax.servlet.servlet; ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.Response; public class servletprocessor1 {public void process (request request, réponse réponse) {String uri = request.geturi (); String servletName = uri.substring (uri.lastIndexof ("/") + 1); // classloader, utilisé pour charger la classe URLClassLoader à partir d'un fichier JAR ou d'un répertoire spécifié (NULL; essayez {urlStreamHandler streamhandler = null; // Créer un chargeur de classe Class = new UrlClassloadher (new URL [] {new URL (null, "file:" + constants.web_servlet_root, streamhandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> MyClass = null; essayez {// Chargez la classe de servlet correspondante myClass = load.LoadClass (servLetName); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; Essayez {// Produire Servlet Instance Servlet = (servlet) myClass.NewInstance (); // Exécuter la méthode de service de la demande d'ervlet servlet.service ((servletRequest), (servletResponse) réponse); } catch (exception e) {System.out.println (e.toString ()); } catch (Throwable E) {System.out.println (e.toString ()); }}}Classe de servlet:
import javax.servlet. *; import java.io.ioException; import java.io.printwriter; public class primitiveservlet implémente servlet {public void init (servletconfig config) lève servletException {System.out.println ("init"); } public void Service (ServLetRequest Request, ServletResponse Response) lève ServletException, ioException {System.out.println ("From Service"); Printwriter out = réponse.getWriter (); Out.println ("Hello. Les roses sont rouges."); Out.print ("Les violettes sont bleues."); } public void destrement () {System.out.println ("destruction"); } public String getServletInfo () {return null; } public serpletConfig getServletConfig () {return null; }} Test des résultats:
Demande de ressources statique:
Demande de servlet (parce que c'est juste la première chaîne en cours de chasse au navigateur, vous ne pouvez pas voir que la deuxième chaîne Violets est bleue. Nous affinerons le conteneur plus tard):
améliorer
Le conteneur servlet mis en œuvre plus tôt a un problème grave. Dans le servlet, l'utilisateur peut transformer directement ServletRequest et ServletResponse en types de demande et de réponse, et appeler directement ses méthodes publiques internes. C'est un mauvais design. La méthode d'amélioration consiste à ajouter des classes d'apparence à la demande et à la réponse, afin que les utilisateurs ne puissent accéder aux méthodes publiques définies dans la classe d'apparence.
Demande la classe d'apparence
Package Ex02.pyrmont.second; import java.io.ioException; import java.io.buffereDader; import java.io.unsuppordencodingException; import java.util.enuneration; import java.util.locale; importather; javax.servlet.servletInputStream; import javax.servlet.servletRequest; import ex02.pyrmont.Request; public class demandeFacade implémente servLetRequest {private servLetRequest request = null; PUBLIC DEMANDFACADE (demande de demande) {this.request = request; } / * Implémentation de ServLetRequest * / Objet public getAttribute (String Attribute) {return request.getAttribute (attribut); } public Enumeration <?> getAtTrributeNames () {return request.getAttributeNames (); } @SuppressWarnings ("Deprécation") String public getRealPath (String Path) {return request.getRealPath (path); } public requestDispatcher getRequestDispatcher (String path) {return request.getRequestDispatcher (path); } public boolean iSsecure () {return request.issecure (); } public String getCacteRencoding () {return request.getCharacTerencoding (); } public int getContentLength () {return request.getContentLength (); } public String getContentType () {return request.getContentType (); } public servleTInputStream getInputStream () lève ioException {return request.getInputStream (); } public public getLocale () {return request.getLocale (); } public Enumeration <?> getLocales () {return request.getLocales (); } public String getParameter (String Name) {return request.getParameter (name); } Map public <?,?> getParameTermap () {return request.getParameTermap (); } public énumération <?> getParameTernames () {return request.getParameTernames (); } public String [] getParameTervalues (paramètre de chaîne) {remerciation.GetParameTervalues (paramètre); } public String getProtoCol () {return request.getProtoCol (); } public BufferedReader getReader () lève ioException {return request.getReader (); } public String getRemoteadDr () {return request.getReMoteaddr (); } public String getRemoteHost () {return request.getRemoteHost (); } public String getScheme () {return request.getscheme (); } public String getServerName () {return request.getServerName (); } public int getServerport () {return request.getServerport (); } public void removeAtTribute (String Attribut) {request.RemoveAtTribute (attribut); } public void setAttribute (clé de chaîne, valeur objet) {request.setAttribute (key, valeur); } public void setCharacTeRencoding (String Encoding) lève unportedEncodingException {request.SetcharAtterencoding (Encoding); }} Classe d'apparence de réponse
Package Ex02.pyrmont.second; Importer java.io.ioException; import java.io.printwriter; import java.util.locale; importer javax.servlet.servletResponse; import javax.servlet.servletoutputStream; Importer ex02.pyrmont. Public ResponseFacade (réponse réponse) {this.Response = réponse; } public void flushbuffer () lève ioException {réponse.flushBuffer (); } public int getBuffeSize () {return réponse.getBuffersize (); } public String getCacteRencoding () {return réponse.getCharacTerencoding (); } public public getLocale () {return réponse.getLocale (); } public servletOutputStream getOutputStream () lève ioException {return réponse.getOutputStream (); } public printwriter getWriter () lève ioException {return réponse.getWriter (); } public boolean iscommitmis () {return réponse.iscommit (); } public void reset () {réponse.resset (); } public void resetBuffer () {réponse.resetBuffer (); } public void SetBuffeSize (int size) {réponse.setBuffersize (taille); } public void resetBuffeSize (taille); } public void resetBuffeSize (INT size); } public void SetBuffeSize (taille); } public void setContentLength (int longueur) {réponse.SetContentLength (longueur); } public void setContentType (type de chaîne) {réponse.setContentType (type); } public void setLocale (paramètres régionaux) {réponse.setLocale (paramètres locaux); }}Traitement de la classe de demande de servlet:
package ex02.pyrmont.second; import java.net.url; import java.net.urlclassloader; import java.net.urlstreamhandler; import java.io.ioexception; import javax.servlet.servlet; ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.Response; public class servletprocessor2 {public void process (request request, réponse réponse) {String uri = request.geturi (); String servletName = uri.substring (uri.lastIndexof ("/") + 1); // Chardeur de classe, utilisé pour charger la classe URLClassloadher à partir d'un fichier JAR ou d'un répertoire spécifié CHARDER = NULL; essayez {urlStreamHandler streamhandler = null; // Créer un chargeur de classe Class = new UrlClassloadher (new URL [] {new URL (null, "file:" + constants.web_servlet_root, streamhandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> MyClass = null; essayez {// Chargez la classe de servlet correspondante myClass = load.LoadClass (servLetName); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; // Ajouter des classes d'apparence à la demande et à la réponse, et des considérations de sécurité sont données pour empêcher les utilisateurs de transformer directement ServLetRequest et ServletResponse en types de demande et de réponse dans les servlets, // et d'appeler directement leurs méthodes publiques internes, car il n'y aura pas de Parse, SendStatingResource et d'autres méthodes dans DemandeFacade et ResponseFacade; RequestFacade requestFacade = new requestFacade (request); ResponseFacade ResponseFacade = new ResponseFacade (réponse); essayez {servlet = (servlet) myclass.newinstance (); servlet.service ((servletRequest) requestFacade, (servletResponse) ResponseFacade); } catch (exception e) {System.out.println (e.toString ()); } catch (Throwable E) {System.out.println (e.toString ()); }}} Les autres codes sont fondamentalement les mêmes que le conteneur servlet implémenté plus tôt.
Le programme de vérification demande respectivement les ressources statiques et les servlets, et constate que les résultats sont cohérents avec le conteneur mis en œuvre plus tôt;
Référence: "Analyse approfondie de Tomcat"
@author un codeur de vent
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.