手寫Tomcat服務器


預備知識

編寫服務器用到的知識點

1) Socket 編程
2) HTML
3) HTTP 協議
4) 反射
5) XML 解析
6) 服務器編寫

Socket編程

https://www.cnblogs.com/bfcs/p/10790130.html

 

HTML知識

HTML:HyperText Markup Language 超文本標記語言用於描述網頁文檔的一種標記語言

表單(form):與用戶之間進行交互

  method:請求方式 get/post

     get 數據量小,安全性低,默認方式

     post 數據量大,安全性高
  action:請求的服務器路徑

  id :(用戶的的瀏覽器在文檔里區分唯一性)前端區分唯一性,js 中

  name:名稱,后端(服務器)區分唯一性,獲取值,只要提交數據給后台(服務器)必須存在 name

 1 <html>
 2     <head>
 3         <title>登陸界面</title>
 4     </head>
 5     <body>
 6         <form action="" method="post" >
 7             <p>用戶名:<input type="text" name="username" id="name"/></p>
 8             <p>密碼:<input type="password" name="password" id="pwd"/></p>
 9             <input type="submit" value="提交"/>
10         </form>
11     </body>
12 </html>
View Code

 

HTTP協議

協議

1) 應用層:HTTP、FTP、TELNET、SNMP、DNS
2) 傳輸層:TCP、UDP
3) 網絡層:IP

HTTP 協議簡介

HTTP:超文本傳輸協議,是網絡應用層的協議,建立在 TCP/IP 協議基礎上,HTTP 使用可靠的 TCP 連接,默認端口為 80。

用戶打開 Web 瀏覽器(常見的 HTTP 客戶端),輸入 URL地址,就能接收到遠程 HTTP 服務器端發送過來的網頁,即HTTP 遵循請求(Request)/應答(Response)模型。

Web 瀏覽器向 Web 服務器發送請求,Web 服務器處理請求並返回適當的應答,所有 HTTP 連接都被構造成一套請求與應答。

HTTP 協議嚴格規定了 HTTP 請求和 HTTP 響應的數據格式

HTTP 請求格式

1) 請求方式、URI(統一資源定位符)、HTTP 協議/版本

2) 請求頭 Request Header

  請求頭包含許多有關客戶端環境和請求正文的有用信息。例如,請求頭可以聲明瀏覽器所用的語言,請求正文的長度等。

3) 請求正文 Requet Content (只有在 post 方式才有)請求頭和請求正文之間必須有符號行(回車符或行結束符),與請求頭分開。這個行非常重要,它表示請求頭已結束,接

下來的是請求正文。 通常 post 方式的數據存放於此,請求正文中可以包含客戶提交的查詢字符串等信息。在實際應用中,HTTP 請求正文可以包含更多的內容

HTTP響應格式

1) HTTP 協議版本、狀態代碼、描述

2) 響應頭(Response Head)

3) 響應正文(Respose Content)

 

Tomcat

是 SUN 公司推出的小型 Servlet/JSP 調試工具)的基礎上發展起來的一個優秀的 Servlet 容器,Tomcat本身完全用 Java 語言編寫

Tomcat 使用

1) 配置 Tomcat

  a) JAVA_HOME Java JDK 的根目錄

  b) CATALINA_HOME Tomcat 根目錄

2) 啟動和關閉 Tomcat

  啟動 Tomcat 服務器:startup.bat  本地主機8080端口

  關閉 Tomcat 服務器:shutdown.bat

3) 部署項目到服務器

  在 webapps 目錄下新建目錄存放.html 頁面     訪問頁面

Tomcat 的運行原理

客戶瀏覽器發出要求,訪問特定的 Servlet 的請求。

1) Tomcat 服務器接收到客戶請求並解析。

2) Tomcat 服 務 器 創 建 一 個 ServletRequest 對 象 , 在ServletRequest 對象中包含了客戶請求信息及其他關於客戶的信息,如請求頭,請求正文,以及客戶機的 IP 地址等。

