主頁 > 後端開發 > 手寫Javaweb服務器

手寫Javaweb服務器

2020-10-26 00:42:19 後端開發

簡單web服務器

回憶socket

創建客服端(在httpClient_1包下)

public class Client {
   public static void main(String[] args) {
       //1.創建socket物件
       Socket client=null;
?
       DataOutputStream dos = null;
       DataInputStream dis =null;
       try {
           client = new Socket("localhost", 8888);
           //2.獲取輸出流請求
           dos = new DataOutputStream(client.getOutputStream());
           dos.writeUTF("我是客服端:服務器你好!");
           //3.獲取輸出流回應
           dis = new DataInputStream(client.getInputStream());
           System.out.println(dis.readUTF());
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           //4.關閉流
           IOClose.closeAll(dis,dos,client);
      }
?
?
  }

創建IOClose類

public class IOClose {
   //關閉全部的工具類
   public static void closeAll(Closeable...c){
       for (Closeable closeable : c) {
           if (closeable!=null){
               try {
                   closeable.close();
              } catch (IOException e) {
                   e.printStackTrace();
              }
          }
      }

創建服務端(在httpserver_1包下)

package com.feng.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;
       Socket client =null;
       DataInputStream dis =null;
       DataOutputStream dos =null;
       try {
           server = new ServerSocket(8888);
           //2.監聽是否有客服端發送請求
           client = server.accept();
           //3.獲取Socket物件
           //4.獲取輸入流 ->得到客服端的請求
           dis = new DataInputStream(client.getInputStream());
           System.out.println(dis.readUTF());
           //5.獲取輸出流 ->給客服端回應結果
           dos = new DataOutputStream(client.getOutputStream());
           dos.writeUTF("客服端你好,我是服務器,我接受到了你的資訊");
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           IOClose.closeAll(dos,dis,client,server);
      }

同樣創建IOClose

在CS結構server(2)

package com.feng.server;
?
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
?
public class Server2 {
   public static void main(String[] args) {
       //1.創建ServerSocket物件
       ServerSocket server = null;
       Socket client =null;
?
       BufferedReader br = null;
       try {
           server = new ServerSocket(8888);
           //2.監聽是否有客服端發送請求
           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) {
           e.printStackTrace();
      } finally {
           IOClose.closeAll(br,client,server);
      }
  }
}

創建HTML

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>javaWeb</title>
</head>
<body>
   <h1>HelloWorld</h1>
   <form action="http://localhost:8888/index.html" method="post">
       <p>用戶名:<input type="text" id="uname" name="username"></p>
       <p>密碼:<input type="password" id="pwd" name="password"></p>
       <p><input type="submit" value=https://www.cnblogs.com/zzy8080/p/"登入"/></p>
   </form>
</body>
</html>

創建server3

獲取來自瀏覽器的請求資訊

//獲取來自瀏覽器的請求資訊
is = client.getInputStream();
byte[] buf = new byte[20480];
int len = is.read(buf);
System.out.println(new String(buf,0,len));

對web瀏覽器做出回應

添加引數

String CRLF="\r\n";
String BLANK=" ";
InputStream is = null;
/**對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);
//2通過輸出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
bw.write(sb.toString());
bw.flush();
bw.close();

整合server3

public class Server3 {
   public static void main(String[] args) {
       //1.創建ServerSocket物件
       ServerSocket server = null;
       Socket client =null;
       String CRLF="\r\n";
       String BLANK=" ";
       InputStream is = null;
       try {
           server = new ServerSocket(8888);
           //2.監聽是否有客服端發送請求
           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);
           //2通過輸出流
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           //6.關閉流
           IOClose.closeAll(is,client,server);
      }
?
?
  }
}

手寫服務器 整體架構,撰寫XML檔案

創建Request,Response,Server,WebApp(在server包下)

創建Servlet,LoginServlet(在servlet包下)

創建IOCloseUtil(在util包下)

創建web.xml(在WEB_INFO包下)

<?xml version="1.0" encoding="UTF-8"?>
<web-app >
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/login</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/log</url-pattern>
   </servlet-mapping>
?
</web-app>

創建Entity,Mapping,ServletContext,WebDom4j,創建IOClose在util包下

配置決議XML檔案

補充物體類

package com.feng.server;
?
public class Entity {  //servlet-name或每一個servlet-name所對應得物體類
   private String name;
   private String clazz;
?
   public Entity() {
  }
?
   public Entity(String name, String clazz) {
       this.name = name;
       this.clazz = clazz;
  }
?
   public 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;
  }
}

補充Mapping類

package com.feng.server;
?
import java.util.ArrayList;
import java.util.List;
?
public class Mapping { //映射關系,多個路徑可以訪問資源
   private String name; //servlet-name
   private List<String> urlPattern;//url-pattern
?
   public 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() {
       this.urlPattern = new ArrayList<String>();
  }
?
   public Mapping(String name, List<String> urlPattern) {
       this.name = name;
       this.urlPattern = urlPattern;
  }
}

配置dom4j

package com.feng.server;
?
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
?
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
?
public class WebDom4j { //用于決議xml
   private List<Entity> entityList; //用于儲存物體類,每一個物體類一個servlet-name對應一個servlet-class
   private List<Mapping> mappingList;//用于儲存映射類,每一個servlet-name對應一個url-pattern
public 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物件的方法
public Document getDocument(){
?
   try {
       //創建SAXReader物件
       SAXReader reader = new SAXReader();
       //呼叫read方法
       return reader.read(new File("web/WEB-INF/web.xml"));
  } catch (DocumentException e) {
       e.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-class
       for (Iterator<Element> subIte = subElement.elementIterator(); subIte.hasNext();) {
           Element ele = subIte.next(); //servlet-name與servlet-class都有可能
           if ("servlet-name".equals(ele.getName())) {
               ent.setName(ele.getText());
          } else if ("servlet-class".equals(ele.getName())) {
               ent.setClazz(ele.getText());
          }
      }
       entityList.add(ent);//放到集合中
  }
   //測驗
  /* for (Entity entity : entityList) {
       System.out.println(entity.getName() + "\t" + entity.getClazz());
   }*/
?
   //決議servlet-mapping
?
   for (Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();){
       Element subEle = ite.next();//得到每一個servlet-mapping
       //創建一個mapping物件
       Mapping map = new Mapping();
       //決議mapping下面每一個子元素
       for (Iterator<Element> subIte = subEle.elementIterator(); subIte.hasNext();){
           Element ele = subIte.next();//可能是name,也可能是url
           if ("servlet-name".equals(ele.getName())) {
               map.setName(ele.getText());
          } else if ("url-pattern".equals(ele.getName())) {
               //獲取集合物件,呼叫集合物件的添加方法,添加元素
               map.getUrlPattern().add(ele.getText());
          }
      }
       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());
  }
}

更新撰寫XML

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/log</url-pattern>
       <url-pattern>/login</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>register</servlet-name>
       <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>register</servlet-name>
       <url-pattern>/reg</url-pattern>
       <url-pattern>/regis</url-pattern>
       <url-pattern>/register</url-pattern>
   </servlet-mapping>
 
</web-app>

撰寫servletContext Servlet 背景關系,容器用于存盤映射關系

package com.feng.server;
?
import java.util.HashMap;
import java.util.Map;
?
/**
*ServletContext 背景關系 就是一個容器
?
*/
public class ServletContext { //Entity與Mapping之間的映射關系
    private Map<String, String> servlet;//key是servlet-name(物體類中的name),值servlet-class,物體類中的值
    private Map<String, String> mapping;//key是url-pattern(Map中的每一個元素),值servlet-name,物體類中的name
?
public 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>();
}
}

