ในบทความก่อนหน้านี้ฉันเขียนการใช้งานเว็บเซิร์ฟเวอร์ Java อย่างง่ายซึ่งสามารถจัดการกับคำขอทรัพยากรแบบคงที่เท่านั้น คอนเทนเนอร์ servlet ที่ใช้ในบทความนี้ได้รับการแก้ไขเล็กน้อยตามเซิร์ฟเวอร์ก่อนหน้านี้เพิ่มการประมวลผลคำขอ servlet
ขั้นตอนการดำเนินการโปรแกรม
1. สร้างวัตถุ Serversocket;
2. เรียกวิธีการยอมรับของวัตถุ Serversocket และรอการเชื่อมต่อ หากการเชื่อมต่อสำเร็จวัตถุซ็อกเก็ตจะถูกส่งคืนมิฉะนั้นจะถูกบล็อกและรอ
3. รับกระแสไบต์อินพุทสตรีมและเอาท์พุทสตรีมจากวัตถุซ็อกเก็ตและสตรีมทั้งสองนี้สอดคล้องกับคำขอคำขอและการตอบสนองการตอบสนองตามลำดับ
4. ประมวลผลคำขอ: อ่านข้อมูลสตรีมไบต์อินพุทสตรีมแปลงเป็นรูปแบบสตริงและแยกวิเคราะห์ การแยกวิเคราะห์ที่นี่ค่อนข้างง่ายและได้รับข้อมูล URI (ตัวระบุทรัพยากรที่เหมือนกัน) เท่านั้น
5. ประมวลผลการตอบกลับ (ในสองประเภทการตอบสนองการร้องขอทรัพยากรแบบสแตติกหรือการตอบสนองการร้องขอเซิร์ฟเล็ต): หากเป็นคำขอทรัพยากรแบบคงที่ตามข้อมูล URI ที่แยกวิเคราะห์ให้ค้นหาไฟล์ทรัพยากรทรัพยากรที่ร้องขอจากไดเรกทอรี Web_root อ่านไฟล์ทรัพยากรและเขียนลงในกระแสไบต์ หากเป็นคำขอ servlet ให้สร้างตัวโหลดคลาส URLCLASSLOADER ก่อนอื่นให้โหลดคลาส Servlet ที่ร้องขอสร้างวัตถุ Servlet และดำเนินการวิธีการบริการ (เขียนข้อมูลการตอบกลับไปยัง OutputStream);
6. ปิดวัตถุซ็อกเก็ต;
7. ไปที่ขั้นตอนที่ 2 และรอคำขอการเชื่อมต่อต่อไป
การใช้รหัส:
เพิ่มการพึ่งพา:
<!-https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <pendency> <merdency> <roupid> javax.servlet </groupId> <ratifactid> servlet-api </artifactid>
รหัสเซิร์ฟเวอร์:
แพ็คเกจ ex02.pyrmont.first; นำเข้า java.net.socket; นำเข้า java.net.serversocket; นำเข้า java.net.inetaddress; นำเข้า java.io.inputstream; นำเข้า java.io.OutputStream; นำเข้า java.ioException; ex02.pyrmont.staticResourceProcessor; คลาสสาธารณะ httpserver1 {// ปิดคำสั่งบริการส่วนตัวสตริงสุดท้ายคงที่ shutdown_command = "/shutdown"; โมฆะคงที่สาธารณะหลัก (สตริง [] args) {httpserver1 เซิร์ฟเวอร์ = ใหม่ httpserver1 (); // รอเซิร์ฟเวอร์คำขอเชื่อมต่อ Await (); } โมฆะสาธารณะรอ () {Serversocket Serversocket = null; พอร์ต int = 8080; ลอง {// Server Socket Object Serversocket = New Serversocket (พอร์ต, 1, InetAddress.getByName ("127.0.0.1")); } catch (ioexception e) {e.printstacktrace (); System.Exit (1); } // loop เพื่อรอคำขอในขณะที่ (จริง) {ซ็อกเก็ตซ็อกเก็ต = null; อินพุตสตรีมอินพุต = null; เอาท์พุทเอาท์พุท = null; ลอง {// รอการเชื่อมต่อหลังจากการเชื่อมต่อสำเร็จแล้วให้ส่งคืนซ็อกเก็ตซ็อกเก็ตซ็อกเก็ต = serversocket.accept (); input = socket.getInputStream (); เอาต์พุต = socket.getOutputStream (); // สร้างคำขอวัตถุคำขอและการร้องขอการแยกวิเคราะห์ = คำขอใหม่ (อินพุต); request.parse (); // ตรวจสอบว่าเป็นคำสั่งบริการปิดระบบถ้า (request.geturi (). เท่ากับ (shutdown_command)) {break; } // สร้างการตอบสนองการตอบสนองของวัตถุ = การตอบกลับใหม่ (เอาต์พุต); Response.SetRequest (คำขอ); if (request.geturi (). startswith ("/servlet/")) {// request uri เริ่มต้นด้วย/servlet/ระบุว่าคำขอ servlet servletprocessor1 โปรเซสเซอร์ = ใหม่ servletProcessor1 (); processor.process (คำขอ, การตอบกลับ); } else {// โปรเซสเซอร์ ResourceresourceProcessor แบบคงที่ = ใหม่ staticResourceProcessor (); processor.process (คำขอ, การตอบกลับ); } // ปิดซ็อกเก็ตซ็อกเก็ต close (); } catch (exception e) {e.printstacktrace (); System.Exit (1); -ชั้นเรียนคงที่:
แพ็คเกจ ex02.pyrmont; นำเข้า java.io.file; ค่าคงที่คลาสสาธารณะ {สตริงสุดท้ายคงที่ web_root = system.getProperty ("user.dir") + file.Sparator + "webroot"; สตริงสุดท้ายคงที่ public web_servlet_root = system.getProperty ("user.dir") + file.Saperator + "เป้าหมาย" + file.Separator + "คลาส"; -ขอ:
แพ็คเกจ ex02.pyrmont; นำเข้า java.io.inputstream; นำเข้า java.io.ioexception; นำเข้า java.io.bufferedreader; นำเข้า java.io.unsupportencodexception; นำเข้า java.util.enumeration; javax.servlet.servletInputStream; นำเข้า Javax.servlet.servletRequest; คำขอคลาสสาธารณะใช้ servletRequest {อินพุตอินพุตส่วนตัว; uri สตริงส่วนตัว; คำขอสาธารณะ (อินพุตอินพุตอินพุต) {this.input = input; } สตริงสาธารณะ geturi () {return uri; } /** * * รูปแบบของการร้องขอมีดังนี้: * get /index.html http /1.1 * โฮสต์: localhost: 8080 * การเชื่อมต่อ: Keep-alive * cache-control: max-age = 0 * ... * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * index1 = requestString.indexof (''); if (index1! = -1) {index2 = requestString.indexof ('', index1 + 1); if (index2> index1) return requeststring.substring (index1 + 1, index2); } return null; } // อ่านชุดอักขระจาก Socket StringBuffer Request = New StringBuffer (2048); int i; ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [2048]; ลอง {i = input.read (บัฟเฟอร์); } 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 * / วัตถุสาธารณะ getAtattribute (แอตทริบิวต์สตริง) {return null; } การแจงนับสาธารณะ <?> getAttributeNames () {return null; } สตริงสาธารณะ getRealPath (เส้นทางสตริง) {return null; } Public RequestDispatcher getRequestDispatcher (เส้นทางสตริง) {return null; } Public Boolean Issecure () {return false; } สตริงสาธารณะ getCharacterencoding () {return null; } สาธารณะ int getContentLength () {return 0; } สตริงสาธารณะ getContentType () {return null; } สาธารณะ servletInputStream getInputStream () พ่น IOException {return null; } สถานที่สาธารณะ 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; } สตริงสาธารณะ getScheme () {return null; } สตริงสาธารณะ getServerName () {return null; } สาธารณะ int getServerport () {return 0; } โมฆะสาธารณะ removeAttribute (แอตทริบิวต์สตริง) {} โมฆะสาธารณะ setAttribute (คีย์สตริง, ค่าวัตถุ) {} โมฆะสาธารณะ setCharacterencoding (การเข้ารหัสสตริง) โยน unsupportencodingexception {}}}}}การตอบสนอง:
แพ็คเกจ ex02.pyrmont; นำเข้า java.io.OutputStream; นำเข้า java.io.ioException; นำเข้า Java.io.fileinputStream; นำเข้า Java.io.filenotfoundException; นำเข้า java.io.file; นำเข้า Java.io.printwriter; javax.servlet.servletoutputStream; การตอบสนองระดับสาธารณะใช้ servletResponse {ส่วนตัวคงที่ int buffer_size = 1024; คำขอคำขอ; เอาต์พุตเอาท์พุทสตรีม; นักเขียน Printwriter; การตอบสนองสาธารณะ (เอาต์พุตเอาท์พุทสตรีม) {this.output = เอาต์พุต; } โมฆะสาธารณะ setRequest (คำขอคำขอ) {this.request = คำขอ; } // เขียนไฟล์เว็บลงใน OutputStream BYTE MOID สาธารณะ SendStaticResource () พ่น IOException {byte [] bytes = byte ใหม่ [buffer_size]; FileInputStream FIS = NULL; ลอง { / * request.geturi ถูกแทนที่ด้วย request.getRequesturi * / ไฟล์ไฟล์ = ไฟล์ใหม่ (ค่าคงที่ web_root, request.geturi ()); FIS = ใหม่ FileInputStream (ไฟล์); / * * http response = status-line ((General-Header | Response-Header | * Entity-Header) Crlf) CRLF [ข้อความ-ร่างกาย] สถานะ-บรรทัด = * http-version sp สถานะรหัส SP วลี crlf */ int ch = fis.read (bytes, 0, buffer_size); ในขณะที่ (ch! = -1) {output.write (ไบต์, 0, ch); ch = fis.read (ไบต์, 0, buffer_size); }} catch (filenotfoundexception e) {string errorMessage = "http/1.1 404 ไฟล์ไม่พบ/r/n" + "ประเภทเนื้อหา: ข้อความ/html/r/n" + "ความยาวเนื้อหา: 23/r/n" + "/n" + "<h1> ไฟล์ไม่พบ </h1>";; output.write (errorMessage.getBytes ()); } ในที่สุด {ถ้า (fis! = null) fis.close (); }} / ** การใช้งานของ servletResponse* / โมฆะสาธารณะ flushbuffer () พ่น ioexception {} public int getBuffersize () {return 0; } สตริงสาธารณะ getCharacterencoding () {return null; } สถานที่สาธารณะ getLocale () {return null; } สาธารณะ servletOutputStream getOutputStream () พ่น IOException {return null; } Public PrintWriter getWriter () พ่น IOException {// autoflush เป็นจริง println () จะล้าง // แต่ print () จะไม่ Writer = New PrintWriter (เอาท์พุทจริง); นักเขียนกลับ; } บูลีนสาธารณะ isCommitted () {return false; } โมฆะสาธารณะรีเซ็ต () {} โมฆะสาธารณะรีเซ็ตบัฟเฟอร์ () {} โมฆะสาธารณะ setBuffersize (ขนาด int) {} โมฆะสาธารณะ setContentLength (ความยาว int) {} โมฆะสาธารณะ setContentType (ประเภทสตริง) {} void setLocale สาธารณะการประมวลผลคำขอทรัพยากรแบบคงที่:
แพ็คเกจ ex02.pyrmont; นำเข้า java.io.ioException; คลาสสาธารณะ StaticResourceProcessor {กระบวนการโมฆะสาธารณะ (คำขอคำขอ, การตอบสนองการตอบสนอง) {ลอง {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 {กระบวนการโมฆะสาธารณะ (คำขอคำขอตอบสนอง) {String uri = request.geturi (); String servletName = uri.substring (uri.lastindexof ("/") + 1); // classloader ใช้ในการโหลดคลาส urlclassloader จากไฟล์ JAR ที่ระบุหรือไดเรกทอรีโหลดเดอร์ = null; ลอง {urlstreamhandler streamhandler = null; // สร้างคลาส loader class = urlclassloader ใหม่ (url ใหม่ [] {url ใหม่ (null, "ไฟล์:" + constants.web_servlet_root, streamhandler)}); } catch (ioexception e) {system.out.println (e.toString ()); } คลาส <?> myclass = null; ลอง {// โหลดคลาส servlet ที่สอดคล้องกัน myclass = loader.loadclass (servletName); } catch (classnotFoundException e) {system.out.println (e.toString ()); } servlet servlet = null; ลอง {// ผลิตอินสแตนซ์ servlet servlet = (servlet) myclass.newinstance (); // ดำเนินการวิธีการบริการของ ervlet servlet.service ((servletrequest) คำขอ, (servletResponse) การตอบสนอง); } catch (exception e) {system.out.println (e.toString ()); } catch (throwable e) {system.out.println (e.toString ()); -คลาสเซิร์ฟเล็ต:
นำเข้า javax.servlet.*; นำเข้า Java.io.ioException; นำเข้า Java.io.printwriter; คลาสสาธารณะ Primitiveservlet ใช้ servlet {โมฆะสาธารณะเริ่มต้น } บริการโมฆะสาธารณะ (คำขอ ServletRequest, การตอบสนอง servletResponse) พ่น servletexception, ioexception {system.out.println ("จากบริการ"); PrintWriter out = response.getWriter (); out.println ("สวัสดีดอกกุหลาบเป็นสีแดง"); out.print ("ไวโอเล็ตเป็นสีน้ำเงิน"); } โมฆะสาธารณะทำลาย () {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.unsupportencodingexception; นำเข้า Java.util.enumeration; นำเข้า Java.util.locale javax.servlet.servletInputStream; นำเข้า Javax.servlet.servletRequest นำเข้า ex02.pyrmont.request; การร้องขอระดับสาธารณะ Public RequestFacade (คำขอคำขอ) {this.request = คำขอ; } / * การใช้งานของ ServletRequest * / วัตถุสาธารณะ getAttribute (แอตทริบิวต์สตริง) {return request.getAttribute (แอตทริบิวต์); } การแจงนับสาธารณะ <?> getAttributeNames () {return request.getattributenames (); } @suppresswarnings ("การเสื่อมสภาพ") สตริงสาธารณะ getRealPath (เส้นทางสตริง) {return request.getRealPath (เส้นทาง); } Public RequestDispatcher GetRequestDispatcher (เส้นทางสตริง) {return request.getRequestDispatcher (เส้นทาง); } Public Boolean Issecure () {return request.issecure (); } Public String getCharacterencoding () {return request.getCharacterencoding (); } public int getContentLength () {return regurt.getContentLength (); } สตริงสาธารณะ getContentType () {return request.getContentType (); } สาธารณะ servletInputStream getInputStream () พ่น IOException {return request.getInputStream (); } สถานที่สาธารณะ locale getLocale () {return regurt.getLocale (); } การแจงนับสาธารณะ <?> getLocales () {return request.getLocales (); } สตริงสาธารณะ getParameter (ชื่อสตริง) {return request.getParameter (ชื่อ); } แผนที่สาธารณะ <?,?> getParameterMap () {return request.getParameterMap (); } การแจงนับสาธารณะ <?> getParameterNames () {return request.getParameterNames (); } สตริงสาธารณะ [] getParameterValues (พารามิเตอร์สตริง) {return request.getParameterValues (พารามิเตอร์); } public String getProtocol () {return request.getProtocol (); } Public BufferedReader GetReader () พ่น IOException {return request.getReader (); } Public String getRemoteaddr () {return request.getRemoteaddr (); } สตริงสาธารณะ getRemoteHost () {return request.getRemoteHost (); } Public String getScheme () {return regurt.getScheme (); } สตริงสาธารณะ getServerName () {return regurt.getServerName (); } public int getServerport () {return regurt.getServerport (); } โมฆะสาธารณะ RemoveAttribute (แอตทริบิวต์สตริง) {request.RemoveAttribute (แอตทริบิวต์); } โมฆะสาธารณะ setAttribute (คีย์สตริง, ค่าวัตถุ) {request.setAttribute (คีย์, ค่า); } โมฆะสาธารณะ setCharacterencoding (การเข้ารหัสสตริง) โยน unsupportencodingException {request.Setcharacterencoding (การเข้ารหัส); - คลาสการตอบสนอง
แพ็คเกจ ex02.pyrmont.second; นำเข้า java.io.ioexception; นำเข้า java.io.printwriter; นำเข้า java.util.locale; นำเข้า Javax.servlet.ServletResponse; นำเข้า javax.servlet.servletutputtream; การตอบสนอง; Public ResponseFacade (การตอบสนองการตอบสนอง) {this.Response = การตอบสนอง; } โมฆะสาธารณะ flushbuffer () พ่น IOException {response.flushbuffer (); } สาธารณะ int getBuffersize () {return response.getBuffersize (); } สตริงสาธารณะ getCharacterencoding () {return response.getCharacterencoding (); } สถานที่สาธารณะ getLocale () {return response.getLocale (); } สาธารณะ servletOutputStream getOutputStream () พ่น IOException {return response.getOutputStream (); } Public PrintWriter getWriter () พ่น IOException {return response.getWriter (); } บูลีนสาธารณะ isCommitted () {return response.iscommitted (); } โมฆะสาธารณะรีเซ็ต () {response.reset (); } โมฆะสาธารณะ RESETBUFFER () {Response.ResetBuffer (); } โมฆะสาธารณะ setBuffersize (ขนาด int) {response.setBuffersize (ขนาด); } โมฆะสาธารณะ resetBuffersize (ขนาด); } โมฆะสาธารณะ resetBuffersize (ขนาด int); } โมฆะสาธารณะ setBuffersize (ขนาด); } โมฆะสาธารณะ setContentLength (ความยาว int) {response.setContentLength (ความยาว); } โมฆะสาธารณะ setContentType (ประเภทสตริง) {response.setContentType (ประเภท); } โมฆะสาธารณะ 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 {กระบวนการโมฆะสาธารณะ (คำขอคำขอตอบสนอง) {String uri = request.geturi (); String servletName = uri.substring (uri.lastindexof ("/") + 1); // คลาสโหลดเดอร์ใช้ในการโหลดคลาส urlclassloader จากไฟล์ JAR ที่ระบุหรือไดเรกทอรีโหลดเดอร์ = null; ลอง {urlstreamhandler streamhandler = null; // สร้างคลาส loader class = urlclassloader ใหม่ (url ใหม่ [] {url ใหม่ (null, "ไฟล์:" + constants.web_servlet_root, streamhandler)}); } catch (ioexception e) {system.out.println (e.toString ()); } คลาส <?> myclass = null; ลอง {// โหลดคลาส servlet ที่สอดคล้องกัน myclass = loader.loadclass (servletName); } catch (classnotFoundException e) {system.out.println (e.toString ()); } servlet servlet = null; // เพิ่มคลาสลักษณะที่ปรากฏในการร้องขอและการตอบสนองและมีการพิจารณาความปลอดภัยเพื่อป้องกันไม่ให้ผู้ใช้เปลี่ยน ServletRequest และ servletResponse โดยตรงไปยังประเภทการร้องขอและการตอบสนองใน Servlets // และเรียกวิธีการสาธารณะภายในโดยตรงเพราะจะไม่มีการแยกวิเคราะห์ SendStaticResource และวิธีการอื่น ๆ requestfacade requestfacade = new RequestFacade (คำขอ); ResponseFacade ResponseFacade = new ResponseFacade (การตอบสนอง); ลอง {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 ()); - รหัสอื่น ๆ นั้นเหมือนกันกับคอนเทนเนอร์ servlet ที่ใช้งานก่อนหน้านี้
โปรแกรมการตรวจสอบร้องขอทรัพยากรแบบคงที่และ Servlets ตามลำดับและพบว่าผลลัพธ์นั้นสอดคล้องกับคอนเทนเนอร์ที่ดำเนินการก่อนหน้านี้
การอ้างอิง: "การวิเคราะห์เชิงลึกของ Tomcat"
@author ผู้เขียนแบบมีลมเหมือนลม
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น