預備知識
編寫服務器用到的知識點
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>
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>
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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>
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 }
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 }
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 }

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 }

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 }
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 }