Dalam artikel sebelumnya, saya menulis implementasi server web Java sederhana, yang hanya dapat menangani beberapa permintaan sumber daya statis. Wadah Servlet yang diimplementasikan dalam artikel ini telah sedikit dimodifikasi berdasarkan server sebelumnya, menambahkan pemrosesan permintaan servlet.
Langkah Eksekusi Program
1. Buat objek server;
2. Hubungi metode penerimaan objek server dan tunggu koneksi. Jika koneksi berhasil, objek soket akan dikembalikan, jika tidak, itu akan diblokir dan ditunggu;
3. Dapatkan stream inputStream dan outputStream byte dari objek soket, dan kedua aliran ini masing -masing sesuai dengan permintaan permintaan dan respons respons;
4. Memproses permintaan: Baca informasi aliran byte inputStream, ubah menjadi formulir string, dan parsing. Parsing di sini relatif sederhana, dan hanya memperoleh informasi URI (pengidentifikasi sumber daya seragam);
5. Proses respons (dalam dua jenis, respons permintaan sumber daya statis atau respons permintaan servlet): Jika itu adalah permintaan sumber daya statis, berdasarkan informasi URI yang diuraikan, temukan file sumber daya sumber daya yang diminta dari direktori Web_root, baca file sumber daya, dan tuliskan ke aliran byte outputStream; Jika ini adalah permintaan servlet, pertama -tama buat loader kelas URLClassLoader, muat kelas servlet yang diminta, buat objek servlet, dan jalankan metode layanan (tulis data respons ke outputStream);
6. Tutup objek soket;
7. Lanjutkan ke Langkah 2 dan lanjutkan menunggu permintaan koneksi;
Implementasi Kode:
Tambahkan dependensi:
<!-https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <dependency> <GroupId> javax.servlet </proupid> <ArTifactId> Servlet-API </artifactid> <versi> 2.3 </version> </Dependency>
Kode Server:
Paket ex02.pyrmont.first; import java.net.socket; impor java.net.serversocket; impor java.net.inetaddress; impor java.io.inputStream; impor ex02.pyrm; impor java.io.ioeksception; impor ex02.pyrm; Impor Java.io.ioException; impor Ex02.pyrM; ex02.pyrmont.staticResourceProcessor; kelas publik httpserver1 {// tutup perintah layanan private static final string shutdown_command = "/shutdown"; public static void main (string [] args) {httpserver1 server = new httpserver1 (); // menunggu server permintaan koneksi.AWAIT (); } public void wait () {serversocket serversocket = null; int port = 8080; coba {// server socket objek serversocket = new serversocket (port, 1, inetaddress.getbyname ("127.0.0.1")); } catch (ioException e) {e.printstacktrace (); System.exit (1); } // loop untuk menunggu permintaan while (true) {socket socket = null; Inputstream input = null; OutputStream output = null; coba {// tunggu koneksi, setelah koneksi berhasil, kembalikan soket soket soket = serversocket.accept (); input = socket.getInputStream (); output = socket.getoutputStream (); // Buat objek permintaan dan permintaan Parse permintaan = permintaan baru (input); request.parse (); // Periksa apakah itu perintah layanan shutdown jika (request.geturi (). Equals (shutdown_command)) {break; } // Buat respons objek respons respons = respons baru (output); response.setRequest (permintaan); if (request.geturi (). startswith ("/servlet/")) {// minta uri dimulai dengan/servlet/, menunjukkan bahwa servlet permintaan servletprocessor1 prosesor = servletprocessor1 baru (); prosesor.process (permintaan, respons); } else {// static resourseresourceProcessor prosesor = staticResourceProcessor baru (); prosesor.process (permintaan, respons); } // tutup socket socket.close (); } catch (Exception e) {E.PrintStackTrace (); System.exit (1); }}}}Kelas Konstan:
Paket ex02.pyrmont; impor java.io.file; konstanta kelas publik {public static final string web_root = system.getProperty ("user.dir") + file.separator + "webroot"; string final public static web_servlet_root = system.getProperty ("user.dir") + file.separator + "target" + file.separator + "kelas"; }Meminta:
Paket ex02.pyrmont; impor java.io.inputstream; impor java.io.ioexception; impor java.io.bufferedreader; impor java.io.unsupportedencodingException; impor java.util.enumeration; impor java.util.locale; impor java.ututute; javax.servlet.requestdispatcher; import javax.servlet.servletinputStream; import javax.servlet.servletrequest; permintaan kelas publik mengimplementasikan servletRequest {input inputStream pribadi; Private String URI; permintaan publik (inputStream input) {this.input = input; } public string geturi () {return uri; } /** * * Bentuk requestString adalah sebagai berikut: * get /index.html http /1.1 * host: localhost: 8080 * Koneksi: Keep-Alive * Cache-Control: Max-AGE = 0 * ... * Tujuan fungsi ini adalah untuk mendapatkan /index.html string * /string private string parseuri (string private parseuri (string string private parseuri (string string private parseuri (string string parseuri (string private parseuri (string string private parseuri (string string parseuri (string string private parseuri) untuk mendapatkan /index.HTML string string private PARSEURI (string private PARSEURI PARSEURI UNTUK index1 = requestString.indexof (''); if (index1! = -1) {index2 = requestString.indexof ('', index1 + 1); if (index2> index1) return requestString.substring (index1 + 1, index2); } return null; } // Baca satu set karakter dari Socket StringBuffer Request = New StringBuffer (2048); int i; byte [] buffer = byte baru [2048]; coba {i = input.read (buffer); } catch (ioException e) {e.printstacktrace (); i = -1; } untuk (int j = 0; j <i; j ++) {request.append ((char) buffer [j]); } System.out.print (request.toString ()); uri = parseuri (request.toString ()); } / * Implementasi ServletRequest * / Obyek publik getAttribute (atribut string) {return null; } enumerasi publik <?> 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 serveTinPutStream getInputStream () melempar ioException {return null; } locale public getLocale () {return null; } enumerasi publik <?> getLocales () {return null; } public string getParameter (nama string) {return null; } peta publik <?,?> getParametermap () {return null; } enumerasi publik <?> getParameternames () {return null; } public string [] getParameterValues (parameter string) {return null; } public String getProtocol () {return null; } public bufferedReader getReader () melempar 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 (atribut string) {} public void setAttribute (tombol string, nilai objek) {} public void setCharacterencoding (string encoding) melempar UnsupportedEncodingEnception {}}Tanggapan:
Paket ex02.pyrmont; impor java.io.outputStream; impor java.io.ioexception; impor java.io.fileinputstream; import java.io.filenotfoundException; impor java.io.file; impor java.io.printwriter; impor java.util.util.utilax. javax.servlet.servletoutputStream; respons kelas publik mengimplementasikan servletResponse {private static final int buffer_size = 1024; Permintaan permintaan; Outputstream output; Penulis printwriter; respons publik (outputStream output) {this.output = output; } public void setRequest (permintaan permintaan) {this.Request = request; } // Tulis file web ke dalam stream byte byte byte public void sendstaticResource () lemparan ioException {byte [] bytes = byte baru [buffer_size]; FileInputStream fis = null; coba { / * request.geturi telah diganti dengan request.getRequesturi * / file file = file baru (constants.web_root, request.geturi ()); fis = FileInputStream baru (file); / * * Http response = status-line ((umum-header | respons-header | * entitas-header) crlf) crlf [pesan-tubuh] status-line = * http-versi status status spasi-frase crlf */ int ch = fis.read (byte, 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 File tidak ditemukan/r/n" + "tipe konten: teks/html/r/n" + "panjang konten: 23/r/n" + "/r/n" + "<h1> file yang tidak ditemukan </h1>"; output.write (errormessage.getbytes ()); } akhirnya {if (fis! = null) fis.close (); }} / ** Implementasi servletResponse* / public void flushBuffer () melempar ioException {} public int getBufferSize () {return 0; } public string getCharacterencoding () {return null; } locale public getLocale () {return null; } public serveTeToutputStream getOutputStream () melempar ioException {return null; } public printwriter getWriter () melempar ioException {// Autoflush adalah benar, println () akan menyiram, // tapi cetak () tidak. penulis = printwriter baru (output, true); penulis kembali; } public boolean isCommitted () {return false; } public void reset () {} public void resetBuffer () {} public void setBufferSize (ukuran int) {} public void setContentLength (int int) {} public void setContentType (string type) {} public void setLocale (locale locale) {{{{{{{{{{{{{{{{{{{{{{{{{{{{publicale) {{{{{{publicale) public publicale))Pemrosesan Permintaan Sumber Daya Statis:
paket ex02.pyrmont; import java.io.ioException; kelas publik staticResourceProcessor {proses public void (permintaan permintaan, respons respons) {coba {response.sendstaticResource (); } catch (ioException e) {e.printstacktrace (); }}}Pemrosesan Permintaan Servlet:
Paket ex02.pyrmont.first; import java.net.url; impor java.net.urlclassloader; impor java.net.urlstreamhandler; impor java.io.ioException; impor javax.servlet. ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.response; kelas publik servletprocessor1 {proses public void (permintaan permintaan, respons respons) {string uri = request.geturi (); String servletname = uri.substring (uri.LastIndexOf ("/") + 1); // classloader, digunakan untuk memuat kelas urlclassloader dari file jar atau direktori loader = null; coba {urlstreamHandler streamHandler = null; // Buat class loader loader = URLClassLoader baru (URL baru [] {URL baru (null, "file:" + constants.web_servlet_root, streamHandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> Myclass = null; coba {// muat kelas servlet yang sesuai myclass = loader.loadclass (servletname); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; coba {// produksi servlet instance servlet = (servlet) myclass.newInstance (); // Jalankan metode layanan dari permintaan ervlet servlet.service ((servletRequest), (servletResponse) respons); } catch (Exception e) {System.out.println (e.toString ()); } catch (Throwable e) {System.out.println (e.toString ()); }}}Kelas Servlet:
impor javax.servlet.*; impor java.io.ioException; impor java.io.printwriter; kelas publik primitiferver mengimplementasikan servlet {public void init (servletconfig config) melempar servletException {System.out.println ("init"); } public void service (permintaan servletRequest, respons servletResponse) melempar servletException, ioException {system.out.println ("from service"); Printwriter out = response.getWriter (); out.println ("Halo. Mawar berwarna merah."); out.print ("Violet berwarna biru."); } public void hancurkan () {System.out.println ("Destroy"); } public string getServletInfo () {return null; } public serveTonConfig getServletConfig () {return null; }} Tes Hasil:
Permintaan Sumber Daya Statis:
Permintaan servlet (karena hanya string pertama yang disegarkan ke browser, Anda tidak dapat melihat string violet kedua berwarna biru. Kami akan memperbaiki wadah nanti):
memperbaiki
Wadah Servlet yang diimplementasikan sebelumnya memiliki masalah serius. Di servlet, pengguna dapat secara langsung mengubah servletRequest dan servletResponse menjadi jenis permintaan dan respons, dan secara langsung memanggil metode publik internal. Ini adalah desain yang buruk. Metode peningkatan adalah menambahkan kelas penampilan untuk meminta dan menanggapi, sehingga pengguna hanya dapat mengakses metode publik yang ditentukan dalam kelas penampilan.
Meminta kelas penampilan
Paket ex02.pyrmont.second; impor java.io.ioexception; impor java.io.bufferedreader; impor java.io.unsupportedencodingException; impor java.util.enumeration; impor java.util.locale; impor java.util. javax.servlet.servletInputStream; import javax.servlet.servletrequest; import ex02.pyrmont.request; permintaan kelas publik Facade mengimplementasikan servletRequest {permintaan private servletRequest = null; public revandeFacade (permintaan permintaan) {this.request = request; } / * Implementasi dari servletRequest * / objek publik getAttribute (atribut string) {return request.getAttribute (atribut); } enumeration public <?> getAttributeNames () {return request.getAttributeNames (); } @SuppressWarnings ("Deprecation") Public String getRealPath (string path) {return revanded.getRealPath (path); } public requestDispatcher getRequestDispatcher (string path) {return request.getRequestDispatcher (path); } public boolean issecure () {return revanded.issecure (); } public string getCharacterencoding () {return revand.getcharacterencoding (); } public int getContentLength () {return request.getContentLength (); } public String getContentType () {return revanded.getContentType (); } public serveTinPutStream getInputStream () melempar ioException {return revanded.getInputStream (); } public locale getLocale () {return request.getLocale (); } enumeration publik <?> getLocales () {return request.getLocales (); } public string getParameter (nama string) {return request.getParameter (name); } peta publik <?,?> getParametermap () {return request.getParametermap (); } enumeration publik <?> getParameternames () {return request.getParameternames (); } public string [] getParameterValues (parameter string) {return request.getParameterValues (parameter); } public string getProtocol () {return revanded.getProtocol (); } public bufferedReader getReader () melempar ioException {return revand.getReader (); } public String getRemOteAddr () {return revanded.getRemOteAddr (); } public string getRemotehost () {return revanded.getRemotehost (); } public string getScheme () {return revand.getscheme (); } public String getServerName () {return revand.getServerName (); } public int getServerport () {return revands.getServerport (); } public void removeAttribute (atribut string) {request.removeattribute (atribut); } public void setAttribute (tombol string, nilai objek) {request.setAttribute (key, value); } public void setCharacterencoding (string encoding) melempar UnsportedencodingException {request.setcharacterencoding (encoding); }} Kelas penampilan respons
Paket ex02.pyrmont.second; import java.io.ioexception; impor java.io.printwriter; impor java.util.locale; impor javax.servlet.servletresponse; impor javax.servlet. Respons servletResponse; responseFacade publik (respons respons) {this.response = respons; } public void flushBuffer () melempar ioException {response.flushBuffer (); } public int getBufferSize () {return response.getBufferSize (); } public string getCharacterencoding () {return response.getcharacterencoding (); } public locale getLocale () {return response.getLocale (); } public serveTeToutPutStream getOutputStream () melempar ioException {return response.getoutputStream (); } public printwriter getWriter () melempar ioException {return response.getWriter (); } public boolean isCommitted () {return response.iscommitted (); } public void reset () {response.reset (); } public void resetBuffer () {response.resetBuffer (); } public void setBufferSize (ukuran int) {response.setBufferSize (size); } public void resetBufferSize (ukuran); } public void resetBufferSize (ukuran int); } public void setBufferSize (ukuran); } public void setContentLength (panjang int) {response.setContentLength (panjang); } public void setContentType (string type) {response.setContentType (type); } public void setLocale (locale locale) {response.setLocale (locale); }}Memproses kelas permintaan servlet:
Paket ex02.pyrmont.second; impor java.net.url; impor java.net.urlclassloader; impor java.net.urlstreamhandler; impor java.io.ioException; impor javax.servlet. ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.response; kelas publik servletprocessor2 {proses public void (permintaan permintaan, respons respons) {string uri = request.geturi (); String servletname = uri.substring (uri.LastIndexOf ("/") + 1); // class loader, digunakan untuk memuat kelas urlclassloader dari file jar atau direktori loader = null; coba {urlstreamHandler streamHandler = null; // Buat class loader loader = URLClassLoader baru (URL baru [] {URL baru (null, "file:" + constants.web_servlet_root, streamHandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> Myclass = null; coba {// muat kelas servlet yang sesuai myclass = loader.loadclass (servletname); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; // Tambahkan kelas penampilan untuk meminta dan menanggapi, dan pertimbangan keamanan diberikan untuk mencegah pengguna dari secara langsung mengubah servletRequest dan servletResponse menjadi jenis permintaan dan respons di servlets, // dan secara langsung memanggil metode publik internal mereka, karena tidak akan ada parse, sendStaticResource dan metode lain dalam permintaan dan responseFacade; RequestFacade requestFacade = new RequestFacade (permintaan); ResponseFacade responseFacade = responseFacade baru (respons); coba {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 ()); }}} Kode lain pada dasarnya sama dengan wadah servlet yang diimplementasikan sebelumnya.
Program verifikasi masing -masing meminta sumber daya statis dan servlet, dan menemukan bahwa hasilnya konsisten dengan wadah yang diterapkan sebelumnya;
Referensi: "Analisis Tomcat yang mendalam"
@Author Coder seperti angin
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.