摘要:項目結構項目結構如下實現細節創建對象首先創建自定義的請求類,其中定義與兩個屬性,表示請求的以及請求的方式。其構造函數需要傳入一個輸入流,該輸入流通過客戶端的套接字對象得到。創建服務端套接字,并綁定某個端口。
緣起
用了那么久tomcat,突然覺得自己對它或許并沒有想象中的那么熟悉,所以趁著放假我研究了一下這只小貓咪,實現了自己的小tomcat,寫出這篇文章同大家一起分享!
照例附上github鏈接。
項目結構如下:
首先創建自定義的請求類,其中定義url與method兩個屬性,表示請求的url以及請求的方式。
其構造函數需要傳入一個輸入流,該輸入流通過客戶端的套接字對象得到。
輸入流中的內容為瀏覽器傳入的http請求頭,格式如下:
GET /student HTTP/1.1 Host: localhost:8080 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: Hm_lvt_eaa22075ffedfde4dc734cdbc709273d=1549006558; _ga=GA1.1.777543965.1549006558
通過對以上內容的分割與截取,我們可以得到該請求的url以及請求的方式。
package tomcat.dome; import java.io.IOException; import java.io.InputStream; //實現自己的請求類 public class MyRequest { //請求的url private String url; //請求的方法類型 private String method; //構造函數 傳入一個輸入流 public MyRequest(InputStream inputStream) throws IOException { //用于存放http請求內容的容器 StringBuilder httpRequest=new StringBuilder(); //用于從輸入流中讀取數據的字節數組 byte[]httpRequestByte=new byte[1024]; int length=0; //將輸入流中的內容讀到字節數組中,并且對長度進行判斷 if((length=inputStream.read(httpRequestByte))>0) { //證明輸入流中有內容,則將字節數組添加到容器中 httpRequest.append(new String(httpRequestByte,0,length)); } //將容器中的內容打印出來 System.out.println("httpRequest = [ "+httpRequest+" ]"); //從httpRequest中獲取url,method存儲到myRequest中 String httpHead=httpRequest.toString().split(" ")[0]; url=httpHead.split("s")[1]; method=httpHead.split("s")[0]; System.out.println("MyRequests = [ "+this+" ]"); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } }
創建自定義的響應類,構造函數需要傳入由客戶端的套接字獲取的輸出流。
定義其write方法,像瀏覽器寫出一個響應頭,并且包含我們要寫出的內容content。
package tomcat.dome; import java.io.IOException; import java.io.OutputStream; //實現自己的響應類 public class MyResponse { //定義輸出流 private OutputStream outputStream; //構造函數 傳入輸出流 public MyResponse(OutputStream outputStream) { this.outputStream=outputStream; } //創建寫出方法 public void write(String content)throws IOException{ //用來存放要寫出數據的容器 StringBuffer stringBuffer=new StringBuffer(); stringBuffer.append("HTTP/1.1 200 OK ") .append("Content-type:text/html ") .append(" ") .append("Hello World ") .append(content) .append(""); //轉換成字節數組 并進行寫出 outputStream.write(stringBuffer.toString().getBytes()); //System.out.println("sss"); outputStream.close(); } }
由于我們自己寫一個Servlet的時候需要繼承HttpServlet,因此在這里首先定義了一個抽象類——MyServlet對象。
在其中定義了兩個需要子類實現的抽象方法doGet和doSet。
并且創建了一個service方法,通過對傳入的request對象的請求方式進行判斷,確定調用的是doGet方法或是doPost方法。
package tomcat.dome; //寫一個抽象類作為servlet的父類 public abstract class MyServlet { //需要子類實現的抽象方法 protected abstract void doGet(MyRequest request,MyResponse response); protected abstract void doPost(MyRequest request,MyResponse response); //父類自己的方法 //父類的service方法對傳入的request以及response //的方法類型進行判斷,由此調用doGet或doPost方法 public void service(MyRequest request,MyResponse response) throws NoSuchMethodException { if(request.getMethod().equalsIgnoreCase("POST")) { doPost(request, response); }else if(request.getMethod().equalsIgnoreCase("GET")) { doGet(request, response); }else { throw new NoSuchMethodException("not support"); } } }
這里我創建了兩個業務相關類:StudentServlet和TeacherServlet。
package tomcat.dome; import java.io.IOException; //實現自己業務相關的Servlet public class StudentServlet extends MyServlet{ @Override protected void doGet(MyRequest request, MyResponse response) { //利用response中的輸出流 寫出內容 try { //System.out.println("!!!!!!!!!!!!!!!!!!"); response.write("I am a student."); //System.out.println("9999999999999999"); }catch(IOException e) { e.printStackTrace(); } } @Override protected void doPost(MyRequest request, MyResponse response) { //利用response中的輸出流 寫出內容 try { response.write("I am a student."); }catch(IOException e) { e.printStackTrace(); } } }
package tomcat.dome; import java.io.IOException; //實現自己業務相關的Servlet public class TeacherServlet extends MyServlet{ @Override protected void doGet(MyRequest request, MyResponse response) { //利用response中的輸出流 寫出內容 try { response.write("I am a teacher."); }catch(IOException e) { e.printStackTrace(); } } @Override protected void doPost(MyRequest request, MyResponse response) { //利用response中的輸出流 寫出內容 try { response.write("I am a teacher."); }catch(IOException e) { e.printStackTrace(); } } }
該結構實現的是請求的url與具體的Servlet之間的關系映射。
package tomcat.dome; //請求url與項目中的servlet的映射關系 public class ServletMapping { //servlet的名字 private String servletName; //請求的url private String url; //servlet類 private String clazz; public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public ServletMapping(String servletName, String url, String clazz) { super(); this.servletName = servletName; this.url = url; this.clazz = clazz; } }
配置類中定義了一個列表,里面存儲著項目中的映射關系。
package tomcat.dome; import java.util.ArrayList; import java.util.List; //創建一個存儲有請求路徑與servlet的對應關系的 映射關系配置類 public class ServletMappingConfig { //使用一個list類型 里面存儲的是映射關系類Mapping public static ListservletMappings=new ArrayList<>(16); //向其中添加映射關系 static { servletMappings.add(new ServletMapping("student","/student", "tomcat.dome.StudentServlet")); servletMappings.add(new ServletMapping("teacher","/teacher", "tomcat.dome.TeacherServlet")); } }
在服務端MyTomcat中主要做了如下幾件事情:
1)初始化請求的映射關系。
2)創建服務端套接字,并綁定某個端口。
3)進入循環,用戶接受客戶端的鏈接。
4)通過客戶端套接字創建request與response對象。
5)根據request對象的請求方式調用相應的方法。
6)啟動MyTomcat!
package tomcat.dome; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; //Tomcat服務器類 編寫對請求做分發處理的相關邏輯 public class MyTomcat { //端口號 private int port=8080; //用于存放請求路徑與對應的servlet類的請求映射關系的map //相應的信息從配置類中獲取 private MapurlServletMap=new HashMap<>(16); //構造方法 public MyTomcat(int port) { this.port=port; } //tomcat服務器的啟動方法 public void start() { //初始化請求映射關系 initServletMapping(); //服務端的套接字 ServerSocket serverSocket=null; try { //創建綁定到某個端口的服務端套接字 serverSocket=new ServerSocket(port); System.out.println("MyTomcat begin start..."); //循環 用于接收客戶端 while(true) { //接收到的客戶端的套接字 Socket socket=serverSocket.accept(); //獲取客戶端的輸入輸出流 InputStream inputStream=socket.getInputStream(); OutputStream outputStream=socket.getOutputStream(); //通過輸入輸出流創建請求與響應對象 MyRequest request=new MyRequest(inputStream); MyResponse response=new MyResponse(outputStream); //根據請求對象的method分發請求 調用相應的方法 dispatch(request, response); //關閉客戶端套接字 socket.close(); } } catch (IOException e) { e.printStackTrace(); } } //初始化請求映射關系,相關信息從配置類中獲取 private void initServletMapping() { for(ServletMapping servletMapping:ServletMappingConfig.servletMappings) { urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz()); } } //通過當前的request以及response對象分發請求 private void dispatch(MyRequest request,MyResponse response) { //根據請求的url獲取對應的servlet類的string String clazz=urlServletMap.get(request.getUrl()); //System.out.println("====="+clazz); try { //通過類的string將其轉化為對象 Class servletClass=Class.forName("tomcat.dome.StudentServlet"); //實例化一個對象 MyServlet myServlet=(MyServlet)servletClass.newInstance(); //調用父類方法,根據request的method對調用方法進行判斷 //完成對myServlet中doGet與doPost方法的調用 myServlet.service(request, response); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } //main方法 直接啟動tomcat服務器 public static void main(String[] args) { new MyTomcat(8080).start(); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73638.html
摘要:算是心血來潮吧,想看看的源碼,順便學習一下。這里就簡單的做點記錄如何用跟蹤查看源碼。當然這里也提供書籍的源碼,可以下載下來對照書看。附上一張運行成功的結果圖 算是心血來潮吧,想看看 Tomcat 的源碼,順便學習一下。 這里就簡單的做點記錄--如何用 IDEA 跟蹤查看 Tomcat 源碼?! ⊥瑫r,這里也推薦下 how-tomcat-works 這本書,雖然書中講的是 tomc...
摘要:接下來我們要配置這個的端口,這樣他們才能運行時端口號不沖突。問題指明不同的端口號訪問也太蠢了吧的確很蠢,所以我們要慢慢過渡學習。接下來我們學習用來進行反向代理。阿里云的部分有一些配置的具體過程。 一、在linux上部署運行多個tomcat 1、以前的我們 雖然說是在linux上,但是windows上也是同樣的道理,只不過我們服務器都是選用linux罷了。 原先,自己有多個項目需要部署在...
閱讀 2562·2023-04-25 18:13
閱讀 770·2021-11-22 12:10
閱讀 2970·2021-11-22 11:57
閱讀 2138·2021-11-19 11:26
閱讀 2164·2021-09-22 15:40
閱讀 1460·2021-09-03 10:28
閱讀 2704·2019-08-30 15:53
閱讀 1950·2019-08-30 15:44