概要
时间:2021-07-11
学习内容: 视频-动手实现Tomcat
提取码:jpdu
内容输出:
- 学习笔记
- 代码demo
1.学习笔记
1)Tomcat底层业务逻辑
2)测试案例1
主要模拟流程中的5-6流程,即客户端向指定服务端服务器发送请求,获取响应信息的过程!
测试代码:
package test;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TestClient001 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
InputStream is = null;
try {
// 1.建立一个和服务端对应的Socket对象,指明需要连接的服务端的ip和端口号
socket = new Socket("www.itcast.cn", 80);
// 2.通过socket获取到指向服务端的输出流对象
is = socket.getInputStream();
// 3.通过socket获取到一个输入流对象
os = socket.getOutputStream();
// 4.将HTTP协议的请求部分参数发送到服务端
os.write("GET /subject/about/index.html HTTP/1.1\n".getBytes());
os.write("HOST:www.itcast.cn\n".getBytes());
os.write("\n".getBytes());
// 5.接收来自服务端数据并输出
int i = is.read();
while (i != -1) {
System.out.print((char) i);
i = is.read();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6.释放资源
closeClient(socket, is, os);
}
}
/**
* 释放资源
* @param socket
* @param is
* @param os
*/
private static void closeClient(Socket socket, InputStream is, OutputStream os) {
if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:
3)测试案例2
主要模拟流程中的2-4流程,即服务端向指定客户端响应请求信息的过程!
测试代码:
package test;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServer001 {
public static void main(String[] args) {
// 浏览器请求地址:http://localhost:8080
ServerSocket serverSocket = null;
Socket socket = null;
OutputStream os = null;
try {
// 1.创建ServerSocket对象,监听本机的8080端口号
int port = 8080;
serverSocket = new ServerSocket(port);
while (true) {
// 2.等待来自客户端的请求和客户端对应的Socket对象
socket = serverSocket.accept();
// 3.通过获取到的Socket对象获取到输出流对象
os = socket.getOutputStream();
// 4.通过获取到的输出流对象将HTTP协议的相应部分发送到客户端
// 响应头
os.write("HTTP/1.1 200 OK\n".getBytes());
os.write("Content-Type:text/html;charset-utf-8\n".getBytes());
os.write("Server:Apache-Coyote/1.1\n".getBytes());
os.write("\n\n".getBytes());
// 响应体
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<head><title>I love you</title></head>");
buffer.append("<body>");
buffer.append("<h1>I love you.</h1>");
buffer.append("<a href=\"#\">I love you too.</a>");
buffer.append("</body>");
buffer.append("</html>");
os.write(buffer.toString().getBytes());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.释放资源
closeServer(socket, os);
}
}
/**
* 释放资源
* @param socket
* @param os
*/
private static void closeServer(Socket socket, OutputStream os) {
if (os != null) {
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:
4)测试案例3-终极版
完整的业务流程图:
解析:
1、如果请求的是demo.html
类的静态资源,直接从项目中找到对应资源信息,以流的方式返回页面信息
2、如果请求的是AAServlet.class
类的动态资源,找到对应的java类,调用其核心方法执行,返回执行结果
demo案例完成结构:
废话不多说,案例相对简单,我直接上代码吧!
核心代码类
TestServer002.java
package test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
public class TestServer002 {
public static String URL = "";
public static String baseFileUrl = "web/file/";
public static Map<String, Object> propertiesMap = new HashMap<>();
static {
FileInputStream fileInputStream = null;
Properties properties = new Properties();
try {
// 加载配置文件 server.properties
fileInputStream = new FileInputStream(new File(baseFileUrl + "\\server.properties"));
properties.load(fileInputStream);
// 遍历获取key,value值
Set<Object> objects = properties.keySet();
// 通过迭代器的方式获取到key
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
String value = properties.getProperty(key);
System.out.println(key + ":" + value);
propertiesMap.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 浏览器请求地址:http://localhost:8080
ServerSocket serverSocket = null;
Socket socket = null;
OutputStream os = null;
InputStream is = null;
int port = 8080;
try {
// 1.创建ServerSocket对象,监听本机的8080端口号
serverSocket = new ServerSocket(port);
while (true) {
// 2.等待来自客户端的请求和客户端对应的Socket对象
socket = serverSocket.accept();
// 3.通过获取到的Socket对象获取到输出流对象
os = socket.getOutputStream();
// 获取输入流信息
is = socket.getInputStream();
// 获取请求地址信息
URL = getRequestUrl(is);
System.out.println("zwd: " + URL);
// 判断url是否包含“.”号(即xxx.xx类型字符串,有则表示请求的是静态文件。这里是简单的分类!)
// 4.通过获取到的输出流对象将HTTP协议的相应部分发送到客户端
if (URL.contains(".")) {
// 输出静态文件信息
writeStaticResponse(os);
} else {
// 输出动态请求信息
writeDynomicResponse(is, os);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.释放资源
closeServer(socket, os, is);
}
}
private static void writeDynomicResponse(InputStream is, OutputStream os) throws Exception {
// 响应头部信息
os.write("HTTP/1.1 200 OK\n".getBytes());
os.write("Content-Type:text/html;charset-utf-8\n".getBytes());
os.write("Server:Apache-Coyote/1.1\n".getBytes());
os.write("\n\n".getBytes());
if (propertiesMap.containsKey(URL)) {
String className = propertiesMap.get(URL) == null ? "" : propertiesMap.get(URL) + "";
try {
// 通过反射创建对象
Class<Servlet> clazz = (Class<Servlet>) Class.forName(className);
Servlet servlet = clazz.newInstance();
// 调用其方法
servlet.init();
servlet.service(is, os);
} catch (Exception e) {
// 异常情况处理
e.printStackTrace();
String errorMsg = e.getMessage();
os.write(errorMsg.getBytes());
}
} else {
// 无效请求情况处理
String errorMsg = "No find request Info!";
os.write(errorMsg.getBytes());
}
}
private static void writeStaticResponse(OutputStream os) throws IOException {
File file = new File(baseFileUrl, URL);
FileInputStream fis = null;
if (file.exists()) {
// 响应头部信息
os.write("HTTP/1.1 200 OK\n".getBytes());
os.write("Content-Type:text/html;charset-utf-8\n".getBytes());
os.write("Server:Apache-Coyote/1.1\n".getBytes());
os.write("\n\n".getBytes());
// 处理响应参数
byte[] bytes = new byte[2048];
fis = new FileInputStream(file);
int ch = fis.read(bytes);
while (ch != -1) {
os.write(bytes, 0, ch);
ch = fis.read(bytes);
}
// 其他方式输出流信息
// int i = fis.read(bytes);
// for (int j = 0; j < i; j++) {
// buffer.append((char) bytes[j]);
// }
} else {
os.write("HTTP/1.1 404 Not found\n".getBytes());
os.write("Content-Type:text/html;charset-utf-8\n".getBytes());
os.write("Server:Apache-Coyote/1.1\n".getBytes());
os.write("\n\n".getBytes());
os.write("<html>".getBytes());
os.write("<head><title>404</title></head>".getBytes());
os.write("<body>".getBytes());
os.write("<h1>404</h1>".getBytes());
os.write("</body>".getBytes());
os.write("</html>".getBytes());
}
if (fis != null) {
fis.close();
}
}
/**
* 获取请求地址信息
* @param is
* @return
*/
private static String getRequestUrl(InputStream is) throws IOException {
StringBuffer content = new StringBuffer(2048);
byte[] buffer = new byte[2048];
// 将读取到的每行数据存储进buffer字节数组中
int i = is.read(buffer);
// 遍历将每个字符数据存储进content中
for (int j = 0; j < i; j++) {
content.append((char) buffer[j]);
}
// System.out.println(content);
// 获取请求的地址信息(例如: GET /demo.html HTTP/1.1中的demo.html信息)
int index1,index2;
index1 = content.indexOf(" ");
if (index1 != -1) {
// 获取第二个节点位置,获取上一个节点的后一个(index1+1)
index2 = content.indexOf(" ", index1+1);
// 第二个节点也存在的话
if (index2 > index1) {
return content.substring(index1+2, index2);
}
}
return "";
}
/**
* 释放资源
* @param socket
* @param os
* @param is
*/
private static void closeServer(Socket socket, OutputStream os, InputStream is) {
if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
其他类
server.properties
aa=test.AAServlet
bb=test.BBServlet
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>/demo.html.</h1>
</body>
</html>
Servlet.java
package test;
import java.io.InputStream;
import java.io.OutputStream;
public interface Servlet {
void init();
void service(InputStream is, OutputStream os);
void destry();
}
AAServlet.java
package test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class AAServlet implements Servlet {
@Override
public void init() {
System.out.println("AAServlet init...");
}
@Override
public void service(InputStream is, OutputStream os) {
String msg = "AAServlet service...";
try {
os.write(msg.getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void destry() {
System.out.println("AAServlet destry...");
}
}
2.代码demo
链接: https://pan.baidu.com/s/1l5050pQA4-2qBkBtzCwCDg
提取码:ze2b