3) Tomcat 服務器創建一個 ServletResponse 對象

4) Tomcat 服務器調用客戶所請求的 Servlet 的 service 服務方法,並且把 ServletRequst 對象和 ServletResponse 對象做為參數傳給該服務方法。

5) Servlet 從 ServletRequest 對象中可獲取客戶的請求信息。

6) Servlet 利用 ServletResponse 對象來生成響應結果。

7) Tomcat 服務器把 Servlet 生成的響應結果發送給客戶。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 

 

 

手寫服務器項目

1.搭建項目框架

 

2.編寫XML文檔

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app>
 3     <servlet>
 4         <servlet-name>login</servlet-name>
 5         <serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class>
 6     </servlet>
 7     <servlet-mapping>
 8         <serlvet-name>login</serlvet-name>
 9         <url-pattern>/login</url-pattern>
10         <url-pattern>/log</url-pattern>
11     </servlet-mapping>
12     <servlet>
13         <servlet-name>register</servlet-name>
14         <serlvet-class>com.bjsxt.servlet.RegisterServlet</serlvet-class>
15     </servlet>
16     <servlet-mapping>
17         <serlvet-name>register</serlvet-name>
18         <url-pattern>/reg</url-pattern>
19         <url-pattern>/register</url-pattern>
20         <url-pattern>/regis</url-pattern>
21     </servlet-mapping>
22     <servlet>
23         <servlet-name>favicon</servlet-name>
24         <serlvet-class>com.bjsxt.servlet.FaviconServlet</serlvet-class>
25     </servlet>
26     <servlet-mapping>
27         <serlvet-name>favicon</serlvet-name>
28         <url-pattern>/favicon.ico</url-pattern>
29         
30     </servlet-mapping>
31 </web-app>
View Code

3.編寫 IOCloseUtil 類

 1 import java.io.Closeable;
 2 import java.io.IOException;
 3 
 4 public class IOCloseUtil { //用於關閉所有流
 5     public static void closeAll(Closeable...close) { //可變參數
 6         for (Closeable closeable : close) {
 7             if(closeable != null) {
 8                 try {
 9                     closeable.close();
10                 } catch (IOException e) {
11                     // TODO 自動生成的 catch 塊
12                     e.printStackTrace();
13                 }
14             }
15         }
16     }
17 }
View Code

4.DOM4J 解析 XML 配置文件

  1)Entity 實體類的編寫

 1 import java.io.File;
 2 import java.util.ArrayList;
 3 import java.util.Iterator;
 4 import java.util.List;
 5 
 6 import org.dom4j.Document;
 7 import org.dom4j.DocumentException;
 8 import org.dom4j.Element;
 9 import org.dom4j.io.SAXReader;
10 import org.omg.CORBA.PUBLIC_MEMBER;
11 
12 public class WebDom4j { //用於解析XML
13     private List<Entitty> entityList;//用於存儲N多Entity,而每一個Entity都是servlet-name與servlet-class
14     private List<Mapping> mappingList;//用於存儲N多Mapping,而每一個Mapping都是一個servlet-name與多個url-pattern
15     
16     //公有取值賦值方法
17     public List<Entitty> getEntityList() {
18         return entityList;
19     }
20     public void setEntityList(List<Entitty> entityList) {
21         this.entityList = entityList;
22     }
23     public List<Mapping> getMappingList() {
24         return mappingList;
25     }
26     public void setMappingList(List<Mapping> mappingList) {
27         this.mappingList = mappingList;
28     }
29     
30     //構造方法
31     public WebDom4j() {
32         entityList = new ArrayList<Entitty>();
33         mappingList = new ArrayList<Mapping>();
34     }
35     //獲取Document對象的方法
36     public Document getDocument() { //Document英語翻譯:文件;文檔
37         //alt+shift+z包圍異常快捷鍵
38         try {
39             //(1)創建SAXReader對象
40             SAXReader reader = new SAXReader();
41             //(2)調用read()方法
42             return reader.read(new File("src/WEB_INFO/web.xml"));
43         } catch (DocumentException e) {
44             // TODO 自動生成的 catch 塊
45             e.printStackTrace();
46         }
47         return null;
48     }
49     //把獲取到的Document對象解析
50     public void parse(Document doc) {
51         //(1)獲取根元素
52         Element root = doc.getRootElement(); //web-app
53         //(2)解析servlet
54         for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
55             Element subElement = ite.next();//得到每一個servlet
56             //創建一個實體類
57             Entitty ent = new Entitty();//用於存儲servlet-name與servlet-class
58             for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
59                 Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
60                 if("servlet-name".equals(ele.getName())) {
61                     ent.setName(ele.getText()); //給實體類中的name賦值
62                 }else if ("servlet-class".equals(ele.getName())) {
63                     ent.setClazz(ele.getText());
64                 }
65             }
66             //經過上面的循環后Entity有值了,把Entity添加到集合中
67             entityList.add(ent);
68         }
69         //解析servlet-mapping
70         for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
71             Element subEle = ite.next();//得到每一個servlet-mapping
72             //創建一個mapping類對象
73             Mapping map = new Mapping();
74             //解析servlet-mapping下的子元素
75             for(Iterator<Element>  subite = subEle.elementIterator(); subite.hasNext();) {
76                 Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
77                 if("servlet-name".equals(ele.getName())) {
78                     map.setName(ele.getText());
79                 }else if("url-pattern".equals(ele.getName())){
80                     //獲取集合對象,調用集合對象的添加方法,添加元素
81                     map.getUrlPattern().add(ele.getText());
82                 }
83             }
84             //mapping添加到集合中
85             mappingList.add(map);
86         }
87     }
88 }
View Code

  2)Mapping 實體類的編寫

 1 /**
 2  * <servlet-mapping>
 3         <servlet-name>login</servlet-name>
 4         <url-pattern>/login</url-pattern>
 5         <url-pattern>/log</url-pattern>
 6     </servlet-mapping>
 7  * @author CHB
 8  *
 9  */
10 
11 import java.util.ArrayList;
12 import java.util.List;
13 
14 public class Mapping { //映射關系  多個路徑訪問共享資源 servlet-name和url-pattern對應的實體類 多個資源與小名之間的關系
15     private String name;//servlet-name
16     private List<String> urlPattern;//url-pattern
17     
18     //公有取值賦值方法
19     public String getName() {
20         return name;
21     }
22     public void setName(String name) {
23         this.name = name;
24     }
25     public List<String> getUrlPattern() {
26         return urlPattern;
27     }
28     public void setUrlPattern(List<String> urlPattern) {
29         this.urlPattern = urlPattern;
30     }
31     //構造方法
32     public Mapping() {
33         urlPattern = new ArrayList<String>();
34     }
35     public Mapping(String name, List<String> urlPattern) {
36         super();
37         this.name = name;
38         this.urlPattern = urlPattern;
39     }
40 }
View Code

  3)解析 XML 文件,WebDom4j類的編寫

  導入Dom4j的jar包:在項目下新建文件夾lib,把jar包復制進去,導入后右鍵jar包選擇構建路徑再選擇添加至構建路徑

 1 import java.io.File;
 2 import java.util.ArrayList;
 3 import java.util.Iterator;
 4 import java.util.List;
 5 
 6 import org.dom4j.Document;
 7 import org.dom4j.DocumentException;
 8 import org.dom4j.Element;
 9 import org.dom4j.io.SAXReader;
