1.预备知识_Socket知识回顾

1.1编写服务器用到的知识点

1)Socket编程
2)HTML
3)HTTP协议
4)反射
5)XML解析
6)服务器编写

1.2复习Socket编程

1)C/S结构:客户端与服务器端一次双向通信
2)B/S结构:浏览器与服务器

httpClient_1

Client.java

package com.bjsxt.test;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;public class Client {public static void main(String[] args) {//(1)创建Socket对象Socket client=null;//(2)获取输出流-->请求DataOutputStream dos=null;DataInputStream dis=null;try {client = new Socket("localhost", 8888);dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("我是客户端:服务器你好!");//(3)获取输入流-->响应dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(4)关闭流IOClose.closeAll(dis,dos,client);}}
}

IOClose.java

package com.bjsxt.test;import java.io.Closeable;
import java.io.IOException;public class IOClose {//关闭全部的工具类public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

httpServer_1

Server.java

package com.bjsxt.server;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;//(3)获取Scoket对象//(4)获取输入流  -->得到客户端的请求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)获取输出流-->给客户端响应结果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客户端您好:我是服务器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(dos,dis,client,server);}}
}

IOClose.java

package com.bjsxt.server;import java.io.Closeable;
import java.io.IOException;public class IOClose {//关闭全部的工具类public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

Server2.java

package com.bjsxt.server;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//获取来自浏览器的请求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(br,client,server);}}
}

2. 预备知识_HTML 简单入门

2.1HTML

HTML: HyperText Markup Language 超文本标记语言用于描述网页文档的一种标记语言

2.2 第一个 HTML 文档

<html><head><title>第一个 HTML</title></head><body><h1>hello world</h1></body>
</html>

2.3 表单 form

作用:与用户之间进行交互
method:请求方式 get/post
get 数据量小,安全性低,默认方式
post 数据量大,安全性高
action:请求的服务器路径

<form action="http://localhost:8888/index.html" method="post"><p>用户名:<input type="text" name="uname" id="name"/></p><p>密码 :<input type="password" name="pwd" id="pass"/></p><p><input type="submit" value="登录" /> </p>
</form>

id : (用户的的浏览器在文档里区分唯一性)前端区分唯一性,js 中
name:名称,后端(服务器)区分唯一性,获取值,只要提交数据
给后台(服务器)必须存在 name

httpServer_2

Server.java

package com.bjsxt.server;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;//(3)获取Scoket对象//(4)获取输入流  -->得到客户端的请求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)获取输出流-->给客户端响应结果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客户端您好:我是服务器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(dos,dis,client,server);}}
}

Server2.java

package com.bjsxt.server;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//获取来自浏览器的请求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(br,client,server);}}
}

Server3.java

package com.bjsxt.server;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server3 {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;InputStream is=null;try {server = new ServerSocket(8888);client = server.accept();//获取来自浏览器的请求信息is=client.getInputStream();byte [] buf=new byte[20480];int len=is.read(buf);System.out.println(new String(buf,0,len));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(is,client,server);}}
}

IOClose.java

package com.bjsxt.server;import java.io.Closeable;
import java.io.IOException;public class IOClose {//关闭全部的工具类public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

index.html

<html><head><title>我的第一个html</title></head><body><h1>hello world</h1><form action="http://localhost:8888/log" method="get"><p>用户名:<input  type="text" id="uname" name="username" /></p><p>密码:<input  type="password" id="pwd" name="password"/></p><p>兴趣爱好<input type="checkbox" name="hobby" value="ball"/>球 <input type="checkbox" name="hobby" value="read"/>读书<input type="checkbox" name="hobby" value="paint"/>画画</p><p><input type="submit" value="登录"/></p></form></body></html>

3.预备知识_HTTP协议入门

3.1协议

1)应用层:HTTP、FTP、TELNET、SNMP、DNS
2)传输层:TCP、UDP
3) 网络层:IP

3.2HTTP协议简介

HTTP:Hypertext Transfer Protocol超文本传输协议,是网络应用层的协议,建立在TCP/IP协议基础上,HTTP使用可靠的TCP连接,默认端口为80.
用户打开web浏览器(常见的HTTP客户端),输入URL地址,就能接收到远程HTTP服务器端发送过来的网页,即HTTP遵循请求(Request)/应答(Response)模型。web浏览器向web服务器发送请求,web服务器处理请求并返回适当的应答,所有HTTP连接都被构造成一套请求与应答。