撰寫WebAPP 初始化程式資料

package com.feng.server;
?
import com.feng.servlet.Servlet;
?
import java.util.List;
import java.util.Map;
?
public class WebApp {  //應用程式
   private static ServletContext context;
   static {
       context = new ServletContext();
       //分別獲取對應關系的Map集合
       Map<String, String> servlet = context.getServlet();
       Map<String, String> mapping = context.getMapping();
       //創建決議XML檔案物件
       WebDom4jTest web = new WebDom4jTest();
       //決議xml
       web.parse(web.getDocument());
       //獲取決議xml之后的List集合
       List<Entity> entityList = web.getEntityList();
       List<Mapping> mappingList = web.getMappingList();
?
       //將List集合儲存到map集合中
       for (Entity entity : entityList) {
           servlet.put(entity.getName(),entity.getClazz());
      }
       //System.out.println(servlet);
       for (Mapping map : mappingList) {
           //遍歷url-pattern的集合
           List<String> urlPattern = map.getUrlPattern();
           for (String s : urlPattern) {
               mapping.put(s,map.getName());
          }
      }
       //System.out.println(mapping);
  }
?
   /*
   * 根據url創建不同的Servlet物件
   * */
   public static Servlet getServlet(String url){
       if (url ==null||url.trim().equals("")){
           return null;
      }
       try {
       //如果url正確
       //根據url的key獲取servlet-name的值
       String servletName = context.getMapping().get(url);
       //根據servlet-name找到對應得servlet-class
       String servletClass = context.getServlet().get(servletName);
       //得到的是一個完整的包+類名的字串
?
       //使用反射創建servlet物件
       Class<?> clazz = Class.forName(servletClass);
       Servlet servlet = (Servlet) clazz.newInstance();
       return servlet;
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      } catch (InstantiationException e) {
           e.printStackTrace();
      } catch (IllegalAccessException e) {
           e.printStackTrace();
      }
       return null;
  }
   public static void main(String[] args) {
       System.out.println(getServlet("/log"));
       System.out.println(getServlet("/login"));
  }
}
?

撰寫服務

?
public class Server { //服務器,用于啟動或停止服務
   private ServerSocket server;
?
   public static void main(String[] args) {
       Server server = new Server();//創建服務器
       server.start();
  }
?
   private void start() {
       this.start(8888);
  }
?
   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//呼叫接受請求的方式
      } catch (IOException e) {
           e.printStackTrace();
      }
  }
?
   private void receive() {
?
       try {
         
               //1監聽
               Socket client = server.accept();
               //創建執行緒類
               Dispatcher dis = new Dispatcher(client);
               //創建代理執行緒
               new Thread(dis).start();
           
           //獲取用戶的請求
           /**InputStream is = client.getInputStream();
           byte[] buf = new byte[20480];
           int len = is.read(buf);
           System.out.println(new String(buf, 0, len));*/
            //封裝請求資訊
           Request req = new Request(client.getInputStream());
           req.show();
         
      } catch (IOException e) {
           e.printStackTrace();
      }
?
  }
   public void stop(){
?
  }
}
?

撰寫Request

package com.feng.server;
?
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.PrivateKey;
import java.util.*;
?
public class Request { //請求
?
   //輸入流
   private InputStream is;
   private String requestInfo; //請求字串,請求方式,請求路徑,引數,協議,協議版本,請求正文,,
   private String method;//請求的方式
   private String url;//請求的路徑
?
   public String getUrl() {
       return url;
  }
?
   /*
   * 輸入框的name為key,值為value
   * */
   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();
  }
   //分解請求資訊的方法
   /**
   * 請求方式
   * 請求路徑
   * 請求的引數
   * */
   public 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可能包含的引數,也可能不包含的引數post
       String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
       //判斷請求方式是GET或POST
       if ("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);
  }
?
 
}
?

撰寫login.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <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=https://www.cnblogs.com/zzy8080/p/"ball"/>足球
                <input type="checkbox" name="hobby" value=https://www.cnblogs.com/zzy8080/p/"read"/>讀書
               <input type="checkbox" name="hobby" value=https://www.cnblogs.com/zzy8080/p/"paint"/>畫畫
       </p>
       <p><input type="submit" value=https://www.cnblogs.com/zzy8080/p/"登入"></p>
   </form>
</body>
</html>

儲存引數,處理中文

/**
  *username = admin
   * pwd = 123
   * hobby =ball
   * hobby = paint
   * */
  public void parseParam(String prarString){
      String[] token = prarString.split("&");
      for (int i=0;i<token.length;i++){
          String keyValues = token[i];
          String[] keyValue = keyValues.split("=");//把=分割掉,得到K和V
          if (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獲取多個值
   public String [] getParamterValues(String name) {
      //根據key獲取value
       List<String> values = parameterMapValues.get(name);
       if (values == null ){
           return null;
      } else {
           return values.toArray(new String[0] );
      }
  }
   public 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) {
               e.printStackTrace();
          }
           return null;
      }
 
?
   public static void main(String[] args) {
       Request req = new Request();
       //呼叫分解引數的方法
       req.parseParam("username=中文加密&pwd=123&hobby=ball&hobby=read");
       System.out.println(req.parameterMapValues);
?
       //呼叫獲取多個值的方法
       String[] str = req.getParamterValues("hobby");
       for (String string : str) {
           System.out.println(string);
      }
       //呼叫單個獲取值的方法
       System.out.println(req.getParamter("pwd"));
  }

加到Server類中,測驗回應

  //封裝請求資訊
           Request req = new Request(client.getInputStream());
           //req.show();
           /**
            * 做出回應
            * */
           StringBuilder sb = new StringBuilder();
           sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
           sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
           //內容
           String str = "<html><head><title>回應結果</title></head><body>成功</body></html>";
           sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
           sb.append("\r\n");
           sb.append(str);
?
           //通過輸出流發送出去
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();

撰寫Response

package com.feng.server;
import com.feng.util.IOCloseUtil;
import java.io.*;
?
public class Response { //回應
   private StringBuilder headInfo;  //回應頭
   private StringBuilder content; //回應內容
   private int length; //回應內容的長度
?
   //流
   private BufferedWriter bw;
?
   //兩個常量,換行和空格
   private static final String CRLF="\r\n";  //換行
   private static final String BLANK=" ";  //空格
?
   //構造方法
   public Response() {
       headInfo= new StringBuilder();
       content = new StringBuilder();
  }
   //帶構造方法
?
   public Response(OutputStream os) {
       this();//呼叫本類的無參構造方法
       try {
           bw = new BufferedWriter(new OutputStreamWriter(os,"utf-8"));
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
  }
   //構造正文部分
   public Response print(String info){
       content.append(info);
       try {
           length+= info.getBytes("utf-8").length;
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
       return this;
  }
   public Response printLn(String info){
       content.append(info).append(CRLF);
       try {
           length+=(info+CRLF).getBytes("utf-8").length;
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
       return this;
  }
?
   //構造回應頭
   private void createHeadInfo(int code){
       headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
       switch (code){
           case 200:
               headInfo.append("OK");
               break;
           case 500:
               headInfo.append("SERVER ERROR");
           default:
               headInfo.append("NOT FOUND");
               break;
      }
       headInfo.append(CRLF);
       headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
       headInfo.append("Content-Length:"+length).append(CRLF);
       headInfo.append(CRLF);
  }
?
   /**
    * 推送到客戶機的瀏覽器
    * */
   public void pushToClient(int code){
       if (headInfo==null){
           code=500;
      }
       //呼叫本類中的構造回應頭
       this.createHeadInfo(code);
       try {
           bw.write(headInfo.toString());
           bw.write(content.toString());
           bw.flush();
           this.close();
      } catch (IOException e) {
           e.printStackTrace();
      }
?
  }
?
   public void close() {
       IOCloseUtil.closeAll(bw);
  }
}
?

然后再把Server里面做出回應那段代碼注釋掉

package com.feng.server;
?
import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;
?
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 Server { //服務器,用于啟動或停止服務
   private ServerSocket server;
 
   public static void main(String[] args) {
       Server server = new Server();//創建服務器
       server.start();
  }
?
   private void start() {
       this.start(8888);
  }
?
   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//呼叫接受請求的方式
      } catch (IOException e) {
            e.printStackTrace();
      }
  }
?
   private void receive() {
?
       try {
           //1監聽
           Socket client = server.accept();
           //創建執行緒類
           Dispatcher dis = new Dispatcher(client);
           //創建代理執行緒
           new Thread(dis).start();
           
           //獲取用戶的請求
          /* InputStream is = client.getInputStream();
           byte[] buf = new byte[20480];
           int len = is.read(buf);
           System.out.println(new String(buf, 0, len));*/
          //封裝請求資訊
           Request req = new Request(client.getInputStream());
           //req.show();
           /**
            * 做出回應
            * */
           /*StringBuilder sb = new StringBuilder();
           sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
           sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
           //內容
           String str = "<html><head><title>回應結果</title></head><body>成功</body></html>";
           sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
           sb.append("\r\n");
           sb.append(str);
?
           //通過輸出流發送出去
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();*/
           Response rep = new Response(client.getOutputStream());
           Servlet servlet = WebApp.getServlet(req.getUrl());
           int code=200;
           if (servlet ==null){
               code=404;
          }
           //呼叫Servlet中的服務方法
           try {
               servlet.service(req,rep);
          } catch (Exception e) {
               e.printStackTrace();
          }
           rep.pushToClient(code);
           IOCloseUtil.closeAll(client);  //單執行緒已被洗掉
      } catch (IOException e) {
           e.printStackTrace();
      }
?
  }
   public void stop(){
?
  }
}
?

封裝Response

撰寫servlet

public abstract class Servlet { //是所有請求servlet的父類
   public void service(Request req, Response rep) throws Exception {
       this.deGet(req,rep);
       this.doPost(req,rep);
  }
?
   public abstract void deGet(Request req, Response rep) throws Exception;
   public abstract void doPost(Request req, Response rep) throws Exception;
?
}

撰寫LoginServlet

public class LoginServlet extends Servlet {
   @Override
   public void deGet(Request req, Response rep) throws Exception {
       //獲取請求引數
       String name = req.getParamter("username");
       String pwd = req.getParamter("pwd");
?
       if (this.login(name,pwd)) {
           //呼叫回應中的構建內容的方法
           rep.printLn(name+"登入成功");
      }else {
           rep.printLn(name+"登錄失敗,對不起,賬號和密碼不準確");
      }
  }
   private boolean login(String name,String pwd){
       if ("admin".equals(name)&&"123".equals(pwd)) {
           return true;
      }
       return false;
  }
?
   @Override
   public void doPost(Request req, Response rep) throws Exception {
?
  }
}
?

封裝分發器,實作多執行緒

package com.feng.server;
?
import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;
?
import java.io.IOException;
import java.net.Socket;
?
/**
* 一個請求與回應就是一個Dispatcher
*
* @author asus
* */
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;
      }
?
  }