10 import org.omg.CORBA.PUBLIC_MEMBER;
11 
12 public class WebDom4j { //用於解析XML
13     private List<Entitty> entityList;//用於存儲N多Entity,而每一個Entity都是servlet-name與servlet-class
14     private List<Mapping> mappingList;//用於存儲N多Mapping,而每一個Mapping都是一個servlet-name與多個url-pattern
15     
16     //公有取值賦值方法
17     public List<Entitty> getEntityList() {
18         return entityList;
19     }
20     public void setEntityList(List<Entitty> entityList) {
21         this.entityList = entityList;
22     }
23     public List<Mapping> getMappingList() {
24         return mappingList;
25     }
26     public void setMappingList(List<Mapping> mappingList) {
27         this.mappingList = mappingList;
28     }
29     
30     //構造方法
31     public WebDom4j() {
32         entityList = new ArrayList<Entitty>();
33         mappingList = new ArrayList<Mapping>();
34     }
35     //獲取Document對象的方法
36     private Document getDocument() { //Document英語翻譯:文件;文檔
37         //alt+shift+z包圍異常快捷鍵
38         try {
39             //(1)創建SAXReader對象
40             SAXReader reader = new SAXReader();
41             //(2)調用read()方法
42             return reader.read(new File("src/WEB_INFO/web.xml"));
43         } catch (DocumentException e) {
44             // TODO 自動生成的 catch 塊
45             e.printStackTrace();
46         }
47         return null;
48     }
49     //把獲取到的Document對象解析
50     public void parse(Document doc) {
51         //(1)獲取根元素
52         Element root = doc.getRootElement(); //web-app
53         //(2)解析servlet
54         for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
55             Element subElement = ite.next();//得到每一個servlet
56             //創建一個實體類
57             Entitty ent = new Entitty();//用於存儲servlet-name與servlet-class
58             for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
59                 Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
60                 if("servlet-name".equals(ele.getName())) {
61                     ent.setName(ele.getText()); //給實體類中的name賦值
62                 }else if ("servlet-class".equals(ele.getName())) {
63                     ent.setClazz(ele.getText());
64                 }
65             }
66             //經過上面的循環后Entity有值了,把Entity添加到集合中
67             entityList.add(ent);
68         }
69         //解析servlet-mapping
70         for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
71             Element subEle = ite.next();//得到每一個servlet-mapping
72             //創建一個mapping類對象
73             Mapping map = new Mapping();
74             //解析servlet-mapping下的子元素
75             for(Iterator<Element>  subite = subEle.elementIterator(); subite.hasNext();) {
76                 Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
77                 if("servlet-name".equals(ele.getName())) {
78                     map.setName(ele.getText());
79                 }else if("url-pattern".equals(ele.getName())){
80                     //獲取集合對象,調用集合對象的添加方法,添加元素
81                     map.getUrlPattern().add(ele.getText());
82                 }
83             }
84             //mapping添加到集合中
85             mappingList.add(map);
86         }
87     }
88 }
View Code

 5.反射創建servlet對象

  1)編寫 ServletContext 類:Servlet 上下文,就是一個容器,用於存儲映射關系

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 
 4 public class ServletContext { //上下文 Entity與Mapping的映射關系 實體與映射關系類
 5     private Map<String, String> servlet;//key是servlet-name,值是servlet-class
 6     private Map<String, String> mapping;//hashmap鍵不能重復,值卻可以,key是url-pattern, 值是servlet-name
 7     
 8     //公有的取值賦值方法
 9     public Map<String, String> getServlet() {
10         return servlet;
11     }
12     public void setServlet(Map<String, String> servlet) {
13         this.servlet = servlet;
14     }
15     public Map<String, String> getMapping() {
16         return mapping;
17     }
18     public void setMapping(Map<String, String> mapping) {
19         this.mapping = mapping;
20     }
21     
22     //構造方法
23     public ServletContext() {
24         servlet = new HashMap<String, String>();
25         mapping = new HashMap<String, String>();
26     }    
27 }
View Code

  2)編寫 WebApp 類

  a) 初始化程序運行的數據

  b) 根據不同的 url 創建所請求的 Servlet 對象

 1 import java.util.List;
 2 import java.util.Map;
 3 
 4 import javax.print.attribute.standard.Severity;
 5 
 6 import cn.chb.servlet.Servlet;
 7 
 8 /*    a) 初始化程序運行的數據
 9   b) 根據不同的 url 創建所請求的 Servlet 對象
10  * */
11 
12 public class WebApp { //app應用程序
13     private static ServletContext context;
14     static {//靜態初始化代碼塊
15         context =  new ServletContext();
16         //分別獲取對應關系的Map集合
17         Map<String, String> servlet = context.getServlet();
18         Map<String, String> mapping = context.getMapping();
19         //解析XML文件對象
20         WebDom4j web = new WebDom4j();
21         web.parse(web.getDocument());//解析XML並把數據放到了entityList和mappingList當中
22         //獲取解析XML之后的List集合
23         List<Entitty> entityList = web.getEntityList();
24         List<Mapping> mappingList = web.getMappingList();
25         
26         //將List集合中的數據存儲到Map集合
27         for(Entitty entity:entityList) {
28             servlet.put(entity.getName(), entity.getClazz());
29         }
30         for(Mapping map:mappingList) {
31             //遍歷url-pattern集合
32             List<String> urlPattern = map.getUrlPattern();
33             for(String s:urlPattern) {
34                 mapping.put(s, map.getName());
35             }
36         }
37     }
38     /**
39      * 根據url創建不同的servlet對象
40      * @param url
41      * @return
42      * 
43      */
44     public static Servlet getServlet(String url){
45         if(url == null||url.trim().equals("")) {
46             return null;
47         }
48         try {
49             //如果url正確
50             String servletName = context.getMapping().get(url);//根據key(url)獲取值(servlet-name)
51             //根據servlet-name得到對應的servlet-class
52             String servletClass = context.getServlet().get(servletName);//等到的是一個完整的包名+類名字符串
53             //使用反射創建servlet對象
54             Class<?> clazz = Class.forName(servletClass);
55             //調用無參構造方法創建servlet對象
56             Servlet servlet = (Servlet)clazz.newInstance();
57             return servlet;
58         } catch (ClassNotFoundException e) {
59             // TODO 自動生成的 catch 塊
60             e.printStackTrace();
61         } catch (InstantiationException e) {
62             // TODO 自動生成的 catch 塊
63             e.printStackTrace();
64         } catch (IllegalAccessException e) {
65             // TODO 自動生成的 catch 塊
66             e.printStackTrace();
67         }
68         return null;
69     }
70 }
View Code

