主流网站建设,p2p网站开发维护,甘肃网站建设公司电话,梅河口信息网目录
引入
Servlet容器
一、优化MyTomcat
①先将MyTomcat的main函数搬过来#xff1a;
②将getClass()函数搬过来 ③创建容器 ④连接ServletConfigMapping和MyTomcat
连接#xff1a;
⑤完整的ServletConfigMapping和MyTomcat方法#xff1a;
a.ServletConfigMappin…目录
引入
Servlet容器
一、优化MyTomcat
①先将MyTomcat的main函数搬过来
②将getClass()函数搬过来 ③创建容器 ④连接ServletConfigMapping和MyTomcat
连接
⑤完整的ServletConfigMapping和MyTomcat方法
a.ServletConfigMapping
b.MyTomcat
二、优化Server 方法1调用可以用但是这里咱们不用过于冗余
方法二 直接嵌套
三、获取类对象
处理请求
实现上述操作后就可以测试是否正确
本地的Key值是 “/myFrist”
去客户端浏览器输入试试
结果 引入 在先前的tomcat搭建学习中已经对tomcat的雏形做了基本的实现即如下的过程 接下来继续tomcat的搭建。 Servlet容器
目前Servlet容器 接下来我们来优化一下MyTomcat:
一、优化MyTomcat
首先在tomcat包下创建一下config包然后在里面创建文件ServletConfigMapping
那么ServletConfigMapping里面编写什么呢就是从MyTomcat中编写的内容现在需要copy到这个文件中实现MyTomcat的解放
【ServletConfigMapping在tomcat中就是为了获取配置信息而MyTomcat中写的正是扫描的过程即未来扫描动态资源映射表的过程所以现在将它放进合适的地方即ServletConfigMapping里面】
注意 不是原封不动的照搬需要做一些小小的调整。
①先将MyTomcat的main函数搬过来
注意这里做了个小调整将MyTomcat的main函数里面的内容放进了代码块中 static代码块的特点在main函数执行之前先执行 static{try {// 1. 扫描包路径 (com.wzh.tomcat.myweb)String packageName com.qcby.tomcat.myweb;ListClass? classes getClasses(packageName); //通过getClasses()方法获取到了myweb这个包下面的所有类的类对象并将其放到了类对象中// 2. 遍历所有类检查是否有WebServlet注解for (Class? clazz : classes) {if (clazz.isAnnotationPresent(WebServlet.class)) {// 3. 获取WebServlet注解的值WebServlet webServlet clazz.getAnnotation(WebServlet.class);System.out.println(类名: clazz.getName() | URL路径: webServlet.url());classMap.put(webServlet.url(),(ClassHttpServlet) clazz);}}} catch (Exception e) {e.printStackTrace();}}
②将getClass()函数搬过来 这里直接copy就好放到刚才的static代码块之下
/*** 获取指定包下的所有类** param packageName 包名例如 com.qcby.tomcat.myweb* return 类对象列表* throws Exception*///将MyTomcat中的getClass方法也粘贴过来private static ListClass? getClasses(String packageName) throws Exception {ListClass? classes new ArrayList(); //将类文件封装进List中String path packageName.replace(., /); // 将包名转换为文件路径// 通过类加载器获取包的资源路径ClassLoader classLoader Thread.currentThread().getContextClassLoader();EnumerationURL resources classLoader.getResources(path);while (resources.hasMoreElements()) {URL resource resources.nextElement();File directory new File(resource.toURI());// 扫描文件夹下的所有类文件if (directory.exists()) {for (File file : directory.listFiles()) {if (file.getName().endsWith(.class)) { //获得.class文件// 获取类的完整类名String className packageName . file.getName().replace(.class, );classes.add(Class.forName(className));}}}}return classes;} 基于static代码块会在main方法之前执行的特性想要执行static中的内容只需要放一个空的main函数运行即可
public static void main(String[] args) {//当然也可以直接将static中的内容放进main函数里面不常用} ③创建容器
真正的servlet容器
public static MapString,ClassHttpServlet classMapnew HashMap(); /* * 至于这里value的位置为什么写HttpServlet呢按理说应该写类对象----多态 * 多态--父类的引用指向子类的对象 * 不妨来看一下能写进来的MyFirstServlet、MySecondServlet、MyThirdServlet等的类对象 * 这些类对象都继承了HttpServlet * 即 * MyFirstServlet的类对象---是HttpServlet的子类 * MySecondServlet的类对象---是HttpServlet的子类 * MyThirdServlet的类对象---是HttpServlet的子类 *【多态性--父类的引用指向子类的对象并且子类的对象可以向上转型为父类的引用】 * */ ④连接ServletConfigMapping和MyTomcat
我们只是想优化MyTomcat而不是彻底换掉MyTomcat所以现在我们要做的就是将创建的ServletConfigMapping和先前的MyTomcat连接起来
当然由于主要代码已经放进ServletConfigMapping中了所以原先的MyTomcat可以清空了。
连接
注意②中的执行方法---放main那么想要连接ServletConfigMapping和MyTomcat我们依旧可以采用这种方法让MyTomcat调用ServletConfigMapping中的方法迫使ServletConfigMapping中的static代码块运行。
public class MyTomcat {public static void main(String[] args) {ServletConfigMapping.init();//通过调用ServletConfigMapping中的静态方法来促使ServletConfigMapping类的执行即将这两个类通过这种方式连接}
}当然这个写在ServletConfigMapping中的方法可以是空的。
⑤完整的ServletConfigMapping和MyTomcat方法
a.ServletConfigMapping
package com.qcby.tomcat.config;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.webservlet.WebServlet;import java.io.File;
import java.net.URL;
import java.util.*;/*
* servlet容器
* */public class ServletConfigMapping {//真正的servlet容器/** 至于这里value的位置为什么写HttpServlet呢按理说应该写类对象----多态* 多态--父类的引用指向子类的对象* 不妨来看一下能写进来的MyFirstServlet、MySecondServlet、MyThirdServlet等的类对象* 这些类对象都继承了HttpServlet* 即* MyFirstServlet的类对象---是HttpServlet的子类* MySecondServlet的类对象---是HttpServlet的子类* MyThirdServlet的类对象---是HttpServlet的子类*【多态性--父类的引用指向子类的对象并且子类的对象可以向上转型为父类的引用】* */public static MapString,ClassHttpServlet classMapnew HashMap();//扫描遍历即MyTomcat之中的内容//static代码块在main方法执行之前执行//将MyTomcat中的main方法放进代码块中static{try {// 1. 扫描包路径 (com.wzh.tomcat.myweb)String packageName com.qcby.tomcat.myweb;ListClass? classes getClasses(packageName); //通过getClasses()方法获取到了myweb这个包下面的所有类的类对象并将其放到了类对象中// 2. 遍历所有类检查是否有WebServlet注解for (Class? clazz : classes) {if (clazz.isAnnotationPresent(WebServlet.class)) {// 3. 获取WebServlet注解的值WebServlet webServlet clazz.getAnnotation(WebServlet.class);System.out.println(类名: clazz.getName() | URL路径: webServlet.url());classMap.put(webServlet.url(),(ClassHttpServlet) clazz);}}} catch (Exception e) {e.printStackTrace();}}/*** 获取指定包下的所有类** param packageName 包名例如 com.qcby.tomcat.myweb* return 类对象列表* throws Exception*///将MyTomcat中的getClass方法也粘贴过来private static ListClass? getClasses(String packageName) throws Exception {ListClass? classes new ArrayList(); //将类文件封装进List中String path packageName.replace(., /); // 将包名转换为文件路径// 通过类加载器获取包的资源路径ClassLoader classLoader Thread.currentThread().getContextClassLoader();EnumerationURL resources classLoader.getResources(path);while (resources.hasMoreElements()) {URL resource resources.nextElement();File directory new File(resource.toURI());// 扫描文件夹下的所有类文件if (directory.exists()) {for (File file : directory.listFiles()) {if (file.getName().endsWith(.class)) { //获得.class文件// 获取类的完整类名String className packageName . file.getName().replace(.class, );classes.add(Class.forName(className));}}}}return classes;}//基于static代码块会在main方法之前执行的特性想要执行static中的内容只需要放一个空的main函数运行即可public static void main(String[] args) {//当然也可以直接将static中的内容放进main函数里面不常用}public static void init(){}}b.MyTomcat
package com.qcby.tomcat;import com.qcby.tomcat.config.ServletConfigMapping;public class MyTomcat {public static void main(String[] args) {ServletConfigMapping.init();//通过调用ServletConfigMapping中的静态方法来促使ServletConfigMapping类的执行即将这两个类通过这种方式连接}
}二、优化Server
用同样的方法首先把server的main函数解放掉
【将main函数中的内容取出并放进新创的serverInit函数中删除原来的main函数即可。】
//优化Server取出main方法public static void serverInit() throws Exception {// 1.打开通信端口 tomcat8080 3306 ---------》进行网络通信ServerSocket serverSocket new ServerSocket(8080);System.out.println(****************server start.....);//2.接受请求数据while (true) {Socket socket serverSocket.accept(); //---------------------注意此时监听网卡的是主线程System.out.println(有客户进行了链接);new Thread(() - {//处理数据---------》数据的处理在于读和写try {handler(socket);} catch (Exception e) {e.printStackTrace();}}).start();}} 方法1调用可以用但是这里咱们不用过于冗余 接着用同样的操作在MyTomcat中调用这新创建的方法 package com.qcby.tomcat;import com.qcby.tomcat.config.ServletConfigMapping;
import com.qcby.tomcat.socket.Server;public class MyTomcat {public static void main(String[] args) {try {//通过调用ServletConfigMapping中的静态方法来促使ServletConfigMapping类的执行即将这两个类通过这种方式连接ServletConfigMapping.init();//初始化servlet容器Server.serverInit();//启动server服务} catch (Exception e) {e.printStackTrace();}}
} 【看着代码变多了很多实际上就加了一行然后为了安全性抛出了异常】 方法二 直接嵌套
这里我们用另一种方法去优化Server即将Server和MyTomcat连接起来
即直接将方才做过修改的代码粘贴到MyTomcat中并且在MyTomcat的main函数中调用Server的serverInit(即过去Server类的main函数)
如下是这一小阶段完成后的MyTomcat代码示意
package com.qcby.tomcat;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.config.ServletConfigMapping;
import com.qcby.tomcat.socket.Server;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class MyTomcat {//实例化Requestpublic static Request request new Request();public static void main(String[] args) throws Exception {ServletConfigMapping.init();serverInit();}//优化Server取出main方法public static void serverInit() throws Exception {// 1.打开通信端口 tomcat8080 3306 ---------》进行网络通信ServerSocket serverSocket new ServerSocket(8080);System.out.println(****************server start.....);//2.接受请求数据while (true) {Socket socket serverSocket.accept(); //---------------------注意此时监听网卡的是主线程System.out.println(有客户进行了链接);new Thread(() - {//处理数据---------》数据的处理在于读和写try {handler(socket);} catch (Exception e) {e.printStackTrace();}}).start();}}public static void handler(Socket socket) throws Exception {//读取请求的数据InputStream inputStream socket.getInputStream();requestContext(inputStream);}public static void requestContext(InputStream inputStream) throws IOException { //获取全部信息//将bit流转为文字信息int count 0;while (count 0) {count inputStream.available();}byte[] bytes new byte[count];inputStream.read(bytes);String Context new String(bytes);System.out.println(Context);//解析数据if (Context.equals()) {System.out.println(你输入了一个空请求);} else {String firstLine Context.split(\\n)[0];String method firstLine.split(\\s)[0];String path firstLine.split(\\s)[1];System.out.println(method path);//任何请求都会被打到这个类中随后就会被解析//将解析后的数据method和path放进申请的static的Request实例中--再被运输给其他需要的地方request.setMethod(method);request.setPath(path);}}
}三、获取类对象
前面已经对MyTomcat做了优化下一步就是去获取类对象
如何获取类对象呢简单来说谁存储着类对象的信息呢---Request
那么就要接着对server类做出优化---因为目前Server和MyTomcat类还是存在问题两者打不通
既然想把两者联系起来那么就要有嵌套调用或是直接嵌套。
在这里我们依旧是用直接嵌套的方法写
处理请求
处理接收到的请求首先在Map映射中寻找是否能够匹配上key值即传送的path值 能查到则取获取Map的value值即类对象 //处理请求public static void dis(Request request) throws Exception {if(!request.getPath().equals()){if(ServletConfigMapping.classMap.get(request.getPath())!null){//能进到这里则说明能够获取Map中对应的key值能够匹配上ClassHttpServlet classServletServletConfigMapping.classMap.get(request.getPath());HttpServlet servletclassServlet.newInstance(); //newInstance动态地创建一个类的新实例对象servlet.doGet(request,response);}}}
上面的代码最终是要被requestContext(InputStream inputStream)函数调用的。
即最终的MyTomcat代码
package com.qcby.tomcat;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.config.ServletConfigMapping;
import com.qcby.tomcat.socket.Server;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class MyTomcat {//实例化Requestpublic static Request request new Request();public static Response response new Response();public static void main(String[] args) throws Exception {//两项调用连接ServletConfigMapping.init();serverInit();}//处理请求public static void dis(Request request) throws Exception {if(!request.getPath().equals()){if(ServletConfigMapping.classMap.get(request.getPath())!null){//能进到这里则说明能够获取Map中对应的key值能够匹配上ClassHttpServlet classServletServletConfigMapping.classMap.get(request.getPath());HttpServlet servletclassServlet.newInstance(); //newInstance动态地创建一个类的新实例对象servlet.doGet(request,response);}}}//优化Server取出main方法public static void serverInit() throws Exception {// 1.打开通信端口 tomcat8080 3306 ---------》进行网络通信ServerSocket serverSocket new ServerSocket(8080);System.out.println(****************server start.....);//2.接受请求数据while (true) {Socket socket serverSocket.accept(); //---------------------注意此时监听网卡的是主线程System.out.println(有客户进行了链接);new Thread(() - {//处理数据---------》数据的处理在于读和写try {handler(socket);} catch (Exception e) {e.printStackTrace();}}).start();}}public static void handler(Socket socket) throws Exception {//读取请求的数据InputStream inputStream socket.getInputStream();requestContext(inputStream);}public static void requestContext(InputStream inputStream) throws Exception { //获取全部信息//将bit流转为文字信息int count 0;while (count 0) {count inputStream.available();}byte[] bytes new byte[count];inputStream.read(bytes);String Context new String(bytes);System.out.println(Context);//解析数据if (Context.equals()) {System.out.println(你输入了一个空请求);} else {String firstLine Context.split(\\n)[0];String method firstLine.split(\\s)[0];String path firstLine.split(\\s)[1];System.out.println(method path);//任何请求都会被打到这个类中随后就会被解析//将解析后的数据method和path放进申请的static的Request实例中--再被运输给其他需要的地方request.setMethod(method);request.setPath(path);}//调用上面的处理函数dis(request);}
}实现上述操作后就可以测试是否正确
本地的Key值是 “/myFrist” 去客户端浏览器输入试试 输入对应key值的
结果
取看输出这里: 可以看出上述代码被顺利执行了。