欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MyTomcat(迷你版)

程序员文章站 2022-05-13 21:46:37
...

Tomcat对于请求实际上会进行下面的处理:

第一:提供Socket服务

Tomcat的启动,必然是Socket服务,只不过它支持HTTP协议而已!

第二:进行请求的分发

要知道一个Tomcat可以为多个Web应用提供服务,那么很显然,Tomcat可以把URL下发到不同的Web应用。

第三:需要把请求和响应封装成request/response

通过输入流,对HTTP协议进行解析,拿到了HTTP请求头的方法以及URL。

package com.mytomcat;

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

public class MyRequest {

	private String url;
	private String method;
	
	public MyRequest() {
		// TODO Auto-generated constructor stub
	}
	
//	public MyRequest(String url, String method) {
//		super();
//		this.url = url;
//		this.method = method;
//	}
	/**
	 * 通过输入流,对HTTP协议进行解析,拿到HTTP请求头的方法以及URL。
	 * @param inputStream
	 * @throws IOException
	 */
	public MyRequest(InputStream inputStream) throws IOException{
		String httpRequest = "";
		byte[] httpRequestBytes = new byte[1024];
		int length = 0;
		if((length = inputStream.read(httpRequestBytes)) > 0){
			httpRequest = new String(httpRequestBytes, 0, length);
		}
		String httpHead = httpRequest.split("\n")[0];
		url = httpHead.split("\\s")[1];
		method = httpHead.split("\\s")[0];
		System.out.println(this);
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}
	
}

基于HTTP协议的格式进行输出写入。

package com.mytomcat;

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

public class MyResponse {

	private OutputStream outputStream;
	
	public MyResponse() {
		// TODO Auto-generated constructor stub
	}
	public MyResponse(OutputStream outputStream){
		this.outputStream = outputStream;
	}
	/**
	 * 基于HTTP协议的格式进行输出写入。
	 * @param content
	 * @throws IOException
	 */
	public void write(String content) throws IOException{
		StringBuffer buffer = new StringBuffer();
		buffer.append("HTTP/1.1 200 OK\n")
			.append("Content-type: text/html\n")
			.append("\r\n")
			.append("<html><body>")
			.append(content)
			.append("</body></html>");
		outputStream.write(buffer.toString().getBytes());
		outputStream.close();
	}
	
}

Servlet常见的doGet/doPost/service方法。

package com.mytomcat;

public abstract class MyServlet {

	public abstract void doGet(MyRequest myRequest, MyResponse myResponse);
	
	public abstract void doPost(MyRequest myRequest, MyResponse myResponse);
	
	public void service(MyRequest myRequest, MyResponse myResponse){
		if("POST".equalsIgnoreCase(myRequest.getMethod())){
			doPost(myRequest, myResponse);
		}else if("GET".equalsIgnoreCase(myRequest.getMethod())){
			doGet(myRequest, myResponse);
		}
	}
}

以下两个java类做测试用:

package com.mytomcat;

import java.io.IOException;

public class FindGirlServlet extends MyServlet {

	@Override
	public void doGet(MyRequest myRequest, MyResponse myResponse) {
		// TODO Auto-generated method stub
		try {
			myResponse.write("get--------FindGirlServlet");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void doPost(MyRequest myRequest, MyResponse myResponse) {
		// TODO Auto-generated method stub
		try {
			myResponse.write("post-----------FindGirlServlet");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}



package com.mytomcat;

import java.io.IOException;

public class HelloWorldServlet extends MyServlet {

	@Override
	public void doGet(MyRequest myRequest, MyResponse myResponse) {
		// TODO Auto-generated method stub
		try {
			myResponse.write("get--------HelloWorldServlet");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void doPost(MyRequest myRequest, MyResponse myResponse) {
		// TODO Auto-generated method stub
		try {
			myResponse.write("post-----------HelloWorldServlet");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

web.xml中通过<servlet></servlet>和<servlet-mapping></servlet-mapping>来进行指定哪个URL交给哪个servlet进行处理。

package com.mytomcat;

public class ServletMapping {

	private String servletName;
	private String url;
	private String clazz;
	
	public ServletMapping() {
		// TODO Auto-generated constructor stub
	}
	public ServletMapping(String servletName, String url, String clazz) {
		super();
		this.servletName = servletName;
		this.url = url;
		this.clazz = clazz;
	}
	public String getServletName() {
		return servletName;
	}
	public void setServletName(String servletName) {
		this.servletName = servletName;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getClazz() {
		return clazz;
	}
	public void setClazz(String clazz) {
		this.clazz = clazz;
	}
	
}






package com.mytomcat;

import java.util.ArrayList;
import java.util.List;

/**
 * web.xml中通过<servlet></servlet>和<servlet-mapping></servlet-mapping>
 * 来进行指定哪个URL交给哪个servlet进行处理。
 * @author kiss
 *
 */
public class ServletMappingConfig {

	public static List<ServletMapping> servletMappings = new ArrayList<ServletMapping>();
	
	static{
		servletMappings.add(new ServletMapping("findgirl", "/girl", "com.mytomcat.FindGirlServlet"));
		servletMappings.add(new ServletMapping("helloworld", "/hellworld", "com.mytomcat.HelloWorldServlet"));
	}
}

利用反射实例化具体的Servlet进行处理即可。

package com.mytomcat;

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;

public class MyTomcat {

	private Integer port = 8080;
	private Map<String, String> urlServletMap = new HashMap<String, String>();
	
	public MyTomcat() {
		// TODO Auto-generated constructor stub
	}

	public MyTomcat(Integer port) {
		super();
		this.port = port;
	}
	
//	public MyTomcat(Integer port, Map<String, String> map) {
//		super();
//		this.port = port;
//		this.urlServletMap = map;
//	}
	/**
	 * 启动mytomcat
	 */
	public void start(){
		initServletMapping();
		ServerSocket serverSocket = null;
		try {
			//相当于服务器启动了,并且监听了port
			serverSocket = new ServerSocket(port);
			System.out.println("MyTomcat is start-------");
			while(true){
				//等待客户端 连接port端口
				Socket socket = serverSocket.accept();
				//获取连接的输入输出流
				InputStream inputStream = socket.getInputStream();
				OutputStream outputStream = socket.getOutputStream();
				MyRequest myRequest = new MyRequest(inputStream);
				MyResponse myResponse = new MyResponse(outputStream);
				dispatch(myRequest, myResponse);
				socket.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(serverSocket != null){
				try {
					serverSocket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 初始化url与对应处理的servlet的关系
	 */
	private void initServletMapping(){
		for (ServletMapping servletMapping : ServletMappingConfig.servletMappings) {
			urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz());
		}
	}
	/**
	 * 请求分发
	 * @param myRequest
	 * @param myResponse
	 */
	private void dispatch(MyRequest myRequest, MyResponse myResponse){
		String clazz = urlServletMap.get(myRequest.getUrl());
		try {
			//反射
			@SuppressWarnings("unchecked")
			Class<MyServlet> myServletClass = (Class<MyServlet>) Class.forName(clazz);
			MyServlet myServlet = myServletClass.newInstance();
			myServlet.service(myRequest, myResponse);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}
}

启动mytomcat

MyTomcat(迷你版)

目前在浏览器上测试,会有两次连接,后一次连接丢失参数,导致会报空指针异常,还没找到原因。用postman测试工具测试一切正常。