6.封裝 Request_method_url

  1) 編寫 Server: 啟動服務   關閉服務

 1 import java.io.BufferedWriter;
 2 import java.io.IOException;
 3 import java.io.InputStream;
 4 import java.io.OutputStreamWriter;
 5 import java.net.ServerSocket;
 6 import java.net.Socket;
 7 
 8 import com.bjsxt.servlet.Servlet;
 9 import com.bjsxt.util.IOCloseUtil;
10 
11 public class Server {//服務器,用於啟動和停止服務
12     private ServerSocket server;
13     private boolean isShutDown=false;//默認沒有出錯
14     public static void main(String[] args) {
15         Server server=new Server();//創建服務器對象
16         server.start();
17     }
18     public void start(){
19         this.start(8888);
20     }
21     public void start(int port){
22         try {
23             server=new ServerSocket(port);
24             this.receive(); //調用接收請求信息的方法
25         } catch (IOException e) {
26             isShutDown=true;
27         }
28     }
29     private void receive() {
30         try {
31             while(!isShutDown){
32                 //(1)監聽
33                 Socket client=server.accept();
34                 //創建線程類的對象
35                 Dispatcher dis=new Dispatcher(client);
36                 //創建線程的代理類,並啟動線程
37                 new Thread(dis).start();
38             }    
39             
40         } catch (IOException e) {
41             this.stop();//關閉服務器
42         }
43         
44     }
45     public void stop(){
46         isShutDown=true;
47         IOCloseUtil.closeAll(server);
48     }
49 }
View Code

  2)編寫 HTML

 1 <html>
 2     <head>
 3         <title>登陸</title>
 4     </head>
 5     <body>
 6         <form action="http://127.0.1:8888/log" method="get" >
 7             <p>用戶名:<input type="text" name="username" id="username"/></p>
 8             <p>密碼:<input type="password" name="pwd" id="password"/></p>
 9             <p>
