web服务器基本概念
请求不能像自己的代码一样,控制什么时候运行。因为不知道什么时候客户端发送请求。 所以webserver处一定要开启长服务。而这个服务就是tomcat。这里面可以嵌入n个applet小程序(购物车模块、订单模块…不同模块接收不同请求进行分别处理。处理逻辑放到webserver里。所以webserver相当于是一个容器,代码来实现、当成安装程序。安装到物理服务器中,启动就能对外提供服务)
web服务器实现——自定义tomcat
- 定义MyRequest类:请求对象。里面有请求方法(get/post)和请求地址url。构造函数传参inputstream,从inputstream中获得请求方法和地址。
- 定义MyResponse类:响应对象。就只有outputstream。有一个write方法,写入响应行、响应头和响应体。
- 定义MyMapping类:请求和处理相应请求的逻辑类(MyServlet)的映射关系。【就是看使用图中哪个applet进行处理】用hashmap存储。value是要要映射到的类,也就是包名+类名(MyServlet)。有一个getMapping方法,返回hashmap。
- 定义MyHttpServlet类:抽象类(图中接口)对servie和applet中格式进行转换。两个抽象方法doGet和doPost。一个service方法,根据传入的请求方式来判断调用doGet还是doPost方法。
- 定义MyServlet类:继承MyHttpServlet抽象类。实现doGet和doPost方法。分别通过参数myResponse的write方法,写入对应的内容。
- 定义MyServer类:定义startServer方法,服务端的接收程序,接收socket请求。里面定义请求对象和响应对象。获得MyMapping的Class对象,通过newInstance创建MyServlet实例,然后调用service方法,从而调用doGet或者doPost方法。
- 测试main方法:调用startServer方法,传入post。
- 到浏览器中,输入localhost:10086/mytomcat,可以看到doGet方法中写入的内容。
localhost:10086/ 显示不出内容,如下:
在MyServer中String clazz = new MyMapping().getMapping().get(myRequest.getRequestUrl());
设置断点。然后浏览器中输入localhost:10086,会发现如下:
也就是getMapping()会获得/mytomcat -> MyServletget()
。然后get(“/“)获得的是null,clazz是null。
所以只有当输入localhost:10086/mytomcat,点进get()
中,会发现getRequestUrl()
中,会发现:
clazz为"MyServlet"
。
通过Class.forName方法来获取对象, 传入一个类的完全限定名即可。
通过反射获取MyServlet类的Class对象myServletClass。
然后根据myServletClass创建对象。
然后调用service方法,发现是请求方法是Get,所以调用doGet方法,输出get mytomcat
具体代码:
MyRequest.java
import java.io.InputStream;
/**
* @Author : LiuYan
* @create 2021/4/19 22:36
* 请求对象
* 需要解析请求
*/
public class MyRequest {
// 请求方法 GET/POST
private String requestMethod;
// 请求地址 统一资源定位符
private String requestUrl;
public MyRequest(InputStream inputStream) throws Exception {
// 缓冲区
byte[] buffer = new byte[1024];
// 读取数据长度
int len = 0;
// 定义请求变量
String str = null;
if ((len = inputStream.read(buffer)) > 0) {
str = new String(buffer, 0, len);
}
// GET 请求地址 http/1.1
String data = str.split("\n")[0];
String[] params = data.split(" ");
this.requestMethod = params[0];
this.requestUrl = params[1];
}
public String getRequestMethod() {
return requestMethod;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
}
MyResponse.java
import java.io.IOException;
import java.io.OutputStream;
/**
* @Author : LiuYan
* @create 2021/4/19 22:45
* 响应对象
* 不需要解析,但是需要write方法,然后把内容返回给客户端浏览器
*/
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
// 响应行 响应头 响应体
public void write(String str) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("HTTP/1.1 200 OK\n")
.append("Content-Type:text/html\n")
.append("\r\n")
.append("<html>")
.append("<body>")
.append("<h1>" + str + "</h1>")
.append("</html>")
.append("</body>");
this.outputStream.write(builder.toString().getBytes());
this.outputStream.flush();
this.outputStream.close();
}
}
MyMapping.java
import java.util.HashMap;
/**
* @Author : LiuYan
* @create 2021/4/19 22:51
* 映射关系
* 请求和对应处理的逻辑类的映射关系
*/
public class MyMapping {
public static HashMap mapping = new HashMap<>();
static {
mapping.put("/mytomcat","MyServlet");
}
public HashMap getMapping() {
return mapping;
}
}
MyHttpServlet.java
import java.io.IOException;
/**
* @Author : LiuYan
* @create 2021/4/19 22:53
*/
public abstract class MyHttpServlet {
// 定义常量
public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST";
// 具体实现
public abstract void doGet(MyRequest myRequest, MyResponse myResponse) throws IOException;
public abstract void doPost(MyRequest myRequest, MyResponse myResponse) throws IOException;
//实现转换功能 根据请求方式来判断调用doGet还是doPost
public void service(MyRequest myRequest, MyResponse myResponse) throws IOException {
if (METHOD_GET.equals(myRequest.getRequestMethod())) {
doGet(myRequest, myResponse);
} else if (METHOD_POST.equals(myRequest.getRequestMethod())) {
doPost(myRequest, myResponse);
}
}
}
MyServlet.java
import java.io.IOException;
/**
* @Author : LiuYan
* @create 2021/4/19 22:59
*/
public class MyServlet extends MyHttpServlet{
@Override
public void doGet(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("get mytomcat");
}
@Override
public void doPost(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("post tomcat");
}
}
MyServer.java
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Author : LiuYan
* @create 2021/4/19 23:02
*/
public class MyServer {
/**
* 定义服务端的接收程序,接收socket请求
* @param post
*/
public static void startServer(int post) throws Exception {
//定义服务端套接字
ServerSocket serverSocket = new ServerSocket(post);
// 定义客户端套接字 每个请求是不同套接字
Socket socket = null;
// 不停接收请求
while (true) {
socket = serverSocket.accept();
// 获取输入和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 定义请求对象
MyRequest myRequest = new MyRequest(inputStream);
// 定义响应对象
MyResponse myResponse = new MyResponse(outputStream);
String clazz = new MyMapping().getMapping().get(myRequest.getRequestUrl());
if (clazz != null) {
Class<MyServlet> myServletClass = (Class<MyServlet>) Class.forName(clazz);
//根据myServletClass创建对象
MyServlet myServlet = myServletClass.newInstance();
myServlet.service(myRequest, myResponse);
}
}
}
public static void main(String[] args) throws Exception {
startServer(10086);
}
}