红番茄 网站点评,宣传片拍摄制作公司报价明细,达人室内设计网官方,专门查企业的网站目录
引入
一、在Java中创建一个新的空项目#xff08;初步搭建#xff09;
问题#xff1a;
要求在tomcat软件包下的MyTomcat类中编写main文件#xff0c;实现在MyTomcat中扫描myweb软件包中的所有Java文件#xff0c;并返回“WebServlet(urlmyFirst)”中…目录
引入
一、在Java中创建一个新的空项目初步搭建
问题
要求在tomcat软件包下的MyTomcat类中编写main文件实现在MyTomcat中扫描myweb软件包中的所有Java文件并返回“WebServlet(urlmyFirst)”中url内填写的值
①main函数解析:
首先main函数用try-catch做了异常处理
指定包名 获取包下所有类的类对象
扫描遍历
二、搭建服务器端
在socket软件包的Server文件中编写当存在客户端连接后获取
分析一下获取路径和请求方法的过程
三、搭建
重写service方法 引入 前面已经提到了TomCat就是项目运行的环境之前用到的Servlet文件都是通过eclipse中的tomcat容器来运行的那么接下来在Java文件中去模拟这个过程。 在tomcat项目中创建Servlet项目。 一、在Java中创建一个新的空项目初步搭建
创建新项目后再去在目录下创建如下软件包和Java类。 WebServlet接口中代码
package com.qcby.tomcat.webservlet;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Retention(value RetentionPolicy.RUNTIME)
Target(value{ElementType.TYPE})
public interface WebServlet {String url() default ;String className() default ;
}myweb里面的MyFirstServlet等三个文件内调用WebServlet接口如下代码 以MyFirstServlet为例
package com.qcby.tomcat.myweb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.webservlet.WebServlet;WebServlet(urlmyFirst)
public class MyFirstServlet extends HttpServlet {}问题
要求在tomcat软件包下的MyTomcat类中编写main文件实现在MyTomcat中扫描myweb软件包中的所有Java文件并返回“WebServlet(urlmyFirst)”中url内填写的值
MyTomcat内
package com.qcby.tomcat;import com.qcby.tomcat.webservlet.WebServlet;import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;public class MyTomcat {public static void main(String[] args) {//扫描myweb这个包下的所有文件并获取到它的WebServlet中的url的值// get current dirtry {// 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());}}} catch (Exception e) {e.printStackTrace();//打印异常}}/*** 获取指定包下的所有类** param packageName 包名例如 com.qcby.tomcat.myweb* return 类对象列表* throws Exception*/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文件.java-.class此处获取的就是经过编译后的.class文件// 获取类的完整类名String className packageName . file.getName().replace(.class, );classes.add(Class.forName(className));}}}}return classes;}
}解析
①main函数解析:
首先main函数用try-catch做了异常处理 try-catch块用于捕获并处理在扫描包和读取注解时可能发生的异常。 指定包名 String packageName com.qcby.tomcat.myweb;定义了一个字符串变量packageName它存储了要扫描的包名。 获取包下所有类的类对象 ListClass? classes getClasses(packageName);这行代码调用了一个名为getClasses的方法后面分析getClasses就知道这是一个获取类对象的方法将这些获取的类对象写入到一个泛型中方便后续遍历。调用getClasses方法传入包名获取该包下所有类的Class对象列表并存储在classes变量中。 扫描遍历 对获得并写入List中的每个文件进行isAnnotationPresent判断是否有WebServlet注解 【注释isAnnotationPresent是Java语言中的一种方法它主要用于判断某个类、方法、变量等元素上是否存在指定类型的注解。】 调用clazz.getAnnotation(WebServlet.class);时Java虚拟机JVM会做以下几件事情 检查clazz对象所代表的类上是否存在WebServlet注解的实例。如果存在返回这个注解的实例。如果不存在返回null。 扫描获得后打印输出。
那么分析完成main函数后接着来分析一下getClases方法具体是怎么实现获取包中类信息的
详细参见注释
// 定义一个静态方法用于获取指定包名下的所有类对象列表
private static ListClass? getClasses(String packageName) throws Exception {ListClass? classes new ArrayList(); // 初始化一个ArrayList用于存储找到的类对象// 将包名中的点.替换为文件路径中的斜杠/以构造资源路径String path packageName.replace(., /);// 获取当前线程的类加载器用于加载资源ClassLoader classLoader Thread.currentThread().getContextClassLoader();// 通过类加载器获取指定路径下的所有资源可能是目录或JAR文件中的条目EnumerationURL resources classLoader.getResources(path);// 遍历所有找到的资源while (resources.hasMoreElements()) {URL resource resources.nextElement(); // 获取下一个资源URL// 注意这里假设资源是一个文件系统上的目录但这不是总是正确的特别是当资源在JAR中时File directory new File(resource.toURI()); // 将资源URL转换为File对象这里存在潜在问题对于JAR文件不适用// 检查目录是否存在对于文件系统上的资源有效if (directory.exists()) {// 遍历目录下的所有文件和子目录for (File file : directory.listFiles()) {// 检查文件是否以.class结尾即是否是类文件.java文件经过编译后的.class文件if (file.getName().endsWith(.class)) {// 构造类的完整名称包括包名String className packageName . file.getName().replace(.class, );// 使用反射加载类并添加到类列表中// 注意这里可能会抛出ClassNotFoundException但在这个方法内部没有捕获处理classes.add(Class.forName(className));}}}}// 返回找到的类对象列表return classes;
}
二、搭建服务器端
在socket软件包的Server文件中编写 当存在客户端连接后获取
package com.qcby.tomcat.socket;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) 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 firstLineContext.split(\\n)[0];String pathfirstLine.split(\\s)[1];String methodfirstLine.split(\\s)[0];System.out.println(path method);}}//获取第一个词和第二个词
// public static void requestContext(InputStream inputStream) throws IOException {
// StringBuilder sb new StringBuilder();
// int ch;
// // 读取输入流直到遇到换行符或文件结束
// while ((ch inputStream.read()) ! -1) {
// if (ch \n) {
// break; // 遇到换行符停止读取
// }
// sb.append((char) ch); // 将读取的字符添加到StringBuilder中
// }
//
// String firstLine sb.toString().trim(); // 获取第一行并去除首尾空格
// if (firstLine.isEmpty()) {
// System.out.println(你输入了一个空请求);
// } else {
// String[] words firstLine.split(\\s); // 使用正则表达式按空格分割单词
// if (words.length 2) {
// System.out.println(第一个词是 words[0]);
// System.out.println(第二个词是 words[1].substring(1));
// } else {
// System.out.println(第一行没有足够的词);
// }
// }
// }}分析一下获取路径和请求方法的过程 String firstLine Context.split(\\n)[0]; 这行代码将 Context 字符串按照换行符\n进行分割并取出分割后的第一个元素即第一行赋值给 firstLine。String path firstLine.split(\\s)[1]; 接着这行代码将 firstLine 按照空白字符包括空格、制表符等\s 是一个正则表达式用于匹配任何空白字符进行分割并取出分割后的第二个元素索引为1赋值给 path。这里假设路径是 firstLine 中方法名后面的第一个元素。String method firstLine.split(\\s)[0]; 这行代码再次对 firstLine 按照空白字符进行分割并取出分割后的第一个元素索引为0赋值给 method。这里假设方法名是 firstLine 中的第一个元素。System.out.println(path method); 最后这行代码打印出 path 和 method 的值但顺序是先打印 path后打印 method中间用空格分隔。 三、搭建 【注接口--接口就是用来定义方法的实现接口类就必须实现接口中的方法
抽象类中可以有抽象方法也可以有具体方法抽象类实现了接口那么抽象类可以有选择性的实现接口中的方法】 重写service方法 HTTP请求 请求方法--Get,Post....等主要是Get\Post方式 而上述实现service方法就是为了获取请求方法并且判断是Get还是Post请求(然后将请求送到doGet()/doPost()方法中)
在HttpServlet包中的方法HttpServlet抽象类中重写service方法
首先创建request
public class Request {private String path;private String method;public String getPath() {return path;}public void setPath(String path) {this.path path;}public String getMethod() {return method;}public void setMethod(String method) {this.method method;}
}并且修改Server来得到path和method
import com.qcby.tomcat.Request.Request;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {//实例化Requestprivate static Request request new Request();public static void main(String[] args) 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);}}
即可通过这种方式让HttpServlet中的service方法得到Http请求的key和请求方法
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.socket.Server;public abstract class HttpServlet {/** 一定不能是抽象方法因为HttpServlet是要被实现的* 根据用户的请求来调用不用的方法去处理* GET请求 doGet()请求* POST请求 doPost()请求** *///重写service()方法public void service(Request request){//一定不能是抽象方法因为HttpServlet是要被实现的if(request.getMethod().equals(GET)){doGet(request);}else if(request.getMethod().equals(POST)){doPost(request);}}//去实现doGet--意味着所有继承HttpServlet抽象类的对象都要去实现这两个方法public abstract void doGet(Request request);//去实现doPostpublic abstract void doPost(Request request);}那么就意味着继承抽象类的实例必须实现抽象类中的方法 那么到这里一个基础的、连贯的tomcat雏形就存在了
四、Tomcat雏形 1.tomcat的server接收到一个请求
发送请求 2.被tomcat的server接收到 3.此时server内部创建了一个static的Request实例并被HttpServlet里面的service接收
通过if-else if判断后被送到对应的doGet或doPost方法 由于HttpServlet是抽象类所以所有继承这个抽象类的实例都要实现抽象类中的所有方法
类似 同时由于doGet()和doPost()方法都是抽象方法所以HttpServlet想要实现这些方法就要去到各自的实例中而这个实例究竟是哪一个则就对应path中存的路径了。
以上就是一个基础的雏形关于tomcat是如何接收并初步处理一个请求的