Java—手写服务器
1.預備知識_Socket知識回顧
1.1編寫服務器用到的知識點
1)Socket編程
2)HTML
3)HTTP協議
4)反射
5)XML解析
6)服務器編寫
1.2復習Socket編程
1)C/S結構:客戶端與服務器端一次雙向通信
2)B/S結構:瀏覽器與服務器
httpClient_1
Client.java
package com.bjsxt.test;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException;public class Client {public static void main(String[] args) {//(1)創建Socket對象Socket client=null;//(2)獲取輸出流-->請求DataOutputStream dos=null;DataInputStream dis=null;try {client = new Socket("localhost", 8888);dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("我是客戶端:服務器你好!");//(3)獲取輸入流-->響應dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(4)關閉流IOClose.closeAll(dis,dos,client);}} }IOClose.java
package com.bjsxt.test;import java.io.Closeable; import java.io.IOException;public class IOClose {//關閉全部的工具類public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }httpServer_1
Server.java
package com.bjsxt.server;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;public class Server {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;//(3)獲取Scoket對象//(4)獲取輸入流 -->得到客戶端的請求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)獲取輸出流-->給客戶端響應結果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客戶端您好:我是服務器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(dos,dis,client,server);}} }IOClose.java
package com.bjsxt.server;import java.io.Closeable; import java.io.IOException;public class IOClose {//關閉全部的工具類public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }Server2.java
package com.bjsxt.server;import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//獲取來自瀏覽器的請求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(br,client,server);}} }2. 預備知識_HTML 簡單入門
2.1HTML
HTML: HyperText Markup Language 超文本標記語言用于描述網頁文檔的一種標記語言
2.2 第一個 HTML 文檔
<html><head><title>第一個 HTML</title></head><body><h1>hello world</h1></body> </html>2.3 表單 form
作用:與用戶之間進行交互
method:請求方式 get/post
get 數據量小,安全性低,默認方式
post 數據量大,安全性高
action:請求的服務器路徑
id : (用戶的的瀏覽器在文檔里區分唯一性)前端區分唯一性,js 中
name:名稱,后端(服務器)區分唯一性,獲取值,只要提交數據
給后臺(服務器)必須存在 name
httpServer_2
Server.java
package com.bjsxt.server;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;public class Server {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;//(3)獲取Scoket對象//(4)獲取輸入流 -->得到客戶端的請求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)獲取輸出流-->給客戶端響應結果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客戶端您好:我是服務器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(dos,dis,client,server);}} }Server2.java
package com.bjsxt.server;import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//獲取來自瀏覽器的請求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(br,client,server);}} }Server3.java
package com.bjsxt.server;import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;public class Server3 {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;InputStream is=null;try {server = new ServerSocket(8888);client = server.accept();//獲取來自瀏覽器的請求信息is=client.getInputStream();byte [] buf=new byte[20480];int len=is.read(buf);System.out.println(new String(buf,0,len));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(is,client,server);}} }IOClose.java
package com.bjsxt.server;import java.io.Closeable; import java.io.IOException;public class IOClose {//關閉全部的工具類public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }index.html
<html><head><title>我的第一個html</title></head><body><h1>hello world</h1><form action="http://localhost:8888/log" method="get"><p>用戶名:<input type="text" id="uname" name="username" /></p><p>密碼:<input type="password" id="pwd" name="password"/></p><p>興趣愛好<input type="checkbox" name="hobby" value="ball"/>球 <input type="checkbox" name="hobby" value="read"/>讀書<input type="checkbox" name="hobby" value="paint"/>畫畫</p><p><input type="submit" value="登錄"/></p></form></body></html>3.預備知識_HTTP協議入門
3.1協議
1)應用層:HTTP、FTP、TELNET、SNMP、DNS
2)傳輸層:TCP、UDP
3) 網絡層:IP
3.2HTTP協議簡介
HTTP:Hypertext Transfer Protocol超文本傳輸協議,是網絡應用層的協議,建立在TCP/IP協議基礎上,HTTP使用可靠的TCP連接,默認端口為80.
用戶打開web瀏覽器(常見的HTTP客戶端),輸入URL地址,就能接收到遠程HTTP服務器端發送過來的網頁,即HTTP遵循請求(Request)/應答(Response)模型。web瀏覽器向web服務器發送請求,web服務器處理請求并返回適當的應答,所有HTTP連接都被構造成一套請求與應答。
HTTP客戶端和服務器分別由不同的軟件開發商提供,它們都可以用任意的編程語言編寫,如用.NET 編寫的客戶程序與用Java編寫的服務器程序順利通信,就必須遵守HTTP協議,這樣才能彼此都懂對方發送的消息,HTTP協議嚴格規定了HTTP請求和HTTP響應的數據格式。
3.3HTTP請求格式
1)請求方式、URL(統一資源定位符)、HTTP協議/版本
2)請求頭 Request Header
a)請求頭包含許多有關客戶端環境和請求正文的有用信息。例如,請求頭可以聲明瀏覽器所有的語言,請求正文的長度等。
3)請求正文 Requet Content (只有在 post 方式才有)
請求頭和請求正文之間必須有符號行(回車符或行結束符),將請求頭與請求正文分開,這個行非常重要,它表示 請求頭已結束,接下來的是請求正文。通常post方式的數據存放于此,請求正文中可以包含客戶提交的查詢字符串等信息。在實際應用中,HTTP請求正文可以包含更多的內容。
3.4HTTP 響應格式
httpServer_2
Server.java
package com.bjsxt.server;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;public class Server {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;//(3)獲取Scoket對象//(4)獲取輸入流 -->得到客戶端的請求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)獲取輸出流-->給客戶端響應結果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客戶端您好:我是服務器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(dos,dis,client,server);}} }Server2.java
package com.bjsxt.server;import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//獲取來自瀏覽器的請求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(br,client,server);}} }Server3.java
package com.bjsxt.server;import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket;public class Server3 {public static void main(String[] args) {String CRLF="\r\n";//換行String BLANK=" ";//空格//(1)創建ServerSocket對象ServerSocket server=null;//(2)監聽是否有客戶端發送請求Socket client=null;InputStream is=null;try {server = new ServerSocket(8888);client = server.accept();//獲取來自瀏覽器的請求信息is=client.getInputStream();byte [] buf=new byte[20480];int len=is.read(buf);System.out.println(new String(buf,0,len));/**對Web瀏覽器的請求作出響應*/StringBuilder sb=new StringBuilder();StringBuilder sbContent=new StringBuilder();//響應的文本sbContent.append("<html><head><title>響應結果</title></head>");sbContent.append("<body>登錄成功</body></html>");//(1)拼接響應頭sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");sb.append(CRLF);//換行sb.append("Content-Type: text/html;charset=utf-8");sb.append(CRLF);//換行sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);sb.append(CRLF);//換行,代表響應頭與響應的正文部門之間的空行sb.append(sbContent);//通過流輸出 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));bw.write(sb.toString());bw.flush();bw.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)關閉流IOClose.closeAll(is,client,server);}} }IOClose.java
package com.bjsxt.server;import java.io.Closeable; import java.io.IOException;public class IOClose {//關閉全部的工具類public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }4.Tomcat服務器的快速使用
4.1Tomcat簡介
Tomcat是在SUN公司的JSWDK( JavaServer Web
DevelopmentKit ,是 SUN 公司推出的小型 Servlet/JSP 調試工
具)的基礎上發展起來的一個優秀的Servlet容器,Tomcat本身完全用Java語言編寫。
4.2Tomcat使用
1)配置Tomcat
a) JAVA_HOME Java JDK 的根目錄
b) CATALINA_HOME Tomcat 根目錄
bin:存放Tomcat腳本目錄
啟動 Tomcat 服務器:startup.bat
關閉 Tomcat 服務器:shutdown.bat
conf:存放配置文件
conf—>server.xml:存放配置信息
存放配置端口信息
lib:存放Tomcat運行所需要的jar包
logs:存放日志文件
temp:存放Tomcat臨時文件
webapps:部署項目到服務器
在 webapps 目錄下新建目錄存放.html 面頁
訪問頁面
**work:**工作目錄,將JSP文件的Java文件轉換為class文件的工作目錄。
部署項目到Tomcat
在webapps目錄下創建自己的文件夾
在該文件夾下新建一個HTML文檔
index.html
<html><head><title>發布到Tomcat中的項目的主頁</title></head><body><h1>hello tomcat</h1></body> </html>bin目錄下雙擊
啟動Tomcat服務
在地址欄輸入http://locathost:8080/myfirst/index.html
5.Tomcat服務器運行原理
5.1Tomcat的運行原理
客戶瀏覽器發出要求訪問特定德Servlet的請求。
1)Tomcat服務器接收到客戶請求并解析
2)Tomcat服務器創建一個ServletRequest對象,在ServletRequest對象中包含了客戶請求信息及其他關于客戶的信息,如請求頭,請求正文,以及客戶機的IP地址等。
3)Tomcat服務器創建一個ServletResponse 對象
4)Tomcat服務器調用客戶所請求的Servlet的service服務方法,并且把ServletRequest對象和ServletResponse對象做為參數傳給該服務方法。
5) Servlet 從 ServletRequest 對象中可獲取客戶的請求信息。
6) Servlet 利用 ServletResponse 對象來生成響應結果。
7) Tomcat 服務器把 Servlet 生成的響應結果發送給客戶。
8)
6.預備_http工具查看網絡交互過程
6.1下載并安裝
httpwatch安裝包:https://pan.baidu.com/s/1ogcMmZSutx6WvIvh2VNpGg 密碼:ggv4
6.2HttpWatch 的使用
IE 瀏覽器?查看?瀏覽器欄?HttpWatch Professional
最新版已經可以支持Google、Microsoft Edge等瀏覽器了下面是官方使用文檔
輸入網址
分析數據
來源:https://blog.csdn.net/cldsj
HttpWatch學習筆記一
HttpWatch學習筆記二
HttpWatch學習筆記三
HttpWatch功能詳細介紹
來源:https://www.cnblogs.com/Chilam007/p/6947235.html
7. 手寫服務器_ 整體架構和接口_ 編寫 XML配置文件
7.1 搭建項目框架
7.2 編寫 XML 文檔
<?xml version="1.0" encoding="UTF-8"?> <web-app><servlet><servlet-name>login</servlet-name><serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class></servlet><servlet-mapping><serlvet-name>login</serlvet-name><url-pattern>/login</url-pattern></servlet-mapping><servlet-mapping><serlvet-name>login</serlvet-name><url-pattern>/log</url-pattern></servlet-mapping> </web-app>7.3 編寫 IOCloseUtil 類
package com.bjsxt.util;import java.io.Closeable; import java.io.IOException;public class IOCloseUtil {//用于關系流public static void closeAll(Closeable...close){for (Closeable closeable : close) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}} }8.DOM4J 解析 XML 配置文件
8.1Entity 實體類的編寫
package com.bjsxt.server; /*** <servlet><servlet-name>login</servlet-name><serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class></servlet>* @author Administrator**/ public class Entity { /**servlet-name和一個servlet-name所對應的一個實體類*/private String name;//servlet-nameprivate String clazz;//servlet-classpublic String getName() {return name;}public void setName(String name) {this.name = name;}public String getClazz() {return clazz;}public void setClazz(String clazz) {this.clazz = clazz;}public Entity(String name, String clazz) {super();this.name = name;this.clazz = clazz;}public Entity() {super();}}8.2Mapping 實體類的編寫
package com.bjsxt.server;import java.util.ArrayList; import java.util.List;/*** <servlet-mapping><serlvet-name>login</serlvet-name><url-pattern>/login</url-pattern><url-pattern>/log</url-pattern></servlet-mapping>* @author Administrator**/ public class Mapping {//映射關系,多個路徑訪問共享資源private String name;//servlet-nameprivate List<String> urlPattern;//url-patternpublic String getName() {return name;}public void setName(String name) {this.name = name;}public List<String> getUrlPattern() {return urlPattern;}public void setUrlPattern(List<String> urlPattern) {this.urlPattern = urlPattern;}public Mapping(){urlPattern=new ArrayList<String>();}public Mapping(String name, List<String> urlPattern) {super();this.name = name;this.urlPattern = urlPattern;}}8.3 解析 XML 文件
package com.bjsxt.server;import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List;import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader;public class WebDom4j {//用于解析XMLprivate List<Entity> entityList;//用于存儲是N多Entity,而每一個Entity都是servlet-name與servlet-classprivate List<Mapping> mappingList;//用于存儲N多Mapping,而每一個Mapping都是一個servlet-name與N多個url-patternpublic List<Entity> getEntityList() {return entityList;}public void setEntityList(List<Entity> entityList) {this.entityList = entityList;}public List<Mapping> getMappingList() {return mappingList;}public void setMappingList(List<Mapping> mappingList) {this.mappingList = mappingList;}//構造方法public WebDom4j() {entityList=new ArrayList<Entity>();mappingList=new ArrayList<Mapping>();}//獲取Document對象的方法private Document getDocument(){try {//(1)創建SAXReader對象SAXReader reader=new SAXReader();//(2)調用read方法return reader.read(new File("src/WEB_INFO/web.xml"));} catch (DocumentException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}public void parse(Document doc){//(1)獲取根元素Element root=doc.getRootElement(); //web-app//(2)獲取servlet子元素for(Iterator<Element> ite=root.elementIterator("servlet");ite.hasNext();){Element subElement=ite.next();//得到每一個servlet//創建一個實體類Entity ent=new Entity(); //用于存儲servlet-name與servlet-classfor(Iterator<Element> subIte=subElement.elementIterator();subIte.hasNext();){Element ele=subIte.next(); //可能是servlet-name,也可能是servlet-classif("servlet-name".equals(ele.getName())){ent.setName(ele.getText()); //給實體類中的name賦值}else if("serlvet-class".equals(ele.getName())){ent.setClazz(ele.getText());}}//將Entity添加到集合中entityList.add(ent);}//測試/**for (Entity entity : entityList) {System.out.println(entity.getName()+"\t"+entity.getClazz());}*///解析servlet-mappingfor(Iterator<Element> ite=root.elementIterator("servlet-mapping");ite.hasNext();){Element subEle=ite.next();//得到每一個servlet-mapping//創建一個Mapping類的對象Mapping map=new Mapping();//解析servlet-mapping下的子元素for(Iterator<Element> subIte=subEle.elementIterator();subIte.hasNext();){Element ele=subIte.next(); //servlet-name,也有可能是url-patternif("serlvet-name".equals(ele.getName())){map.setName(ele.getText());}else if("url-pattern".equals(ele.getName())){//獲取集合對象,調用集合對象的添加方法,添加元素素map.getUrlPattern().add(ele.getText());}}//Mapping添加到集合中mappingList.add(map);}//測試for (Mapping m : mappingList) {System.out.println(m.getName());for(String s:m.getUrlPattern()){System.out.println(s);}}}//用于測試public static void main(String[] args) {WebDom4j web=new WebDom4j();web.parse(web.getDocument());} }9. 反射創建 Servlet 對象
9.1 編寫 ServletContext 類
Servlet 上下文,就是一個容器,用于存儲映射關系
package com.bjsxt.server;import java.util.HashMap; import java.util.Map;/*** Servlet上下用,就是一個容器,* @author Administrator**/ public class ServletContext { //Entity與Mapping的映射關系private Map<String,String> servlet;//key是servlet-name (Entity中的name),值serlvet-class Entity中的clazzprivate Map<String,String> mapping;//key是url-pattern (Mapping中的List集合中的每一個元素),value是serlvet-name,是Mapping中的namepublic Map<String, String> getServlet() {return servlet;}public void setServlet(Map<String, String> servlet) {this.servlet = servlet;}public Map<String, String> getMapping() {return mapping;}public void setMapping(Map<String, String> mapping) {this.mapping = mapping;}public ServletContext() {servlet=new HashMap<String,String>();mapping=new HashMap<String,String>();} }9.2 編寫 WebApp 類
10. 封裝 Request_method_url
10.1 編寫 Server
10.2 編寫 HTML
login.html
<html><head><title>登錄</title></head><body><form action="http://localhost:8888/log" method="post"><p>用戶名:<input type="text" name="username" id="username"/></p><p>密碼:<input type="password" name="pwd" id="password"/></p><p>愛好:<input type="checkbox" name="hobby" value="ball"/>足球<input type="checkbox" name="hobby" value="read"/>讀書<input type="checkbox" name="hobby" value="paint"/>畫畫</p><p><input type="submit" value="登錄"/></p></form></body> </html>10.3 封裝 Request_method_url
package com.bjsxt.server;import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map;public class Request {/*請求*/private InputStream is;//輸入流private String requestInfo;//請求字符串,請求方式,請求的路徑,參數,協議,協議版本,請求的正文。。。private String method;//請求的方式private String url;//請求的url//輸入框的name為key,值為value/** key: username value :bjsxt* key:pwd value:123* key:hobby value :read,ball* */private Map<String,List<String>> parametermapValues;//參數private static final String CRLF="\r\n";//換行private static final String BLANK=" ";//空格//構造方法,初始化屬性public Request() {parametermapValues=new HashMap<String,List<String>>();method="";url="";requestInfo="";}public Request(InputStream is){this();//調用本類無參的構造方法this.is=is;try {byte [] buf=new byte[20480];int len=this.is.read(buf);requestInfo=new String(buf,0,len);} catch (IOException e) {return;}//調用本類中的分解請求信息的方法this.parseRequestInfo();}//分解請求信息的方法/*** 請求方式* 請求路徑* 請求的參數* */private void parseRequestInfo(){String paraString="";//用于存儲請求參數//獲取請求參數的第一行String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//從0開始,到第一個換行的位置//分解出請求方式int index=firstLine.indexOf("/");this.method=firstLine.substring(0, index).trim();//分解url ,get可能包含參數,也可能不包含參數postString urlString= firstLine.substring(index,firstLine.indexOf("HTTP/")).trim();//判斷請求方式是GET還 是POSTif("get".equalsIgnoreCase(this.method)){ //包含請求參數if (urlString.contains("?")) {String [] urlArray=urlString.split("\\?");this.url=urlArray[0];paraString=urlArray[1];}else{this.url=urlString;}}else{//post不包含請求參數this.url=urlString;paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();}if (paraString.equals("")) {return;}//請求參數//System.out.println(paraString);}//用于測試/*public void show(){System.out.println(this.url);System.out.println(this.method);}*/ }11. 封裝 Request_ 存儲參數_ 處理中文
11.1 編寫分解參數的方法
package com.bjsxt.server;import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map;public class Request {/*請求*/private InputStream is;//輸入流private String requestInfo;//請求字符串,請求方式,請求的路徑,參數,協議,協議版本,請求的正文。。。private String method;//請求的方式private String url;//請求的url//輸入框的name為key,值為value/** key: username value :bjsxt* key:pwd value:123* key:hobby value :read,ball* */private Map<String,List<String>> parametermapValues;//參數private static final String CRLF="\r\n";//換行private static final String BLANK=" ";//空格//構造方法,初始化屬性public Request() {parametermapValues=new HashMap<String,List<String>>();method="";url="";requestInfo="";}public Request(InputStream is){this();//調用本類無參的構造方法this.is=is;try {byte [] buf=new byte[20480];int len=this.is.read(buf);requestInfo=new String(buf,0,len);} catch (IOException e) {return;}//調用本類中的分解請求信息的方法this.parseRequestInfo();}//分解請求信息的方法/*** 請求方式* 請求路徑* 請求的參數* */private void parseRequestInfo(){String paraString="";//用于存儲請求參數//獲取請求參數的第一行String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//從0開始,到第一個換行的位置//分解出請求方式int index=firstLine.indexOf("/");this.method=firstLine.substring(0, index).trim();//分解url ,get可能包含參數,也可能不包含參數postString urlString= firstLine.substring(index,firstLine.indexOf("HTTP/")).trim();//判斷請求方式是GET還 是POSTif("get".equalsIgnoreCase(this.method)){ //包含請求參數if (urlString.contains("?")) {String [] urlArray=urlString.split("\\?");this.url=urlArray[0];paraString=urlArray[1];}else{this.url=urlString;}}else{//post不包含請求參數this.url=urlString;paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();}if (paraString.equals("")) {return;}//請求參數//System.out.println(paraString);//調用本類中分解請求參數的方法this.parseParam(paraString);}//用于測試/*public void show(){System.out.println(this.url);System.out.println(this.method);}*///username=bjsxt&pwd=123&hobby=ball&hobby=paint/*** username=bjsxt* pwd=123* hobby=ball* hobby=paint* * username=* @param prarString*/private void parseParam(String prarString){String [] token=prarString.split("&");for(int i=0;i<token.length;i++){String keyValues=token[i];String []keyValue=keyValues.split("="); //username bjsxt pwd 123if (keyValue.length==1) { //username=keyValue=Arrays.copyOf(keyValue, 2);keyValue[1]=null;}//將 表單元素的name與name對應的值存儲到Map集合String key=keyValue[0].trim();String value=keyValue[1]==null?null:decode(keyValue[1].trim(), "utf-8");//放到集合中存儲if (!parametermapValues.containsKey(key)) {parametermapValues.put(key, new ArrayList<String>());}List<String> values=parametermapValues.get(key);values.add(value);}}//根據表單元素的name獲取多個值private String [] getParamterValues(String name){//根據key獲取valueList<String> values=parametermapValues.get(name);if (values==null) {return null;}else{return values.toArray(new String [0] );}}private String getParamter(String name){//調用本類中根據name獲取多個值的方法String [] values=this.getParamterValues(name);if (values==null) {return null;}else{return values[0];}}//處理中文,因類瀏覽器對中文進行了編碼,進行解碼private String decode(String value,String code){try {return URLDecoder.decode(value, code);} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}public static void main(String[] args) {Request req=new Request();//調用分解參數的方法req.parseParam("username=%E5%8C%97%E4%BA%AC%E5%B0%9A%E5%AD%A6%E5%A0%82&pwd=123&hobby=ball&hobby=paint");System.out.println(req.parametermapValues);//調用獲取多個值的方法String [] str=req.getParamterValues("hobby");for (String string : str) {System.out.println(string);}//調用獲取單個值的方法System.out.println(req.getParamter("pwd"));}}11.2 編寫根據頁面上的 name 獲取多個值的方法
11.3 編寫根據頁面上的 name 獲取單個值的方法
11.4 編寫解碼的方法 1
1.5 測試
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=%E5%8C%97%E
4%BA%AC%E5%B0%9A%E5%AD%A6%E5%A0%82&rsv_pq=f65f15f40003a658&rsv_t=d74
7OilFeeFkf73QkinDYpKiB4y%2Ffj3mxWfE865IJ0VxoTk5Obwtc4z41pM&rqlang=cn&rsv_ente
r=1&rsv_sug3=19&rsv_sug1=21&rsv_sug7=101
12. 封裝 Response
12.1 封裝 Response
12.2 編寫相應的 Servlet 構造響應內容
package com.bjsxt.servlet;import com.bjsxt.server.Request; import com.bjsxt.server.Response;public abstract class Servlet { //是所有的請求的Servlet的父類public void service(Request req,Response rep) throws Exception{this.doGet( req, rep);this.doPost( req, rep);}public abstract void doGet(Request req,Response rep) throws Exception;public abstract void doPost(Request req,Response rep) throws Exception; }LogServlet.java
package com.bjsxt.servlet;import com.bjsxt.server.Request; import com.bjsxt.server.Response;public class LoginServlet extends Servlet {@Overridepublic void doGet(Request req, Response rep) throws Exception {//獲取請求參數String name=req.getParameter("username");String pwd=req.getParameter("pwd");if(this.login(name, pwd)){//調用響應中的構建內容的方rep.println(name+"登錄成功");}else{rep.println(name+"登錄失敗,對不起,賬號或密碼不正確");}}private boolean login(String name,String pwd){if ("bjsxt".equals(name)&&"123".equals(pwd)) {return true;}return false;}@Overridepublic void doPost(Request req, Response rep) throws Exception {// TODO Auto-generated method stub} }12.3 啟動服務器進行測試
13. 封裝分發器_實現多線程
Dispatcher.java
package com.bjsxt.server;import java.io.IOException; import java.net.Socket;import com.bjsxt.servlet.Servlet; import com.bjsxt.util.IOCloseUtil;/*** 一個請求與響應就是一個Dispatcher* @author Administrator**/ public class Dispatcher implements Runnable {private Request req;private Response rep;private Socket client;private int code=200;//狀態碼//構造方法初始化屬性public Dispatcher(Socket client) {//將局部變量的值賦給成員變量this.client=client;try {req=new Request(this.client.getInputStream());rep=new Response(this.client.getOutputStream());} catch (IOException e) {code=500;return ;}}@Overridepublic void run() {//根據不同的url創建指定的Servlet對象System.out.println(req.getUrl());Servlet servlet=WebApp.getServlet(req.getUrl());if (servlet==null) {this.code=404;}else{//調用相應的Servlet中的service方法try {servlet.service(req,rep);} catch (Exception e) {this.code=500;}}//將響應結果推送到客戶機的瀏覽器rep.pushToClient(code);IOCloseUtil.closeAll(client);}}14. 整合最終版
14.1 查缺補漏完善項目
FaviconServlet.java
package com.bjsxt.servlet;import com.bjsxt.server.Request; import com.bjsxt.server.Response;public class FaviconServlet extends Servlet {@Overridepublic void doGet(Request req, Response rep) throws Exception {// TODO Auto-generated method stub}@Overridepublic void doPost(Request req, Response rep) throws Exception {// TODO Auto-generated method stub}}15. 總結和期望
15.1 項目總結
涉及知識點
15.2 項目思路
15.3 思想是從鍵盤中敲出來的
轉化為能力
的自己比昨天的自己有進步,就是成功。
附源碼:
鏈接:https://pan.baidu.com/s/1upUHY0bGXmLfLZKOt5ICxg
提取碼:pfz1
總結
以上是生活随笔為你收集整理的Java—手写服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最小二乘法(Ordinary Least
- 下一篇: 西游记中孙悟空大闹天宫时玉帝为什么不亲自