HTTP客户端和服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写,如用.NET 编写的客户程序与用Java编写的服务器程序顺利通信,就必须遵守HTTP协议,这样才能彼此都懂对方发送的消息,HTTP协议严格规定了HTTP请求和HTTP响应的数据格式。

3.3HTTP请求格式

1)请求方式、URL(统一资源定位符)、HTTP协议/版本
2)请求头 Request Header
a)请求头包含许多有关客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所有的语言,请求正文的长度等。
3)请求正文 Requet Content (只有在 post 方式才有)
请求头和请求正文之间必须有符号行(回车符或行结束符),将请求头与请求正文分开,这个行非常重要,它表示 请求头已结束,接下来的是请求正文。通常post方式的数据存放于此,请求正文中可以包含客户提交的查询字符串等信息。在实际应用中,HTTP请求正文可以包含更多的内容。

3.4HTTP 响应格式

  1. HTTP 协议版本、状态代码、描述
  2. 响应头(Response Head)
  3. 响应正文(Respose Content)

httpServer_2

Server.java

package com.bjsxt.server;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;//(3)获取Scoket对象//(4)获取输入流  -->得到客户端的请求DataInputStream dis=null;DataOutputStream dos=null;try {server = new ServerSocket(8888);client = server.accept();dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF());//(5)获取输出流-->给客户端响应结果dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("客户端您好:我是服务器,我收到了你的信息");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(dos,dis,client,server);}}
}

Server2.java

package com.bjsxt.server;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server2 {public static void main(String[] args) {//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;BufferedReader br=null;try {server = new ServerSocket(8888);client = server.accept();//获取来自浏览器的请求信息br=new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));String str=null;while((str=br.readLine()).length()>0){System.out.println(str);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(br,client,server);}}
}

Server3.java

package com.bjsxt.server;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;public class Server3 {public static void main(String[] args) {String CRLF="\r\n";//换行String BLANK=" ";//空格//(1)创建ServerSocket对象ServerSocket server=null;//(2)监听是否有客户端发送请求Socket client=null;InputStream is=null;try {server = new ServerSocket(8888);client = server.accept();//获取来自浏览器的请求信息is=client.getInputStream();byte [] buf=new byte[20480];int len=is.read(buf);System.out.println(new String(buf,0,len));/**对Web浏览器的请求作出响应*/StringBuilder sb=new StringBuilder();StringBuilder sbContent=new StringBuilder();//响应的文本sbContent.append("<html><head><title>响应结果</title></head>");sbContent.append("<body>登录成功</body></html>");//(1)拼接响应头sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");sb.append(CRLF);//换行sb.append("Content-Type: text/html;charset=utf-8");sb.append(CRLF);//换行sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);sb.append(CRLF);//换行,代表响应头与响应的正文部门之间的空行sb.append(sbContent);//通过流输出 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));bw.write(sb.toString());bw.flush();bw.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{//(6)关闭流IOClose.closeAll(is,client,server);}}
}

IOClose.java

package com.bjsxt.server;import java.io.Closeable;
import java.io.IOException;public class IOClose {//关闭全部的工具类public static void closeAll(Closeable...c){for (Closeable closeable : c) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

4.Tomcat服务器的快速使用

4.1Tomcat简介

Tomcat是在SUN公司的JSWDK( JavaServer Web
DevelopmentKit ,是 SUN 公司推出的小型 Servlet/JSP 调试工
具)的基础上发展起来的一个优秀的Servlet容器,Tomcat本身完全用Java语言编写。

4.2Tomcat使用

1)配置Tomcat
a) JAVA_HOME Java JDK 的根目录

b) CATALINA_HOME Tomcat 根目录

bin:存放Tomcat脚本目录

  1. 启动和关闭 Tomcat
    启动 Tomcat 服务器:startup.bat
    关闭 Tomcat 服务器:shutdown.bat

    conf:存放配置文件


conf—>server.xml:存放配置信息
存放配置端口信息


lib:存放Tomcat运行所需要的jar包

logs:存放日志文件

temp:存放Tomcat临时文件

webapps:部署项目到服务器
在 webapps 目录下新建目录存放.html 面页
访问页面

**work:**工作目录,将JSP文件的Java文件转换为class文件的工作目录。

部署项目到Tomcat
在webapps目录下创建自己的文件夹

在该文件夹下新建一个HTML文档

index.html

<html><head><title>发布到Tomcat中的项目的主页</title></head><body><h1>hello tomcat</h1></body>
</html>

bin目录下双击

启动Tomcat服务

在地址栏输入http://locathost:8080/myfirst/index.html

5.Tomcat服务器运行原理

5.1Tomcat的运行原理

客户浏览器发出要求访问特定德Servlet的请求。
1)Tomcat服务器接收到客户请求并解析
2)Tomcat服务器创建一个ServletRequest对象,在ServletRequest对象中包含了客户请求信息及其他关于客户的信息,如请求头,请求正文,以及客户机的IP地址等。
3)Tomcat服务器创建一个ServletResponse 对象
4)Tomcat服务器调用客户所请求的Servlet的service服务方法,并且把ServletRequest对象和ServletResponse对象做为参数传给该服务方法。
5) Servlet 从 ServletRequest 对象中可获取客户的请求信息。
6) Servlet 利用 ServletResponse 对象来生成响应结果。
7) Tomcat 服务器把 Servlet 生成的响应结果发送给客户。
8)

6.预备_http工具查看网络交互过程

6.1下载并安装

httpwatch安装包:https://pan.baidu.com/s/1ogcMmZSutx6WvIvh2VNpGg 密码:ggv4

6.2HttpWatch 的使用

  1. IE 浏览器查看浏览器栏HttpWatch Professional

    最新版已经可以支持Google、Microsoft Edge等浏览器了下面是官方使用文档

  2. 输入网址

  3. 分析数据

来源:https://blog.csdn.net/cldsj

HttpWatch学习笔记一
HttpWatch学习笔记二
HttpWatch学习笔记三

HttpWatch功能详细介绍
来源:https://www.cnblogs.com/Chilam007/p/6947235.html

7. 手写服务器_ 整体架构和接口_ 编写 XML配置文件

7.1 搭建项目框架

7.2 编写 XML 文档

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

7.3 编写 IOCloseUtil 类

