前の記事では、静的なリソース要求のみを処理できる簡単なJava Webサーバーの実装を書きました。この記事で実装されているサーブレットコンテナは、以前のサーバーに基づいてわずかに変更されており、サーブレットリクエストの処理を追加しています。
プログラムの実行手順
1。サーバーソケットオブジェクトを作成します。
2。Serversocketオブジェクトの受け入れ方法を呼び出して、接続を待ちます。接続が成功した場合、ソケットオブジェクトが返され、それ以外の場合はブロックされて待機されます。
3.ソケットオブジェクトから入力ストリームおよび出力ストリームバイトストリームを取得し、これらの2つのストリームは要求要求と応答の応答にそれぞれ対応します。
4。リクエストを処理します:inputstreamバイトストリーム情報を読み取り、文字列形式に変換し、解析します。ここでの解析は比較的単純であり、URI(均一なリソース識別子)情報のみを取得します。
5。応答を処理します(2つのタイプで、静的リソース要求応答またはサーブレットリクエスト応答):解析されたURI情報に基づいて静的リソース要求である場合、Web_Rootディレクトリから要求されたリソースファイルを見つけ、リソースファイルを読み取り、出力ストリームバイトストリームに書き込みます。サーブレットリクエストの場合、最初にURLClassloaderクラスローダーを生成し、要求されたサーブレットクラスをロードし、サーブレットオブジェクトを作成し、サービスメソッドを実行します(Response DataをOutputStreamに書き込みます)。
6.ソケットオブジェクトを閉じます。
7。ステップ2に進み、接続要求を待ち続けます。
コード実装:
依存関係を追加:
<! - https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <dependency> <shivax.servlet </groupid> <artifactid> servlet- </artifactid> <バージョン> 2.3 </バージョン> </dependency>
サーバーコード:
パッケージex02.pyrmont.first; import java.net.socket; import java.net.serversocket; import java.net.inetaddress; import java.utputstream; Import java.outputStream; Import Java.io.ioexception; ex02.pyrmont.staticresourceprocessor; public class httpserver1 {// close service command private static final string shutdown_command = "/shutdown"; public static void main(string [] args){httpserver1 server = new httpserver1(); //接続要求server.await()を待機します。 } public void await(){Serversocket Serversocket = null; int port = 8080; try {//サーバーソケットオブジェクトServersocket = new Serversocket(port、1、inetAddress.getByname( "127.0.0.1")); } catch(ioexception e){e.printstacktrace(); System.Exit(1); } //(true){socket socket = null; inputstream input = null; outputStream output = null; try {//接続を待ちます。接続が成功したら、ソケットオブジェクトソケット= serversocket.accept()を返します。 input = socket.getInputStream(); output = socket.getOutputStream(); //リクエストオブジェクトを作成し、リクエストリクエスト= new request(input); request.parse(); //シャットダウンサービスコマンドであるかどうかを確認します(request.geturi()。equals(shutdown_command)){break; } //応答オブジェクト応答の作成応答= new Response(output); Response.setRequest(リクエスト); if(request.geturi()。startswith( "/servlet/")){// request uriは/servlet/で起動します。 processor.process(request、response); } else {// static resourseSourceProcessor processor = new staticResourceProcessor(); processor.process(request、response); } // socketsocket.close(); } catch(Exception e){e.printstacktrace(); System.Exit(1); }}}}一定のクラス:
パッケージex02.pyrmont; import java.io.file; public final string web_root = system.getProperty( "user.dir") + file.separator + "webroot"; public static final string web_servlet_root = system.getProperty( "user.dir") + file.separator + "target" + file.separator + "classes"; }
リクエスト:
パッケージex02.pyrmont; import java.io.inputstream; import java.io.ioexception; Import java.io.bufferedreader; Import java.io.unsupportedencodingincection; Import java.util.Enumeration; Import Java.util.locale; Import java.util.util.map javax.servlet.requestdispatcher; Import javax.servlet.servletinputStream; Import javax.servlet.servletRequest;パブリッククラスのリクエストServletRequest {private inputstream input;プライベートストリングURI; public request(inputstream input){this.input = input; } public string geturi(){return uri; } /** * * requestStringの形式は次のとおりです。 index1 = requestString.indexof( ''); if(index1!= -1){index2 = requestString.indexof( ''、index1 + 1); if(index2> index1)RequestString.Substring(index1 + 1、index2)を返します。 } nullを返します。 } // Socket StringBuffer request = new StringBuffer(2048)から文字のセットを読み取ります。 int i; byte [] buffer = new byte [2048]; try {i = input.read(buffer); } catch(ioexception e){e.printstacktrace(); i = -1; } for(int j = 0; j <i; j ++){request.append((char)buffer [j]); } system.out.print(request.toString()); uri = parseuri(request.toString()); } / * ServletRequestの実装 * / public Object getAttribute(String属性){return null; } public Enumeration <?> getattributenames(){return null; } public string getRealPath(String Path){return null; } public requestDispatcher getRequestDispatcher(String Path){return null; } public boolean issecure(){return false; } public String getCharActerEncoding(){return null; } public int getContentLength(){return 0; } public string getContentType(){return null; } public servletinputStream getInputStream()throws ioException {return null; } public locale getLocale(){return null; } public Enumeration <?> getLocales(){return null; } public string getParameter(string name){return null; } public map <?、?> getParametermap(){return null; } public Enumeration <?> getParameternames(){return null; } public string [] getParametervalues(string parameter){return null; } public string getProtocol(){return null; } public bufferedreader getReader()throws ioexception {return null; } public string getRemoteadDr(){return null; } public string getRemoteHost(){return null; } public string getScheme(){return null; } public string getServername(){return null; } public int getServerport(){return 0; } public void removeattribute(string attribute){} public void setattribute(string key、object value){} public void setCharacterEncoding(String encoding)throws unsupportedencodingException {}}応答:
パッケージex02.pyrmont; import java.outputstream; Import java.io.io.ioexception; Import java.io.fileinputStream; Import java.filenotfoundexception; Import java.io.file; Import java.io.printwriter; Import Java.util.util.util.util. javax.servlet.servletoutputStream; public class ResponseはservletResponseを実装します{private static final int buffer_size = 1024;リクエストリクエスト。出力ストリーム出力。プリントライターライター。 public Response(outputstream output){this.output = output; } public void setRequest(request request){this.request = request; } // webファイルをoutputstream byte streamに書き込みますpublic void sendstaticResource()throws ioexception {byte [] bytes = new byte [buffer_size]; fileinputStream fis = null; try { / * request.geturiはrequest.getRequesturi * / file file = new file(constants.web_root、request.geturi())に置き換えられました。 fis = new fileInputStream(file); / * * http response = status-line((general-header | response-header | * entity-header)crlf)crlf [message-body] status-line = * http-version sp status-code sp regay-phrase crlf */ int ch = fis.read(bytes、0、buffer_size); while(ch!= -1){output.write(bytes、0、ch); ch = fis.read(bytes、0、buffer_size); }} catch(filenotfoundexception e){string errormessage = "http/1.1 404ファイルが見つかっていない/r/n" + "content-type:text/html/r/n" + "content-length:23/n" + "/r/n" + "<h1>ファイルnot </h1"; output.write(errormessage.getBytes()); }最後に{if(fis!= null)fis.close(); }} / ** servletResponseの実装* / public void flushbuffer()throws ioexception {} public int getBufferSize(){return 0; } public String getCharActerEncoding(){return null; } public locale getLocale(){return null; } public servletoutputStream getOutputStream()throws ioException {return null; } public PrintWriter getWriter()throws ioException {// autoflush is true、println()は// print()はそうではありません。 writer = new Printwriter(output、true);帰りのライター。 } public boolean iscommitted(){return false; } public void reset(){} public void resetbuffer(){} public void setBufferize(int size){} public void setContentLength(intcontentLength(} public void setContentType(String型){} public void setlocale(locale){}}}}}静的リソース要求処理:
パッケージex02.pyrmont; import java.io.ioexception; public class stateCresourceProcessor {public void Process(request request、response response){try {respons.sendstaticResource(); } catch(ioexception e){e.printstacktrace(); }}}サーブレットリクエスト処理:
パッケージex02.pyrmont.first; import java.net.url; Import java.net.urlclassloader; import java.net.urlstreamhandler; Import javax.servlet.servlet; Import javax.servletest.servletest.servletest.servletest.servletest.servletest.servletest.servletrequest; ex02.pyrmont.constants; import ex02.pyrmont.request; Import ex02.pyrmont.response; public class servletprocessor1 {public void process(request request、response response){string uri = request.geturi(); string servletname = uri.substring(uri.lastindexof( "/") + 1); // ClassLoader、指定されたJARファイルまたはディレクトリローダー= nullからクラスのurlclassloaderをロードするために使用されます。 try {urlstreamhandler streamhandler = null; // create classローダーローダー= new urlclassloader(new Url [] {new URL(null、 "file:" + constants.web_servlet_root、stramehandler)}); } catch(ioException e){system.out.println(e.toString()); } class <?> myclass = null; try {//対応するサーブレットクラスmyclass = loader.loadclass(servletname)をロードしてください。 } catch(classNotFoundException e){system.out.println(e.toString()); }サーブレットサーブレット= null; try {//サーブレットインスタンスサーブレット=(サーブレット)myclass.newinstance(); // ervlet servlet.service((servletRequest)request、(servletResponse)Response)のサービスメソッドを実行します。 } catch(Exception e){System.out.println(e.toString()); } catch(throwable e){system.out.println(e.toString()); }}}サーブレットクラス:
Import javax.servlet。*; import java.io.ioexception; import java.io.printwriter; public class primitiveservlet explments servlet {public void init(servletconfig config)throws servletexception {system.out.println( "init"); } public void service(servletRequest request、servletResponse応答)servletexception、ioexception {system.out.println( "from service"); printwriter out = response.getWriter(); out.println( "こんにちは。バラは赤です。"); out.print( "スミレは青です。"); } public void Destroy(){System.out.println( "Destroy"); } public string getservletinfo(){return null; } public servletconfig getServletconfig(){return null; }}結果テスト:
静的リソースリクエスト:
サーブレットリクエスト(ブラウザにリフレッシュされる最初の文字列であるため、2番目のストリングスミレが青であることがわかりません。後でコンテナを改良します):
改善する
以前に実装されたサーブレットコンテナには深刻な問題があります。サーブレットでは、ユーザーはServleTRequestとServleTResponseをリクエストと応答の種類に直接変換し、内部のパブリックメソッドを直接呼び出すことができます。これは悪いデザインです。改善方法は、外観クラスをリクエストと応答に追加して、ユーザーが外観クラスで定義されているパブリックメソッドのみにアクセスできるようにすることです。
外観クラスをリクエストします
ex02.pyrmont.second; import java.io.ioexception; Import java.io.bufferederer; Import java.io.unsupportedencodinginception; Import java.util.enumeration; Import java.util.locale; import java.util.util.map.map.servletelet.servelet.servelet.servelet.servelet.servelet javax.servlet.servletinputStream; Import javax.servlet.servletrequest; Import ex02.pyrmont.request; public class requestfacadeはservletrequest {private servletrequest = null; public requestfacade(request request){this.request = request; } / * ServletRequestの実装 * / public Object getAttribute(String属性){return request.getAttribute(属性); } public enumeration <?> getAttributEnames(){return request.getAttributEnames(); } @suppresswarnings( "deprecation")public string getRealPath(String Path){return request.getRealPath(PATH); } public requestDispatcher getRequestDispatcher(String Path){return request.getRequestDispatcher(PATH); } public boolean secure(){return request.issecure(); } public string getCharActerEncoding(){return request.getCharacterEncoding(); } public int getContentLength(){return request.getContentLength(); } public string getContentType(){return request.getContentType(); } public servletinputStream getInputStream()throws ioException {return request.getInputStream(); } public locale getLocale(){return request.getLocale(); } public enumeration <?> getLocales(){return request.getLocales(); } public string getParameter(string name){return request.getParameter(name); } public Map <?、? } public enumeration <?> getParameternames(){return request.getParameternames(); } public string [] getParametervalues(String Parameter){return request.getParametervalues(parameter); } public string getProtocol(){return request.getProtocol(); } public BufferedReader getReader()throws 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 attribute){request.RemoveAttribute(Attribute); } public void setAttribute(String key、object value){request.setattribute(key、value); } public void setCharActerEncoding(String encoding)は、unsupportedencodingExceptionをスローします{request.setcharacterencoding(encoding); }}応答外観クラス
package ex02.pyrmont.second;import java.io.IOException;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletResponse;import javax.servlet.ServletOutputStream;import ex02.pyrmont.Response;public class ResponseFacade implements ServletResponse { private ServletResponse 応答; public ResponseFacade(Response Response){this.response = Response; } public void flushbuffer()throws ioexception {respons.flushbuffer(); } public int getBufferSize(){return Response.getBufferSize(); } public string getCharActerEncoding(){return Response.getCharacterenCoding(); } public locale getLocale(){return Response.getLocale(); } public servletoutputStream getOutputStream()throws ioException {return Response.getOutputStream(); } public PrintWriter getWriter()throws ioException {return Response.getWriter(); } public boolean iscommitted(){return response.iscommitt(); } public void reset(){respons.reset(); } public void resetbuffer(){respons.resetbuffer(); } public void setBufferize(int size){respons.setBufferize(size); } public void resetbufferize(size); } public void resetbuffersize(int size); } public void setBufferSize(size); } public void setContentLength(int length){respons.setContentLength(length); } public void setContentType(string type){respons.setContentType(type); } public void setlocale(locale locale){respons.setlocale(locale); }}サーブレットリクエストクラスの処理:
ex02.pyrmont.second; import java.net.url; import java.net.urlclassloader; import java.net.urlstreamhandler; import javax.servlet.servlet; import javax.servletest.servletest.servletest.servletest.servletest.servletest.servletest.servletest.servletrequent; ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.response; public class servletprocessor2 {public void process(request request、response response){string uri = request.geturi(); string servletname = uri.substring(uri.lastindexof( "/") + 1); //クラスローダー、指定されたJARファイルまたはディレクトリローダー= nullからクラスのurlclassloaderをロードするために使用されます。 try {urlstreamhandler streamhandler = null; // create classローダーローダー= new urlclassloader(new Url [] {new URL(null、 "file:" + constants.web_servlet_root、stramehandler)}); } catch(ioException e){system.out.println(e.toString()); } class <?> myclass = null; try {//対応するサーブレットクラスmyclass = loader.loadclass(servletname)をロードしてください。 } catch(classNotFoundException e){system.out.println(e.toString()); }サーブレットサーブレット= null; //リクエストと応答に外観クラスを追加すると、ユーザーがサーブレットとサーブレスポンスをサーブレットのリクエストと応答タイプに直接変換するのを防ぐためにセキュリティ上の考慮事項が与えられます。 requestfacade requestfacade = new requestfacade(request); ResponseFacade ResponseFacade = new ResponseFacade(Response); try {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()); }}}他のコードは、基本的に以前に実装されたサーブレットコンテナと同じです。
検証プログラムは、それぞれ静的リソースとサーブレットを要求し、結果が以前に実装されたコンテナと一致していることがわかります。
参照:「Tomcatの詳細な分析」
@author風のようなコーダー
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。