?
   @Override
   public void run() {
       //根據不同的url創建指定的servlet物件
       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);
  }
}
?

實作多執行緒

package com.feng.server;
?
import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;
?
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 Server { //服務器,用于啟動或停止服務
   private ServerSocket server;
   private boolean isShutDown=false; //默認沒有出錯
?
   public static void main(String[] args) {
       Server server = new Server();//創建服務器
       server.start();
  }
?
   private void start() {
       this.start(8888);
  }
?
   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//呼叫接受請求的方式
      } catch (IOException e) {
           isShutDown=true;
      }
  }
?
   private void receive() {
?
       try {
           while (!isShutDown){
               //1監聽
               Socket client = server.accept();
               //創建執行緒類
               Dispatcher dis = new Dispatcher(client);
               //創建代理執行緒
               new Thread(dis).start();
          }
         
      } catch (IOException e) {
           e.printStackTrace();
      }
?
  }
   public void stop(){
isShutDown=true;
IOCloseUtil.closeAll(server);
  }
}
?

可能會出現空指標例外

缺少favicon映射類,在xml里面配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/log</url-pattern>
       <url-pattern>/login</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>register</servlet-name>
       <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>register</servlet-name>
       <url-pattern>/reg</url-pattern>
       <url-pattern>/regis</url-pattern>
       <url-pattern>/register</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>favicon</servlet-name>
       <servlet-class>com.feng.servlet.FaviconServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>favicon</servlet-name>
       <url-pattern>/favicon.ico</url-pattern>
   </servlet-mapping>
?
</web-app>

添加FaviconServlet

package com.feng.servlet;
?
import com.feng.server.Request;
import com.feng.server.Response;
?
public class FaviconServlet extends Servlet {
   @Override
   public void deGet(Request req, Response rep) throws Exception {
?
  }
?
   @Override
   public void doPost(Request req, Response rep) throws Exception {
?
  }
}
?

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/191118.html

標籤:Java

上一篇:Docker簡介[1]

下一篇:Centos7安裝Java8

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more