package com.bjsxt.util;import java.io.Closeable;
import java.io.IOException;public class IOCloseUtil {//用于关系流public static void closeAll(Closeable...close){for (Closeable closeable : close) {if (closeable!=null) {try {closeable.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

8.DOM4J 解析 XML 配置文件

8.1Entity 实体类的编写

package com.bjsxt.server;
/*** <servlet><servlet-name>login</servlet-name><serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class></servlet>* @author Administrator**/
public class Entity { /**servlet-name和一个servlet-name所对应的一个实体类*/private String name;//servlet-nameprivate String clazz;//servlet-classpublic String getName() {return name;}public void setName(String name) {this.name = name;}public String getClazz() {return clazz;}public void setClazz(String clazz) {this.clazz = clazz;}public Entity(String name, String clazz) {super();this.name = name;this.clazz = clazz;}public Entity() {super();}}

8.2Mapping 实体类的编写

package com.bjsxt.server;import java.util.ArrayList;
import java.util.List;/*** <servlet-mapping><serlvet-name>login</serlvet-name><url-pattern>/login</url-pattern><url-pattern>/log</url-pattern></servlet-mapping>* @author Administrator**/
public class Mapping {//映射关系,多个路径访问共享资源private String name;//servlet-nameprivate List<String> urlPattern;//url-patternpublic String getName() {return name;}public void setName(String name) {this.name = name;}public List<String> getUrlPattern() {return urlPattern;}public void setUrlPattern(List<String> urlPattern) {this.urlPattern = urlPattern;}public Mapping(){urlPattern=new ArrayList<String>();}public Mapping(String name, List<String> urlPattern) {super();this.name = name;this.urlPattern = urlPattern;}}

8.3 解析 XML 文件

package com.bjsxt.server;import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;public class WebDom4j {//用于解析XMLprivate List<Entity> entityList;//用于存储是N多Entity,而每一个Entity都是servlet-name与servlet-classprivate List<Mapping> mappingList;//用于存储N多Mapping,而每一个Mapping都是一个servlet-name与N多个url-patternpublic List<Entity> getEntityList() {return entityList;}public void setEntityList(List<Entity> entityList) {this.entityList = entityList;}public List<Mapping> getMappingList() {return mappingList;}public void setMappingList(List<Mapping> mappingList) {this.mappingList = mappingList;}//构造方法public WebDom4j() {entityList=new ArrayList<Entity>();mappingList=new ArrayList<Mapping>();}//获取Document对象的方法private Document getDocument(){try {//(1)创建SAXReader对象SAXReader reader=new SAXReader();//(2)调用read方法return reader.read(new File("src/WEB_INFO/web.xml"));} catch (DocumentException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}public void parse(Document doc){//(1)获取根元素Element root=doc.getRootElement(); //web-app//(2)获取servlet子元素for(Iterator<Element> ite=root.elementIterator("servlet");ite.hasNext();){Element subElement=ite.next();//得到每一个servlet//创建一个实体类Entity ent=new Entity(); //用于存储servlet-name与servlet-classfor(Iterator<Element> subIte=subElement.elementIterator();subIte.hasNext();){Element ele=subIte.next(); //可能是servlet-name,也可能是servlet-classif("servlet-name".equals(ele.getName())){ent.setName(ele.getText()); //给实体类中的name赋值}else if("serlvet-class".equals(ele.getName())){ent.setClazz(ele.getText());}}//将Entity添加到集合中entityList.add(ent);}//测试/**for (Entity entity : entityList) {System.out.println(entity.getName()+"\t"+entity.getClazz());}*///解析servlet-mappingfor(Iterator<Element> ite=root.elementIterator("servlet-mapping");ite.hasNext();){Element subEle=ite.next();//得到每一个servlet-mapping//创建一个Mapping类的对象Mapping map=new Mapping();//解析servlet-mapping下的子元素for(Iterator<Element> subIte=subEle.elementIterator();subIte.hasNext();){Element ele=subIte.next();  //servlet-name,也有可能是url-patternif("serlvet-name".equals(ele.getName())){map.setName(ele.getText());}else if("url-pattern".equals(ele.getName())){//获取集合对象,调用集合对象的添加方法,添加元素素map.getUrlPattern().add(ele.getText());}}//Mapping添加到集合中mappingList.add(map);}//测试for (Mapping m : mappingList) {System.out.println(m.getName());for(String s:m.getUrlPattern()){System.out.println(s);}}}//用于测试public static void main(String[] args) {WebDom4j web=new WebDom4j();web.parse(web.getDocument());}
}

9. 反射创建 Servlet 对象

9.1 编写 ServletContext 类

Servlet 上下文,就是一个容器,用于存储映射关系

package com.bjsxt.server;import java.util.HashMap;
import java.util.Map;/*** Servlet上下用,就是一个容器,* @author Administrator**/
public class ServletContext { //Entity与Mapping的映射关系private Map<String,String> servlet;//key是servlet-name  (Entity中的name),值serlvet-class Entity中的clazzprivate Map<String,String> mapping;//key是url-pattern (Mapping中的List集合中的每一个元素),value是serlvet-name,是Mapping中的namepublic Map<String, String> getServlet() {return servlet;}public void setServlet(Map<String, String> servlet) {this.servlet = servlet;}public Map<String, String> getMapping() {return mapping;}public void setMapping(Map<String, String> mapping) {this.mapping = mapping;}public ServletContext() {servlet=new HashMap<String,String>();mapping=new HashMap<String,String>();}
}

9.2 编写 WebApp 类

  1. 初始化程序运行的数据
  2. 根据不同的 url 创建所请求的 Servlet 对象
package com.bjsxt.server;import java.util.List;
import java.util.Map;import com.bjsxt.servlet.Servlet;public class WebApp {//App的意思是应用程序private static ServletContext contxt;static{contxt=new ServletContext();//分别获取对应关系的Map集合Map<String,String> servlet=contxt.getServlet();Map<String,String> mapping=contxt.getMapping();//创建解析XML文件对象WebDom4j web=new WebDom4j();web.parse(web.getDocument());//解析xml//获取解析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对象* @param url* @return*/public static Servlet getServlet(String url){if (url==null||url.trim().equals("")) {return null;}//调用无参构造方法创建Servlet对象try {//如果url正确//根据url的key获取servlet-name的值 /log=login, /reg=registerString servletName=contxt.getMapping().get(url);//根据servletName得到对应的servlet-classString servletClass=contxt.getServlet().get(servletName);  //得到的是一个完整个的包名+类的字符串//使用反射创建 Servlet对象Class<?> clazz=Class.forName(servletClass);Servlet servlet = (Servlet) clazz.newInstance();return servlet;} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}//测试public static void main(String[] args) {System.out.println(getServlet("/log"));System.out.println(getServlet("/login"));}
}

10. 封装 Request_method_url

10.1 编写 Server

  1. 启动服务
  2. 关闭服务
package com.bjsxt.server;import java.io.IOException;
import java.io.InputStream;
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();}public void start(){this.start(8888);}public void start(int port){try {server=new ServerSocket(port);this.receive(); //调用接收请求信息的方法} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private void receive() {try {//(1)监听Socket client=server.accept();//获取用户的请求/**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) {// TODO Auto-generated catch blocke.printStackTrace();}}public void stop(){}
}

10.2 编写 HTML

login.html

<html><head><title>登录</title></head><body><form action="http://localhost:8888/log" method="post"><p>用户名:<input  type="text" name="username" id="username"/></p><p>密码:<input  type="password" name="pwd" id="password"/></p><p>爱好:<input  type="checkbox" name="hobby" value="ball"/>足球<input  type="checkbox" name="hobby" value="read"/>读书<input type="checkbox" name="hobby" value="paint"/>画画</p><p><input  type="submit" value="登录"/></p></form></body>
</html>

10.3 封装 Request_method_url

package com.bjsxt.server;import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class Request {/*请求*/private InputStream is;//输入流private String requestInfo;//请求字符串,请求方式,请求的路径,参数,协议,协议版本,请求的正文。。。private String method;//请求的方式private String url;//请求的url//输入框的name为key,值为value/**  key: username    value  :bjsxt*  key:pwd          value:123*  key:hobby        value   :read,ball* */private Map<String,List<String>> parametermapValues;//参数private static final String CRLF="\r\n";//换行private static final String BLANK=" ";//空格//构造方法,初始化属性public Request() {parametermapValues=new HashMap<String,List<String>>();method="";url="";requestInfo="";}public Request(InputStream is){this();//调用本类无参的构造方法this.is=is;try {byte [] buf=new byte[20480];int len=this.is.read(buf);requestInfo=new String(buf,0,len);} catch (IOException e) {return;}//调用本类中的分解请求信息的方法this.parseRequestInfo();}//分解请求信息的方法/*** 请求方式* 请求路径* 请求的参数* */private void parseRequestInfo(){String paraString="";//用于存储请求参数//获取请求参数的第一行String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始,到第一个换行的位置//分解出请求方式int index=firstLine.indexOf("/");this.method=firstLine.substring(0, index).trim();//分解url  ,get可能包含参数,也可能不包含参数postString urlString= firstLine.substring(index,firstLine.indexOf("HTTP/")).trim();//判断请求方式是GET还 是POSTif("get".equalsIgnoreCase(this.method)){  //包含请求参数if (urlString.contains("?")) {String [] urlArray=urlString.split("\\?");this.url=urlArray[0];paraString=urlArray[1];}else{this.url=urlString;}}else{//post不包含请求参数this.url=urlString;paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();}if (paraString.equals("")) {return;}//请求参数//System.out.println(paraString);}//用于测试/*public void show(){System.out.println(this.url);System.out.println(this.method);}*/
}

11. 封装 Request_ 存储参数_ 处理中文

11.1 编写分解参数的方法

package com.bjsxt.server;import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class Request {/*请求*/private InputStream is;//输入流private String requestInfo;//请求字符串,请求方式,请求的路径,参数,协议,协议版本,请求的正文。。。private String method;//请求的方式private String url;//请求的url//输入框的name为key,值为value/**  key: username    value  :bjsxt*  key:pwd          value:123*  key:hobby        value   :read,ball* */private Map<String,List<String>> parametermapValues;//参数private static final String CRLF="\r\n";//换行private static final String BLANK=" ";//空格//构造方法,初始化属性public Request() {parametermapValues=new HashMap<String,List<String>>();method="";url="";requestInfo="";}public Request(InputStream is){this();//调用本类无参的构造方法this.is=is;try {byte [] buf=new byte[20480];int len=this.is.read(buf);requestInfo=new String(buf,0,len);} catch (IOException e) {return;}//调用本类中的分解请求信息的方法this.parseRequestInfo();}//分解请求信息的方法/*** 请求方式* 请求路径* 请求的参数* */private void parseRequestInfo(){String paraString="";//用于存储请求参数//获取请求参数的第一行String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始,到第一个换行的位置//分解出请求方式int index=firstLine.indexOf("/");this.method=firstLine.substring(0, index).trim();//分解url  ,get可能包含参数,也可能不包含参数postString urlString= firstLine.substring(index,firstLine.indexOf("HTTP/")).trim();//判断请求方式是GET还 是POSTif("get".equalsIgnoreCase(this.method)){  //包含请求参数if (urlString.contains("?")) {String [] urlArray=urlString.split("\\?");this.url=urlArray[0];paraString=urlArray[1];}else{this.url=urlString;}}else{//post不包含请求参数this.url=urlString;paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();}if (paraString.equals("")) {return;}//请求参数//System.out.println(paraString);//调用本类中分解请求参数的方法this.parseParam(paraString);}//用于测试/*public void show(){System.out.println(this.url);System.out.println(this.method);}*///username=bjsxt&pwd=123&hobby=ball&hobby=paint/*** username=bjsxt* pwd=123* hobby=ball* hobby=paint* * username=* @param prarString*/private void parseParam(String prarString){String [] token=prarString.split("&");for(int i=0;i<token.length;i++){String keyValues=token[i];String []keyValue=keyValues.split("=");  //username   bjsxt   pwd   123if (keyValue.length==1) {  //username=keyValue=Arrays.copyOf(keyValue, 2);keyValue[1]=null;}//将  表单元素的name与name对应的值存储到Map集合String key=keyValue[0].trim();String value=keyValue[1]==null?null:decode(keyValue[1].trim(), "utf-8");//放到集合中存储if (!parametermapValues.containsKey(key)) {parametermapValues.put(key, new ArrayList<String>());}List<String> values=parametermapValues.get(key);values.add(value);}}//根据表单元素的name获取多个值private String [] getParamterValues(String name){//根据key获取valueList<String> values=parametermapValues.get(name);if (values==null) {return null;}else{return values.toArray(new String [0] );}}private String getParamter(String name){//调用本类中根据name获取多个值的方法String [] values=this.getParamterValues(name);if (values==null) {return null;}else{return values[0];}}//处理中文,因类浏览器对中文进行了编码,进行解码private String decode(String value,String code){try {return URLDecoder.decode(value, code);} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}public static void main(String[] args) {Request req=new Request();//调用分解参数的方法req.parseParam("username=%E5%8C%97%E4%BA%AC%E5%B0%9A%E5%AD%A6%E5%A0%82&pwd=123&hobby=ball&hobby=paint");System.out.println(req.parametermapValues);//调用获取多个值的方法String [] str=req.getParamterValues("hobby");for (String string : str) {System.out.println(string);}//调用获取单个值的方法System.out.println(req.getParamter("pwd"));}}

11.2 编写根据页面上的 name 获取多个值的方法

11.3 编写根据页面上的 name 获取单个值的方法

11.4 编写解码的方法 1

1.5 测试

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=%E5%8C%97%E
4%BA%AC%E5%B0%9A%E5%AD%A6%E5%A0%82&rsv_pq=f65f15f40003a658&rsv_t=d74
7OilFeeFkf73QkinDYpKiB4y%2Ffj3mxWfE865IJ0VxoTk5Obwtc4z41pM&rqlang=cn&rsv_ente
r=1&rsv_sug3=19&rsv_sug1=21&rsv_sug7=101

12. 封装 Response

12.1 封装 Response

  1. 构造响应头
  2. 推送到客户端
package com.bjsxt.server;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;import com.bjsxt.util.IOCloseUtil;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) {headInfo=null;}}//构造正文部分public Response print(String info){content.append(info);try {length+=info.getBytes("utf-8").length;} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return this;}public Response println(String info){content.append(info).append(CRLF);try {length+=(info+CRLF).getBytes("utf-8").length;} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.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");break;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);}/*** 推送到客户机的浏览器* @param code*/public void pushToClient(int code){if (headInfo==null) {code=500;}try {//调用本类中的构造响应头this.createHeadInfo(code);bw.write(headInfo.toString());bw.write(content.toString());bw.flush();this.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void close(){IOCloseUtil.closeAll(bw);}
}

12.2 编写相应的 Servlet 构造响应内容

package com.bjsxt.servlet;import com.bjsxt.server.Request;
import com.bjsxt.server.Response;public abstract class Servlet { //是所有的请求的Servlet的父类public void service(Request req,Response rep) throws Exception{this.doGet( req, rep);this.doPost( req, rep);}public abstract void doGet(Request req,Response rep) throws Exception;public abstract void doPost(Request req,Response rep) throws Exception;
}

LogServlet.java

package com.bjsxt.servlet;import com.bjsxt.server.Request;
import com.bjsxt.server.Response;public class LoginServlet extends Servlet {@Overridepublic void doGet(Request req, Response rep) throws Exception {//获取请求参数String name=req.getParameter("username");String pwd=req.getParameter("pwd");if(this.login(name, pwd)){//调用响应中的构建内容的方rep.println(name+"登录成功");}else{rep.println(name+"登录失败,对不起,账号或密码不正确");}}private boolean login(String name,String pwd){if ("bjsxt".equals(name)&&"123".equals(pwd)) {return true;}return false;}@Overridepublic void doPost(Request req, Response rep) throws Exception {// TODO Auto-generated method stub}
}

12.3 启动服务器进行测试

13. 封装分发器_实现多线程

Dispatcher.java

package com.bjsxt.server;import java.io.IOException;
import java.net.Socket;import com.bjsxt.servlet.Servlet;
import com.bjsxt.util.IOCloseUtil;/*** 一个请求与响应就是一个Dispatcher* @author Administrator**/
public class Dispatcher implements Runnable {private Request req;private Response rep;private Socket client;private int code=200;//状态码//构造方法初始化属性public Dispatcher(Socket client) {//将局部变量的值赋给成员变量this.client=client;try {req=new Request(this.client.getInputStream());rep=new Response(this.client.getOutputStream());} catch (IOException e) {code=500;return ;}}@Overridepublic void run() {//根据不同的url创建指定的Servlet对象System.out.println(req.getUrl());Servlet servlet=WebApp.getServlet(req.getUrl());if (servlet==null) {this.code=404;}else{//调用相应的Servlet中的service方法try {servlet.service(req,rep);} catch (Exception e) {this.code=500;}}//将响应结果推送到客户机的浏览器rep.pushToClient(code);IOCloseUtil.closeAll(client);}}

14. 整合最终版

14.1 查缺补漏完善项目

FaviconServlet.java

package com.bjsxt.servlet;import com.bjsxt.server.Request;
import com.bjsxt.server.Response;public class FaviconServlet extends Servlet {@Overridepublic void doGet(Request req, Response rep) throws Exception {// TODO Auto-generated method stub}@Overridepublic void doPost(Request req, Response rep) throws Exception {// TODO Auto-generated method stub}}

15. 总结和期望

15.1 项目总结

涉及知识点

  1. 集合
  2. IO
  3. 多线程
  4. 网络编程
  5. 面向对象
  6. 反射
  7. XML
  8. HTML

15.2 项目思路

  1. 先分析
  2. 搭建项目框架
  3. 一步一步实现,先从会的开始实现
  4. 整体思路,宏观使用面向对象,微观使用面向过程
  5. 注重代码的调试

15.3 思想是从键盘中敲出来的

  1. 多注重实战
  2. 学知识不是目的,目的是对知识的综合运用,才能将知识
    转化为能力
  3. 不要气馁,每天进步一点点,人最大的敌人是自己,今天
    的自己比昨天的自己有进步,就是成功。
  4. 今天所有的付出,都会在明天以 RMB 的形式还给你。
  5. 加油!!!

附源码:
链接:https://pan.baidu.com/s/1upUHY0bGXmLfLZKOt5ICxg
提取码:pfz1

Java—手写服务器相关推荐

  1. java 手写 jvm高性能缓存

    java 手写 jvm高性能缓存,键值对存储,队列存储,存储超时设置 缓存接口 1 package com.ws.commons.cache; 2 3 import java.util.functio ...

  2. Java 手写一个SQL分页

    Java手写一个类似PageHelper的分页SQL 目前分页插件众所周知的莫过于和mybatis完美融合的PageHelper了,简单两行代码就实现了sql分页,配合PageInfo类,将数据总数量 ...

  3. Java手写线程池-第一代(原创)

    个人简介 作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门. 文章目录 个人简介 Java手写线程池(第一代) ...

  4. Java 手写签字去除背景 背景透明

    Java 手写签字去除背景 背景透明 /*** 白底照片去除白底 形成透明底图片* @param file 需要去除背景的图片* @param Path 去除背景后保存图片的路径* @return t ...

  5. 纯jsp实现评论功能_自己实现的java手写tomcat

    这是一个java写的模拟tomcat工作原理的demo,是一个极简的tomcat服务器,也是我们培训班(邦邦IT教育)的讲义,是整个j2ee培训的精髓,理解了这个demo其实后面的很多东西都是可以自学 ...

  6. 用Java手写一个微型下载资源网站

    文章目录 手写一个微型下载资源网站[Java实现用户注册.登陆.下载功能] 一.技术栈 二.流程分析图 注册 登陆 下载 三.案例实现效果 首页 注册 登陆 下载网主页 壁纸下载 书籍下载 影视下载 ...

  7. java手写一个分页的方法_java web手写实现分页功能

    现在很多流行的框架,都可以很快的把分页效果做出来,但是作为一名程序员你必须得知道手写分页的流程: 场景效果: 一.分页的思路 首先我们得知道写分页代码的思路,保持思路清晰,才能行云流水的去写代码,其实 ...

  8. java手写实现BST

    难易程度:★★★ 重要性:★★★★★ 今日头条的面试中有过要求:手写实现BST import java.util.*;public class MyBSTImpl {// BST中的节点TreeNod ...

  9. Java手写HashSet

    一:引言 HashSet类继承于 Set接口 其方法均可被直接调用,不用手写,本篇敲的码是为了熟悉底层原理,HashMap的特点:无序,无重复.其底层用的也是map<key,value>容 ...

最新文章

  1. android 多个绑定事件,Android RxJava 实际应用讲解:联合判断多个事件
  2. 快速人脸验证--MobileFaceNets: Efficient CNNs for Accurate Real-time Face Verification on Mobile Devices
  3. Linux+nfs配置开机启动,linux NFS配置:NFS开机自动启用及其原理
  4. WSDM 2021 | 基于双向推理的多跳知识库问答技术
  5. (转)静态变量和全局变量的区别
  6. 克劳斯比的零缺陷——《可以量化的管理学》
  7. Notepad++ WebEdit插件
  8. a4如何打印双面小册子_a4如何排版打印双面小册子?
  9. 2013年锦绣中华民俗村迷情聊斋夜
  10. 计算日期在当月是第几周-【自然周(每月第一个周一为该月第一周)做法以及1号为第一周做法】
  11. NetLimiter
  12. python查询12306余票_python命令行查询12306火车票
  13. dhcp设置(Padavan dhcp设置)
  14. Alarm Clock C/C++ Version
  15. MPB:使用QIIME 2分析微生物组16S rRNA基因扩增子测序数据(视频)
  16. Pytorch实现Bert模型
  17. 光敏电阻规格型号的含义解读研究总结
  18. html css超链接字体颜色,HTML-CSS设置超链接颜色字体
  19. 2018中国智造金长城奖:创新能力与行业竞争力并重
  20. XILINX DSP Slice功能特点

热门文章

  1. phpstrom函数注释模板_PHPSTORM模板变量注释
  2. 2020科目一考试口诀_2021年科目一考试口诀
  3. Compose Android 开发终极挑战赛: 天气应用
  4. 惠普前高管欧明哲任联想台湾区总经理
  5. Introduce Python to data sience/Python 在数据科学中的应用
  6. 启动weblogic提示BEA-000386错误,java.lang.NumberFormatException: null
  7. 哔哩哔哩(B站)的前端之路
  8. python制作猜数字小游戏
  9. python爬虫《向往的生活》豆瓣短评,来看看Henry大华的路人评价变化~
  10. mysql数据库应用与开发姜桂洪 课后答案_数据库应用与开发姜桂洪课后答案