#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet

在上一篇文章中,我们已经可以通过程序来对web.xml中的配置项进行读取了,现在,我们通过我们自己定义的MyHttpRequest得到访问的URI,然后通过map里面的映射关系,实现游览器对Servlet的访问。
思路分析 我们创建一个MyServletThread类,这个类实现了Runnable接口,这个类里面有一个Socket,这个socket在类创建时必须传入一个Socket,我们通过这个socket就可以得到InputStream和OutputStream,通过这2个流我们就能够创建MyHttpRequest对象和MyHttpResponse对象,其中MyHttpRequest对象可以获取到访问的URI,通过URI和我们在上一篇文章中的map就能够实现对MyServlet的定位。
#|【手写Tomcat】9.实现游览器访问我们自定义的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 ,显示如下
#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet
文章图片

我们再访问http://localhost:8080/cat,显示如下
#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet
文章图片

我们可能忘记了MyDogServlet和MyCatServlet的内容,这2个MyServlet的内容如下
#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet
文章图片

#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet
文章图片

【#|【手写Tomcat】9.实现游览器访问我们自定义的MyServlet】我们发现游览器显示的和我们再doGet中写的一样,说明我们就已经实现了游览器访问MyServlet。
经过漫长的版本迭代和大量的代码,我们终于实现了游览器访问我们自己定义的MyServlet,我们成功啦!!! 现在我们的tomcat已经可以访问MyServlet了,但是还缺少一个重要功能,就是游览器访问我们的静态资源,我将在下一篇文章中实现这个功能,下一篇文章也是【手写Tomcat】的最后一篇文章,相信大家在看完后也一定对Tomcat的运行机制有了更加深入的理解。
下一篇文章中将会实现一个相对比较完善的迷你Tomcat,我也会在下一篇文章中给出所有的源代码,感谢大家的游览!!!

    推荐阅读