Tomcat-- done manually tomcat2

Case 1. Demand

When the client sends a request to the server, the server can run java code period, and response data to the client

2. code implementation

Project directory structure diagram

2.1 defines an interface Servlet

The interface is a Java applet to run all server interface must follow

package cn.bjc.mytomcat.v2;

import java.io.InputStream;
import java.io.OutputStream;

public interface Servlet {
	public void init();
	public void service(InputStream in,OutputStream out);
	public void destroy();
}

2.2 implement server-side JAVA applets and Servlet AServlet

AServlet

package cn.bjc.mytomcat.v2;

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

public class AServlet implements Servlet {

	@Override
	public void init() {
		System.out.println("A Servlet init...");
	}

	@Override
	public void service(InputStream in, OutputStream out) {
		System.out.println("A Servlet service");
		try {
			out.write("from A Servlet!".getBytes());
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void destroy() {
		System.out.println("A Servlet Destroy");
	}

}

BServlet

package cn.bjc.mytomcat.v2;

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

public class BServlet implements Servlet {

	@Override
	public void init() {
		System.out.println("B Servlet init...");
	}

	@Override
	public void service(InputStream in, OutputStream out) {
		System.out.println("B Servlet service");
		try {
			out.write("from B Servlet!".getBytes());
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void destroy() {
		System.out.println("B Servlet Destroy");
	}

}

2.3 Configuration parameters for the server-side applet

config.properties

aa=cn.bjc.mytomcat.v2.AServlet
bb=cn.bjc.mytomcat.v2.BServlet

2.4 server configuration parameters to start studying

TestServer configuration information define a static type of Map, the storage server config.properties

// 定义一个静态类型的Map,存储服务端config.properties中的配置信息
private static Map<String,String> map = new HashMap<String,String>();
// 服务端启动之前将配置参数中的信息加载到Map
static {
	// 1. 创建一个Properties对象
	Properties pro = new Properties();
	try {
		// 2. 加载WebContent目录下的config.properties文件
		pro.load(new FileInputStream(WEB_ROOT+"\\config.properties"));
		// 3. 将配置文件中的数据读取到Map
		Set keys = pro.keySet();
		Iterator iterator = keys.iterator();
		while(iterator.hasNext()){
			String key = (String) iterator.next();
			String value = pro.getProperty(key);
			map.put(key, value);
		}
	} catch (Exception e) {
		e.printStackTrace();
	}	
}

2.5 send dynamic resource

// 发送动态资源
private static void sendDynamicResource(InputStream in,OutputStream out) throws Exception{
	// 1. 判断HTTP协议的响应行和响应头发送到客户端
	out.write("HTTP/1.1 200 OK\n".getBytes());
	out.write("Server:apache-Coyote/1.1\n".getBytes());
	out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
	out.write("\n".getBytes());
	// 2. 判断map中是否存在一个key,这个key是否与本次请求的资源路径一致
	if(map.containsKey(url)){
		// 3. 如果包含指定的key,获取到Map中的key对应的value
		String value = map.get(url);
		// 4. 通过反射,将对应的java程序加载到内存
		Class clazz = Class.forName(value);
		Servlet servlet = (Servlet)clazz.newInstance();
		// 5. 执行init
		servlet.init();
		// 6. 执行service方法
		servlet.service(in, out);	
	} else {
		String errMsg = "no mapping for " + url;
		out.write(errMsg.getBytes());
	}
}

run:

 

Complete Code TestServer

package cn.bjc.mytomcat.v2;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class TestServer {

	// 定义静态变量,用于存放服务端weContent目录的绝对路径
	public static String WEB_ROOT = System.getProperty("user.dir")+File.separator+"webContent";
	// 定义静态变量,用于存放本次请求的静态页面的名称
	private static String url;
	
	// 定义一个静态类型的Map,存储服务端config.properties中的配置信息
	private static Map<String,String> map = new HashMap<String,String>();
	// 服务端启动之前将配置参数中的信息加载到Map
	static {
		// 1. 创建一个Properties对象
		Properties pro = new Properties();
		try {
			// 2. 加载WebContent目录下的config.properties文件
			pro.load(new FileInputStream(WEB_ROOT+"\\config.properties"));
			// 3. 将配置文件中的数据读取到Map
			Set keys = pro.keySet();
			Iterator iterator = keys.iterator();
			while(iterator.hasNext()){
				String key = (String) iterator.next();
				String value = pro.getProperty(key);
				map.put(key, value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	public static void main(String[] args) throws Exception {
		ServerSocket server = null;
		Socket socket = null;
		OutputStream out = null;
		InputStream in = null;
		// 1. 创建ServerSocket,监听本地8080端口,等待来自客户端的请求
		try {
			server = new ServerSocket(8080);
			while(true){
				// 获取客户端对应的socket
				socket = server.accept();
				// 获取输入流对象
				in = socket.getInputStream();
				// 获取输出流对象
				out = socket.getOutputStream();
				// 获取HTTP协议的请求部分,截取客户端要访问的资源名称,将这个资源名称赋值给url
				parse(in);
				// 根据url判断请求的是静态还是动态的
				if(null != url){
					if(url.indexOf(".") != -1){
						// 发送静态资源
						sendStaticResource(out);
					} else {
						sendDynamicResource(in, out);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			
		}
	}
	
	// 发送动态资源
	private static void sendDynamicResource(InputStream in,OutputStream out) throws Exception{
		// 1. 判断HTTP协议的响应行和响应头发送到客户端
		out.write("HTTP/1.1 200 OK\n".getBytes());
		out.write("Server:apache-Coyote/1.1\n".getBytes());
		out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
		out.write("\n".getBytes());
		// 2. 判断map中是否存在一个key,这个key是否与本次请求的资源路径一致
		if(map.containsKey(url)){
			// 3. 如果包含指定的key,获取到Map中的key对应的value
			String value = map.get(url);
			// 4. 通过反射,将对应的java程序加载到内存
			Class clazz = Class.forName(value);
			Servlet servlet = (Servlet)clazz.newInstance();
			// 5. 执行init
			servlet.init();
			// 6. 执行service方法
			servlet.service(in, out);
			
		} else {
			String errMsg = "no mapping for " + url;
			out.write(errMsg.getBytes());
		}
	}
	
	// 发送静态资源
	private static void sendStaticResource(OutputStream out) throws Exception {
		// 1. 定义一个字节数组,用于存放本次请求的静态资源demo01.html的内容
		byte[] bytes = new byte[2048];
		// 2. 定义一个文件输入流,用户获取静态资源demo01.html中的内容
		FileInputStream fis = null;
		try {
			// 3. 创建文件对象File,代表本次要请求的资源demo01.html
			File file = new File(WEB_ROOT,url);
			// 4. 如果文件存在
			if(file.exists()){
				// 4.1 向客户端输出HTTP协议的响应行/响应头
				out.write("HTTP/1.1 200 OK\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				// 4.2 获取到文件输入流对象
				fis = new FileInputStream(file);
				// 4.3 读取静态资源demo01.html中的内容到数组中
				int ch = fis.read(bytes);
				while(ch != -1){
					// 4.4 将读取到数组中的内容通过输出流发送到客户端
					out.write(bytes, 0, ch);
					ch = fis.read(bytes);
				}
			}else {
				// 5. 如果文件不存在
				// 5.1 向客户端响应文件不存在的消息
				out.write("HTTP/1.1 404 not found\n".getBytes());
				out.write("Server:apache-Coyote/1.1\n".getBytes());
				out.write("Content-Type:text/html;charset=utf-8\n".getBytes());
				out.write("\n".getBytes());
				String errMsg = "file not found";
				out.write(errMsg.getBytes());
			}
		} catch(Exception e){
			e.printStackTrace();
		}finally {
			// 6. 释放资源
			if(null != fis){
				fis.close();
			}
		}
		
	}
	private static void parse(InputStream in) throws Exception {
		// 1. 定义一个变量,存放HTTP协议请求部分数据
		StringBuffer content = new StringBuffer();
		// 2. 定义一个数组,存放HTTP协议请求部分数据
		byte[] buffer = new byte[2048];
		// 3. 定义一个变量i,代表读取数据到数组中之后,数据量的大小
		int i = -1;
		// 4. 读取客户端发过来的数据,将数据读取到字节数组buffer中,i代表读取数据量的大小311字节
		i = in.read(buffer);
		// 5. 遍历字节数组,将数组中的数据追加到content变量中
		for(int j = 0 ; j < i ; j++){
			content.append((char)buffer[j]);
		}
		// 6. 打印HTTP协议请求部分数据
		System.out.println(content);
		// 7. 截取客户端要请求的资源路径 demo.html,赋值给url
		parseUrl(content.toString());
		System.out.println(url);
	}

	// 解析请求数据得到请求连接
	private static void parseUrl(String content) {
		/*
		 * 	GET /erp/dep/getAll HTTP/1.1
			Host: localhost:8080
			Connection: keep-alive
			Upgrade-Insecure-Requests: 1
			User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
			Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng;q=0.8
			Accept-Encoding: gzip, deflate, br
			Accept-Language: zh-CN,zh;q=0.9
			Cookie: __guid=111872281.1743065663273879000.1567260921404.8972
		 * 
		 * */
		// 1. 截取客户端请求资源的名称   /erp/dep/getAll
		// 2. 定义2个变量,存放请求行的2个空格位置
		int index1,index2;
		// 3. 获取http请求行的第一个空格的位置
		index1 = content.indexOf(" ");
		if(index1 != -1){ // 表示存在第一个空格
			// 从第一个空格之后开始查找
			// 4. 获取http请求行的第二个空格的位置
			index2 = content.indexOf(" ", index1+1);
			if(index2 > index1){
				// 5. 截取字符串获取到本次请求的资源的名称
				url = content.substring(index1+2, index2);
			}
		}
	}

}

to sum up:

        By manually implement tomcat, we can still find a java applet running on the server side java program nature, but we need to implement the agreed Servlet this interface, you only need to do the corresponding configuration information, then we can through the browser to the server sends a request, so that the service side of the java applet execution!

Published 128 original articles · won praise 6 · views 3231

Guess you like

Origin blog.csdn.net/weixin_43318134/article/details/103749160