• 手写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="
    ";//换行
     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="
    ";//换行
     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
  • 相关阅读:
    002 下载文件
    001 okhttp3的POST使用
    000 okhttp3的Get使用
    008 webpack的其他使用方式
    007 webpack基本的用法
    three.js 3d三维网页代码加密的实现方法
    物联网开发技术栈
    9个顶级开发IoT项目的开源物联网平台
    hibernate缓存机制详细分析
    机器学习大牛最常用的5个回归损失函数,你知道几个?
  • 原文地址:https://www.cnblogs.com/bfcs/p/10848129.html
Copyright © 2020-2023  润新知