10                 愛好:<input type="checkbox" name="hobby" value="ball"/>足球
11                      <input type="checkbox" name="hobby" value="read"/>讀書
12                      <input type="checkbox" name="hobby" value="pain"/>畫畫
13             </p>
14             <p><input type="submit" value="登陸"/></p>
15             <input type="submit" value="提交"/>
16         </form>
17     </body>
18 </html>
View Code

  3) 封裝 Request_method_url

  1 import java.io.InputStream;
  2 import java.io.UnsupportedEncodingException;
  3 import java.net.URLDecoder;
  4 import java.util.ArrayList;
  5 import java.util.Arrays;
  6 import java.util.HashMap;
  7 import java.util.List;
  8 import java.util.Map;
  9 
 10 public class Request { /*請求類*/
 11     private InputStream is;//輸入流
 12     private String requestInfo;//請求字符串:請求方式,路徑,參數,協議/協議版本,請求正文
 13     private String method;//請求方式
 14     private String url;//請求的url
 15     
 16     //輸入框中的name為key,值為輸入的內容
 17     /*
 18      * key:username  value:chb
 19      * key:pwd         value:123456
 20      */
 21     private Map<String, List<String>> parametermapValues;//參數
 22     private static final String CRLF="\r\n";//換行
 23     private static final String BLANK=" ";//空格
 24     //構造方法,初始化屬性
 25     public Request() {
 26         parametermapValues = new HashMap<String, List<String>>();
 27         method = "";
 28         requestInfo = "";
 29         url = "";
 30     }
 31     public Request(InputStream is) {
 32         this();
 33         this.is = is;
 34         try {
 35             byte [] buf = new byte [20480];
 36             int len = this.is.read(buf);
 37             requestInfo = new String(buf, 0, len);
 38         } catch (Exception e) {
 39             // TODO 自動生成的 catch 塊
 40             e.printStackTrace();
 41         }
 42         //調用本類中分解請求信息的方法
 43         this.parseRequestInfo();
 44     }
 45     //分解請求信息的方法 方式、路徑、參數
 46     private void parseRequestInfo() {
 47         String paraString ="";//用於存儲請求參數
 48         //獲取請求參數的第一行
 49         String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//從0開始到第一個換行
 50         //分解出請求方式
 51         int index = firstLine.indexOf("/");//找出斜線的位置GET /(這里) HTTP/1.1
 52         this.method = firstLine.substring(0, index).trim();//trim()去掉空格
 53         //分解url,可能包含參數,也可能不包含參數
 54         String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
 55         //判斷請求方式是GET還是POST
 56         if("get".equalsIgnoreCase(this.method)) {//GET包含請求參數
 57             if(urlString.contains("?")) {//包含有問號,說明有參數
 58                 String [] urlArray = urlString.split("\\?");//以?號分割獲取參數
 59                 this.url = urlArray[0];
 60                 paraString = urlArray[1];
 61             }else {
 62                 this.url = urlString;
 63             }
 64         }else {//POST不包含請求參數,參數在請求正文
 65             this.url = urlString;
 66             //最后一個換行到結尾是請求正文
 67             paraString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
 68         }
 69         if(paraString.equals("")) {//如果沒有參數
 70             return;
 71         }
 72     }
 73     //username=chbt&pwd=123&hobby=ball&hobby=paint
 74         /**
 75          * username=chb
 76          * pwd=123
 77          * hobby=ball
 78          * hobby=paint
 79          * 
 80          * username=
 81          * @param prarString
 82          */
 83         private void parseParam(String prarString){
 84             String [] token=prarString.split("&");
 85             for(int i=0;i<token.length;i++){
 86                 String keyValues=token[i];
 87                 String []keyValue=keyValues.split("=");  //username   chb   pwd   123
 88                 if (keyValue.length==1) {  //username=
 89                     keyValue=Arrays.copyOf(keyValue, 2);
 90                     keyValue[1]=null;
 91                 }
 92                 //將  表單元素的name與name對應的值存儲到Map集合
 93                 String key=keyValue[0].trim();
 94                 String value=keyValue[1]==null?null:decode(keyValue[1].trim(), "utf-8");
 95                 //放到集合中存儲
 96                 if (!parametermapValues.containsKey(key)) {
 97                     parametermapValues.put(key, new ArrayList<String>());
 98                 }
 99                 List<String> values=parametermapValues.get(key);
100                 values.add(value);
101             }
102         }
103         //根據表單元素的name獲取多個值
104         private String [] getParamterValues(String name){
105             //根據key獲取value
106             List<String> values=parametermapValues.get(name);
107             if (values==null) {
108                 return null;
109             }else{
110                 return values.toArray(new String [0] );
111             }
112             
113         }
114         private String getParamter(String name){
115             //調用本類中根據name獲取多個值的方法
116             String [] values=this.getParamterValues(name);
117             if (values==null) {
118                 return null;
119             }else{
120                 return values[0];
121             }
122         }
123         
124         //處理中文,因類瀏覽器對中文進行了編碼,進行解碼
125         private String decode(String value,String code){
126             try {
127                 return URLDecoder.decode(value, code);
128             } catch (UnsupportedEncodingException e) {
129                 // TODO Auto-generated catch block
130                 e.printStackTrace();
131             }
132             return null;
133         }
134 }
View Code

