day29(v3、v4、Map接口、v5)
作者:互联网
day29(v3、v4、Map接口、v5)
1.v3
1.主要内容
-
解析请求
HTTP协议要求客户端连接后会发送一个请求,每个请求由三部分构成:- 请求行
- 消息头
- 消息正文
-
首先请求行和消息头有一个共同的特点:都是以CRLF结尾的一行字符串.
因此先实现读取一行字符串的操作,测试将请求行读取出来并进行解析.之后可以再利用这个
操作完成消息头的读取并解析. -
实现:
在ClientHandler中完成读取一行字符串的操作.
2.WebServerApplication
package com.webserver.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* WebServer主类
* WebServer是一个Web容器,实现了Tomcat中的基础功能,通过这个项目的学习了解Tomcat的
* 底层工作逻辑。
* Web容器是一个Web服务端程序,主要负责两方面的工作:
* 1:管理部署在容器中的所有网络应用
* 2:与客户端(通常就是浏览器)进行TCP通讯,并基于HTTP协议进行应用交互,使得客户端可以
* 通过网络远程调用容器下不同网络应用中的内容。
*
* 网络应用(webapp):包含的内容大致有:网页,处理业务的代码,其他资源等。就是俗称的"网站"
*/
public class WebServerApplication {
private ServerSocket serverSocket;
public WebServerApplication(){
try {
System.out.println("正在启动服务端...");
serverSocket = new ServerSocket(8088);
System.out.println("服务端启动完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接了!");
//启动一个线程处理该客户端交互
ClientHandler handler = new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
WebServerApplication application = new WebServerApplication();
application.start();
}
}
3.ClientHandler
package com.webserver.core;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/**
* 该线程任务负责与指定客户端完成HTTP交互
* 与客户端交流的流程分成三步:
* 1:解析请求
* 2:处理请求
* 3:发送响应
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//读取客户端发过来的消息
InputStream in = socket.getInputStream();
char pre='a',cur='a';//pre上次读取的字符,cur本次读取的字符
StringBuilder builder = new StringBuilder();
int d;
while((d = in.read())!=-1){
cur = (char)d;//本次读取到的字符
if(pre==13&&cur==10){//判断是否连续读取到了回车和换行符
break;
}
builder.append(cur);
pre = cur;//在进行下次读取字符前将本次读取的字符记作上次读取的字符
}
String line = builder.toString().trim();
System.out.println(line);
//请求行相关信息
String method;//请求方式
String uri;//抽象路径
String protocol;//协议版本
String[] array = line.split("\\s");
method = array[0];
uri = array[1];//这里可能会出现数组下标越界异常!原因:浏览器空请求,后期会解决
protocol = array[2];
// http://localhost:8088/myweb/index.html
System.out.println("method:"+method); //GET
System.out.println("uri:"+uri); // /myweb/index.html
System.out.println("protocol:"+protocol);//HTTP/1.1
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.v4
1.主要内容
-
继续解析请求
上一个版本完成了解析请求行的操作,继续使用该操作完成解析消息头 -
实现:
1:在ClientHandler中定义方法:readLine,用于将读取一行字符串的操作重用
2:将解析请求行中读取第一行内容的操作改为调用readLine
3:继续利用readLine读取消息头并保存每个消息头
2.WebServerApplication
package com.webserver.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* WebServer主类
* WebServer是一个Web容器,实现了Tomcat中的基础功能,通过这个项目的学习了解Tomcat的
* 底层工作逻辑。
* Web容器是一个Web服务端程序,主要负责两方面的工作:
* 1:管理部署在容器中的所有网络应用
* 2:与客户端(通常就是浏览器)进行TCP通讯,并基于HTTP协议进行应用交互,使得客户端可以
* 通过网络远程调用容器下不同网络应用中的内容。
*
* 网络应用(webapp):包含的内容大致有:网页,处理业务的代码,其他资源等。就是俗称的"网站"
*/
public class WebServerApplication {
private ServerSocket serverSocket;
public WebServerApplication(){
try {
System.out.println("正在启动服务端...");
serverSocket = new ServerSocket(8088);
System.out.println("服务端启动完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接了!");
//启动一个线程处理该客户端交互
ClientHandler handler = new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
WebServerApplication application = new WebServerApplication();
application.start();
}
}
3.ClientHandler
package com.webserver.core;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 该线程任务负责与指定客户端完成HTTP交互
* 与客户端交流的流程分成三步:
* 1:解析请求
* 2:处理请求
* 3:发送响应
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//1 解析请求
//1.1解析请求行
String line = readLine();
System.out.println(line);
//请求行相关信息
String method;//请求方式
String uri;//抽象路径
String protocol;//协议版本
String[] array = line.split("\\s");
method = array[0];
uri = array[1];//这里可能会出现数组下标越界异常!原因:浏览器空请求,后期会解决
protocol = array[2];
// http://localhost:8088/myweb/index.html
System.out.println("method:"+method); //GET
System.out.println("uri:"+uri); // /myweb/index.html
System.out.println("protocol:"+protocol);//HTTP/1.1
//1.2解析消息头
Map<String,String> headers = new HashMap<>();
while(true) {
line = readLine();
if(line.isEmpty()){
break;
}
System.out.println("消息头:" + line);
//将消息头按照"冒号空格"拆分为消息头的名字和值并以key,value存入headers
array = line.split(":\\s");
headers.put(array[0],array[1]);
}
System.out.println("headers:"+headers);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 通过socket获取的输入流读取客户端发送过来的一行字符串
* @return
*/
private String readLine() throws IOException {
InputStream in = socket.getInputStream();
char pre='a',cur='a';//pre上次读取的字符,cur本次读取的字符
StringBuilder builder = new StringBuilder();
int d;
while((d = in.read())!=-1){
cur = (char)d;//本次读取到的字符
if(pre==13&&cur==10){//判断是否连续读取到了回车和换行符
break;
}
builder.append(cur);
pre = cur;//在进行下次读取字符前将本次读取的字符记作上次读取的字符
}
return builder.toString().trim();
}
}
3.Map接口
1.定义
- 引用:java.util.Map 接口
- Map称为查找表,体现的结构是一个多行两列的表格。其中左列称为key,右列称为value.
- Map总是根据key获取对应的value。
2.常用实现类
1.java.util.HashMap:(散列表,哈希表)
称为散列表,哈希表。是使用散列算法实现的Map,当今查询速度最快的数据结构
2.java.util.TreeMap:
使用二叉树算法实现的Map
3.代码
package map;
import java.util.HashMap;
import java.util.Map;
/**
* java.util.Map 接口
* Map称为查找表,体现的结构是一个多行两列的表格。其中左列称为key,右列称为value.
* Map总是根据key获取对应的value。
*
* 常用实现类:
* java.util.HashMap:称为散列表,哈希表。是使用散列算法实现的Map,当今查询速度最快的
* 数据结构
* java.util.TreeMap:使用二叉树算法实现的Map
*/
public class MapDemo1 {
public static void main(String[] args) {
/*
Map的key和value可以分别指定不同类型
*/
Map<String,Integer> map = new HashMap<>();
/*
V put(K k,V v)
将一组键值对存入Map中。
Map要求key不允许重复。
如果put方法存入的键值对中,key不存在时,则直接将key-value存入,返回值为null
如果key存在,则是替换value操作,此时返回值为被替换的value
*/
Integer value = map.put("语文",99);
System.out.println(value);//没有被替换的value
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
value = map.put("物理",60);
System.out.println(map);
System.out.println(value);
/*
V get(Object k)
根据给定的key获取对应的value,如果给定的key不存在,则返回值为null
*/
value = map.get("化学");
System.out.println(value);
value = map.get("体育");
System.out.println(value);
int size = map.size();
System.out.println("size:"+size);
boolean ck = map.containsKey("语文");
System.out.println("包含key:"+ck);
ck = map.containsKey("音乐");
System.out.println("包含key:"+ck);
/*
可判断Map是否包含给定的key或value
*/
boolean cv = map.containsValue(99);
System.out.println("包含value:"+cv);
cv = map.containsValue(66);
System.out.println("包含value:"+cv);
/*
V remove(Object key)
从map中删除给定的key对应的这一组键值对。返回值为该key对应的value
*/
System.out.println(map);
value = map.remove("语文");
System.out.println(map);
System.out.println(value);
}
}
4.map的遍历
1.遍历所有的key :Set keySet()
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的遍历
* Map提供了三种遍历方式:
* 1:遍历所有的key
* 2:遍历每一组键值对
* 3:遍历所有的value(该操作不常用)
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("语文",99);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
/*
Set keySet()
将当前Map中所有的key以一个Set集合形式返回,遍历该集合等同于遍历所有的key
*/
Set<String> keySet = map.keySet();
for(String key : keySet){
System.out.println("key:"+key);
}
}
}
2.遍历每一组键值对:Set entrySet()
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的遍历
* Map提供了三种遍历方式:
* 1:遍历所有的key
* 2:遍历每一组键值对
* 3:遍历所有的value(该操作不常用)
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("语文",99);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
/*
Set entrySet()
将当前Map中每一组键值对以一个Entry实例形式表示,并存入Set集合后返回
java.util.Map.Entry的每一个实例用于表示Map中的一组键值对,其中方法:
K getKey():获取对应的key
V getValue():获取对应的value
*/
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
for(Map.Entry<String,Integer> e : entrySet){
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key+":"+value);
}
}
}
3.遍历所有的value(该操作不常用): Collection values()
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的遍历
* Map提供了三种遍历方式:
* 1:遍历所有的key
* 2:遍历每一组键值对
* 3:遍历所有的value(该操作不常用)
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("语文",99);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);
System.out.println(map);
/*
Collection values()
将当前Map中所有的value以一个集合形式返回
*/
Collection<Integer> values = map.values();
for(Integer value : values){
System.out.println("value:"+value);
}
}
}
4.v5
1.主要内容
-
重构
进行功能个拆分,将ClientHandler中第一个环节解析请求的细节拆分出去,使得
ClientHandler仅关心处理一次HTTP交互的流程控制. -
实现:
1:新建一个包:com.webserver.http
2:在http包下新建类:HttpServletRequest 请求对象
使用这个类的每一个实例表示客户端发送过来的一个HTTP请求
3:在HttpServletRequest的构造方法中完成解析请求的工作
4:ClientHandler第一步解析请求只需要实例化一个HttpServletRequest即可.
2.WebServerApplication
package com.webserver.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* WebServer主类
* WebServer是一个Web容器,实现了Tomcat中的基础功能,通过这个项目的学习了解Tomcat的
* 底层工作逻辑。
* Web容器是一个Web服务端程序,主要负责两方面的工作:
* 1:管理部署在容器中的所有网络应用
* 2:与客户端(通常就是浏览器)进行TCP通讯,并基于HTTP协议进行应用交互,使得客户端可以
* 通过网络远程调用容器下不同网络应用中的内容。
*
* 网络应用(webapp):包含的内容大致有:网页,处理业务的代码,其他资源等。就是俗称的"网站"
*/
public class WebServerApplication {
private ServerSocket serverSocket;
public WebServerApplication(){
try {
System.out.println("正在启动服务端...");
serverSocket = new ServerSocket(8088);
System.out.println("服务端启动完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接了!");
//启动一个线程处理该客户端交互
ClientHandler handler = new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
WebServerApplication application = new WebServerApplication();
application.start();
}
}
3.ClientHandler
package com.webserver.core;
import com.webserver.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 该线程任务负责与指定客户端完成HTTP交互
* 与客户端交流的流程分成三步:
* 1:解析请求
* 2:处理请求
* 3:发送响应
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//1 解析请求
HttpServletRequest request = new HttpServletRequest(socket);
//2 处理请求
//3 发送响应
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.HttpServletRequest
package com.webserver.http;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* HTTP请求对象
* 该类的每一个实例用于表示一个HTTP请求内容
* 每个请求由三部分构成:
* 请求行,消息头,消息正文
*/
public class HttpServletRequest {
private Socket socket;
//请求行相关信息
private String method;//请求方式
private String uri;//抽象路径
private String protocol;//协议版本
//消息头相关信息
private Map<String,String> headers = new HashMap<>();
public HttpServletRequest(Socket socket) throws IOException {
this.socket = socket;
//1.1解析请求行
parseRequestLine();
//1.2解析消息头
parseHeaders();
//1.3解析消息正文
parseContent();
}
/**
* 解析请求行
* parse:解析
*/
private void parseRequestLine() throws IOException {
String line = readLine();
System.out.println(line);
String[] array = line.split("\\s");
method = array[0];
uri = array[1];//这里可能会出现数组下标越界异常!原因:浏览器空请求,后期会解决
protocol = array[2];
System.out.println("method:"+method); //GET
System.out.println("uri:"+uri); // /myweb/index.html
System.out.println("protocol:"+protocol);//HTTP/1.1
}
/**
* 解析消息头
*/
private void parseHeaders() throws IOException {
while(true) {
String line = readLine();
if(line.isEmpty()){
break;
}
System.out.println("消息头:" + line);
//将消息头按照"冒号空格"拆分为消息头的名字和值并以key,value存入headers
String[] array = line.split(":\\s");
headers.put(array[0],array[1]);
}
System.out.println("headers:"+headers);
}
/**
* 解析消息正文
*/
private void parseContent(){}
/**
* 通过socket获取的输入流读取客户端发送过来的一行字符串
* @return
*/
private String readLine() throws IOException {
InputStream in = socket.getInputStream();
char pre='a',cur='a';//pre上次读取的字符,cur本次读取的字符
StringBuilder builder = new StringBuilder();
int d;
while((d = in.read())!=-1){
cur = (char)d;//本次读取到的字符
if(pre==13&&cur==10){//判断是否连续读取到了回车和换行符
break;
}
builder.append(cur);
pre = cur;//在进行下次读取字符前将本次读取的字符记作上次读取的字符
}
return builder.toString().trim();
}
public String getMethod() {
return method;
}
public String getUri() {
return uri;
}
public String getProtocol() {
return protocol;
}
/*
根据消息头的名字获取对应消息头的值
*/
public String getHeader(String name) {
return headers.get(name);
}
}
标签:Map,day29,map,System,v3,import,println,java,out 来源: https://www.cnblogs.com/xiaoyezilei/p/16125393.html