分析

一般我们使用Servlet,需要在web.xml文件中配置:

迷你版Tomcat手写_ide

然后写一个TestServlet继承HttpSerevlet,重写doGet()和doPost()方法。

这时难免会有这样的疑问:

迷你版Tomcat手写_tomcat_02

迷你版Tomcat手写_ide_03

总体:

迷你版Tomcat手写_tomcat_04

Request:

package com.dongguabai.tomcat.http;

import java.io.IOException;
import java.io.InputStream;

/**
* @author Dongguabai
* @date 2018/10/9 21:10
*/
public class DongguabaiRequest {

private String method;
private String url;

public DongguabaiRequest(InputStream is){
String content = "";
byte[] buff = new byte[1024];
int len = 0;
try {
if ((len=is.read(buff))>0){
content = new String(buff,0,len);
//content
// GET /web/user/query.json?name=zhangsan HTTP/1.1
// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134
// Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
// Upgrade-Insecure-Requests: 1
// Accept-Encoding: gzip, deflate
// Host: localhost:18888
// Connection: Keep-Alive
// Cookie: expand_index=0; theme=bda-green-white
//System.out.println(content);
String line = content.split("\\n")[0];
String[] arr = line.split("\\s");
//获取方法参数也可以这么解析,这里就不演示了
this.method = arr[0];
this.url = arr[1].split("\\?")[0];

}
} catch (IOException e) {
e.printStackTrace();
}
}

public String getMethod() {
return method;
}

public String getUrl() {
return url;
}
}

Response:

package com.dongguabai.tomcat.http;

import java.io.IOException;
import java.io.OutputStream;

/**
* @author Dongguabai
* @date 2018/10/9 21:10
*/
public class DongguabaiResponse {

private OutputStream os;

public DongguabaiResponse(OutputStream os){
this.os = os;
}

public void write(String outString) throws IOException {
os.write(outString.getBytes());
}
}

Servlet:

package com.dongguabai.tomcat.http;

/**
* @author Dongguabai
* @date 2018/10/9 21:10
*/
public abstract class DongguabaiServlet {

/**
* Does nothing, because this is an abstract class.
*/
public DongguabaiServlet() {
// NOOP
}

public void service(DongguabaiRequest request,DongguabaiResponse response) throws Exception{
//由Servie方法觉得是执行post还是get方法
if ("GET".equalsIgnoreCase(request.getMethod())){
doGet(request,response);
}else if ("POST".equalsIgnoreCase(request.getMethod())){
doPost(request,response);
}
}

public void destroy(DongguabaiRequest request,DongguabaiResponse response) throws Exception{

}

public abstract void doGet(DongguabaiRequest request, DongguabaiResponse response) throws Exception;

public abstract void doPost(DongguabaiRequest request, DongguabaiResponse response) throws Exception;
}

demo:

package com.dongguabai.tomcat.servlet;

import com.dongguabai.tomcat.http.DongguabaiRequest;
import com.dongguabai.tomcat.http.DongguabaiResponse;
import com.dongguabai.tomcat.http.DongguabaiServlet;

/**
* @author Dongguabai
* @date 2018/10/9 21:13
*/
public class Demo1Servlet extends DongguabaiServlet {
@Override
public void doGet(DongguabaiRequest request, DongguabaiResponse response) throws Exception {
doPost(request,response);
}

@Override
public void doPost(DongguabaiRequest request, DongguabaiResponse response) throws Exception {
response.write("this is demo1");
}
}
package com.dongguabai.tomcat.servlet;

import com.dongguabai.tomcat.http.DongguabaiRequest;
import com.dongguabai.tomcat.http.DongguabaiResponse;
import com.dongguabai.tomcat.http.DongguabaiServlet;

/**
* @author Dongguabai
* @date 2018/10/9 21:13
*/
public class Demo2Servlet extends DongguabaiServlet {
@Override
public void doGet(DongguabaiRequest request, DongguabaiResponse response) throws Exception {
doPost(request,response);
}

@Override
public void doPost(DongguabaiRequest request, DongguabaiResponse response) throws Exception {
response.write("this is demo2");
}
}

Tomcat:

package com.dongguabai.tomcat;

import com.dongguabai.tomcat.http.DongguabaiRequest;
import com.dongguabai.tomcat.http.DongguabaiResponse;
import com.dongguabai.tomcat.http.DongguabaiServlet;
import com.dongguabai.tomcat.util.PropUtil;

import java.io.FileInputStream;
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;
import java.util.Properties;

/**
* @author Dongguabai
* @date 2018/10/9 21:04
*/
public class DongguabaiTomcat {

private int defaultPort = 8888;
private ServerSocket server;

private Properties webXml = new Properties();
private Map<String,DongguabaiServlet> servletMapping = new HashMap<>();

private DongguabaiTomcat() {
}

public static void main(String[] args) {
new DongguabaiTomcat().start();
}

private void start() {
init();
int port;
try {
String userPort = PropUtil.getProperty("port");
port = Integer.valueOf(userPort);
} catch (Exception e) {
port = defaultPort;
e.printStackTrace();
}
try {
server = new ServerSocket(port);
System.out.println("Tomcat已经启动了,监听端口为:" + port);
//接收用户请求
while (true) {
Socket socket = server.accept();
process(socket);
}
} catch (Exception e) {
e.printStackTrace();
}
}

private void init() {
//根据web.properties,初始化ServletMapping
try {
//相当于WEB-INF下的web.xml
String webInf = this.getClass().getResource("/").getPath();
webXml.load(new FileInputStream(webInf + "web.properties"));
for (Object o : webXml.keySet()) {
String key = o.toString();
if (key.endsWith(".url")) {
String servletName = key.replaceAll("\\.url$", "");
String url = webXml.getProperty(key);
String className = webXml.getProperty(servletName + ".className");
DongguabaiServlet servlet = (DongguabaiServlet) Class.forName(className).newInstance();
servletMapping.put(url,servlet);
}
}

} catch (Exception e) {
e.printStackTrace();
}
}

private void process(Socket client){
//获取Socket对象,将Socket.getInputStream()封装成Request,Socket.getOuputStream()封装成Response
try {
try (OutputStream outputStream = client.getOutputStream();InputStream inputStream = client.getInputStream();) {
DongguabaiRequest request = new DongguabaiRequest(inputStream);
DongguabaiResponse response = new DongguabaiResponse(outputStream);
//实现动态调用doGet/doPost方法,并且能够自定义返回结果
//拿到用户请求的url
String url = request.getUrl();
if (servletMapping.containsKey(url)) {
servletMapping.get(request.getUrl()).service(request, response);
}else {
response.write("404-NOT FOUND");
}
//因为http请求是短链接,这里要关闭
client.close();
}
} catch (Exception e) {
e.printStackTrace();
}

}
}

测试结果:

迷你版Tomcat手写_tomcat_05

迷你版Tomcat手写_tomcat_06

迷你版Tomcat手写_tomcat_07