7.封裝 Response

1) 構造響應頭

2) 推送到客戶端

  1 import java.io.BufferedWriter;
  2 import java.io.IOException;
  3 import java.io.OutputStream;
  4 import java.io.OutputStreamWriter;
  5 import java.io.UnsupportedEncodingException;
  6 
  7 import com.bjsxt.util.IOCloseUtil;
  8 
  9 public class Response {//響應
 10     private StringBuilder headInfo;//響應頭
 11     private StringBuilder content;//響應內容
 12     private int length;//響應內容的長度
 13     //
 14     private BufferedWriter bw;
 15     
 16     //兩個常量,換行和空格
 17     private static final String CRLF="\r\n";//換行
 18     private static final String BLANK=" ";//空格
 19     
 20     //構造方法
 21     public Response() {
 22         headInfo=new StringBuilder();
 23         content=new StringBuilder();
 24         
 25     }
 26     //帶參構造方法
 27     public Response(OutputStream os){
 28         this();//調用本類的無參構造方法
 29         try {
 30             bw=new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
 31         } catch (UnsupportedEncodingException e) {
 32             headInfo=null;
 33         }
 34         
 35     }
 36     //構造正文部分
 37     public Response print(String info){
 38         content.append(info);
 39         try {
 40             length+=info.getBytes("utf-8").length;
 41         } catch (UnsupportedEncodingException e) {
 42             // TODO Auto-generated catch block
 43             e.printStackTrace();
 44         }
 45         return this;
 46     }
 47     public Response println(String info){
 48         content.append(info).append(CRLF);
 49         try {
 50             length+=(info+CRLF).getBytes("utf-8").length;
 51         } catch (UnsupportedEncodingException e) {
 52             // TODO Auto-generated catch block
 53             e.printStackTrace();
 54         }
 55         return this;
 56     }
 57     
 58     //構造響應頭
 59     
 60     private void createHeadInfo(int code){
 61         headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
 62         switch (code) {
 63         case 200:
 64             headInfo.append("OK");
 65             break;
 66         case 500:
 67             headInfo.append("SERVER ERROR");
 68             break;
 69         default:
 70             headInfo.append("NOT FOUND");
 71             break;
 72         }
 73         headInfo.append(CRLF);
 74         headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
 75         headInfo.append("Content-Length:"+length).append(CRLF);
 76         headInfo.append(CRLF);
 77     }
 78     /**
 79      * 推送到客戶機的瀏覽器
 80      * @param code
 81      */
 82     public void pushToClient(int code){
 83         if (headInfo==null) {
 84             code=500;
 85         }
 86         try {
 87             //調用本類中的構造響應頭
 88             this.createHeadInfo(code);
 89             bw.write(headInfo.toString());
 90             bw.write(content.toString());
 91             bw.flush();
 92             this.close();
 93         } catch (IOException e) {
 94             // TODO Auto-generated catch block
 95             e.printStackTrace();
 96         }
 97     }
 98     public void close(){
 99         IOCloseUtil.closeAll(bw);
100     }
101 }
View Code

