在上一篇文章中,我们已经可以通过程序来对web.xml中的配置项进行读取了,现在,我们通过我们自己定义的MyHttpRequest得到访问的URI,然后通过map里面的映射关系,实现游览器对Servlet的访问。
思路分析 我们创建一个MyServletThread类,这个类实现了Runnable接口,这个类里面有一个Socket,这个socket在类创建时必须传入一个Socket,我们通过这个socket就可以得到InputStream和OutputStream,通过这2个流我们就能够创建MyHttpRequest对象和MyHttpResponse对象,其中MyHttpRequest对象可以获取到访问的URI,通过URI和我们在上一篇文章中的map就能够实现对MyServlet的定位。
文章图片
我们的思路差不多就是这个样子,废话就不说了,直接开始撸代码。
代码实现
首先创建类,实现Runnable接口。
public class MyServletThread implements Runnable{
}
定义Socket成员属性,并在构造器中对Socket进行赋值
//定义一个socket对象
private Socket socket = null;
//在初始化对象时传入socket
public MyServletThread(Socket socket) {
this.socket = socket;
}
实现run方法
@Override
public void run() {
}
我们具体的逻辑就在run方法中进行编写,按照上面的图,我们首先获取到InputStream和OutputStream,并且通过这2个流创建MyHttpRequest和MyHttpResponse
//获取输入流,并且通过输入流创建MyHttpRequest对象
MyHttpRequest request = new MyHttpRequestImpl(socket.getInputStream());
//获取输出流,并且通过输出流创建MyHttpResponse对象
MyHttpResponse response = new MyHttpResponseImpl(socket.getOutputStream());
我们通过MyHttpRequest得到访问的URI
//得到访问的URI
String uri = request.getUri() == null ? "": request.getUri();
下面,我们就通过URI来进行一系列的判断,判断游览器访问的MyServlet是否存在,是不是第一次访问MyServlet等
//判断是否已经创建过MyServlet实例
if(MyServletHandler.PATTERN_CLASS.containsKey(uri)){
//如果已经创建过了,直接调用该MyServlet的service方法
MyServlet myServlet = MyServletHandler.PATTERN_CLASS.get(uri);
myServlet.service(request,response);
}else if (MyServletHandler.PATTERN_NAME.containsKey(uri)){
//如果是第一次访问,我们就创建MyServlet实例,并且将该实例存入map中
String name = MyServletHandler.PATTERN_NAME.get(uri);
String classPath = MyServletHandler.NAME_CLASS.get(name);
MyServlet myServlet = (MyServlet) Class.forName(classPath).newInstance();
MyServletHandler.PATTERN_CLASS.put(uri,myServlet);
//第一次访问是调用init方法和service方法
myServlet.init();
myServlet.service(request,response);
}else {
//如果MyServlet不存在,我们直接返回404 NOT FOUND
response.setStatus(404);
response.write("404 NOT FOUND");
}
完整代码如下
import com.clucky.myTomcat.MyServletHandler;
import com.clucky.myTomcat.myHttp.MyHttpRequest;
import com.clucky.myTomcat.myHttp.MyHttpRequestImpl;
import com.clucky.myTomcat.myHttp.MyHttpResponse;
import com.clucky.myTomcat.myHttp.MyHttpResponseImpl;
import com.clucky.myTomcat.myServlet.MyServlet;
import java.net.Socket;
public class MyServletThread implements Runnable{//定义一个socket对象
private Socket socket = null;
//在初始化对象时传入socket
public MyServletThread(Socket socket) {
this.socket = socket;
}@Override
public void run() {
try {
//获取输入流,并且通过输入流创建MyHttpRequest对象
MyHttpRequest request = new MyHttpRequestImpl(socket.getInputStream());
//获取输出流,并且通过输出流创建MyHttpResponse对象
MyHttpResponse response = new MyHttpResponseImpl(socket.getOutputStream());
//得到访问的URI
String uri = request.getUri() == null ? "": request.getUri();
//判断是否已经创建过MyServlet实例
if(MyServletHandler.PATTERN_CLASS.containsKey(uri)){
//如果已经创建过了,直接调用该MyServlet的service方法
MyServlet myServlet = MyServletHandler.PATTERN_CLASS.get(uri);
myServlet.service(request,response);
}else if (MyServletHandler.PATTERN_NAME.containsKey(uri)){
//如果是第一次访问,我们就创建MyServlet实例,并且将该实例存入map中
String name = MyServletHandler.PATTERN_NAME.get(uri);
String classPath = MyServletHandler.NAME_CLASS.get(name);
MyServlet myServlet = (MyServlet) Class.forName(classPath).newInstance();
MyServletHandler.PATTERN_CLASS.put(uri,myServlet);
//第一次访问是调用init方法和service方法
myServlet.init();
myServlet.service(request,response);
}else {
//如果MyServlet不存在,我们直接返回404 NOT FOUND
response.setStatus(404);
response.write("404 NOT FOUND");
}
//关闭流
socket.close();
} catch (Exception e) {
System.out.println("创建servlet发生异常...");
}
}
}
现在,我们的每一个Servlet都编写好了,我们来创建我们的第3个版本的tomcat。创建一个类,这个类的名字就是MyTomcat03,这个类就是我们的主类,对8080端口进行监听,并负责创建MyServletThread线程对象,开启线程。
代码很简单,下面就直接给出了。
import com.clucky.myTomcat.thread.MyServletThread;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MyTomcat03{public void startUp(){
MyServletHandler.init();
try {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器在8080端口监听");
while (!serverSocket.isClosed()){
Socket socket = serverSocket.accept();
System.out.println("创建了一个线程");
MyServletThread myServletHandler = new MyServletThread(socket);
new Thread(myServletHandler).start();
}
} catch (IOException e) {
System.out.println("启动服务器异常");
}
}public static void main(String[] args) {
new MyTomcat03().startUp();
}
}
运行MyTomcat进行测试
我们启动MyTomcat03这个类,游览器访问http://localhost:8080/dog ,显示如下
文章图片
我们再访问http://localhost:8080/cat,显示如下
文章图片
我们可能忘记了MyDogServlet和MyCatServlet的内容,这2个MyServlet的内容如下
文章图片
文章图片
【#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet】我们发现游览器显示的和我们再doGet中写的一样,说明我们就已经实现了游览器访问MyServlet。经过漫长的版本迭代和大量的代码,我们终于实现了游览器访问我们自己定义的MyServlet,我们成功啦!!! 现在我们的tomcat已经可以访问MyServlet了,但是还缺少一个重要功能,就是游览器访问我们的静态资源,我将在下一篇文章中实现这个功能,下一篇文章也是【手写Tomcat】的最后一篇文章,相信大家在看完后也一定对Tomcat的运行机制有了更加深入的理解。
下一篇文章中将会实现一个相对比较完善的迷你Tomcat,我也会在下一篇文章中给出所有的源代码,感谢大家的游览!!!
推荐阅读
- javaWeb|HTTP请求
- #|HTTP基本介绍
- java|safari chrome_Mac用户应放弃Safari的Google Chrome浏览器
- 如何写好 Java 业务代码(这也是有很多规范的..)
- Spring Boot项目微信云托管入门部署
- 国产化之 Arm64 CPU + 银河麒麟系统 安装 .NetCore
- #|基于蒙特卡洛法的规模化电动汽车充电负荷预测(Python&Matlab实现)
- #|一场樱花雨(Python实现)
- #|最详细matlab 2018a安装教程步骤.