1.封装请求对象
package tomcat.http;
import lombok.Getter;
import lombok.ToString;
import java.io.IOException;
import java.io.InputStream;
/**
* 通过输入流,对HTTP协议进行解析,拿到HTTP请求头的方法以及URL。
*
* @author Manaphy
*/
@Getter
@ToString
public class MyRequest {
private final String url;
private final String method;
public MyRequest(InputStream inputStream) throws IOException {
String httpRequest = "";
byte[] httpRequestBytes = new byte[1024];
int length;
if ((length = inputStream.read(httpRequestBytes)) > 0) {
httpRequest = new String(httpRequestBytes, 0, length);
}
// HTTP请求协议
// GET /favicon.ico HTTP/1.1
// Accept: */*
// Accept-Encoding: gzip, deflate
// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36
// Connection: keep-alive
String httpHead = httpRequest.split("\n")[0];
url = httpHead.split("\\s")[1];
method = httpHead.split("\\s")[0];
System.out.println(this);
}
}
2.封装响应对象
package tomcat.http;
import java.io.IOException;
import java.io.OutputStream;
/**
* 基于HTTP协议的格式进行输出写入。
*
* @author Manaphy
*/
public class MyResponse {
private final OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
public void write(String content) throws IOException {
/*
HTTP响应协议
HTTP/1.1 200 OK
Content-Type: text/html
<html><body></body></html>
*/
String httpResponse = "HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" +
"<html><body>" +
content +
"</body></html>";
outputStream.write(httpResponse.getBytes());
outputStream.close();
}
}
3. Servlet 请求处理基类
package tomcat.http;
import java.io.IOException;
/**
* Servlet 请求处理基类
*
* @author Manaphy
*/
public abstract class AbstractServlet {
private static final String POST = "POST";
private static final String GET = "GET";
/**
* get请求
*
* @param myRequest 我的请求
* @param myResponse 我的响应
* @throws IOException IOException
*/
public abstract void doGet(MyRequest myRequest, MyResponse myResponse) throws IOException;
/**
* post请求
*
* @param myRequest 我的请求
* @param myResponse 我的响应
* @throws IOException IOException
*/
public abstract void doPost(MyRequest myRequest, MyResponse myResponse) throws IOException;
public void service(MyRequest myRequest, MyResponse myResponse) throws IOException {
if (POST.equalsIgnoreCase(myRequest.getMethod())) {
doPost(myRequest, myResponse);
} else if (GET.equalsIgnoreCase(myRequest.getMethod())) {
doGet(myRequest, myResponse);
}
}
}
4.Servlet 实现类
package tomcat.servlet;
import tomcat.http.AbstractServlet;
import tomcat.http.MyRequest;
import tomcat.http.MyResponse;
import java.io.IOException;
/**
* 测试用的实现类
*
* @author Manaphy
*/
public class FindGirlServlet extends AbstractServlet {
@Override
public void doGet(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("get girl...");
}
@Override
public void doPost(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("post girl...");
}
}
package tomcat.servlet;
import tomcat.http.AbstractServlet;
import tomcat.http.MyRequest;
import tomcat.http.MyResponse;
import java.io.IOException;
/**
* 测试用的实现类
*
* @author Manaphy
*/
public class HelloWorldServlet extends AbstractServlet {
@Override
public void doGet(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("get world...");
}
@Override
public void doPost(MyRequest myRequest, MyResponse myResponse) throws IOException {
myResponse.write("post world...");
}
}
5.Servlet 配置
package tomcat.servlet;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
/**
* web.xml中servlet的对象
*
* @author Manaphy
*/
@Getter
@Setter
@AllArgsConstructor
public class ServletMapping {
private String servletName;
private String url;
private String clazz;
}
package tomcat.servlet;
import java.util.ArrayList;
import java.util.List;
/**
* servlet映射配置
* 我们在servlet开发中,会在web.xml中通过<servlet></servlet>
* 和<servlet-mapping></servlet-mapping>来进行指定哪个URL交给哪个servlet进行处理。
*
* @author Manaphy
*/
public class ServletMappingConfig {
public static List<ServletMapping> servletMappingList = new ArrayList<>();
static {
servletMappingList.add(new ServletMapping("findGirl", "/girl", "tomcat.servlet.FindGirlServlet"));
servletMappingList.add(new ServletMapping("helloWorld", "/world", "tomcat.servlet.HelloWorldServlet"));
}
}
6.主启动类
package tomcat;
import tomcat.http.AbstractServlet;
import tomcat.http.MyRequest;
import tomcat.http.MyResponse;
import tomcat.servlet.ServletMapping;
import tomcat.servlet.ServletMappingConfig;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* Tomcat主程序
* 1.提供Socket服务
* 2.进行请求的分发
* 3.需要把请求和响应封装成request/response
*
* @author Manaphy
*/
public class TomcatMain {
private int port = 8080;
private final Map<String, AbstractServlet> urlServletMap = new HashMap<>();
public TomcatMain(int port) {
this.port = port;
}
public TomcatMain() {
}
public void start() {
//初始化 URL 与对应处理的 servlet 的关系
initServletMapping();
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Tomcat started on port(s): " + port);
while (true) {
Socket socket = serverSocket.accept();
//请求分发
dispatch(socket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void initServletMapping() {
try {
for (ServletMapping servletMapping : ServletMappingConfig.servletMappingList) {
String url = servletMapping.getUrl();
AbstractServlet servlet = (AbstractServlet) Class.forName(servletMapping.getClazz()).newInstance();
urlServletMap.put(url, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void dispatch(Socket socket) {
try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream()) {
MyRequest myRequest = new MyRequest(inputStream);
MyResponse myResponse = new MyResponse(outputStream);
String url = myRequest.getUrl();
if (urlServletMap.containsKey(url)) {
urlServletMap.get(url).service(myRequest, myResponse);
} else {
myResponse.write("404 NOT FOUNT");
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new TomcatMain().start();
}
}
7.测试
控制台输出