3)編寫相應的 Servlet 構造響應內容

 1 import com.bjsxt.server.Request;
 2 import com.bjsxt.server.Response;
 3 
 4 public abstract class Servlet { //是所有的請求的Servlet的父類
 5     public void service(Request req,Response rep) throws Exception{
 6         this.doGet( req, rep);
 7         this.doPost( req, rep);
 8     }
 9     public abstract void doGet(Request req,Response rep) throws Exception;
10     public abstract void doPost(Request req,Response rep) throws Exception;
11 }
View Code
 1 import com.bjsxt.server.Request;
 2 import com.bjsxt.server.Response;
 3 
 4 public class LoginServlet extends Servlet {
 5 
 6     @Override
 7     public void doGet(Request req, Response rep) throws Exception {
 8             //獲取請求參數
 9         String name=req.getParameter("username");
10         String pwd=req.getParameter("pwd");
11         
12         if(this.login(name, pwd)){
13             //調用響應中的構建內容的方
14             rep.println(name+"登錄成功");
15         }else{
16             rep.println(name+"登錄失敗,對不起,賬號或密碼不正確");
17         }
18         
19     }
20     private boolean login(String name,String pwd){
21         if ("bjsxt".equals(name)&&"123".equals(pwd)) {
22             return true;
23         }
24         return false;
25     }
26 
27     @Override
28     public void doPost(Request req, Response rep) throws Exception {
29         // TODO Auto-generated method stub
30         
31     }
32 }
View Code
 1 import com.bjsxt.server.Request;
 2 import com.bjsxt.server.Response;
 3 
 4 public class FaviconServlet extends Servlet {
 5 
 6     @Override
 7     public void doGet(Request req, Response rep) throws Exception {
 8         // TODO Auto-generated method stub
 9         
10     }
11 
12     @Override
13     public void doPost(Request req, Response rep) throws Exception {
14         // TODO Auto-generated method stub
15         
16     }
17 
18 }
View Code

8.封裝分發器實現多線程

 1 import java.io.IOException;
 2 import java.net.Socket;
 3 
 4 import com.bjsxt.servlet.Servlet;
 5 import com.bjsxt.util.IOCloseUtil;
 6 
 7 /**
 8  * 一個請求與響應就是一個Dispatcher
 9  * @author Administrator
10  *
11  */
12 public class Dispatcher implements Runnable {
13     private Request req;
14     private Response rep;
15     private Socket client;
16     private int code=200;//狀態碼
17     //構造方法初始化屬性
18     public Dispatcher(Socket client) {
19         //將局部變量的值賦給成員變量
20         this.client=client;
21         try {
22             req=new Request(this.client.getInputStream());
23             rep=new Response(this.client.getOutputStream());
24         } catch (IOException e) {
25             code=500;
26             return ;
27         }
28     }
29     @Override
30     public void run() {
31         //根據不同的url創建指定的Servlet對象
32         //System.out.println(req.getUrl());
33         Servlet servlet=WebApp.getServlet(req.getUrl());
34         if (servlet==null) {
35             this.code=404;
36         }else{
37             //調用相應的Servlet中的service方法
38             try {
39                 servlet.service(req,rep);
40             } catch (Exception e) {
41                 this.code=500;
42             }
43         }
44         //將響應結果推送到客戶機的瀏覽器
45         rep.pushToClient(code);
46         IOCloseUtil.closeAll(client);
47     }
48 
49 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM