Commit f50e6d38 by 董大萌

实现了v2版本,处理动态资源

parent cac12b84
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectPlainTextFileTypeManager">
<file url="file://$PROJECT_DIR$/src/main/java/com/dm/core/server/HttpWorkerThread.kt" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="openjdk-16 (2)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MyTomcat.iml" filepath="$PROJECT_DIR$/MyTomcat.iml" />
</modules>
</component>
</project>
\ No newline at end of file
package com.dm.tomcat.v1;
import com.dm.tomcat.v1.config.GlobalConfig;
import com.dm.tomcat.v1.server.HttpServer;
/**
* @author Chongming
* @description
* @date 2021年08月08日 19:54
*/
public class DynamicServer {
public static void main(String[] args) {
// 开启服务
int port = getPort(args);
HttpServer httpServer = new HttpServer(port);
// 设置请求文件的全局路径
String staticPath = System.getProperty("user.dir") + "\\" + "WebContent";
GlobalConfig.globalConfig().setProperty(GlobalConfig.STATIC_PATH, staticPath);
httpServer.start();
}
/**
* 从命令行中获得参数port
*/
private static int getPort(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java -jar static-server.jar <port>");
System.exit(0);
}
int port = 0;
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
System.out.println("Error:please enter a correct port!");
System.exit(0);
}
return port;
}
}
package com.dm.core;
package com.dm.tomcat.v1;
import com.dm.core.config.GlobalConfig;
import com.dm.core.server.HttpServer;
import com.dm.tomcat.v1.config.GlobalConfig;
import com.dm.tomcat.v1.server.HttpServer;
/**
* @Author: Chongming
......
package com.dm.core.config;
import java.util.HashMap;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description: 全局配置
*/
public class GlobalConfig extends HashMap<String, String> {
/**
* name:静态路径
*/
public static String STATIC_PATH = "staticPath";
private static GlobalConfig globalConfig = new GlobalConfig();
public static GlobalConfig globalConfig() {
return globalConfig;
}
public void setProperty(String name, String value) {
this.put(name, value);
}
public String getProperty(String name) {
return this.get(name);
}
}
package com.dm.tomcat.v1.config;
import java.util.HashMap;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description: 全局配置
*/
public class GlobalConfig extends HashMap<String, String> {
/**
* name:静态路径
*/
public static String STATIC_PATH = "staticPath";
private static GlobalConfig globalConfig = new GlobalConfig();
public static GlobalConfig globalConfig() {
return globalConfig;
}
public void setProperty(String name, String value) {
this.put(name, value);
}
public String getProperty(String name) {
return this.get(name);
}
}
package com.dm.core.handle;
import com.dm.core.http.HttpRequest;
import com.dm.core.http.HttpResponse;
import java.io.InputStream;
/**
* @Author: Chongming
* @Date: 2021年08月05日 10:40
* @Description: Handler接口
*/
public interface Handler {
InputStream handle(HttpRequest request, HttpResponse response);
}
package com.dm.tomcat.v1.handle;
import com.dm.tomcat.v1.http.HttpRequest;
import com.dm.tomcat.v1.http.HttpResponse;
import java.io.InputStream;
/**
* @Author: Chongming
* @Date: 2021年08月05日 10:40
* @Description: Handler接口
*/
public interface Handler {
InputStream handle(HttpRequest request, HttpResponse response);
}
package com.dm.tomcat.v1.handle.dynamicHandle;
import com.dm.tomcat.v1.handle.Handler;
import com.dm.tomcat.v1.http.HttpRequest;
import com.dm.tomcat.v1.http.HttpResponse;
import java.io.InputStream;
/**
* @author Chongming
* @description 动态处理器
* @date 2021年08月08日 19:54
*/
public class DynamicHandler implements Handler {
@Override
public InputStream handle(HttpRequest request, HttpResponse response) {
return null;
}
}
package com.dm.core.handle.staticHandle;
import com.dm.core.config.GlobalConfig;
import com.dm.core.handle.Handler;
import com.dm.core.http.HttpRequest;
import com.dm.core.http.HttpResponse;
import com.dm.core.http.enums.HttpResponseStatus;
import java.io.*;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description:
*/
public class StaticHandler implements Handler {
@Override
public InputStream handle(HttpRequest request, HttpResponse response) {
// 拼接请求路径
String path =
//资源静态路径
GlobalConfig.globalConfig().getProperty(GlobalConfig.STATIC_PATH)
// 请求的资源
+ request.getLine(HttpRequest.LINE_URL);
// 当前系统分隔符
path = path.replace("/", File.separator);
try {
// 获取文件
File file = new File(path);
if (!file.exists()) {
response.error(HttpResponseStatus.ERROR, "文件不存在");
}
response.sendFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dm.tomcat.v1.handle.staticHandle;
import com.dm.tomcat.v1.config.GlobalConfig;
import com.dm.tomcat.v1.handle.Handler;
import com.dm.tomcat.v1.http.HttpRequest;
import com.dm.tomcat.v1.http.HttpResponse;
import com.dm.tomcat.v1.http.enums.HttpResponseStatus;
import java.io.*;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description:
*/
public class StaticHandler implements Handler {
@Override
public InputStream handle(HttpRequest request, HttpResponse response) {
// 拼接请求路径
String path =
//资源静态路径
GlobalConfig.globalConfig().getProperty(GlobalConfig.STATIC_PATH)
// 请求的资源
+ request.getLine(HttpRequest.LINE_URL);
// 当前系统分隔符
path = path.replace("/", File.separator);
try {
// 获取文件
File file = new File(path);
if (!file.exists()) {
response.error(HttpResponseStatus.ERROR, "文件不存在");
}
response.sendFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dm.core.http;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求解析器
*/
public class HttpParse {
private InputStream inputStream;
/**
* 构造对象时设置输入流
* @param inputStream
*/
public HttpParse(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* 获取协议的请求部分,截取客户端要访问的资源路径
* @return HttpRequest
*/
public HttpRequest parse() throws IOException {
HttpRequest httpRequest = new HttpRequest();
// 读取请求报文的内容
String content = readRequestContent();
// 打印一下请求报文
System.out.println(content);
// 读取请求行:GET /demo01.html HTTP/1.1\r\n
String[] requestLine = readRequestLine(content);
httpRequest.addLine(HttpRequest.LINE_METHOD, requestLine[0]);
httpRequest.addLine(HttpRequest.LINE_URL, requestLine[1]);
httpRequest.addLine(HttpRequest.LINE_VERSION, requestLine[2]);
return httpRequest;
}
/**
* 读取请求头
* @param inputStream
* @return
* @throws IOException
*/
private Map<String, String> readRequestHeader(InputStream inputStream) throws IOException {
HashMap<String, String> HeaderMap = new HashMap<>();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
reader.readLine();
String temp;
while ((temp = reader.readLine()) != null) {
int i = temp.indexOf(": ");
int j = temp.indexOf("\n");
String name = temp.substring(0,i);
String value = temp.substring(i+1);
// 考虑使用set集合的contains方法判断请求头的name属性
// 这里有空再实现
}
return null;
}
/**
* 读取请求报文,得到String类型字符串
* @return content
*/
private String readRequestContent() throws IOException {
// 1.定义一个String变量content,存放HTTP协议请求报文
StringBuffer content = new StringBuffer(2048);
// 2.定义一个字节数组buffer,存放单次读取到缓冲区的数据
byte[] buffer = new byte[2048];
// 3.定义一个变量size,代表读取到数组中的数据量的大小
int size = -1;
// 4.读取请求报文,将数据读入字节数组buffer中,size代表读取到的数据量的大小
size = inputStream.read(buffer);
// 5.遍历字节数组,将数组中的数据追加到content变量中
for (int i = 0; i < size; i++) {
content.append((char) buffer[i]);
}
return content.toString();
}
/**
* 读取请求行 生成存放请求行内容的字符串数组
* @return 0:method 1:url 2:version
*/
private String[] readRequestLine(String content) {
StringBuffer buffer = new StringBuffer(content);
String[] lines = new String[3];
// 定义2个变量,存放请求行的2个空格的位置
int index1,index2;
// 获取HTTP请求行部分第1个空格的位置
index1 = buffer.indexOf(" ");
if (index1 != -1){
// indexOf(i,"a")表示从第i个索引代表的字符位置(包含当前位置)往后查,返回查到的a字符的索引
// 我们需要查找第二个空格(因为查找时包含当前位置,所以我们要跳过这个空格的位置),所以从索引index1+1开始往后查.
index2 = buffer.indexOf(" ",index1+1);
if (index2 > index1) {
lines[0] = buffer.substring(0,index1);
lines[1] = buffer.substring(index1+1, index2);
lines[2] = buffer.substring(index2+1,buffer.indexOf("\r\n"));
return lines;
}
}
return null;
}
}
package com.dm.tomcat.v1.http;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求解析器
*/
public class HttpParse {
private InputStream inputStream;
/**
* 构造对象时设置输入流
* @param inputStream
*/
public HttpParse(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* 获取协议的请求部分,截取客户端要访问的资源路径
* @return HttpRequest
*/
public HttpRequest parse() throws IOException {
HttpRequest httpRequest = new HttpRequest();
// 读取请求报文的内容
String content = readRequestContent();
// 打印一下请求报文
System.out.println(content);
// 读取请求行:GET /demo01.html HTTP/1.1\r\n
String[] requestLine = readRequestLine(content);
httpRequest.addLine(HttpRequest.LINE_METHOD, requestLine[0]);
httpRequest.addLine(HttpRequest.LINE_URL, requestLine[1]);
httpRequest.addLine(HttpRequest.LINE_VERSION, requestLine[2]);
return httpRequest;
}
/**
* 读取请求头
* @param inputStream
* @return
* @throws IOException
*/
private Map<String, String> readRequestHeader(InputStream inputStream) throws IOException {
HashMap<String, String> HeaderMap = new HashMap<>();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
reader.readLine();
String temp;
while ((temp = reader.readLine()) != null) {
int i = temp.indexOf(": ");
int j = temp.indexOf("\n");
String name = temp.substring(0,i);
String value = temp.substring(i+1);
// 考虑使用set集合的contains方法判断请求头的name属性
// 这里有空再实现
}
return null;
}
/**
* 读取请求报文,得到String类型字符串
* @return content
*/
private String readRequestContent() throws IOException {
// 1.定义一个String变量content,存放HTTP协议请求报文
StringBuffer content = new StringBuffer(2048);
// 2.定义一个字节数组buffer,存放单次读取到缓冲区的数据
byte[] buffer = new byte[2048];
// 3.定义一个变量size,代表读取到数组中的数据量的大小
int size = -1;
// 4.读取请求报文,将数据读入字节数组buffer中,size代表读取到的数据量的大小
size = inputStream.read(buffer);
// 5.遍历字节数组,将数组中的数据追加到content变量中
for (int i = 0; i < size; i++) {
content.append((char) buffer[i]);
}
return content.toString();
}
/**
* 读取请求行 生成存放请求行内容的字符串数组
* @return 0:method 1:url 2:version
*/
private String[] readRequestLine(String content) {
StringBuffer buffer = new StringBuffer(content);
String[] lines = new String[3];
// 定义2个变量,存放请求行的2个空格的位置
int index1,index2;
// 获取HTTP请求行部分第1个空格的位置
index1 = buffer.indexOf(" ");
if (index1 != -1){
// indexOf(i,"a")表示从第i个索引代表的字符位置(包含当前位置)往后查,返回查到的a字符的索引
// 我们需要查找第二个空格(因为查找时包含当前位置,所以我们要跳过这个空格的位置),所以从索引index1+1开始往后查.
index2 = buffer.indexOf(" ",index1+1);
if (index2 > index1) {
lines[0] = buffer.substring(0,index1);
lines[1] = buffer.substring(index1+1, index2);
lines[2] = buffer.substring(index2+1,buffer.indexOf("\r\n"));
return lines;
}
}
return null;
}
}
package com.dm.core.http;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求
*/
public class HttpRequest {
/* 请求行参数 */
public static final String LINE_METHOD = "method";
public static final String LINE_URL = "url";
public static final String LINE_VERSION = "version";
/* 请求体参数 */
/**
* 请求行
*/
private Map<String,String> line = new HashMap<>();
/**
* 存放请求头的Map集合
*/
private Map<String,String> headers = new HashMap<>();
/**
* 设置请求行参数
* @param name
* @param value
*/
public void addLine(String name, String value) {
line.put(name, value);
}
/**
* 获得请求行参数
*/
public String getLine(String name) {
return line.get(name);
}
/**
* 设置请求头参数
* @param name
* @param value
*/
public void addHeader(String name, String value) {
headers.put(name, value);
}
/**
* 获得请求头参数
* @param name
* @return
*/
public String getHeader(String name) {
return headers.get(name);
}
}
package com.dm.tomcat.v1.http;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求
*/
public class HttpRequest {
/* 请求行参数 */
public static final String LINE_METHOD = "method";
public static final String LINE_URL = "url";
public static final String LINE_VERSION = "version";
/* 请求体参数 */
/**
* 请求行
*/
private Map<String,String> line = new HashMap<>();
/**
* 存放请求头的Map集合
*/
private Map<String,String> headers = new HashMap<>();
/**
* 设置请求行参数
* @param name
* @param value
*/
public void addLine(String name, String value) {
line.put(name, value);
}
/**
* 获得请求行参数
*/
public String getLine(String name) {
return line.get(name);
}
/**
* 设置请求头参数
* @param name
* @param value
*/
public void addHeader(String name, String value) {
headers.put(name, value);
}
/**
* 获得请求头参数
* @param name
* @return
*/
public String getHeader(String name) {
return headers.get(name);
}
}
package com.dm.core.http;
package com.dm.tomcat.v1.http;
import com.dm.core.http.enums.HttpResponseStatus;
import com.dm.tomcat.v1.http.enums.HttpResponseStatus;
import java.io.File;
import java.io.FileInputStream;
......
package com.dm.core.http.enums;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:48
* @Description:
*/
public enum HttpResponseStatus {
SC_OK(200, "OK"),
SC_NOTFOUND(404, "NOT FOUND"),
ERROR(500,"ERROR")
;
/**
* 状态码
*/
int code;
/**
* 状态描述
*/
String description;
HttpResponseStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
package com.dm.tomcat.v1.http.enums;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:48
* @Description:
*/
public enum HttpResponseStatus {
SC_OK(200, "OK"),
SC_NOTFOUND(404, "NOT FOUND"),
ERROR(500,"ERROR")
;
/**
* 状态码
*/
int code;
/**
* 状态描述
*/
String description;
HttpResponseStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
package com.dm.core.server;
import com.dm.core.config.GlobalConfig;
import com.dm.core.handle.staticHandle.StaticHandler;
import com.dm.core.http.HttpParse;
import com.dm.core.http.HttpRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Chongming
* @description
* @date 2021年08月05日 15:37
*/
public class HttpServer {
/**
* 需要监听的端口号
*/
private int port;
public HttpServer(int port) {
this.port = port;
}
/**
* 运行服务器
*/
public void start() {
System.out.println("服务器已启动!");
// 创建ServerSocket对象,监听8081端口
while (true) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
// 等待来自客户端的请求
while (true) {
// 获取到客户端对应的socket
Socket socket = serverSocket.accept();
// 启动Http工作线程
new HttpWorkerThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.dm.tomcat.v1.server;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Chongming
* @description
* @date 2021年08月05日 15:37
*/
public class HttpServer {
/**
* 需要监听的端口号
*/
private int port;
public HttpServer(int port) {
this.port = port;
}
/**
* 运行服务器
*/
public void start() {
System.out.println("服务器已启动!");
// 创建ServerSocket对象,监听8081端口
while (true) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
// 等待来自客户端的请求
while (true) {
// 获取到客户端对应的socket
Socket socket = serverSocket.accept();
// 启动Http工作线程
new HttpWorkerThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
\ No newline at end of file
package com.dm.core.server;
package com.dm.tomcat.v1.server;
import com.dm.core.handle.staticHandle.StaticHandler;
import com.dm.core.http.HttpParse;
import com.dm.core.http.HttpRequest;
import com.dm.core.http.HttpResponse;
import com.dm.tomcat.v1.handle.staticHandle.StaticHandler;
import com.dm.tomcat.v1.http.HttpParse;
import com.dm.tomcat.v1.http.HttpRequest;
import com.dm.tomcat.v1.http.HttpResponse;
import java.io.IOException;
import java.io.InputStream;
......
package com.dm.tomcat.v2;
import com.dm.tomcat.v2.config.GlobalConfig;
import com.dm.tomcat.v2.config.MappingConfig;
import com.dm.tomcat.v2.server.HttpServer;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
/**
* @author Chongming
* @description 动态资源服务器的启动类
* @date 2021年08月08日 19:54
*/
public class DynamicServer {
public static void main(String[] args) {
// 开启服务
int port = getPort(args);
HttpServer httpServer = new HttpServer(port);
// 设置请求文件的路径
String staticPath = System.getProperty("user.dir") + "\\" + "WebContent" + "\\cgxz";
GlobalConfig.globalConfig().setProperty(GlobalConfig.STATIC_PATH, staticPath);
// 读取配置文件
String propertiesPath = System.getProperty("user.dir") + "\\src\\main\\java\\com\\dm\\tomcat\\v2\\mapping.properties";
try {
readProperties(propertiesPath);
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
// 启动服务器
httpServer.start();
}
/**
* 从命令行中获得参数port
*/
private static int getPort(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java -jar static-server.jar <port>");
System.exit(0);
}
int port = 0;
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
System.out.println("Error:please enter a correct port!");
System.exit(0);
}
return port;
}
/**
* 读取配置文件
* Java核心技术读书笔记:对于异常要早抛出,晚处理
*/
public static void readProperties(String propertiesPath) throws IOException {
// 加载配置文件
Properties properties = new Properties();
properties.load(new FileInputStream(propertiesPath));
// 将配置文件中的数据读取到MappingConfig中
Set set = properties.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
String value = properties.getProperty(key);
MappingConfig.mappingConfig().put(key,value);
}
}
}
package com.dm.tomcat.v2.config;
import java.util.HashMap;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description: 全局配置
*/
public class GlobalConfig extends HashMap<String, String> {
/**
* name:静态路径
*/
public static String STATIC_PATH = "staticPath";
private static GlobalConfig globalConfig = new GlobalConfig();
public static GlobalConfig globalConfig() {
return globalConfig;
}
public void setProperty(String name, String value) {
this.put(name, value);
}
public String getProperty(String name) {
return this.get(name);
}
}
package com.dm.tomcat.v2.config;
import java.util.HashMap;
/**
* @author Chongming
* @description 存放mapping.properties中映射到的servlet
* @date 2021年08月08日 21:18
*/
public class MappingConfig extends HashMap<String, String> {
private static MappingConfig mappingConfig = new MappingConfig();
public static MappingConfig mappingConfig() {
return mappingConfig;
}
}
package com.dm.tomcat.v2.handle;
import com.dm.tomcat.v2.http.HttpRequest;
import com.dm.tomcat.v2.http.HttpResponse;
import java.io.InputStream;
/**
* @Author: Chongming
* @Date: 2021年08月05日 10:40
* @Description: Handler接口
*/
public interface Handler {
InputStream handle(HttpRequest request, HttpResponse response);
}
package com.dm.tomcat.v2.handle.dynamicHandle;
import com.dm.tomcat.v2.handle.Handler;
import com.dm.tomcat.v2.http.HttpRequest;
import com.dm.tomcat.v2.http.HttpResponse;
import com.dm.tomcat.v2.config.GlobalConfig;
import com.dm.tomcat.v2.http.enums.HttpResponseStatus;
import java.io.File;
import java.io.InputStream;
/**
* @author Chongming
* @description
* @date 2021年08月08日 21:58
*/
public class DynamicHandler implements Handler {
@Override
public InputStream handle(HttpRequest request, HttpResponse response) {
// 资源路径,这里要指向具体的资源文件了
String path = GlobalConfig.globalConfig().getProperty(GlobalConfig.STATIC_PATH) + "\\index.html";
// 当前系统分隔符
path = path.replace("/", File.separator);
try {
// 获取文件
File file = new File(path);
if (!file.exists()) {
response.error(HttpResponseStatus.ERROR, "文件不存在");
}
response.sendFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dm.tomcat.v2.handle.staticHandle;
import com.dm.tomcat.v2.config.GlobalConfig;
import com.dm.tomcat.v2.handle.Handler;
import com.dm.tomcat.v2.http.HttpRequest;
import com.dm.tomcat.v2.http.HttpResponse;
import com.dm.tomcat.v2.http.enums.HttpResponseStatus;
import java.io.File;
import java.io.InputStream;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:47
* @Description:
*/
public class StaticHandler implements Handler {
@Override
public InputStream handle(HttpRequest request, HttpResponse response) {
// 拼接请求路径
String path =
//资源静态路径
GlobalConfig.globalConfig().getProperty(GlobalConfig.STATIC_PATH)
// 请求的资源
+ request.getLine(HttpRequest.LINE_URL);
// 当前系统分隔符
path = path.replace("/", File.separator);
try {
// 获取文件
File file = new File(path);
if (!file.exists()) {
response.error(HttpResponseStatus.ERROR, "文件不存在");
}
response.sendFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dm.tomcat.v2.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求解析器
*/
public class HttpParse {
private InputStream inputStream;
/**
* 构造对象时设置输入流
* @param inputStream
*/
public HttpParse(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* 获取协议的请求部分,截取客户端要访问的资源路径
* @return HttpRequest
*/
public HttpRequest parse() throws IOException {
HttpRequest httpRequest = new HttpRequest();
// 读取请求报文的内容
String content = readRequestContent();
// 打印一下请求报文
System.out.println(content);
// 读取请求行:GET /demo01.html HTTP/1.1\r\n
String[] requestLine = readRequestLine(content);
httpRequest.addLine(HttpRequest.LINE_METHOD, requestLine[0]);
httpRequest.addLine(HttpRequest.LINE_URL, requestLine[1]);
httpRequest.addLine(HttpRequest.LINE_VERSION, requestLine[2]);
return httpRequest;
}
/**
* 读取请求头
* @param inputStream
* @return
* @throws IOException
*/
private Map<String, String> readRequestHeader(InputStream inputStream) throws IOException {
HashMap<String, String> HeaderMap = new HashMap<>();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
reader.readLine();
String temp;
while ((temp = reader.readLine()) != null) {
int i = temp.indexOf(": ");
int j = temp.indexOf("\n");
String name = temp.substring(0,i);
String value = temp.substring(i+1);
// 考虑使用set集合的contains方法判断请求头的name属性
// 这里有空再实现
}
return null;
}
/**
* 读取请求报文,得到String类型字符串
* @return content
*/
private String readRequestContent() throws IOException {
// 1.定义一个String变量content,存放HTTP协议请求报文
StringBuffer content = new StringBuffer(2048);
// 2.定义一个字节数组buffer,存放单次读取到缓冲区的数据
byte[] buffer = new byte[2048];
// 3.定义一个变量size,代表读取到数组中的数据量的大小
int size = -1;
// 4.读取请求报文,将数据读入字节数组buffer中,size代表读取到的数据量的大小
size = inputStream.read(buffer);
// 5.遍历字节数组,将数组中的数据追加到content变量中
for (int i = 0; i < size; i++) {
content.append((char) buffer[i]);
}
return content.toString();
}
/**
* 读取请求行 生成存放请求行内容的字符串数组
* @return 0:method 1:url 2:version
*/
private String[] readRequestLine(String content) {
StringBuffer buffer = new StringBuffer(content);
String[] lines = new String[3];
// 定义2个变量,存放请求行的2个空格的位置
int index1,index2;
// 获取HTTP请求行部分第1个空格的位置
index1 = buffer.indexOf(" ");
if (index1 != -1){
// indexOf(i,"a")表示从第i个索引代表的字符位置(包含当前位置)往后查,返回查到的a字符的索引
// 我们需要查找第二个空格(因为查找时包含当前位置,所以我们要跳过这个空格的位置),所以从索引index1+1开始往后查.
index2 = buffer.indexOf(" ",index1+1);
if (index2 > index1) {
lines[0] = buffer.substring(0,index1);
lines[1] = buffer.substring(index1+1, index2);
lines[2] = buffer.substring(index2+1,buffer.indexOf("\r\n"));
return lines;
}
}
return null;
}
}
package com.dm.tomcat.v2.http;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Chongming
* @Date: 2021年08月05日 9:26
* @Description: Http请求
*/
public class HttpRequest {
/* 请求行参数 */
public static final String LINE_METHOD = "method";
public static final String LINE_URL = "url";
public static final String LINE_VERSION = "version";
/* 请求体参数 */
/**
* 请求行
*/
private Map<String,String> line = new HashMap<>();
/**
* 存放请求头的Map集合
*/
private Map<String,String> headers = new HashMap<>();
/**
* 设置请求行参数
* @param name
* @param value
*/
public void addLine(String name, String value) {
line.put(name, value);
}
/**
* 获得请求行参数
*/
public String getLine(String name) {
return line.get(name);
}
/**
* 设置请求头参数
* @param name
* @param value
*/
public void addHeader(String name, String value) {
headers.put(name, value);
}
/**
* 获得请求头参数
* @param name
* @return
*/
public String getHeader(String name) {
return headers.get(name);
}
}
package com.dm.tomcat.v2.http;
import com.dm.tomcat.v2.http.enums.HttpResponseStatus;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @Author: DongMeng
* @Date: 2021年08月05日 9:27
* @Description:
*/
public class HttpResponse {
/**
* 响应状态(枚举)
*/
private HttpResponseStatus status;
/**
* 网络输出流
*/
private OutputStream outputStream;
/**
* 构造对象时设置网络输出流
*
* @param outputStream
*/
public HttpResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
/**
* 设置响应状态
*
* @param httpResponseStatus
*/
public void setStatus(HttpResponseStatus httpResponseStatus) {
this.status = status;
}
/**
* 获得网络输出流
*
* @return
*/
public OutputStream getOutputStream() {
return outputStream;
}
public void error(HttpResponseStatus status, String message) {
// 设置响应报文
String responseContent = message;
String responseLine = "HTTP/1.1" + " " + status.getCode() + " " + status.getDescription() + "\r\n";
String responseHeaders = "content-type:text;charset=utf-8\r\n";
responseHeaders += "content-length:" + responseContent.length() + "\r\n";
// 设置当前请求结束了关闭请求
responseHeaders += "connection:close\r\n";
String blankLine = "\r\n";
try {
// 响应行
outputStream.write(responseLine.getBytes());
// 响应头
outputStream.write(responseHeaders.getBytes());
// 空行
outputStream.write(blankLine.getBytes());
// 响应体
outputStream.write(responseContent.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭请求
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送文件
* @param file
*/
public void sendFile(File file) {
// 设置响应报文
String responseLine = "HTTP/1.1" + " " + HttpResponseStatus.SC_OK.getCode() + " " + HttpResponseStatus.SC_OK.getDescription() + "\r\n";
// 获取文件的content-type
String fileSuffix = getContentType(file.getName());
String responseHeaders = "content-type:" + fileSuffix + "\r\n";
responseHeaders += "content-length:" + file.length() + "\r\n";
// 设置当前请求结束了关闭请求
responseHeaders += "connection:keep-alive\r\n";
String blankLine = "\r\n";
System.out.println(responseLine + responseHeaders+blankLine);
try {
// 响应行
outputStream.write(responseLine.getBytes());
// 响应头
outputStream.write(responseHeaders.getBytes());
// 空行
outputStream.write(blankLine.getBytes());
// 响应体,写出文件
byte[] fileBuff = new byte[5096];
FileInputStream fileInputStream = new FileInputStream(file);
int length = -1;
while ( (length = fileInputStream.read(fileBuff)) != -1 ) {
outputStream.write(fileBuff, 0, length);
outputStream.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String getContentType(String fileName) {
if (fileName.endsWith(".html")) {
return "text/html;charset:utf-8\n";
} else if (fileName.endsWith(".js")) {
return "application/x-javascript";
} else if (fileName.endsWith(".png")) {
return "image/png";
} else if (fileName.endsWith(".css")) {
return "text/css";
} else if (fileName.endsWith(".ico")) {
return "application/x-ico";
} else {
return "text/plain";
}
}
}
package com.dm.tomcat.v2.http.enums;
/**
* @Author: Chongming
* @Date: 2021年08月05日 14:48
* @Description:
*/
public enum HttpResponseStatus {
SC_OK(200, "OK"),
SC_NOTFOUND(404, "NOT FOUND"),
ERROR(500,"ERROR")
;
/**
* 状态码
*/
int code;
/**
* 状态描述
*/
String description;
HttpResponseStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
/aaa=com.dm.tomcat.v2.handle.dynamicHandle.DynamicHandler
\ No newline at end of file
package com.dm.tomcat.v2.server;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Chongming
* @description
* @date 2021年08月05日 15:37
*/
public class HttpServer {
/**
* 需要监听的端口号
*/
private int port;
public HttpServer(int port) {
this.port = port;
}
/**
* 运行服务器
*/
public void start() {
System.out.println("服务器已启动!");
// 创建ServerSocket对象,监听8081端口
while (true) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
// 等待来自客户端的请求
while (true) {
// 获取到客户端对应的socket
Socket socket = serverSocket.accept();
// 启动Http工作线程
new HttpWorkerThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
\ No newline at end of file
package com.dm.tomcat.v2.server;
import com.dm.tomcat.v2.config.MappingConfig;
import com.dm.tomcat.v2.handle.dynamicHandle.DynamicHandler;
import com.dm.tomcat.v2.handle.staticHandle.StaticHandler;
import com.dm.tomcat.v2.http.HttpParse;
import com.dm.tomcat.v2.http.HttpRequest;
import com.dm.tomcat.v2.http.HttpResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author Chongming
* @description http工作线程
* @date 2021年08月05日 16:01
*/
public class HttpWorkerThread extends Thread {
private Socket clientSocket;
public HttpWorkerThread(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
HttpResponse httpResponse;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
/* 解析http请求,拿到request对象 */
inputStream = clientSocket.getInputStream();
outputStream = clientSocket.getOutputStream();
HttpParse httpParse = new HttpParse(inputStream);
HttpRequest httpRequest = httpParse.parse();
/* 构造response对象 */
httpResponse = new HttpResponse(outputStream);
// 判断到如果Request中的路径没有后缀名,则需要调用动态处理器,用反射获得
int flag = httpRequest.getLine(HttpRequest.LINE_URL).indexOf(".");
if (flag == -1) {
/* 创建静态处理器,调用handle方法处理request和response,拿到输入流对象 */
String url = httpRequest.getLine(HttpRequest.LINE_URL);
Class clazz = Class.forName(MappingConfig.mappingConfig().get(url));
DynamicHandler dynamicHandler = (DynamicHandler)clazz.getDeclaredConstructor().newInstance();
dynamicHandler.handle(httpRequest,httpResponse);
} else {
StaticHandler staticHandler = new StaticHandler();
staticHandler.handle(httpRequest,httpResponse);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
outputStream.close();
clientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment