في المقالة السابقة ، كتبت تطبيق خادم ويب Java بسيط ، والذي يمكنه فقط التعامل مع بعض طلبات الموارد الثابتة. تم تعديل حاوية Servlet التي تم تنفيذها في هذه المقالة بشكل طفيف بناءً على الخادم السابق ، مما يضيف معالجة طلبات Servlet.
خطوات تنفيذ البرنامج
1. إنشاء كائن Serversocket ؛
2. استدعاء طريقة قبول كائن Serversocket وانتظر الاتصال. إذا كان الاتصال ناجحًا ، فسيتم إرجاع كائن المقبس ، وإلا سيتم حظره وانتظره ؛
3. احصل على تدفقات البايت inputstream و outputstream من كائن المقبس ، وهذان المجاريان يتوافقان مع طلب الطلب والاستجابة على التوالي ؛
4. معالجة الطلب: اقرأ معلومات دفق البايت inputstream ، وتحويلها إلى نموذج سلسلة ، وحوضه. التحليل هنا بسيط نسبيًا ، ويحصل فقط على معلومات URI (معرف الموارد الموحد) ؛
5. معالجة الاستجابة (في نوعين ، استجابة طلب المورد الثابت أو استجابة طلب Servlet): إذا كان طلب مورد ثابت ، استنادًا إلى معلومات URI المحلية ، ابحث عن ملف المورد المطلوب من دليل Web_Root ، وقراءة ملف المورد ، واكتبه إلى دفق البايت OutputStream ؛ إذا كان طلب Servlet ، قم أولاً بإنشاء محمل فئة UrlClassLaStloader ، وقم بتحميل فئة Servlet المطلوبة ، وإنشاء كائن Servlet ، وتنفيذ طريقة الخدمة (اكتب بيانات الاستجابة إلى OutputStream) ؛
6. أغلق كائن المقبس ؛
7. انتقل إلى الخطوة 2 واستمر في انتظار طلب الاتصال ؛
تنفيذ الكود:
إضافة تبعيات:
<!-https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <reperence> <roupiD> javax.servlet </groupId> <StifactId> servlet-api </shintifactid> <soph>
رمز الخادم:
package ex02.pyrmont.first ؛ import java.net.socket ؛ استيراد java.net.serversocket ؛ استيراد java.net.inetaddress ؛ استيراد java.io.inputStream ؛ import java.io.outputstream ؛ import java.ioexception ؛ import ex02.pyrmont.request ؛ ex02.pyrmont.StaticResourceProcessor ؛ فئة عامة httpserver1 {// Close Service Command Private Static String string knowdown_command = "/stakdown" ؛ public static void main (string [] args) {httpserver1 server = new httpserver1 () ؛ // في انتظار طلب الاتصال server.await () ؛ } public void await () {serversocket serversite = null ؛ INT PORT = 8080 ؛ TREE {// Server Socket Object ServerSocket = New ServersOcket (المنفذ ، 1 ، inetaddress.getByName ("127.0.0.1")) ؛ } catch (ioException e) {E.PrintStackTrace () ؛ System.exit (1) ؛ } // loop لانتظار الطلب بينما (صحيح) {Socket Socket = null ؛ إدخال inputStream = فارغ ؛ OutputStream Output = null ؛ جرب {// انتظر الاتصال ، بعد أن يكون الاتصال ناجحًا ، قم بإرجاع مقبس كائن المقبس = serversocket.accept () ؛ الإدخال = socket.getInputStream () ؛ الإخراج = socket.getOutputStream () ؛ // إنشاء طلب طلب طلب وطلب تحليل = طلب جديد (إدخال) ؛ request.parse () ؛ // } // إنشاء استجابة استجابة كائن استجابة = استجابة جديدة (الإخراج) ؛ استجابة. if (request.geturi (). startswith ("/servlet/")) {// request يبدأ URI باستخدام/servlet/، مما يشير إلى أن Servlet request ServleTprocessor1 Processor = new ServleTprocessor1 () ؛ المعالج. عملية (طلب ، استجابة) ؛ } آخر {// Static ResourcerSourceProcessor Processor = New StaticResourceProcessor () ؛ المعالج. عملية (طلب ، استجابة) ؛ } // إغلاق socket.close () ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ System.exit (1) ؛ }}}}فئة ثابتة:
حزمة ex02.pyrmont ؛ استيراد java.io.file ؛ ثوابت الفئة العامة {public static final string web_root = system.getProperty ("user.dir") + file.separator + "webroot" ؛ السلسلة النهائية الثابتة العامة web_servlet_root = system.getProperty ("user.dir") + file.separator + "target" + file.separator + "classes" ؛ }طلب:
package ex02.pyrmont ؛ import java.io.inputstream ؛ import java.io.ioException ؛ import java.io.bufferedreader ؛ import java.io.unsupportedencodingexception ؛ import java.util.enumeration javax.servlet.requestDispatcher ؛ استيراد javax.servlet.servletinputStream ؛ استيراد javax.servlet.servletrequest ؛ طلب الفئة العامة ينفذ servletrequest سلسلة خاصة أوري ؛ طلب عام (إدخال inputStream) {this.input = input ؛ } السلسلة العامة geturi () {return uri ؛ } /** * * شكل requestString كما يلي: * get /index.html http /1.1 * المضيف: localhost: 8080 * الاتصال: keep-alive * cache-control: max-mage = 0 * ... index1 = requestString.indexof ('') ؛ if (index1! = -1) {index2 = requestString.indexof ('' ، index1 + 1) ؛ if (index2> index1) return requestString.SubString (index1 + 1 ، index2) ؛ } إرجاع فارغ ؛ } // اقرأ مجموعة من الأحرف من طلب Socket StringBuffer = جديد StringBuffer (2048) ؛ int أنا ؛ Byte [] Buffer = New Byte [2048] ؛ حاول {i = input.Read (buffer) ؛ } catch (ioException e) {E.PrintStackTrace () ؛ i = -1 ؛ } لـ (int j = 0 ؛ j <i ؛ j ++) {request.append ((char) buffer [j]) ؛ } system.out.print (request.toString ()) ؛ uri = parseuri (request.toString ()) ؛ } / * تنفيذ servletRequest * / الكائن العام getAttribute (سمة السلسلة) {return null ؛ } التعداد العام <؟> getAttributenames () {return null ؛ } السلسلة العامة getRealPath (مسار السلسلة) {return null ؛ } requestDispatcher getRequestDispatcher (مسار السلسلة) {return null ؛ } issecure issecure () {return false ؛ } السلسلة العامة getCharacterEncoding () {return null ؛ } public int getContentLength () {return 0 ؛ } السلسلة العامة getContentType () {return null ؛ } public servleTinputStream getInputStream () يلقي ioException {return null ؛ } locale getlocale () {return null ؛ } التعداد العام <؟> getLocales () {return null ؛ } السلسلة العامة getParameter (اسم السلسلة) {return null ؛ } الخريطة العامة <؟ ،؟> getParameterMap () {return null ؛ } التعداد العام <؟> getParameterNames () {return null ؛ } السلسلة العامة [] getParAmetervalues (المعلمة سلسلة) {return null ؛ } السلسلة العامة getProtocol () {return null ؛ } Public BufferedReader GetReader () يلقي ioException {return null ؛ } السلسلة العامة getRemoteadDr () {return null ؛ } السلسلة العامة getRemoteHost () {return null ؛ } السلسلة العامة getCheme () {return null ؛ } سلسلة عامة getServerName () {return null ؛ } public int getServerPort () {return 0 ؛ } public void removeAttribute (سمة السلسلة) {} public void setAttribute (مفتاح السلسلة ، قيمة الكائن) {} public void setcharacterencoding (string charsing) يلقي UnsupportedEncodingException {}}إجابة:
حزمة ex02.pyrmont ؛ استيراد java.io.outputstream ؛ استيراد java.io.ioException ؛ استيراد java.io.fileInputStream ؛ استيراد java.io.filenotfound javax.servlet.servletoutputstream ؛ استجابة الفئة العامة تنفذ servletResponse {private static final buffer_size = 1024 ؛ طلب طلب ؛ إخراج الإخراج كاتب printwriter الاستجابة العامة (إخراج outputStream) {this.output = الإخراج ؛ } public void setRequest (طلب طلب) {this.request = request ؛ } // اكتب ملف الويب في Stream Byte Stream public sendStaticResource () يلقي ioException {byte [] bytes = new byte [buffer_size] ؛ FileInputStream Fis = NULL ؛ TREE { / * request.geturi تم استبداله بـ request.getRequesturi * / file file = ملف جديد (constants.web_root ، request.geturi ()) ؛ FIS = جديد fileInputStream (ملف) ؛ / * * http response = status-line ((General-Header | Response-Header | * * Entity-Header) crlf) crlf [message-body] status-line = * http-version sp status-code sprase-rase crlf */ int ch = fis.read (bytes ، 0 ، buffer_size) ؛ بينما (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" + "نوع المحتوى: text/html/r/n" + "طول المحتوى: 23/r/n" + "/r/n" + "<h1> ملف </h1>" ؛ output.write (errormessage.getBytes ()) ؛ } أخيرًا {if (fis! = null) fis.close () ؛ }} / ** تنفيذ servletResponse* / public void flushbuffer () يلقي ioException {} public int getBuffersize () {return 0 ؛ } السلسلة العامة getCharacterEncoding () {return null ؛ } locale getlocale () {return null ؛ } public ServleToutPutStream getOutputStream () يلقي ioException {return null ؛ } printwriter publicwriter getWriter () يلقي ioException {// autoflush صحيح ، سوف println () سوف يتدفق ، // print () لن. الكاتب = New PrintWriter (الإخراج ، صحيح) ؛ كاتب العودة ) } public void reset () {} public void resetBuffer () {} public void setBuffersize (int size) {} public void setContentLength (int length) {} public void setContentType (نوع سلسلة) {}معالجة طلب الموارد الثابت:
حزمة ex02.pyrmont ؛ استيراد java.io.ioException ؛ الطبقة العامة staticResourceProcessor {public void process (طلب طلب ، استجابة الاستجابة) {try {response.SendStaticResource () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}}معالجة طلب Servlet:
حزمة ex02.pyrmont.first ؛ استيراد java.net.url ؛ استيراد java.net.urlclassloader ؛ استيراد java.net.urlstreamhandler ؛ استيراد java.io.ioException ؛ استيراد javax.servlet.servlet ex02.pyrmont.constants ؛ استيراد ex02.pyrmont.request ؛ استيراد ex02.pyrmont.response ؛ الطبقة العامة servletprocessor1 {public void process (طلب طلب ، استجابة الاستجابة) {String uri = request.geturi () ؛ String servletName = uri.substring (uri.lastindexof ("/") + 1) ؛ // classloader ، يستخدم لتحميل urlClassloader من فئة من ملف جرة محدد أو محمل دليل = null ؛ حاول {urlstreamhandler streamHandler = null ؛ // إنشاء تحميل فئة loader = جديد urlClassLoader (URL جديد [] {url new (null ، "file:" + constants.web_servlet_root ، StreamHandler)}) ؛ } catch (ioException e) {system.out.println (e.ToString ()) ؛ } class <؟> myClass = null ؛ حاول {// تحميل فئة servlet المقابلة myClass = loader.loadClass (servletName) ؛ } catch (classnotfoundException e) {system.out.println (e.toString ()) ؛ } servlet servlet = null ؛ جرب {// إنتاج مثيل servlet servlet = (servlet) myclass.newinstance () ؛ . } catch (استثناء e) {system.out.println (e.toString ()) ؛ } catch (throwable e) {system.out.println (e.ToString ()) ؛ }}}فئة Servlet:
استيراد javax.servlet.*؛ استيراد java.io.ioException ؛ استيراد java.io.printwriter ؛ Public Class Primitiveserflet servlet {public void init (servletconfig config) يلقي servletexception {system.out.println ("init") ؛ } خدمة void العامة (طلب servletRequest ، استجابة servletResponse) يلقي servleTexception ، ioException {system.out.println ("من الخدمة") ؛ printWriter out = response.getWriter () ؛ Out.println ("مرحبًا. الورود حمراء.") ؛ out.print ("البنفسجي أزرق.") ؛ } public void destroy () {system.out.println ( } السلسلة العامة getServleTinfo () {return null ؛ } public servletconfig getServletConfig () {return null ؛ }} اختبار النتائج:
طلب الموارد الثابت:
طلب Servlet (لأنها مجرد السلسلة الأولى التي يتم تحديثها للمستعرض ، لا يمكنك رؤية السلسلة الثانية البنفسجي الأزرق. سنقوم بتحسين الحاوية لاحقًا):
يحسن
حاوية servlet التي تم تنفيذها في وقت سابق لديها مشكلة خطيرة. في Servlet ، يمكن للمستخدم تحويل ServleTRequest و ServletResponse مباشرة إلى أنواع الطلب والاستجابة ، والاتصال مباشرة بأساليبه العامة الداخلية. هذا تصميم سيء. تتمثل طريقة التحسين في إضافة فئات المظهر لطلب الاستجابة والاستجابة ، بحيث يمكن للمستخدمين الوصول إلى الأساليب العامة المحددة في فئة المظهر فقط.
طلب فئة المظهر
حزمة ex02.pyrmont.second ؛ استيراد java.io.ioException ؛ استيراد java.io.bufferedReader ؛ استيراد java.io.unsupportedencodingexception ؛ import java.util.enum. javax.servlet.servletinputstream ؛ استيراد javax.servlet.servletrequest ؛ استيراد ex02.pyrmont.request ؛ requestfacade public requestfacade servletrequest {private servletrequest request = null ؛ requestFacade (طلب طلب) {this.request = request ؛ } / * تنفيذ servletRequest * / الكائن العام getAttribute (سمة السلسلة) {return request.getAttribute (السمة) ؛ } التعداد العام <؟> getAttributenames () {return request.getAttributEnames () ؛ } suppresswarnings ("deprecation") السلسلة العامة getRealPath (مسار السلسلة) {return request.getRealPath (path) ؛ } requestDispatcher getRequestDispatcher (مسار السلسلة) {return request.getRequestDispatcher (path) ؛ } boolean public issecure () {return request.issecure () ؛ } السلسلة العامة getCharacterEncoding () {return request.getCharCterEncoding () ؛ } public int getContentLength () {return request.getContentLength () ؛ } السلسلة العامة getContentType () {return request.getContentType () ؛ } public servleTinputStream getInputStream () يلقي ioException {return request.getInputStream () ؛ } public locale getLocale () {return request.getLocale () ؛ } التعداد العام <؟> getLocales () {return request.getLocales () ؛ } السلسلة العامة getParameter (اسم السلسلة) {return request.getParameter (name) ؛ } الخريطة العامة <؟ } التعداد العام <؟> getParameterNames () {return request.getParameterNames () ؛ } السلسلة العامة [] getParamEtervalues (المعلمة سلسلة) {return request.getParamEtervalues (المعلمة) ؛ } السلسلة العامة getProtocol () {return request.getProtocol () ؛ } public BufferedReader GetReader () يلقي ioException {return request.getReader () ؛ } السلسلة العامة getRemoteadDr () {return request.getRemoteadDr () ؛ } السلسلة العامة getRemoteHost () {return request.getRemoteHost () ؛ } السلسلة العامة getCheme () {return request.getScheme () ؛ } السلسلة العامة getServerName () {return request.getServerName () ؛ } public int getServerPort () {return request.getServerPort () ؛ } public void removeAttribute (string attribute) {request.RemoVeatTribute (السمة) ؛ } public void setAttribute (مفتاح السلسلة ، قيمة الكائن) {request.setAttribute (المفتاح ، القيمة) ؛ } public void setcharcterencoding (ترميز السلسلة) يلقي UnduportedEncodingException {request.setcharacterencoding (الترميز) ؛ }} فئة مظهر الاستجابة
package ex02.pyrmont.second ؛ استيراد java.io.ioException ؛ استيراد java.io.printwriter ؛ استيراد java.util.locale ؛ استيراد javax.servlet.servletresponse ؛ repressing javax.servlet.servletuttream ؛ expront.pyront.response. استجابة عامة (استجابة الاستجابة) {this.response = الاستجابة ؛ } public void flushbuffer () يلقي ioException {reponse.flushbuffer () ؛ } public int getBufferSize () {return reponse.getBuffersize () ؛ } السلسلة العامة getCharacterEncoding () {return response.getCharCterEncoding () ؛ } public locale getLocale () {return reponse.getLocale () ؛ } public servleToutPutStream getOutputStream () يلقي ioException {return reponse.getOutputStream () ؛ } printwriter public getWriter () يلقي ioException {return response.getWriter () ؛ ) } public void reset () {response.Reset () ؛ } public void resetBuffer () {response.ResetBuffer () ؛ } public void setBuffersize (int size) {reponse.setBuffersize (size) ؛ } public void resetBuffersize (size) ؛ } إعادة صياغة الفراغ العام (حجم int) ؛ } public void setBuffersize (size) ؛ } public void setContEntLength (int length) {response.setContentLength (length) ؛ } public void setContentType (نوع السلسلة) {response.setContentType (type) ؛ } public void setlocale (locale locale) {response.setLocale (locale) ؛ }}معالجة فئة طلب servlet:
حزمة ex02.pyrmont.second ؛ استيراد java.net.url ؛ استيراد java.net.urlclassloader ؛ استيراد java.net.urlstreamhandler ؛ استيراد java.io.ioException ؛ استيراد javax.servlet.servlet ex02.pyrmont.constants ؛ استيراد ex02.pyrmont.request ؛ استيراد ex02.pyrmont.response ؛ فئة عامة servletprocessor2 {public void process (طلب طلب ، استجابة الاستجابة) {String uri = request.geturi () ؛ String servletName = uri.substring (uri.lastindexof ("/") + 1) ؛ // class loader ، يستخدم لتحميل urlClassloader فئة من ملف جرة محدد أو محمل دليل = null ؛ حاول {urlstreamhandler streamHandler = null ؛ // إنشاء تحميل فئة loader = جديد urlClassLoader (URL جديد [] {url new (null ، "file:" + constants.web_servlet_root ، StreamHandler)}) ؛ } catch (ioException e) {system.out.println (e.ToString ()) ؛ } class <؟> myClass = null ؛ حاول {// تحميل فئة servlet المقابلة myClass = loader.loadClass (servletName) ؛ } catch (classnotfoundException e) {system.out.println (e.toString ()) ؛ } servlet servlet = null ؛ // أضف فئات المظهر لطلب واستجابة ، ويتم إعطاء اعتبارات الأمان لمنع المستخدمين من تحويل ServleTrequest و ServletResponse مباشرة إلى أنواع الطلب والاستجابة في servlets ، // واتصال أساليبهم العامة الداخلية بشكل مباشر ، لأنه لن يكون هناك حاجز ، sendStaticResource وطرق أخرى في requestfacade و reponsefacade ؛ requestFacade requestFacade = new requestFacade (request) ؛ استجابة Facade Responsefacade = استجابة جديدة (استجابة) ؛ حاول {servlet = (servlet) myclass.newinstance () ؛ servlet.service ((servletRequest) requestFacade ، (servletResponse) ResponseFacade) ؛ } catch (استثناء e) {system.out.println (e.toString ()) ؛ } catch (throwable e) {system.out.println (e.ToString ()) ؛ }}} الرموز الأخرى هي في الأساس نفس حاوية servlet التي تم تنفيذها في وقت سابق.
يطلب برنامج التحقق من الموارد الثابتة و servlets على التوالي ، ويجد أن النتائج تتفق مع الحاوية المنفذة سابقًا ؛
المرجع: "تحليل متعمق لـ Tomcat"
Author مشفر يشبه الرياح
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.